--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserverplugins/openwfc/src/openwfcwrapper.cpp Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,1171 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description: Owns, hides, and provides an interface to the OpenWFC compositor for use by the final (display) render stage.
+
+#include "openwfcwrapper.h"
+#include "panic.h"
+#include "utils.h"
+
+#include <WF/wfc.h>
+#include "elementwrapper.h"
+#include <graphics/compositionsurfaceupdate.h>
+#include <graphics/symbianstream.h>
+#include "openwfcpanics.h"
+#include "openwfcjobmanager.h"
+
+#include <graphics/eglsynchelper.h>
+
+#define KRgbaBlack 0x000000FF
+
+void Panic(TOpenWfcPanic aPanic)
+ {
+ _LIT(KPanic, "OpenWFC");
+ User::Panic(KPanic, aPanic);
+ }
+
+class COpenWfcWrapper::OffScreenComposeGuard
+ {
+ public:
+ OffScreenComposeGuard(TRequestStatus*& aRequestStatus);
+ void SetOffScreenNativeStream(WFCNativeStreamType aNativeStream);
+ void SetTargetNativeStream(WFCNativeStreamType aNativeStream);
+ void SetSync(EGLSyncKHR aSync, EGLDisplay aDpy);
+ void SetDeviceAndContext(WFCDevice aDevice, WFCContext aContext);
+ void Close();
+ void LogRequestStatusError(TInt aRequestStatusError);
+ private:
+ TRequestStatus*& iRequestStatus;
+ EGLSyncKHR iSync;
+ EGLDisplay iEGLDisplay;
+ WFCDevice iDevice;
+ WFCContext iContext;
+ TInt iRequestStatusError;
+ };
+
+COpenWfcWrapper::OffScreenComposeGuard::OffScreenComposeGuard(TRequestStatus*& aRequestStatus):
+iRequestStatus(aRequestStatus),
+iSync(EGL_NO_SYNC_KHR),
+iDevice(WFC_INVALID_HANDLE),
+iContext(WFC_INVALID_HANDLE),
+iRequestStatusError(KErrNone)
+ {}
+
+
+void COpenWfcWrapper::OffScreenComposeGuard::SetSync(EGLSyncKHR aSync, EGLDisplay aDpy)
+ {
+ iSync = aSync;
+ iEGLDisplay = aDpy;
+ }
+
+void COpenWfcWrapper::OffScreenComposeGuard::SetDeviceAndContext(WFCDevice aDevice, WFCContext aContext)
+ {
+ iContext = aContext;
+ iDevice = aDevice;
+ }
+
+void COpenWfcWrapper::OffScreenComposeGuard::LogRequestStatusError(TInt aRequestStatusError)
+ {
+ iRequestStatusError=aRequestStatusError;
+ }
+
+void COpenWfcWrapper::OffScreenComposeGuard::Close()
+ {
+ if (iContext != WFC_INVALID_HANDLE)
+ {
+ DestroyAllContextElements(iDevice, iContext);
+ wfcDestroyContext(iDevice, iContext);
+ }
+
+ if (iSync != EGL_NO_SYNC_KHR)
+ {
+ eglDestroySyncKHR(iEGLDisplay, iSync);
+ }
+
+ if (iRequestStatus)
+ {
+ User::RequestComplete(iRequestStatus, iRequestStatusError);
+ }
+ }
+
+TEMPLATE_SPECIALIZATION class RHashTableBase::Defaults<TSurfaceId, RHashTableBase::EDefaultSpecifier_Normal>
+ {
+public:
+ inline static TGeneralHashFunction32 Hash();
+ inline static TGeneralIdentityRelation Id();
+ };
+
+inline TGeneralHashFunction32 RHashTableBase::Defaults<TSurfaceId, RHashTableBase::EDefaultSpecifier_Normal>::Hash()
+ {return (TGeneralHashFunction32)&DefaultHash::Integer;}
+
+inline TGeneralIdentityRelation RHashTableBase::Defaults<TSurfaceId, RHashTableBase::EDefaultSpecifier_Normal>::Id()
+ {return (TGeneralIdentityRelation)&DefaultIdentity::Integer;}
+
+TUint32 COpenWfcWrapper::HashFunction(const TSurfaceId& aHashKey)
+ {
+ TPckgC<TSurfaceId> pckg(aHashKey);
+ return DefaultHash::Des8(pckg);
+ }
+COpenWfcWrapper* COpenWfcWrapper::NewL(TInt aScreenNo, CDisplayPolicy* aDisplayPolicy)
+ {
+ COpenWfcWrapper* wrapper = new (ELeave) COpenWfcWrapper(aDisplayPolicy);
+ CleanupStack::PushL(wrapper);
+ wrapper->ConstructL(aScreenNo);
+ CleanupStack::Pop(wrapper);
+ return wrapper;
+ }
+
+COpenWfcWrapper::COpenWfcWrapper(CDisplayPolicy* aDisplayPolicy)
+ : iUiSurface(TSurfaceId::CreateNullId()), iDisplayPolicy(aDisplayPolicy),
+ iSourceMap(THashFunction32<TSurfaceId>(COpenWfcWrapper::HashFunction), TIdentityRelation<TSurfaceId>()),
+ iDevice(WFC_INVALID_HANDLE),
+ iOnScreenContext(WFC_INVALID_HANDLE),
+ iScreenNumber(-1),
+ iJobManager(NULL),
+ iRotation(MWsScene::ESceneAntiClockwise0),
+ iAutonomousCompositionInitiated(EFalse)
+ {
+ }
+
+void COpenWfcWrapper::ConstructL(TInt aScreenId)
+ {
+ _LIT(KOpenWfcLog, "+ COpenWfcWrapper::ConstructL");
+ RDebug::Print(KOpenWfcLog);
+
+ iScreenNumber = aScreenId;
+ WFCint filterList[] = { WFC_DEVICE_FILTER_SCREEN_NUMBER, iScreenNumber, WFC_NONE};
+
+ iEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(iEGLDisplay, NULL, NULL);
+
+ WFCint dev = 0;
+ if ((wfcEnumerateDevices(&dev, 1, filterList) == 1) &&
+ (dev != WFC_INVALID_HANDLE))
+ {
+ // clean previous errors
+ wfcGetError(iDevice);
+
+ // Let's get the device handle, opening in the same time the device
+ iDevice = wfcCreateDevice(dev, NULL);
+ if (iDevice==NULL)
+ {
+ //Not enough information to deduce why the device could not be created. Report as memory failure
+ User::Leave(KErrNoMemory);
+ }
+ //Can't clean previous errors until we have a device, and the errors should be none if it created successfully.
+ OPENWFC_ASSERT_DEBUG(!wfcGetError(iDevice),EPanicWfcStartupErrorUnexpected);
+
+ iOnScreenContext = wfcCreateOnScreenContext(iDevice, iScreenNumber, NULL);
+ if (iOnScreenContext==NULL)
+ {
+ TInt err = wfcGetError(iDevice);
+ OPENWFC_ASSERT_DEBUG(err==WFC_ERROR_OUT_OF_MEMORY,EPanicWfcContextNotCreated);
+ User::Leave((err==WFC_ERROR_OUT_OF_MEMORY)?KErrNoMemory:KErrUnknown);
+ }
+
+ wfcSetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_ROTATION, WFC_ROTATION_0);
+ wfcSetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_BG_COLOR, KRgbaBlack);
+
+ iContextDisplayControl = NULL;
+
+ User::LeaveIfNull(iJobManager = COpenWfcJobManger::NewL(*this, iDevice, iOnScreenContext, iScreenNumber));
+ }
+ else
+ {
+ // we cannot continue because we cannot find a device for the given screenId
+ // Not enough information to get detailed error! Report as parameter not accepted.
+ User::Leave(KErrArgument);
+ }
+ iSurfaceManager.Open();
+
+ iSourceMap.Reserve(iInitialSourceMapSize);
+ }
+
+COpenWfcWrapper::~COpenWfcWrapper()
+ {
+ iUiElement1 = NULL;
+ iUiElement2 = NULL;
+ if(!iUiSurface.IsNull())
+ UnregisterSurface(iUiSurface);
+
+ if (iJobManager)
+ {
+ PauseComposition();
+ delete iJobManager;
+ }
+
+ //destroy all the elements, which should remove all the element references.
+ while (iCleanupElementList)
+ {
+ CElementWrapper* cleanupElement = iCleanupElementList;
+ delete cleanupElement;
+ OPENWFC_ASSERT_DEBUG(cleanupElement != iCleanupElementList,EPanicWfcElementNotRemovedOnShutdown);
+ if (cleanupElement == iCleanupElementList)
+ {
+ break; //can't keep cleaning up the same front item
+ }
+ }
+ THashMapIter<TSurfaceId, SourceAndRef> iter(iSourceMap);
+ const TSurfaceId* nextKey = iter.NextKey();
+ while (nextKey)
+ {
+ const SourceAndRef* pSource = NULL;
+ //destroy any remaining registered surfaces
+ pSource = iter.CurrentValue();
+ OPENWFC_ASSERT_DEBUG(pSource && pSource->elementRef == 0,EPanicWfcElementNotRemovedOnShutdown);
+ wfcDestroySource(iDevice,pSource->source);
+ nextKey = iter.NextKey();
+ }
+
+ iSourceMap.Close();
+ iSurfaceManager.Close();
+ eglTerminate(iEGLDisplay);
+
+ // Destroying the context should take care of any sources or masks
+ wfcDestroyContext(iDevice, iOnScreenContext);
+ wfcDestroyDevice(iDevice);
+ }
+
+class CBaseExtension: public CBase
+ {
+ public:
+ virtual TInt Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
+ { return CBase::Extension_(aExtensionId,a0,a1); }
+ };
+TInt COpenWfcWrapper::Extension_(TUint aExtensionId, TAny*& aRetPtr, TAny* aExtra)
+ {
+#ifndef _DEBUG
+ (void) aExtra;
+#endif
+
+ switch (aExtensionId)
+ {
+#ifdef _DEBUG
+ case EExtensionDebugBackendGuid:
+ return KErrNotSupported;
+ case EExtensionDebugContextGuid:
+ aRetPtr=(TAny*)OnScreenContext();
+ return KErrNone;
+ case EExtensionDebugDeviceGuid:
+ aRetPtr=(TAny*)Device();
+ return KErrNone;
+ case EExtensionDebugElementGuid:
+ if (aExtra)
+ {
+ CElementWrapper* newElement=static_cast<CElementWrapper*>(aExtra);
+ aRetPtr=(TAny*)newElement->Element();
+ return KErrNone;
+ }
+ else
+ {
+ return KErrBadHandle;
+ }
+ case EExtensionDebugSourceGuid:
+ if (aExtra)
+ {
+ TSurfaceId* surfId=static_cast<TSurfaceId*>(aExtra);
+ SourceAndRef* foundSourceAndRef=iSourceMap.Find(*surfId);
+ if (foundSourceAndRef)
+ {
+ aRetPtr=(TAny*)foundSourceAndRef->source;
+ return KErrNone;
+ }
+ else
+ {
+ return KErrNotFound;
+ }
+ }
+ else
+ {
+ return KErrBadHandle;
+ }
+#endif
+ case MCompositionSurfaceUpdate::ETypeId:
+ {
+ CBaseExtension* basePtr = NULL;
+ SymbianStreamHasRegisteredScreenNotifications(iScreenNumber,reinterpret_cast<void**>(&basePtr));
+ if (basePtr)
+ {
+ return basePtr->Extension_(MCompositionSurfaceUpdate::KUidCompositionSurfaceUpdate,aRetPtr,aExtra);
+ }
+ else
+ {
+ return KErrNotSupported;
+ }
+ }
+ case MWsDisplayControl::ETypeId:
+ if (iContextDisplayControl)
+ {
+ aRetPtr= static_cast<MWsDisplayControl*>(this);
+ return KErrNone;
+ }
+ else
+ {
+ return KErrNotSupported;
+ }
+ case MDisplayControlBase::ETypeId:
+ if (iContextDisplayControl)
+ {
+ aRetPtr= static_cast<MDisplayControlBase*>(this);
+ return KErrNone;
+ }
+ else
+ {
+ return KErrNotSupported;
+ }
+ default:
+ return KErrNotSupported;
+ }
+ }
+MWsElement* COpenWfcWrapper::CreateElementL()
+ {
+ CElementWrapper* element = CElementWrapper::NewL(*this,iCleanupElementList);
+ return element;
+ }
+
+void COpenWfcWrapper::DestroyElement(MWsElement* aElement)
+ {
+ if(aElement)
+ {
+ CElementWrapper* element=static_cast<CElementWrapper*>(aElement);
+ RemoveElementFromSceneList(element);
+ if (!(element->UpdateFlags()&CElementWrapper::EUpdate_SceneCommited))
+ {
+ delete element;
+ }
+ }
+ }
+
+void COpenWfcWrapper::Compose(TRequestStatus* aCompleted)
+ {
+ STD_ASSERT_DEBUG(CompositionDue(), EPluginPanicCompositionSequenceError);
+
+ OPENWFC_ASSERT_DEBUG(iJobManager, EPanicWfcThreadManagerNotInitialised);
+ if (!iAutonomousCompositionInitiated)
+ {
+ ResumeComposition();
+ }
+ iJobManager->ComposeRequest(aCompleted);
+
+ iCompositionModified = EFalse;
+ ResumeCompositorIfPaused();
+ }
+
+TSize COpenWfcWrapper::ScreenSize() const
+ {
+ // clean previous errors
+ #ifdef _DEBUG
+ (void)wfcGetError(iDevice);
+ #endif
+
+ TInt height = wfcGetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_TARGET_HEIGHT);
+ OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
+
+ TInt width = wfcGetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_TARGET_WIDTH);
+ OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
+
+ WFCint rotation = wfcGetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_ROTATION);
+ OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
+
+ return rotation == WFC_ROTATION_0 || rotation == WFC_ROTATION_180 ? TSize(width, height) : TSize(height, width);
+ }
+
+TInt COpenWfcWrapper::RegisterSurface (const TSurfaceId& aSurface)
+ {
+ // clean previous errors
+ wfcGetError(iDevice);
+ //check surface id not null
+ if (aSurface.IsNull())
+ {
+ return KErrArgument;
+ }
+
+ if (!IsValidSurface(aSurface))
+ {
+ return KErrBadHandle;
+ }
+
+ //look for surface being registered
+ SourceAndRef* sourceAndRef = iSourceMap.Find(aSurface);
+ if (sourceAndRef)
+ {
+ //if registered increase ref count and return
+ sourceAndRef->sourceRef++;
+ return KErrNone;
+ }
+
+ // Surface not currently registered so do so now.
+ // Initialise struct. Could be handled via. constructor.
+ SourceAndRef newSourceAndRef;
+ newSourceAndRef.source = NULL;
+ newSourceAndRef.sourceRef = 1; //Surface reference count
+ newSourceAndRef.elementRef = 0; //Element reference count
+
+ //No need to acquire stream as public NativeStream handle is TSurfaceId
+ WFCNativeStreamType stream = reinterpret_cast<WFCNativeStreamType>(&aSurface);
+
+ //create source
+ newSourceAndRef.source = wfcCreateSourceFromStream(iDevice,iOnScreenContext,stream,NULL);
+ //check for valid surface size should be performed by compositor in CreateSource.
+ if (newSourceAndRef.source == WFC_INVALID_HANDLE)
+ {
+ return TranslateOpenWfcError(wfcGetError(iDevice));
+ }
+ //add to list
+ TInt err = iSourceMap.Insert(aSurface,newSourceAndRef);
+ if (err != KErrNone)
+ {
+ wfcDestroySource(iDevice,newSourceAndRef.source);
+ return KErrNoMemory;
+ }
+
+ return KErrNone;
+ }
+
+TInt COpenWfcWrapper::UnregisterSurface (const TSurfaceId& aSurface)
+ {
+ //check surface id not null
+ if (aSurface.IsNull())
+ {
+ return KErrArgument;
+ }
+
+ if (!IsValidSurface(aSurface))
+ {
+ return KErrArgument;
+ }
+
+ SourceAndRef* sourceAndRef = iSourceMap.Find(aSurface);
+
+ if (sourceAndRef && sourceAndRef->sourceRef == 0)
+ {
+ sourceAndRef = NULL;
+ }
+ if (sourceAndRef)
+ {
+ if (sourceAndRef->sourceRef <= 1)
+ {
+ sourceAndRef->sourceRef = 0;
+
+ if (sourceAndRef->elementRef > 0)
+ {
+ //if elements are currently in use
+ return KErrInUse;
+ }
+ wfcDestroySource(iDevice,sourceAndRef->source); //removing source reference on the stream
+
+ //destroy entry
+ iSourceMap.Remove(aSurface);
+ return KErrNone;
+ }
+ sourceAndRef->sourceRef--;
+ return KErrNone;
+ }
+ return KErrBadHandle;
+ }
+
+TBool COpenWfcWrapper::IsValidSurface(const TSurfaceId& aSurface)
+ {
+ if (aSurface.Type() != TSurfaceId::EScreenSurface)
+ {
+ RSurfaceManager::TInfoBuf buff;
+ TInt err = SurfaceManager().SurfaceInfo(aSurface, buff);
+
+ if (err == KErrArgument)
+ {
+ return EFalse;
+ }
+ }
+ return ETrue;
+ }
+
+/**
+ * Finds the source for a registered surface ID and increments its "element" reference count
+ * @return registered source handle or WFC_INVALID_HANDLE if not registered
+ **/
+WFCSource COpenWfcWrapper::IncEltRefRegSource(const TSurfaceId& aHashKey)
+ {
+ SourceAndRef* foundSourceAndRef=iSourceMap.Find(aHashKey);
+ if (foundSourceAndRef && foundSourceAndRef->sourceRef)
+ { //still registered
+ foundSourceAndRef->elementRef++;
+ return foundSourceAndRef->source;
+ }
+ return WFC_INVALID_HANDLE;
+ }
+
+
+/**
+ * Finds the source for a registered surface ID and decrements the "element" reference count.
+ * If all counts are zero then the source is unregistered and the mapping removed
+ * @return positive if not destroyed, 0 if destroyed
+ * or KErrBadHandle if bad surface id or surface has no element reference count
+ **/
+TInt COpenWfcWrapper::DecEltRefRegSource(const TSurfaceId& aHashKey)
+ {
+ SourceAndRef* foundSourceAndRef=iSourceMap.Find(aHashKey);
+ if (foundSourceAndRef && foundSourceAndRef->elementRef>0)
+ {
+ TInt retRefs=((--foundSourceAndRef->elementRef)+foundSourceAndRef->sourceRef);
+ if (retRefs==0)
+ {
+ wfcDestroySource(iDevice,foundSourceAndRef->source);
+ iSourceMap.Remove(aHashKey);
+ }
+ return retRefs;
+ }
+ return KErrBadHandle;
+ }
+
+void COpenWfcWrapper::RemoveElement(MWsElement* aElement)
+ {
+ if (!aElement)
+ {
+ return;
+ }
+
+ CElementWrapper* removeElement = static_cast<CElementWrapper*>(aElement);
+
+ //the UI element is a special case since we set and maintain the surface
+ TUint32 renderStageFlags;
+ removeElement->GetRenderStageFlags(renderStageFlags);
+ if (renderStageFlags & MWsElement::EElementIsIndirectlyRenderedUserInterface ||
+ renderStageFlags & MWsElement::EElementIsDirectlyRenderedUserInterface)
+ {
+ if(removeElement == iUiElement1)
+ iUiElement1 = NULL;
+ else if(removeElement == iUiElement2)
+ iUiElement2 = NULL;
+ else
+ STD_ASSERT_DEBUG(EFalse, EPluginPanicNonMatchingRemovalOfUiElement);
+ }
+
+ RemoveElementFromSceneList(removeElement);
+ removeElement->InsertAfter(iRemoveElementList,NULL,CElementWrapper::EUpdate_Remove); //insert into remove element list!!!
+ SetCompositionModified();
+ }
+
+void COpenWfcWrapper::RemoveElementFromSceneList(CElementWrapper* aElement)
+ {
+ CElementWrapper** refFromElementBelow=NULL;
+ if (iSceneElementList==aElement)
+ {
+ refFromElementBelow=&iSceneElementList; //remove from bottom of scene
+ }
+ else if (iRemoveElementList==aElement)
+ {
+ refFromElementBelow=&iRemoveElementList;
+ }
+ else
+ {
+ refFromElementBelow=aElement->RefsMyElementBelow(); //remove from current mid-list position
+ }
+
+ aElement->RemoveAfter(refFromElementBelow);
+ }
+
+TInt COpenWfcWrapper::SetUiSurface(const TSurfaceId& aNewUiSurface)
+ {
+ TInt err = RegisterSurface(aNewUiSurface);
+ if (!err)
+ {
+ if(iUiElement1)
+ {
+ err = iUiElement1->ConnectSurface(aNewUiSurface);
+ STD_ASSERT_DEBUG(!err, EPluginPanicNewUiSurfaceUnsettable);
+ }
+ if(iUiElement2)
+ {
+ err = iUiElement2->ConnectSurface(aNewUiSurface);
+ STD_ASSERT_DEBUG(!err, EPluginPanicNewUiSurfaceUnsettable);
+ }
+ }
+
+ if(!err)
+ {
+ if(!iUiSurface.IsNull())
+ {
+ // This should not fail as the surface will no longer be used by any element
+ err = UnregisterSurface(iUiSurface);
+
+ if (err == KErrInUse) // This is not needed once openwf implementation is corrected:
+ // It should not return KErrInUse if it is only the backend holding onto it.
+ {
+ err = KErrNone;
+ }
+
+ STD_ASSERT_DEBUG(!err, EPluginPanicPreviousUiSurfaceUnregisterable);
+ }
+
+ iUiSurface = aNewUiSurface;
+ }
+ return err;
+ }
+
+TInt COpenWfcWrapper::AddElement(MWsElement* aElement, MWsElement* aAbove)
+ {
+ TInt err = KErrNone;
+ CElementWrapper* addedElement = static_cast<CElementWrapper*>(aElement);
+ CElementWrapper* insertAboveThisElement = static_cast<CElementWrapper*>(aAbove);
+
+ if (aElement == aAbove)
+ {
+ return KErrArgument;
+ }
+
+ if (addedElement == NULL || &addedElement->Owner()!=this ||
+ (insertAboveThisElement && &insertAboveThisElement->Owner()!=this) ||
+ (addedElement->UpdateFlags() & CElementWrapper::EUpdate_Destroy))
+ {
+ return KErrArgument;
+ }
+
+ if (insertAboveThisElement &&
+ ((!insertAboveThisElement->RefsMyElementBelow() && iSceneElementList != insertAboveThisElement) ||
+ (insertAboveThisElement->UpdateFlags() & (CElementWrapper::EUpdate_Remove | CElementWrapper::EUpdate_Destroy))))
+ {
+ return KErrArgument;
+ }
+
+ //the UI element is a special case since we set and maintain the surface
+ TUint32 renderStageFlags;
+ addedElement->GetRenderStageFlags(renderStageFlags);
+ if (renderStageFlags & MWsElement::EElementIsIndirectlyRenderedUserInterface ||
+ renderStageFlags & MWsElement::EElementIsDirectlyRenderedUserInterface)
+ {
+ err = AttachSurfaceToUiElement(addedElement);
+ }
+
+ if(!err)
+ {
+ //figure out which element to add the element above
+ const TSurfaceId& newSurf = addedElement->ConnectedSurface();
+ if (!addedElement->ConnectedSurface().IsNull())
+ {
+ //is surface registered
+ WFCSource newSource = IncEltRefRegSource(newSurf);
+ if (newSource == WFC_INVALID_HANDLE)
+ { //suggests the surface was not registered
+ return KErrArgument;
+ }
+ DecEltRefRegSource(newSurf); //only need to decrement if it found a source
+ }
+
+ RemoveElementFromSceneList(addedElement);
+
+ // figure out which element to add it below
+ CElementWrapper** insertBelowThisElement = NULL;
+ if (insertAboveThisElement)
+ {
+ insertBelowThisElement=&insertAboveThisElement->MyElementAbove();
+ }
+ else
+ {
+ insertBelowThisElement=&iSceneElementList;
+ }
+
+ addedElement->InsertAfter(*insertBelowThisElement,insertAboveThisElement,CElementWrapper::EUpdate_Insert);
+
+ SetCompositionModified();
+ }
+
+ return err;
+ }
+
+void COpenWfcWrapper::Compose(const TSurfaceId& aOffScreenTarget, TRequestStatus* aCompleted)
+ {
+ if (aOffScreenTarget.IsNull())
+ {
+ if (aCompleted)
+ {
+ User::RequestComplete(aCompleted, KErrNone);
+ return;
+ }
+ }
+ ComposeInternal(aOffScreenTarget,TPoint(0,0),iSceneElementList,NULL,aCompleted);
+ }
+
+void COpenWfcWrapper::Compose(const TSurfaceId& aOffScreenTarget, const TPoint& aOrigin,
+ MWsElement* aStart, MWsElement* aEnd, TRequestStatus* aCompleted)
+ {
+ if (aOffScreenTarget.IsNull())
+ {
+ if (aCompleted)
+ {
+ User::RequestComplete(aCompleted, KErrNone);
+ return;
+ }
+ }
+
+ CElementWrapper* startElement=static_cast<CElementWrapper*>(aStart);
+ CElementWrapper* endElement=static_cast<CElementWrapper*>(aEnd);
+
+ if (startElement)
+ {
+ if ( &startElement->Owner()!=this
+ || (startElement!=iSceneElementList && !startElement->ElementBelow())
+ || (startElement->UpdateFlags() & (startElement->EUpdate_Remove|startElement->EUpdate_Destroy))
+ )
+ {
+ if (aCompleted)
+ {
+ RThread().RequestComplete(aCompleted, KErrArgument);
+ }
+ return;
+ }
+ if (endElement)
+ { //If endElement is NULL then draw to end else draw including the specified endElement
+ TBool fail=EFalse;
+ if ( &endElement->Owner()!=this
+ || (endElement->UpdateFlags() & (endElement->EUpdate_Remove|endElement->EUpdate_Destroy))
+ )
+ {
+ fail=ETrue;
+ }
+ else
+ {
+ for (CElementWrapper* sceneElement=startElement;sceneElement!=endElement;sceneElement=sceneElement->MyElementAbove())
+ {
+ if (sceneElement==NULL)
+ {
+ fail=ETrue;
+ break;
+ }
+ }
+ }
+ if (fail)
+ {
+ if (aCompleted)
+ {
+ RThread().RequestComplete(aCompleted, KErrArgument);
+ }
+ return;
+ }
+ aEnd=aEnd->ElementAbove(); //now scene does NOT include endElement. May now be NULL!
+ }
+ }
+ else
+ {
+ aEnd=NULL;
+ }
+ ComposeInternal(aOffScreenTarget,aOrigin,aStart,aEnd,aCompleted);
+ }
+
+/** Internal compose does not check some errors.
+ * They should have already been checked by the public API caller.
+ * NOTE element aEnd is NOT composed by this internal method!
+ * Any elements pending removal will not be displayed (including aStart and aEnd.
+ *
+ * @param aOffScreenTarget A valid surface for offscreen composition.
+ * @param aOrigin The origin sets where the top-left corner of the
+ * surface is within the element coordinate system.
+ * @param aStart The starting element of the elements to be composed.
+ * @param aEnd The element above the last element to be composed (or NULL).
+ * @param aCompleted NULL or request status that will be set to KErrNone when
+ * the composition finishes.
+ **/
+void COpenWfcWrapper::ComposeInternal (const TSurfaceId& aOffScreenTarget,
+ const TPoint& aOrigin,
+ MWsElement* aStart,
+ MWsElement* aEnd,
+ TRequestStatus* aCompleted)
+ {
+ // Initial approach reuses the device but it may be more safer to create, and destroy, its own device
+ CElementWrapper* startElement=static_cast<CElementWrapper*>(aStart);
+ CElementWrapper* endElement=static_cast<CElementWrapper*>(aEnd);
+
+ TInt err = KErrNone;
+#ifdef _DEBUG
+ // clean previous errors
+ wfcGetError(iDevice);
+#endif
+
+ if (aCompleted)
+ {
+ *aCompleted = KRequestPending;
+ }
+
+ OffScreenComposeGuard composeGuard(aCompleted);
+
+ WFCNativeStreamType stream=reinterpret_cast<WFCNativeStreamType>(&aOffScreenTarget);
+
+ RSurfaceManager::TInfoBuf buff;
+ err=SurfaceManager().SurfaceInfo(aOffScreenTarget,buff);
+ OPENWFC_ASSERT_DEBUG(err==KErrNone,TOpenWfcPanic(__LINE__));
+ if (err!=KErrNone || buff().iSize.iWidth ==0 || buff().iSize.iHeight == 0)
+ {
+ composeGuard.LogRequestStatusError(KErrArgument);
+ composeGuard.Close();
+ return;
+ }
+
+ // Create the native stream target
+ TSurfaceId targetSurfaceId = TSurfaceId::CreateNullId();
+ WFCNativeStreamType targetStream = WFC_INVALID_HANDLE;
+ OPENWFC_ASSERT_DEBUG(wfcGetError(iDevice)==WFC_ERROR_NONE,(TOpenWfcPanic)__LINE__);
+
+ targetSurfaceId = aOffScreenTarget;
+ targetStream = stream;
+
+ EGLint attrib_list[1] = {EGL_NONE };
+
+ EGLSyncKHR sync = eglCreateSyncKHR(iEGLDisplay,
+ EGL_SYNC_REUSABLE_KHR,
+ attrib_list);
+
+ if (sync == EGL_NO_SYNC_KHR)
+ {
+ composeGuard.LogRequestStatusError(KErrNoMemory);
+ composeGuard.Close();
+ return;
+ }
+ composeGuard.SetSync(sync, iEGLDisplay);
+
+ // Now, that we have the target surface stream we can create the temporary context
+ WFCContext offScreenContext = wfcCreateOffScreenContext(iDevice, targetStream, NULL);
+
+ if (offScreenContext == WFC_INVALID_HANDLE)
+ {
+ composeGuard.LogRequestStatusError(TranslateOpenWfcError(wfcGetError(iDevice)));
+ composeGuard.Close();
+ return;
+ }
+
+ composeGuard.SetDeviceAndContext(iDevice, offScreenContext);
+
+ TInt contextBackGroundColour = wfcGetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_BG_COLOR);
+ wfcSetContextAttribi(iDevice, offScreenContext, WFC_CONTEXT_BG_COLOR, contextBackGroundColour);
+ OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
+
+ TPoint elementOffset(-aOrigin.iX,-aOrigin.iY);
+ // let's replicate the scene to the offscreen context
+ WFCElement previousTargetElement = WFC_INVALID_HANDLE;
+ for (CElementWrapper* elementScene = startElement; elementScene !=endElement; elementScene = elementScene->MyElementAbove())
+ {
+ if (!(elementScene->UpdateFlags()&(elementScene->EUpdate_Destroy|elementScene->EUpdate_Remove)))
+ {
+ // we do our best to replicate the elements
+ TInt err=elementScene->ReplicateElements(offScreenContext, previousTargetElement,elementOffset);
+ if (err)
+ {
+ composeGuard.LogRequestStatusError(err);
+ composeGuard.Close();
+ return;
+ }
+ }
+ }
+
+ // let's compose
+ wfcCommit(iDevice, offScreenContext, WFC_TRUE);
+ wfcCompose(iDevice, offScreenContext, WFC_TRUE);
+ wfcFence(iDevice, offScreenContext, iEGLDisplay, sync);
+ EGLTimeKHR timeout = (EGLTimeKHR) EGL_FOREVER_KHR;
+ OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
+ eglClientWaitSyncKHR(iEGLDisplay, sync, 0, timeout);
+
+ composeGuard.Close();
+ }
+
+void COpenWfcWrapper::PauseComposition (void)
+ {
+
+ OPENWFC_ASSERT_DEBUG(iJobManager, EPanicWfcThreadManagerNotInitialised);
+ iAutonomousCompositionInitiated = ETrue;
+ iJobManager->CompositionPauseRequest();
+ }
+
+void COpenWfcWrapper::ResumeComposition (void)
+ {
+ OPENWFC_ASSERT_DEBUG(iJobManager, EPanicWfcThreadManagerNotInitialised);
+ iAutonomousCompositionInitiated = ETrue;
+ iJobManager->CompositionResumeRequest();
+ }
+
+TBitFlags32 COpenWfcWrapper::SupportedScreenRotations() const
+ {
+ TBitFlags32 result;
+ // we DO support, by default, all these rotations
+ result.Set(MWsScene::ESceneAntiClockwise0);
+ result.Set(MWsScene::ESceneAntiClockwise90);
+ result.Set(MWsScene::ESceneAntiClockwise180);
+ result.Set(MWsScene::ESceneAntiClockwise270);
+ return result;
+ }
+
+void COpenWfcWrapper::SetScreenRotation(MWsScene::TSceneRotation aRotation)
+ {
+#ifdef _DEBUG
+ // clean previous errors
+ (void)wfcGetError(iDevice);
+#endif
+
+ if (aRotation != iRotation)
+ {
+ WFCRotation wfcRotation = WFC_ROTATION_0;
+ switch (aRotation)
+ {
+ case MWsScene::ESceneAntiClockwise90:
+ wfcRotation = WFC_ROTATION_90;
+ break;
+ case MWsScene::ESceneAntiClockwise180:
+ wfcRotation = WFC_ROTATION_180;
+ break;
+ case MWsScene::ESceneAntiClockwise270:
+ wfcRotation = WFC_ROTATION_270;
+ break;
+ default:
+ wfcRotation = WFC_ROTATION_0;
+ break;
+ }
+ iRotation = aRotation;
+ wfcSetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_ROTATION, wfcRotation);
+ OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
+ }
+
+ SetCompositionModified();
+ }
+
+TInt COpenWfcWrapper::SetConfiguration(const TDisplayConfiguration& aConfig)
+ {
+ return iContextDisplayControl->SetConfiguration (aConfig);
+ }
+
+MWsScene::TSceneRotation COpenWfcWrapper::ScreenRotation() const
+ {
+#ifdef _DEBUG
+ // clean previous errors
+ (void)wfcGetError(iDevice);
+#endif
+ WFCint result = wfcGetContextAttribi(iDevice, iOnScreenContext, WFC_CONTEXT_ROTATION);
+ OPENWFC_ASSERT_DEBUG(TranslateOpenWfcError(wfcGetError(iDevice)) == KErrNone, EPanicWfcBadAttribute);
+ MWsScene::TSceneRotation rotation = MWsScene::ESceneAntiClockwise0;
+ switch (result)
+ {
+ case WFC_ROTATION_90:
+ rotation = MWsScene::ESceneAntiClockwise90;
+ break;
+ case WFC_ROTATION_180:
+ rotation = MWsScene::ESceneAntiClockwise180;
+ break;
+ case WFC_ROTATION_270:
+ rotation = MWsScene::ESceneAntiClockwise270;
+ break;
+ case WFC_ROTATION_0:
+ default:
+ OPENWFC_ASSERT_DEBUG(result==WFC_ROTATION_0,(TOpenWfcPanic)__LINE__);
+ rotation = MWsScene::ESceneAntiClockwise0;
+ break;
+ }
+
+ return rotation;
+ }
+
+TInt COpenWfcWrapper::NumberOfResolutions()const
+ {
+ if (iContextDisplayControl)
+ {
+ return iContextDisplayControl->NumberOfResolutions();
+ }
+ return KErrNotSupported;
+ }
+
+TInt COpenWfcWrapper::GetResolutions(RArray<TResolution>& aResolutions)const
+ {
+ if (iContextDisplayControl)
+ {
+ return iContextDisplayControl->GetResolutions(aResolutions);
+ }
+ return KErrNotSupported;
+ }
+
+void COpenWfcWrapper::GetConfiguration(TDisplayConfiguration& aConfig)const
+ {
+ if (iContextDisplayControl)
+ {
+ iContextDisplayControl->GetConfiguration (aConfig);
+ }
+ }
+
+TInt COpenWfcWrapper::PreferredDisplayVersion() const
+ {
+ if (iContextDisplayControl)
+ {
+ return iContextDisplayControl->PreferredDisplayVersion();
+ }
+ return KErrNotSupported;
+ }
+
+void COpenWfcWrapper::NotifyOnDisplayChange(TRequestStatus& aStatus)
+ {
+ // Stub for future implementation.
+ TRequestStatus *status = &aStatus;
+ RThread().RequestComplete(status, KErrNotSupported);
+ }
+
+void COpenWfcWrapper::NotifyOnDisplayChangeCancel()
+ {
+ // Stub for future implementation.
+ }
+
+void COpenWfcWrapper::NotifyOnConfigChange(TRequestStatus& aStatus)
+ {
+ // Stub for future implementation.
+ TRequestStatus *status = &aStatus;
+ RThread().RequestComplete(status, KErrNotSupported);
+ }
+
+void COpenWfcWrapper::NotifyOnConfigChangeCancel()
+ {
+ // Stub for future implementation.
+ }
+
+
+void COpenWfcWrapper::FlushSceneElementChanges()
+ {
+ while (CElementWrapper* curr = iRemoveElementList)
+ {
+ curr->FlushSceneChanges();
+ RemoveElementFromSceneList(curr);
+ if (curr->UpdateFlags() & CElementWrapper::EUpdate_Destroy)
+ {
+ delete curr;
+ }
+ }
+ iRemoveElementList=NULL;
+ if (CElementWrapper* curr=iSceneElementList)
+ {
+ for (CElementWrapper*next=curr->MyElementAbove(); curr; curr=next,next=curr?curr->MyElementAbove():NULL)
+ {
+ curr->FlushSceneChanges();
+ }
+ }
+ }
+
+TInt COpenWfcWrapper::TranslateOpenWfcError(WFCErrorCode error)
+ {
+ switch (error)
+ {
+ case WFC_ERROR_NONE:
+ return KErrNone;
+ case WFC_ERROR_OUT_OF_MEMORY:
+ return KErrNoMemory;
+ case WFC_ERROR_ILLEGAL_ARGUMENT:
+ return KErrArgument;
+ case WFC_ERROR_BAD_ATTRIBUTE:
+ return KErrArgument;
+ case WFC_ERROR_BAD_DEVICE:
+ return KErrArgument;
+ case WFC_ERROR_UNSUPPORTED:
+ return KErrNotSupported;
+ case WFC_ERROR_IN_USE:
+ return KErrInUse;
+ case WFC_ERROR_BUSY:
+ return KErrServerBusy;
+ case WFC_ERROR_BAD_HANDLE:
+ return KErrBadHandle;
+ case WFC_ERROR_INCONSISTENCY:
+ return KErrGeneral;
+ case WFC_ERROR_FORCE_32BIT:
+ // intentional fall through
+ default:
+ return KErrUnknown;
+ }
+ }
+
+void COpenWfcWrapper::DestroyAllContextElements(WFCDevice dev, WFCContext ctx)
+ {
+ // we try our best to destroy all elements of the specified context
+ if (dev != WFC_INVALID_HANDLE && ctx != WFC_INVALID_HANDLE)
+ {
+ WFCElement element = wfcGetContextAttribi(dev, ctx, WFC_CONTEXT_LOWEST_ELEMENT);
+ if (element != WFC_INVALID_HANDLE)
+ {
+ wfcDestroyElement(dev, element);
+ }
+ }
+ }
+
+void COpenWfcWrapper::PauseCompositorIfNeeded()
+ {
+ if (!iPaused && iAllowCompositorPause && iWithinBeginEnd)
+ {
+ PauseComposition();
+ iPaused = ETrue;
+ }
+ }
+
+/**
+Sets the system state for modified scene composition.
+ - Pause OpenWF composition if the standard render stage is within a begin/end block.
+ - If not within a pause/end block then set a flag to indicate that the scene composition
+ has been modified. On entering the begin/end block composition will be paused appropriatly.
+*/
+void COpenWfcWrapper::SetCompositionModified()
+ {
+ PauseCompositorIfNeeded();
+ iCompositionModified = ETrue;
+ }
+
+void COpenWfcWrapper::ResumeCompositorIfPaused()
+ {
+ if (iPaused)
+ ResumeComposition();
+ iPaused = EFalse;
+ }
+
+void COpenWfcWrapper::Begin(const TRegion* aRegion)
+ {
+ iWithinBeginEnd = ETrue;
+ iAllowCompositorPause = (aRegion && !aRegion->IsEmpty());
+
+ if (iCompositionModified)
+ PauseCompositorIfNeeded();
+ }
+
+TBool COpenWfcWrapper::CompositionDue()
+ {
+ return (iWithinBeginEnd && iCompositionModified);
+ }
+
+void COpenWfcWrapper::End()
+ {
+ iWithinBeginEnd = EFalse;
+ }
+
+TInt COpenWfcWrapper::FlushedSetConfiguration(const TDisplayConfiguration& /*aConfig*/)
+ {
+ OPENWFC_ASSERT_DEBUG(0, EPanicMethodNotImplemented);
+ TInt retval=KErrNone;
+ if (retval<=KErrNone)
+ {
+ SetCompositionModified();
+ }
+ return retval;
+ }
+
+CDisplayPolicy* COpenWfcWrapper::DisplayPolicy()
+ {
+ return iDisplayPolicy;
+ }
+
+TInt COpenWfcWrapper::AttachSurfaceToUiElement(CElementWrapper* aNewUiElement)
+ {
+ STD_ASSERT_DEBUG(!iUiSurface.IsNull(), EPluginPanicUiSurfaceIsNull);
+ if(iUiElement1 == NULL || iUiElement1 == aNewUiElement)
+ iUiElement1 = aNewUiElement;
+ else if(iUiElement2 == NULL || iUiElement2 == aNewUiElement)
+ iUiElement2 = aNewUiElement;
+ else
+ STD_ASSERT_DEBUG(EFalse, EPluginPanicDuplicateUiElement);
+
+ return aNewUiElement->ConnectSurface(iUiSurface);
+ }