windowing/windowserverplugins/openwfc/src/openwfcwrapper.cpp
author William Roberts <williamr@symbian.org>
Thu, 03 Jun 2010 17:39:46 +0100
branchNewGraphicsArchitecture
changeset 87 0709f76d91e5
parent 18 5e30ef2e26cb
child 45 36b2e23a8629
child 140 13a436a0995b
permissions -rw-r--r--
Add MMP files to build libOpenVG_sw.lib which uses LINKAS to redirect to libOpenVG.dll (and the same for libEGL_sw.lib and libOpenVGU_sw.lib). Only the libEGL_sw.lib redirection isn't activated - this can't happen until there is a merged libEGL.dll which supports the OpenWF synchronisation and also implements the graphical support functions. The overall aim is to eliminate the *_sw.dll implementations, at least as a compile-time way of choosing a software-only implementation.The correct way to choose is to put the right set of libraries into a ROM with suitable renaming, and in the emulator to use the "switching DLL" technique to pick the right set. As the Symbian Foundation doesn't have any alternative implementations, we don't need the switching DLLs and we can build directly to the correct name.

// 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)
	{
#ifdef _DEBUG
    _LIT(KOpenWfcLog, "+ COpenWfcWrapper::ConstructL");
    RDebug::Print(KOpenWfcLog);
#endif

    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);
	}