--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nga/SERVER/openwfc/windowelementset.cpp Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,2004 @@
+// Copyright (c) 2006-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:
+//
+
+#include <e32std.h>
+#include "cliwin.h"
+#include "server.h"
+#include "windowelementset.h"
+#include "regionextend.h"
+#include <graphics/wsscene.h>
+#include <graphics/wsgraphicdrawer.h>
+#include "panics.h"
+#include "wstop.h"
+
+#include "EVENT.H"
+
+#ifndef KCacheListGranularity
+ enum {KCacheListGranularity = 8};
+#endif
+#ifndef KCacheExtensionReserve
+ enum {KCacheExtensionReserve = 1};
+#endif
+
+
+
+/** Element to gc rotation function
+*/
+LOCAL_C inline CFbsBitGc::TGraphicsOrientation ElementToGcRotation(MWsElement::TElementRotation aElementRotation)
+ {
+ CFbsBitGc::TGraphicsOrientation gcRotation = CFbsBitGc::EGraphicsOrientationNormal;
+
+ switch (aElementRotation)
+ {
+ case MWsElement::EElementAntiClockwise90:
+ gcRotation = CFbsBitGc::EGraphicsOrientationRotated90;
+ break;
+ case MWsElement::EElementAntiClockwise180:
+ gcRotation = CFbsBitGc::EGraphicsOrientationRotated180;
+ break;
+ case MWsElement::EElementAntiClockwise270:
+ gcRotation = CFbsBitGc::EGraphicsOrientationRotated270;
+ break;
+ default:
+ break;
+ }
+ return gcRotation;
+ }
+
+//
+// CWindowElement
+//
+
+CWindowElement::CWindowElement(const CWsClientWindow& aWindow) :
+ iWindow(aWindow), iCache(KCacheListGranularity), iHighestReusedIndex(-1)
+ {}
+
+
+/** Finds all elements within the window that overlap with the region and
+marks them as unassigned.
+If any part of these unassigned elements are outside the region, they are also
+marked overlapping and locked config.
+
+@param aRegion The region that is being redrawn.
+@return KErrNone on success or KErrNoMemory if critical calculations could not be made.
+
+@see CWindowElementSet::UnassignPlacedElements
+**/
+TInt CWindowElement::UnassignPlacedElements(const TRegion& aRegion,TInt aGcDrawingCount)
+ {
+ iFlags = 0; //reset flags
+ iStartGcDrawingCount = aGcDrawingCount; //Detect any drawing between calls
+ iBackgroundElement.SetDrawnOverLast(iBackgroundElement.DrawnOver());
+ iNonRedrawVisibleRegion.Clear();
+ iNonRedrawVisibleRegion.Copy(const_cast<CWsClientWindow&>(iWindow).VisibleRegion());
+ iNonRedrawVisibleRegion.SubRegion(aRegion);
+ if (iNonRedrawVisibleRegion.CheckError())
+ { //memory error. Still needs to cope if whole window is being redrawn
+ iNonRedrawVisibleRegion.Clear();
+ TInt fullWindowRedraw = TRegionExtend::Cast(aRegion).TestDifference(const_cast<CWsClientWindow&>(iWindow).VisibleRegion());
+ if (fullWindowRedraw != 0)
+ { //not a full window redraw, return immediately
+ return KErrNoMemory;
+ }
+ }
+ TInt placedElements = iPlacedElements.Count();
+ TInt unassignedCount = 0;
+ TInt ii;
+ TBool cacheError = EFalse;
+
+ STACK_REGION tempSurfaceBaseArea;
+ if (iCache.Reserve(placedElements + KCacheExtensionReserve) < KErrNone) //quite often there may need to be room for more
+ { //failed to reserve space
+ cacheError = ETrue;
+ }
+ TRect tempExtent;
+ TRect tempIntersect;
+
+ for (ii=0; ii<placedElements; ii++)
+ {
+ if (!cacheError)
+ { //cache is ok up to this point but does not contain cache for this element yet
+ RRegion newRegion;
+ if (iCache.Append(newRegion) < KErrNone)
+ {
+ cacheError = ETrue;
+ }
+ newRegion.Close();
+ }
+
+ iPlacedElements[ii].iElement->GetDestinationRectangle(tempExtent);
+ TInt regionReturn = TRegionExtend::Cast(aRegion).TestDifference(tempExtent);
+ iPlacedElements[ii].SetDrawnOverLast(iPlacedElements[ii].DrawnOver()); //allows detection of change of state
+ if (!(regionReturn&TRegionExtend::ENoIntersect))
+ { //redraw region intersects with element
+ iPlacedElements[ii].SetUnassigned();
+ iPlacedElements[ii].SetDrawnOver(EFalse);
+ unassignedCount++;
+
+ if (!(regionReturn&TRegionExtend::EAdd))
+ { //surface is entirely within the redraw region
+ iPlacedElements[ii].SetOverlapping(EFalse);
+ iPlacedElements[ii].SetLockedConfig(EFalse);
+ if(!cacheError)
+ {
+ TRect destinationRect;
+ tempSurfaceBaseArea.Clear();
+ iPlacedElements[ii].iElement->GetDestinationRectangle(destinationRect);
+ tempSurfaceBaseArea.AddRect(destinationRect);
+ if (!tempSurfaceBaseArea.CheckError())
+ {
+ tempSurfaceBaseArea.Offset(tempExtent.iTl); //cache needs to be in absolute coords
+ iCache[ii].Copy(tempSurfaceBaseArea);
+ }
+ if (tempSurfaceBaseArea.CheckError() || iCache[ii].CheckError())
+ { //cache is no good from this point onwards
+ iCache[ii].Close();
+ iCache.Remove(ii);
+ cacheError = ETrue;
+ }
+ }
+ }
+ else
+ {
+ TRect destinationRect;
+ tempSurfaceBaseArea.Clear();
+ iPlacedElements[ii].iElement->GetDestinationRectangle(destinationRect);
+ tempSurfaceBaseArea.AddRect(destinationRect);
+ if (tempSurfaceBaseArea.CheckError())
+ { //critical failure, clear cache and return error
+ for (ii=iCache.Count(); ii>0; ii--)
+ {
+ iCache[ii-1].Close();
+ iCache.Remove(ii-1);
+ }
+ iCache.Reset();
+ iNonRedrawVisibleRegion.Close();
+ tempSurfaceBaseArea.Close();
+ return KErrNoMemory;
+ }
+ else
+ {
+ tempSurfaceBaseArea.Offset(tempExtent.iTl); //change to absolute coordinates
+ regionReturn = TRegionExtend::Cast(iNonRedrawVisibleRegion ).TestDifference(tempSurfaceBaseArea);
+ if (regionReturn&TRegionExtend::ENoIntersect)
+ { //element base area entirely inside redraw region
+ iPlacedElements[ii].SetOverlapping(EFalse);
+ iPlacedElements[ii].SetLockedConfig(EFalse);
+ }
+ else
+ { //element base area is at least partly within non redraw visible region
+ iPlacedElements[ii].SetOverlapping(ETrue);
+ iPlacedElements[ii].SetLockedConfig(ETrue);
+ }
+ if(!cacheError)
+ {
+ iCache[ii].Copy(tempSurfaceBaseArea);
+ if (iCache[ii].CheckError())
+ { //cache is no good from this point onwards
+ iCache[ii].Close();
+ iCache.Remove(ii);
+ cacheError = ETrue;
+ }
+ }
+ }
+ }
+ }
+ else
+ { //element does not intersect with redraw region
+ iPlacedElements[ii].SetUnassigned(EFalse);
+ }
+ }
+ tempSurfaceBaseArea.Close();
+
+ if (iRemovedSurfaces.Reserve(unassignedCount) == KErrNone)
+ {
+ iRemovedSurfacesValid = ETrue;
+ }
+ else
+ {
+ iRemovedSurfacesValid = EFalse;
+ }
+ return KErrNone;
+ }
+
+/** Marks all elements that have been assigned since the unassign as drawn over.
+
+@see CWindowElementSet::FlagAssignedElementsDrawnOver
+**/
+void CWindowElement::FlagAssignedElementsDrawnOver(TInt aGcDrawingCount)
+ {
+ iStartGcDrawingCount = aGcDrawingCount;
+ if (iBackgroundElement.iElement)
+ {
+ iBackgroundElement.SetDrawnOver();
+ }
+ TInt placedElementCount = iPlacedElements.Count();
+ for (TInt ii = 0; ii < placedElementCount; ii++)
+ {
+ if(!iPlacedElements[ii].Unassigned() && iPlacedElements[ii].LockedConfig())
+ {
+ iPlacedElements[ii].SetDrawnOver();
+ }
+ else if(iPlacedElements[ii].Unassigned() && iPlacedElements[ii].LockedConfig() &&
+ !iPlacedElements[ii].ChangedClip() && iPlacedElements[ii].Overlapping())
+ {
+ iPlacedElements[ii].SetDrawnOver();
+ }
+ }
+ }
+
+/** Checks whether a elements configuration is the same as that of the surface configuration, taking
+into account the stateflags (TPlacedAttributes) passed in.
+It must match surfaceId and extent.
+If it is a locked config it will need to match viewport and orientation as well.
+
+@param aElement Element to compare against.
+@param aSurfaceConfiguration Configuration to compare.
+@param aStateFlags The TPlacedAttributes flags for the element.
+@return ETrue if a match, otherwise EFalse.
+*/
+TBool CWindowElement::IsElementAMatch(MWsElement& aElement, const TSurfaceConfiguration& aSurfaceConfiguration,
+ TInt aStateFlags)
+ {
+ TBool match = EFalse;
+
+ TRect tempElementExtent;
+ TRect tempCRPExtent;
+ aElement.GetDestinationRectangle(tempElementExtent);
+ aSurfaceConfiguration.GetExtent(tempCRPExtent);
+ if (tempElementExtent == tempCRPExtent)
+ {
+ TSurfaceId tempElementSurfaceId;
+ TSurfaceId tempCRPSurfaceId;
+ aSurfaceConfiguration.GetSurfaceId(tempElementSurfaceId);
+ tempCRPSurfaceId = aElement.ConnectedSurface();
+ if (tempElementSurfaceId == tempCRPSurfaceId)
+ {
+ match = ETrue;
+ if (aStateFlags&TPlacedAttributes::ELockedConfig)
+ {
+ match = EFalse;
+ TBool orientationOK = EFalse;
+ TRect tempCRPViewport;
+ aSurfaceConfiguration.GetViewport(tempCRPViewport);
+ //if explicit viewport flagged
+ TRect tempElementViewport;
+ aElement.GetSourceRectangle(tempElementViewport);
+ if (tempElementViewport == tempCRPViewport)
+ {
+ CFbsBitGc::TGraphicsOrientation tempElementOrientation;
+ MWsElement::TElementRotation tempCRPRotation;
+ CFbsBitGc::TGraphicsOrientation tempCRPOrientation;
+ tempElementOrientation = aSurfaceConfiguration.Orientation();
+ tempCRPRotation = aElement.SourceRotation();
+ tempCRPOrientation = ElementToGcRotation(tempCRPRotation); //convert to common type
+ if (tempElementOrientation == tempCRPOrientation)
+ {
+ orientationOK = ETrue;
+ }
+ }
+ if(orientationOK)
+ {
+ TBool tempElementFlip = aSurfaceConfiguration.Flip();
+ TBool tempCRPFlip = aElement.SourceFlipping();
+ if(tempElementFlip == tempCRPFlip)
+ {
+ match = ETrue;
+ }
+ }
+ }
+ }
+ }
+ return match;
+ }
+
+/** Sets the surfaceconfiguration to the element.
+
+@param aElement The element to set.
+@param aSurfaceConfiguration The configuration to set to the element.
+@param aLimitedSet Set all values if EFalse, otherwise only set viewport and orientation.
+@return KErrNone on success, error from compositor if it could not set the surface id.
+*/
+TInt CWindowElement::SetElement(MWsElement& aElement, const TSurfaceConfiguration& aSurfaceConfiguration, TBool aLimitedSet)
+ { //aLimitedSet - EFalse = set all . ETrue = set viewport and orientation only
+ if (!aLimitedSet)
+ {
+ //set surface id
+ TSurfaceId newSurfaceId;
+ aSurfaceConfiguration.GetSurfaceId(newSurfaceId);
+ TInt error = aElement.ConnectSurface(newSurfaceId);
+ if (error != KErrNone)
+ {
+ return error;
+ }
+
+ //set extent
+ TRect newExtent;
+ aSurfaceConfiguration.GetExtent(newExtent);
+ aElement.SetDestinationRectangle(newExtent);
+ }
+
+ //set viewport
+ TRect newViewport;
+ aSurfaceConfiguration.GetViewport(newViewport);
+ if (newViewport.iTl.iX < 0 || newViewport.iTl.iY < 0)
+ {
+ return KErrArgument;
+ }
+
+ if (!newViewport.IsEmpty())
+ { //need to check if viewport is valid size
+ TInt error = aElement.SetSourceRectangle(newViewport);
+ if (error != KErrNone)
+ {
+ return error;
+ }
+ }
+
+ //set orientation
+ //Note for compatibility with Oghma:
+ //This method does not properly error check or return KErrArgument,
+ //as that would propagate a client panic in SetBackgroundSurface which did not previously occur.
+ aElement.SetSourceRotation(GcToElementRotation(aSurfaceConfiguration.Orientation()));
+ // Set or clear flip if the element flags are changing
+ if (aSurfaceConfiguration.Flip() != aElement.SourceFlipping())
+ {
+ aElement.SetSourceFlipping(!aElement.SourceFlipping());
+ }
+ return KErrNone;
+ }
+
+/** Attempts to insert a region cache in to the the windows iCache.
+If it fails, it will remove all cache beyond its index as it is now out of step.
+
+@param aIndexToInsert The index of where to insert the cache.
+@return ETrue on success, else EFalse.
+*/
+
+TBool CWindowElement::InsertCache(TInt aIndexToInsert)
+ {
+ RRegion newRegion;
+ TInt cacheInsertError = iCache.Insert(newRegion, aIndexToInsert);
+ if (cacheInsertError == KErrNone)
+ {
+ newRegion.Close();
+ return ETrue; //inserted cache
+ }
+ if (iCache.Count() > aIndexToInsert)
+ { //if insert failed and there is more cache above where its trying to insert
+ iCache.Remove(iCache.Count()-1);
+ cacheInsertError = iCache.Insert(newRegion, aIndexToInsert);
+
+ if (cacheInsertError == KErrNone)
+ {
+ newRegion.Close();
+ return ETrue; //inserted cache
+ }
+ }
+
+ //cant insert this cache, there may be invalid cache to destroy
+ TInt count = iCache.Count();
+ while(count > aIndexToInsert)
+ { //if there is cache where we wished to insert, it and everything above is now invalid
+ iCache[count-1].Close();
+ iCache.Remove(count-1);
+ count--;
+ };
+ newRegion.Close();
+ return EFalse; //failed to insert
+ }
+
+/** Will send a notification that a surface being unreferenced if it is not
+found in any WindowElementSet
+
+@pre Make sure the element being removed has already had its surfaceid set to NULL.
+@param aSurfaceId The surface being removed
+*/
+void CWindowElement::NotifyReleasingSurface(TSurfaceId aSurfaceId)
+ {
+ if (CWsTop::SearchDuplicateSurfaceId(aSurfaceId) == EFalse)
+ { //NOT found other instance of surface id, send notification now
+ TWservCrEvent crEvent(TWservCrEvent::ESurfaceUnreferenced, sizeof(aSurfaceId), &aSurfaceId);
+ TWindowServerEvent::NotifyDrawer(crEvent);
+ }
+ }
+
+/** Called to place a element within the window.
+It will either create a new element, recycle a element, or extend a element .
+
+@pre UnassignPlacedElements has already been called.
+@param aPlacedAttributes Returns the attributes of the surface placed.
+@param aSurfaceConfiguration The surface configuration for the surface to place.
+@param aUserDefinedRegion The user defined clipping of the window.
+@param aScene Access to the scene.
+@return Serious error, otherwise flags to describe what extra work needs doing.
+
+@see CWindowElementSet::AssignPlacedElement
+*/
+TInt CWindowElement::AssignPlacedElement(
+ TPlacedAttributes*& aPlacedAttributes,
+ const TSurfaceConfiguration& aSurfaceConfiguration,
+ const TRegion& aUserDefinedRegion,
+ MWsScene& aScene,
+ TInt aGcDrawingCount
+ )
+ {
+ if (iStartGcDrawingCount!=aGcDrawingCount)
+ {
+ FlagAssignedElementsDrawnOver(aGcDrawingCount);
+ }
+
+ if (iNonRedrawVisibleRegion.CheckError())
+ {
+ //CANNOT DO ANYTHING, LEAVE
+ return KErrNotReady; //error
+ }
+
+ TRect surfaceExtent;
+ aSurfaceConfiguration.GetExtent(surfaceExtent);
+ if (!aUserDefinedRegion.Intersects(surfaceExtent))
+ {
+ //clippedRegion.Close();
+ return KErrCancel; //no intersection, so nothing to do
+ }
+
+ TInt matchFound = -1;
+
+ //check 'current' (last placed element) to see if it is a match
+ if (iHighestReusedIndex != -1)
+ {
+ if (IsElementAMatch(*(iPlacedElements[iHighestReusedIndex].iElement),aSurfaceConfiguration,iPlacedElements[iHighestReusedIndex].Flags()) )
+ {
+ matchFound = iHighestReusedIndex;
+ }
+ }
+
+ if (matchFound == -1)
+ {
+ //check current unassigned elements to see if there is a match
+ for (TInt ii = (iHighestReusedIndex == -1)?0:iHighestReusedIndex+1; ii < iPlacedElements.Count(); ii++)
+ {
+ if (IsElementAMatch(*(iPlacedElements[ii].iElement),aSurfaceConfiguration,iPlacedElements[ii].Flags()))
+ {
+ matchFound = ii;
+ break;
+ }
+ }
+ }
+ TInt returnValue = 0;
+ if (matchFound == -1)
+ { //not found a element to extend
+ //iResort = ETrue;
+ matchFound = 0;
+ while(1)
+ {
+ if (iPlacedElements.Count() == 0 || iHighestReusedIndex == -1 || matchFound == iHighestReusedIndex) //reached last re assigned element, so cannot reuse one
+ {
+ matchFound = -1;
+ break;
+ }
+ if (iPlacedElements[matchFound].Unassigned() && !iPlacedElements[matchFound].LockedConfig()) //found a element to reuse
+ {
+ break;
+ }
+ matchFound++;
+ };
+
+ if (matchFound != -1)
+ { //found a element to recycle
+ returnValue = AssignRecycleElement(matchFound,aSurfaceConfiguration,aUserDefinedRegion,aScene);
+ }
+ else
+ { //need to create a new element
+ returnValue = AssignCreateElement(aSurfaceConfiguration,aUserDefinedRegion,aScene);
+ }
+ }
+ else
+ { //found a candidate to extend
+ returnValue = AssignExtendElement(matchFound,aSurfaceConfiguration,aUserDefinedRegion,aScene);
+ }
+ if (returnValue < KErrNone)
+ { //failed with error
+ return returnValue;
+ }
+ aPlacedAttributes = &iPlacedElements[iHighestReusedIndex];
+ iFlags|=returnValue; //update window wide flags
+ return returnValue;
+ }
+
+/** Recycle a element assigned to the window.
+
+@param aIndex The index of the placed element to recycle.
+@param aSurfaceConfiguration The surface configuration for the surface to place.
+@param aUserDefinedRegion The user defined clipping of the window.
+@param aScene Access to the scene.
+@return Serious error, otherwise flags to describe what extra work needs doing.
+
+@see CWindowElement::AssignPlacedElement
+*/
+TInt CWindowElement::AssignRecycleElement(const TInt aIndex, const TSurfaceConfiguration& aSurfaceConfiguration, const TRegion& aUserDefinedRegion, MWsScene& aScene)
+ {
+ TInt returnValue = 0;
+ TInt error = KErrNone;
+ STACK_REGION clippedRegion;
+ TRect surfaceExtent;
+ aSurfaceConfiguration.GetExtent(surfaceExtent);
+ clippedRegion.AddRect(surfaceExtent);
+ clippedRegion.Intersect(aUserDefinedRegion);
+ if (clippedRegion.CheckError())
+ { //failed crucial calculation, leave while nothing has been changed!
+ clippedRegion.Close();
+ return KErrNoMemory;
+ }
+ WS_ASSERT_DEBUG(!clippedRegion.IsEmpty(),EWsPanicRegion);
+ if (clippedRegion.IsEmpty())
+ {
+ return KErrArgument;
+ }
+
+ //keep note of surface being removed
+ TSurfaceId oldSurfaceId = iPlacedElements[aIndex].iElement->ConnectedSurface();
+
+ //set element with new attributes
+ error = SetElement(*(iPlacedElements[aIndex].iElement),aSurfaceConfiguration,EFalse);
+
+ if (error < KErrNone)
+ { //must be a bad surface id or bad viewport, leave while nothing has been changed!
+ clippedRegion.Close();
+ return error;
+ }
+
+ returnValue|=EFastPath;
+ returnValue|=EPauseComposition;
+ //element has been altered, must make sure old surface unreferenced notify will be called
+ if (!iRemovedSurfacesValid)
+ { //didnt reserve space for surface ids, do search immediately
+ NotifyReleasingSurface(oldSurfaceId);
+ }
+ else
+ { //keep memory of surface id - search will be done during cleanup. Space already been reserved
+ iRemovedSurfaces.Append(oldSurfaceId);
+ }
+
+ //order placed element correctly in iPlacedElements
+ TPlacedAttributes tempAttributes = iPlacedElements[aIndex];
+ iPlacedElements.Remove(aIndex);
+ //keep cache up to date
+ if (iCache.Count() > aIndex)
+ {
+ iCache[aIndex].Close();
+ iCache.Remove(aIndex);
+ }
+
+ WS_ASSERT_DEBUG(iHighestReusedIndex != -1,EWsPanicRecycleElement);
+ if (iHighestReusedIndex == -1)
+ {
+ return KErrArgument;
+ }
+
+ error = iPlacedElements.Insert(tempAttributes, iHighestReusedIndex);
+ if (error < KErrNone)
+ { //must destroy the element and leave. Old elements surface unregistration already dealt with
+ aScene.DestroySceneElement(tempAttributes.iElement);
+ clippedRegion.Close();
+ return KErrNoMemory;
+ }
+ returnValue|=EResort; //element has been moved, will need a resort
+ //set placed element attributes
+ iPlacedElements[iHighestReusedIndex].SetUnassigned(EFalse);
+ iPlacedElements[iHighestReusedIndex].SetLockedConfig(ETrue);
+ iPlacedElements[iHighestReusedIndex].SetChangedClip(ETrue);
+
+ TRect tempViewport;
+ aSurfaceConfiguration.GetViewport(tempViewport);
+
+ TBool cacheSaved = EFalse;
+ if (iCache.Count() >= iHighestReusedIndex)
+ { //need to update cache with visible region of element
+ TBool insertSuccess = InsertCache(iHighestReusedIndex);
+ if (insertSuccess != EFalse)
+ {
+ iCache[iHighestReusedIndex].Copy(clippedRegion);
+ if (!iCache[iHighestReusedIndex].CheckError())
+ {
+ cacheSaved = ETrue;
+ }
+ }
+ }
+ if (cacheSaved == EFalse)
+ { //need to set clipping to element immediately
+ TInt count = iCache.Count();
+ while(count > iHighestReusedIndex)
+ { //if there is cache where we wished to insert, it and everything above is now invalid
+ iCache[count-1].Close();
+ iCache.Remove(count-1);
+ count--;
+ };
+ }
+ clippedRegion.Close();
+ return returnValue;
+ }
+
+/** Create a new element for the placed surface.
+
+@param aSurfaceConfiguration The surface configuration for the surface to place.
+@param aUserDefinedRegion The user defined clipping of the window.
+@param aScene Access to the scene.
+@return Serious error, otherwise flags to describe what extra work needs doing.
+
+@see CWindowElement::AssignPlacedElement
+*/
+TInt CWindowElement::AssignCreateElement(const TSurfaceConfiguration& aSurfaceConfiguration, const TRegion& aUserDefinedRegion, MWsScene& aScene)
+ {
+ TInt returnValue = 0;
+ TInt error = KErrNone;
+ STACK_REGION clippedRegion;
+ TRect surfaceExtent;
+ aSurfaceConfiguration.GetExtent(surfaceExtent);
+ //calculate region
+ clippedRegion.AddRect(surfaceExtent);
+ clippedRegion.Intersect(aUserDefinedRegion);
+ if (clippedRegion.CheckError())
+ { //failed, return KErrNoMemory
+ clippedRegion.Close();
+ return KErrNoMemory;
+ }
+
+ TPlacedAttributes newElement;
+ if (iHighestReusedIndex == -1)
+ {
+ error = iPlacedElements.Insert(newElement,0);
+ }
+ else
+ { //insert above current highest reused element
+ error = iPlacedElements.Insert(newElement,iHighestReusedIndex+1);
+ }
+ if (error >= KErrNone)
+ {
+ iHighestReusedIndex++;
+ }
+ else
+ {
+ //FAILED! LEAVE FUNCTION. nothing has been changed
+ clippedRegion.Close();
+ return KErrNoMemory;
+ }
+
+ //create new element with new configuration
+ MWsElement* element = NULL;
+ TRAP(error,element = aScene.CreateSceneElementL());
+ if (error != KErrNone)
+ {
+ //FAILED! LEAVE FUNCTION. nothing has been changed
+ clippedRegion.Close();
+ return error;
+ }
+
+ element->SetGlobalAlpha( 0xFF );
+
+ iPlacedElements[iHighestReusedIndex].iElement = element;
+ error = SetElement(*element,aSurfaceConfiguration,EFalse);
+ if (error < KErrNone)
+ {
+ //must be a bad surface id or viewport. Leave now.
+ aScene.DestroySceneElement(element);
+ clippedRegion.Close();
+ iPlacedElements.Remove(iHighestReusedIndex);
+ iHighestReusedIndex--;
+ return error;
+ }
+
+ //Now certain that these must be flagged
+ returnValue|=EFastPath;
+ returnValue|=EPauseComposition;
+ returnValue|=EResort;
+
+ //set placed element attributes
+ iPlacedElements[iHighestReusedIndex].SetUnassigned(EFalse);
+ iPlacedElements[iHighestReusedIndex].SetChangedClip(ETrue);
+ iPlacedElements[iHighestReusedIndex].SetLockedConfig(ETrue);
+
+ TRect tempViewport;
+ aSurfaceConfiguration.GetViewport(tempViewport);
+
+ TBool cacheSaved = EFalse;
+ if (iCache.Count() >= iHighestReusedIndex)
+ { //should try to add new elements region to cache
+ TBool insertSuccess = InsertCache(iHighestReusedIndex);
+ if (insertSuccess != EFalse)
+ {
+ iCache[iHighestReusedIndex].Copy(clippedRegion);
+ if (!iCache[iHighestReusedIndex].CheckError())
+ {
+ cacheSaved = ETrue;
+ }
+ }
+ }
+ if (cacheSaved == EFalse)
+ { //need to clear cache from this point onward, and set clipping to element immediately
+ TInt count = iCache.Count();
+ while(count > iHighestReusedIndex)
+ { //if there is cache where we wished to insert, it and everything above is now invalid
+ iCache[count-1].Close();
+ iCache.Remove(count-1);
+ count--;
+ };
+ }
+ //add the new element to the scene
+ error = aScene.InsertSceneElement(element, NULL); //place at the back. will get ordered correctly later
+ WS_ASSERT_DEBUG(error == KErrNone,EWsPanicSceneErrorIgnored);
+ clippedRegion.Close();
+ return returnValue;
+ }
+
+/** Extend an existing placed surface element.
+
+@param The index of the element to extend.
+@param aSurfaceConfiguration The surface configuration for the surface to place.
+@param aUserDefinedRegion The user defined clipping of the window.
+@param aScene Access to the scene.
+@return Serious error, otherwise flags to describe what extra work needs doing.
+
+@see CWindowElement::AssignPlacedElement
+*/
+TInt CWindowElement::AssignExtendElement(const TInt aIndex, const TSurfaceConfiguration& aSurfaceConfiguration, const TRegion& aUserDefinedRegion, MWsScene& /*aScene*/)
+ {
+ TInt returnValue = 0;
+ TInt error = KErrNone;
+ STACK_REGION backupRegionAgainstFail;
+ STACK_REGION clippedRegion;
+ TRect surfaceExtent;
+ aSurfaceConfiguration.GetExtent(surfaceExtent);
+ TRect surfaceViewport;
+ aSurfaceConfiguration.GetViewport(surfaceViewport);
+
+ if (!iPlacedElements[aIndex].LockedConfig())
+ { //set element now. If viewport is invalid its ok to fail now
+ error = SetElement(*iPlacedElements[aIndex].iElement,aSurfaceConfiguration,ETrue);
+ if (error < KErrNone)
+ {
+ backupRegionAgainstFail.Close();
+ clippedRegion.Close();
+ return error;
+ }
+ }
+
+ if(iPlacedElements[aIndex].Unassigned() && !iPlacedElements[aIndex].Overlapping())
+ {
+ //backup stays clear
+ clippedRegion.Copy(aUserDefinedRegion);
+ }
+ else
+ {
+ clippedRegion.Copy(iNonRedrawVisibleRegion);
+ if (iCache.Count() > aIndex) //if cache is ok
+ {
+ clippedRegion.Intersect(iCache[aIndex]);
+ clippedRegion.Union(iCache[aIndex]); //previously added regions should be kept
+ }
+ else
+ {
+ STACK_REGION tempSurfaceBaseArea;
+ TRect destinationRect;
+ iPlacedElements[aIndex].iElement->GetDestinationRectangle(destinationRect);
+ tempSurfaceBaseArea.AddRect(destinationRect);
+ tempSurfaceBaseArea.Offset(surfaceExtent.iTl);
+ clippedRegion.Intersect(tempSurfaceBaseArea);
+ clippedRegion.Union(tempSurfaceBaseArea);
+ tempSurfaceBaseArea.Close();
+ }
+ backupRegionAgainstFail.Copy(clippedRegion);
+ //clipped region should contain something
+ clippedRegion.Union(aUserDefinedRegion);
+ }
+ clippedRegion.ClipRect(surfaceExtent);
+
+ if (backupRegionAgainstFail.CheckError() || clippedRegion.CheckError())
+ { //failed critical calculations, leave now before anything has been changed
+ clippedRegion.Close();
+ backupRegionAgainstFail.Close();
+ return KErrNoMemory;
+ }
+
+ TBool setCache = EFalse;
+ if (iCache.Count() > aIndex) //if Cache is ok
+ {
+ //compare
+ TInt compareReturn;
+ compareReturn = TRegionExtend::Cast(iCache[aIndex]).TestDifference(clippedRegion);
+
+ if (compareReturn&TRegionExtend::EDiffers) //element has changed
+ {
+ iPlacedElements[aIndex].SetChangedClip(ETrue);
+ if (compareReturn&TRegionExtend::EAdd) //element has become revealed on the screen
+ {
+ returnValue|=EPauseComposition; //need to pause before the end of assign placed element
+ }
+ else
+ {
+ returnValue|=EFastPath; //fastpath and pause will be called during cleanup
+ }
+ }
+
+ //copy clipped region to cache
+ iCache[aIndex].Copy(clippedRegion); //can fail
+ setCache = ETrue;
+ if (iCache[aIndex].CheckError())
+ { //copy failed, remove cache from this element onwards
+ TInt count = iCache.Count();
+ while(count > aIndex)
+ { //if there is cache where we wished to insert, it and everything above is now invalid
+ iCache[count-1].Close();
+ iCache.Remove(count-1);
+ count--;
+ };
+ setCache = EFalse;
+ }
+ }
+ if (setCache == EFalse)
+ { //need to pause composition and update element immediately
+ returnValue|=EPauseComposition;
+ }
+ iPlacedElements[aIndex].SetUnassigned(EFalse);
+ iPlacedElements[aIndex].SetLockedConfig(ETrue);
+ iHighestReusedIndex = aIndex;
+ backupRegionAgainstFail.Close();
+ clippedRegion.Close();
+ return returnValue;
+ }
+
+/** Called at the end of a redraw to set cached changed to elements, and
+removed elements that are still unassigned.
+
+@param aScene Access to the scene.
+@return Flags to describe what extra work needs doing.
+@see CWindowElementSet::CleanUpPlacedElements
+*/
+TInt CWindowElement::CleanUpPlacedElements(MWsScene& aScene, TInt aGcDrawingCount)
+ {
+ if (iStartGcDrawingCount!=aGcDrawingCount)
+ {
+ FlagAssignedElementsDrawnOver(aGcDrawingCount);
+ }
+ TInt returnFlags = iFlags;
+ if (iFlags > 0)
+ { //copy flags to return, and ensure pause is flagged
+ returnFlags|=EPauseComposition;
+ }
+ TInt ii;
+ TBool removeElements = EFalse;
+ //destroy placed element reference
+ for (ii=0; ii<iPlacedElements.Count(); ii++)
+ {
+ if (iPlacedElements[ii].Unassigned() && !iPlacedElements[ii].Overlapping())
+ {
+ returnFlags|=EFastPath; //need to invoke 1108
+ if (iRemovedSurfacesValid)
+ {
+ iRemovedSurfaces.Append(iPlacedElements[ii].iElement->ConnectedSurface());
+ iPlacedElements[ii].iElement->ConnectSurface(TSurfaceId::CreateNullId());
+ }
+ else
+ {
+ TSurfaceId tempId = iPlacedElements[ii].iElement->ConnectedSurface();
+ iPlacedElements[ii].iElement->ConnectSurface(TSurfaceId::CreateNullId());
+ NotifyReleasingSurface(tempId);
+ }
+ removeElements = ETrue;
+ }
+ }
+
+ if (removeElements)
+ { //there will be elements to remove
+ for (ii=0; ii<iPlacedElements.Count(); ii++)
+ {
+ if (iPlacedElements[ii].iElement->ConnectedSurface().IsNull())
+ {
+ aScene.DestroySceneElement(iPlacedElements[ii].iElement);
+ iPlacedElements.Remove(ii);
+ if (iCache.Count() > ii)
+ { //there is cache for this element, remove it
+ iCache[ii].Close();
+ iCache.Remove(ii);
+ }
+ ii--;
+ }
+ }
+ }
+
+ if (iRemovedSurfaces.Count() > 1)
+ { //remove duplicates of surface id from removal list
+ for (ii = 0; ii < iRemovedSurfaces.Count() - 1; ii++)
+ {
+ for (TInt jj = ii+1; jj < iRemovedSurfaces.Count(); jj++)
+ {
+ if (iRemovedSurfaces[ii] == iRemovedSurfaces[jj])
+ {
+ iRemovedSurfaces.Remove(jj);
+ jj--;
+ }
+ }
+ }
+ }
+
+ //do global search for surface ids
+ while (iRemovedSurfaces.Count()>0)
+ {
+ TInt tempRemoval = iRemovedSurfaces.Count() - 1;
+ NotifyReleasingSurface(iRemovedSurfaces[tempRemoval]);
+ iRemovedSurfaces.Remove(tempRemoval);
+ };
+
+ iRemovedSurfaces.Reset();
+
+ //clip unassigned overlapping entries, mark as changedclip if region changed
+ for (ii=0; ii<iPlacedElements.Count(); ii++)
+ {
+ if (iPlacedElements[ii].Unassigned()) //non overlapping unassigned have already been destroyed
+ { //these must overlap
+ TBool failureOccured = EFalse;
+ if (iCache.Count() > ii)
+ {
+ //if cache region is entirely inside non redraw vis region, nothing to update!
+ TInt changed =
+ TRegionExtend::Cast(iCache[ii]).TestDifference(iNonRedrawVisibleRegion);
+ if (changed&TRegionExtend::ESub)
+ { //the clipping will change
+ iCache[ii].Intersect(iNonRedrawVisibleRegion);
+ if (iCache[ii].CheckError())
+ {
+ failureOccured = ETrue;
+ iCache[ii].Close();
+ iCache.Remove(ii);
+ }
+ else
+ {
+ iPlacedElements[ii].SetChangedClip(ETrue); //changed clipping
+ }
+ }
+ }
+ else
+ { //attempt getting element region to perform calculation and update element directly
+ STACK_REGION elementRegion;
+ TRect destinationRect;
+ iPlacedElements[ii].iElement->GetDestinationRectangle(destinationRect);
+ elementRegion.AddRect(destinationRect);
+ if (elementRegion.CheckError())
+ {
+ failureOccured = ETrue;
+ }
+ else
+ {
+ TRect elementExtent;
+ iPlacedElements[ii].iElement->GetDestinationRectangle(elementExtent);
+ elementRegion.Offset(elementExtent.iTl); //get element region into absolute coordinates
+ TInt changed =
+ TRegionExtend::Cast(elementRegion).TestDifference(iNonRedrawVisibleRegion);
+ if (changed&TRegionExtend::ESub)
+ { //need to clip element back
+ elementRegion.Intersect(iNonRedrawVisibleRegion);
+ if (!elementRegion.CheckError())
+ {
+ elementRegion.Offset(-elementExtent.iTl); //put element region back into relative coords
+ returnFlags|=EFastPath;
+ }
+ else
+ {
+ failureOccured = ETrue;
+ }
+ }
+ }
+ elementRegion.Close();
+ }
+ if (failureOccured)
+ { //need to release element
+ TSurfaceId tempId = iPlacedElements[ii].iElement->ConnectedSurface();
+ iPlacedElements[ii].iElement->ConnectSurface(TSurfaceId::CreateNullId());
+ NotifyReleasingSurface(tempId);
+ aScene.DestroySceneElement(iPlacedElements[ii].iElement);
+ returnFlags|=EFailed;
+ iPlacedElements.Remove(ii); //remove placed element entry, cache is already removed
+ ii--;
+ }
+ }
+ }
+
+ //update any elements marked as changedclip , clear all cache, clear flags
+ for (ii=0; ii<iPlacedElements.Count(); ii++)
+ {
+ if (iPlacedElements[ii].ChangedClip())
+ {
+ returnFlags|=EFastPath; //need to invoke 1108
+ }
+ else
+ if ( !(returnFlags&EFastPath)
+ && iPlacedElements[ii].LockedConfig() && !iPlacedElements[ii].Unassigned()
+ && iPlacedElements[ii].DrawnOver()!=iPlacedElements[ii].DrawnOverLast() )
+ {
+ returnFlags|=EFastPath;
+ }
+ iPlacedElements[ii].ClearRedrawFlags();
+ if (iCache.Count() > ii)
+ {
+ iCache[ii].Clear();
+ }
+ }
+ iCache.Reset();
+ iNonRedrawVisibleRegion.Clear();
+ iHighestReusedIndex = -1;
+ return returnFlags;
+ }
+
+/** Move all elements in this windowelement to above the supplied element in the scene
+
+@param aScene Access to the scene.
+@param aElement The element to set all this windows elements above.
+*/
+
+void CWindowElement::MoveToAboveGivenElement(MWsScene& aScene, MWsElement* aElement)
+ {
+ MWsElement* newAboveElement = iBackgroundElement.iElement;
+ MWsElement* previousAboveElement = aElement;
+ if (newAboveElement)
+ {
+ aScene.InsertSceneElement(newAboveElement, previousAboveElement); //background element is put on first
+ previousAboveElement = newAboveElement;
+ }
+ TInt placedElements = iPlacedElements.Count();
+ if (placedElements != 0)
+ {
+ for (TInt ii = 0; ii < placedElements; ii++)
+ {
+ newAboveElement = iPlacedElements[ii].iElement;
+ aScene.InsertSceneElement(newAboveElement, previousAboveElement); //place element above previous above element
+ previousAboveElement = newAboveElement;
+ }
+ }
+ }
+
+/** Updates the elements extent, whether from a window movement or a change in window size
+
+@param aOffset The movement of the window. If NULL then the window has changed size.
+@see CWindowElementSet::UpdateElementExtent
+*/
+void CWindowElement::UpdateElementExtent(const TPoint* aOffset)
+ {
+ if (aOffset) //window moved
+ {
+ TRect tempExtent;
+ MWsElement* element = iBackgroundElement.iElement;
+ TBool complete = EFalse;
+ TInt placedElementDone = -1;
+ while (!complete)
+ {
+ if (!element && placedElementDone < iPlacedElements.Count()-1)
+ {
+ placedElementDone++;
+ element = iPlacedElements[placedElementDone].iElement;
+ }
+ if (!element)
+ {
+ complete = ETrue;
+ }
+ else
+ {
+ tempExtent = const_cast<CWsClientWindow&>(iWindow).GetOriginalDestElementRect();
+ tempExtent.Move(*aOffset);
+ element->SetDestinationRectangle(tempExtent);
+ const_cast<CWsClientWindow&>(iWindow).SetOriginalDestElementRect(tempExtent);
+ }
+ element = NULL;
+ }
+ }
+ else //window changed size
+ {
+ if (!iBackgroundElement.ExplicitExtent() && iBackgroundElement.iElement)
+ {
+ iBackgroundElement.iElement->SetDestinationRectangle(iWindow.FullRect());
+ const_cast<CWsClientWindow&>(iWindow).SetOriginalDestElementRect(iWindow.FullRect());
+ }
+ }
+ }
+
+/** Checks the windows placed elements when the windows visibility is changed.
+If the placed elements are no longer visible, they are removed.
+
+@param aRegion The new visible region of the window.
+@param aScene Access to the scene.
+@return ETrue if any elements have been removed, otherwise EFalse.
+@see CWindowElementSet::SetVisibleRegion
+*/
+TBool CWindowElement::SetVisibleRegion(const TRegion& aRegion, MWsScene& aScene)
+ {
+ TBool retcode=EFalse;
+ if (iPlacedElements.Count() == 0)
+ {
+ return EFalse; //there is noting to do
+ }
+
+ STACK_REGION tempRegion;
+ for (TInt ii = 0; ii < iPlacedElements.Count(); ii++)
+ {
+ TRect tempExtent;
+ tempRegion.Clear();
+ iPlacedElements[ii].iElement->GetDestinationRectangle(tempExtent);
+ tempRegion.AddRect(tempExtent);
+ if (tempRegion.CheckError()) //if there was error getting region
+ {
+ tempRegion.Clear();
+ tempRegion.AddRect(tempExtent);
+ }
+ else
+ { //offset basearea of element
+ tempRegion.Offset(tempExtent.iTl);
+ }
+ TInt regionReturn = TRegionExtend::Cast(aRegion).TestDifference(tempRegion);
+ if (regionReturn&TRegionExtend::ENoIntersect)
+ { //placed surface needs to be removed
+ TSurfaceId tempId = iPlacedElements[ii].iElement->ConnectedSurface();
+ iPlacedElements[ii].iElement->ConnectSurface(TSurfaceId::CreateNullId());
+ NotifyReleasingSurface(tempId);
+ aScene.DestroySceneElement(iPlacedElements[ii].iElement);
+ retcode = ETrue; //a element has been removed
+ iPlacedElements.Remove(ii);
+ if (iCache.Count() > ii)
+ { //keep cache up to date
+ iCache[ii].Close();
+ iCache.Remove(ii);
+ }
+ ii--;
+ }
+ }
+ tempRegion.Close();
+ return retcode;
+ }
+
+/** Checks if any of the windows element ids match the one in question.
+
+@param aSurfaceId The surface id to match against.
+@return ETrue if a match is found, otherwise EFalse.
+
+@see CWindowElementSet::SearchDuplicateSurfaceId
+*/
+TBool CWindowElement::SearchDuplicateSurfaceId(const TSurfaceId& aSurfaceId)
+ {
+ if (iBackgroundElement.iElement)
+ {
+ if (iBackgroundElement.iElement->ConnectedSurface() == aSurfaceId)
+ {
+ return ETrue;
+ }
+ }
+ if (iPlacedElements.Count() > 0)
+ {
+ for (TInt ii = 0; ii < iPlacedElements.Count(); ii++)
+ {
+ if (iPlacedElements[ii].iElement) //if removed without reserved space for ids, could be a null element
+ {
+ if (iPlacedElements[ii].iElement->ConnectedSurface() == aSurfaceId)
+ {
+ return ETrue;
+ }
+ }
+ }
+ }
+ return EFalse;
+ }
+
+/** Sets the opacity for the background surface and if setting to 0 removes placed surfaces.
+
+@param aOpacity The opacity to set.
+@param aScene Access to the scene.
+@see CWindowElementSet::SetElementOpacity
+*/
+void CWindowElement::SetElementOpacity(TInt aOpacity, MWsScene& aScene)
+ {
+ if (iBackgroundElement.iElement)
+ {
+ TUint32 flags = 0;
+ iBackgroundElement.iElement->GetTargetRendererFlags(flags);
+ flags |= MWsElement::EElementTransparencyGlobalAlpha;
+ iBackgroundElement.iElement->SetTargetRendererFlags(MWsElement::EElementTransparencyGlobalAlpha);
+ iBackgroundElement.iElement->SetGlobalAlpha(aOpacity);
+ iBackgroundElement.SetConcealed(aOpacity==0);
+ }
+ if (aOpacity == 0)
+ {
+ while (iPlacedElements.Count() > 0)
+ { //remove any placed elements
+ TInt placedElement = iPlacedElements.Count()-1;
+ TSurfaceId tempId = iPlacedElements[placedElement].iElement->ConnectedSurface();
+ iPlacedElements[placedElement].iElement->ConnectSurface(TSurfaceId::CreateNullId());
+ NotifyReleasingSurface(tempId);
+ aScene.DestroySceneElement(iPlacedElements[placedElement].iElement);
+ iPlacedElements.Remove(placedElement);
+ };
+ }
+ }
+
+MWsElement* CWindowElement::Element() const
+ {
+ return iBackgroundElement.iElement;
+ }
+
+//
+// CWindowElementSet
+//
+
+/** Destroys the set of window-element pairs.
+*/
+CWindowElementSet::~CWindowElementSet()
+ {
+ ASSERT(iElements.Count() == 0);
+ iElements.Close();
+ }
+
+/** Basic NewL constructor
+@param aScene To allow access to the scene.
+@param aComposer To allow access to the composer.
+*/
+CWindowElementSet* CWindowElementSet::NewL(MWsScene& aScene)
+ {
+ CWindowElementSet* wls = new (ELeave) CWindowElementSet(aScene);
+ return wls;
+ }
+
+/** Sets a new background surface on the window supplied.
+Will remove any previous background surface.
+
+@param aWindow The window to place a background surface on.
+@return A reference to the new background surface attributes.
+*/
+TBackgroundAttributes& CWindowElementSet::AcquireBackgroundElementL(CWsClientWindow& aWindow)
+ {
+ // Find the matching element.
+ TInt index;
+ TInt result = FindEntry(aWindow, index);
+ MWsElement* element;
+
+ // If a background element is already associated with the window, then unregister
+ // the surface. Create and add a new element to scene.
+ // This will ensure that the element has default values.
+ if (result != KErrNotFound && iElements[index]->iBackgroundElement.iElement)
+ {
+ element = iElements[index]->iBackgroundElement.iElement;
+ TSurfaceId surface = element->ConnectedSurface();
+ element->ConnectSurface(TSurfaceId::CreateNullId());
+ UnregisterSurface(surface);
+ iScene.DestroySceneElement(element);
+ }
+ if (index < 0)
+ {
+ index = 0;
+ }
+
+ // Allocate a new element and add it to the set and the scene
+ element = iScene.CreateSceneElementL();
+
+ TInt returnCode;
+ if (result == KErrNotFound)
+ {
+ CWindowElement* winelement = new CWindowElement(aWindow);
+ if (!winelement)
+ {
+ iScene.DestroySceneElement(element);
+ User::Leave(KErrNoMemory);
+ }
+ returnCode = iElements.Insert(winelement, index);
+ if(returnCode != KErrNone)
+ {
+ delete winelement;
+ iScene.DestroySceneElement(element);
+ User::Leave(returnCode);
+ }
+ }
+
+ // Use the element below the insertion point to decide where the element
+ // goes in the scene
+ returnCode = KErrNone;
+ if (index == 0)
+ {
+ returnCode = iScene.InsertSceneElement(element, NULL);
+ }
+ else
+ {
+ //Find highest element in window below
+ MWsElement* below;
+ TInt placedCount = iElements[index-1]->iPlacedElements.Count();
+ if (placedCount > 0)
+ {
+ below = iElements[index-1]->iPlacedElements[placedCount-1].iElement;
+ }
+ else
+ { //below = above = background surface
+ below = iElements[index-1]->iBackgroundElement.iElement;
+ }
+ returnCode = iScene.InsertSceneElement(element, below);
+ }
+
+ __ASSERT_DEBUG(returnCode == KErrNone, Panic(EWsPanicSceneErrorIgnored));
+
+ iElements[index]->iBackgroundElement.iElement = element;
+ return iElements[index]->iBackgroundElement;
+ }
+
+/** Removes the background element of the specified window.
+
+@param aWindow The window to remove the background element from.
+@param aWindowClosing ETrue if aWindow is in between closing state.
+@return KErrNone on success or a system-wide error code.
+*/
+TInt CWindowElementSet::ReleaseBackgroundElement(const CWsClientWindow& aWindow, TBool aWindowClosing /*= EFalse*/)
+ {
+ TInt index;
+
+ TInt err = FindEntry(aWindow, index, aWindowClosing);
+ __ASSERT_DEBUG(err != KErrNotFound, Panic(EWsPanicNoWindowElement));
+
+ if (err==KErrNone)
+ {
+ CWindowElement* winElement=iElements[index];
+ if (winElement->iPlacedElements.Count() == 0)
+ { //destroy the window entry
+ DestroyWindowElementEntry(index);
+ }
+ else
+ { // just destroy the background
+ if (winElement->iBackgroundElement.iElement)
+ {
+ winElement->iBackgroundElement.Destroy(iScene, ETrue);
+ }
+ }
+ }
+ return err;
+ }
+
+/** Destroys the element associated with this set of attributes
+
+@param aScene To allow access to the scene.
+@param aUnregister Whether to call unregister on the surface id.
+@return ETrue if a element existed to be destroyed, otherwise EFalse.
+*/
+TBool TAttributes::Destroy(MWsScene& aScene, TBool aUnregister)
+ {
+ MWsElement* element = iElement;
+ if (element)
+ {
+ TSurfaceId surface = element->ConnectedSurface();
+ element->ConnectSurface(TSurfaceId::CreateNullId());
+ if (aUnregister)
+ {
+ aScene.UnregisterSurface(surface);
+ }
+ aScene.DestroySceneElement(element);
+ iElement = NULL;
+ }
+ return element!=NULL;
+ }
+
+/** Destroys all elements associated with the window and removes the window from the element set
+
+@param aWinElementIndex The index of the window in the element set
+*/
+void CWindowElementSet::DestroyWindowElementEntry(const TInt aWinElementIndex)
+ {
+ CWindowElement* winElement=iElements[aWinElementIndex];
+ const CWsClientWindow& window = winElement->iWindow;
+ winElement->iBackgroundElement.Destroy(iScene, ETrue);
+ for (TInt placedIndex=0,maxindex=winElement->iPlacedElements.Count();placedIndex<maxindex;placedIndex++)
+ {
+ winElement->iPlacedElements[placedIndex].Destroy(iScene, EFalse);
+ }
+ winElement->iPlacedElements.Close();
+ delete winElement;
+ iElements.Remove(aWinElementIndex);
+ window.Redraw()->SetHasElement(EFalse);
+ window.Screen()->ElementRemoved();
+ }
+
+/** Removes all elements in the associated window.
+
+@param aWindow The window to remove the elements for.
+@param aWindowClosing ETrue if aWindow is in between closing state.
+@return KErrNone on success, KErrNotFound if there was no windowelement entry.
+*/
+TInt CWindowElementSet::ReleaseAllElements(const CWsClientWindow& aWindow, TBool aWindowClosing /*= EFalse*/)
+ {
+ TInt index;
+
+ TInt err = FindEntry(aWindow, index, aWindowClosing);
+ __ASSERT_DEBUG(err != KErrNotFound, Panic(EWsPanicNoWindowElement));
+ if (err==KErrNone)
+ {
+ DestroyWindowElementEntry(index);
+ }
+ return err;
+ }
+
+/** For every window element, checks if any of the windows element ids match the one in question.
+
+@param aSurfaceId The surface id to match against.
+@return ETrue if a match is found, otherwise EFalse.
+
+@see CWindowElement::SearchDuplicateSurfaceId
+*/
+TBool CWindowElementSet::SearchDuplicateSurfaceId(const TSurfaceId& aSurfaceId)
+ {
+ TInt windowElements = iElements.Count();
+ for (TInt ii = 0; ii < windowElements; ii++)
+ {
+ if (iElements[ii]->SearchDuplicateSurfaceId(aSurfaceId))
+ {
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
+
+/** For a window, sets the opacity for the background surface and if setting to
+0 removes placed surfaces.
+
+@param aWindow The window to perform the function on.
+@param aOpacity The opacity to set.
+@see CWindowElement::SetElementOpacity
+*/
+void CWindowElementSet::SetElementOpacity(CWsClientWindow& aWindow, TInt aOpacity)
+ {
+ WS_ASSERT_DEBUG(aOpacity == 0 || aOpacity == 255,EWsPanicUnexpectedOpacity);
+ return FindElement(aWindow)->SetElementOpacity(aOpacity, iScene);
+ }
+
+/** Finds all elements within the window that overlap with the region and
+marks them as unassigned.
+If any part of these unassigned elements are outside the region, they are also
+marked overlapping and locked config.
+
+@param aRedrawRegion The region in which elements will be unassigned
+@param aWindow The window to perform the function on.
+@return KErrNone on success or KErrNoMemory if critical calculations could not be made.
+@see CWindowElement::UnassignPlacedElements
+*/
+TInt CWindowElementSet::UnassignPlacedElements(const TRegion& aRedrawRegion, const CWsClientWindow& aWindow, TInt aGcDrawingCount)
+ {
+ return FindElement(aWindow)->UnassignPlacedElements(aRedrawRegion, aGcDrawingCount);
+ }
+
+/** Called to place a element within the window.
+It will either create a new element, recycle a element, or extend a element .
+
+@param aPlacedAttributes Returns the attributes of the surface placed.
+@param aSurfaceConfiguration The surface configuration for the surface to place.
+@param aUserDefinedRegion The user defined clipping of the window.
+@param aWindow The window to perform the function on.
+@return KErrNone on success or a system-wide error code.
+@see CWindowElement::AssignPlacedElement
+*/
+TInt CWindowElementSet::AssignPlacedElement(
+ TPlacedAttributes*& aPlacedAttributes,
+ const TSurfaceConfiguration& aSurfaceConfiguration,
+ const TRegion& aUserDefinedRegion,
+ const CWsClientWindow& aWindow,
+ TInt aGcDrawingCount )
+ {
+ TInt index;
+ TInt error = KErrNone;
+ TInt result = FindEntry(aWindow, index);
+ TBool insertedElement = EFalse;
+ if (result == KErrNotFound)
+ {
+ CWindowElement* winelement = new CWindowElement(aWindow);
+ if (!winelement)
+ {
+ return KErrNoMemory; //memory error
+ }
+ error = iElements.Insert(winelement, index);
+ if (error == KErrNone)
+ {
+ insertedElement = ETrue;
+ aWindow.Redraw()->SetHasElement(ETrue);
+ STACK_REGION windowRegion = aWindow.Abs();
+ if (!windowRegion.CheckError())
+ {
+ error = iElements[index]->UnassignPlacedElements(windowRegion, aGcDrawingCount);
+ }
+ else
+ {
+ error = KErrNoMemory;
+ }
+ windowRegion.Close();
+ }
+ else
+ {
+ delete winelement;
+ }
+ }
+ if (error == KErrNone)
+ {
+
+ TInt assignReturn = iElements[index]->AssignPlacedElement(aPlacedAttributes, aSurfaceConfiguration,
+ aUserDefinedRegion, iScene, aGcDrawingCount);
+ error = assignReturn; //return assign flags
+ }
+ if (error < KErrNone && insertedElement)
+ { //remove this element that has just been created
+ aWindow.Redraw()->SetHasElement(EFalse);
+ iElements.Remove(index);
+ }
+ return error;
+ }
+
+/** Marks all elements that have been assigned since the unassign as drawn over.
+
+@param aWindow The window to perform the function on.
+@see CWindowElement::FlagAssignedElementsDrawnOver
+**/
+//void CWindowElementSet::FlagAssignedElementsDrawnOver(const CWsClientWindow& aWindow)
+// {
+// FindElement(aWindow)->FlagAssignedElementsDrawnOver();
+// }
+
+/** Called at the end of a redraw to set cached changed to elements, and
+removed elements that are still unassigned.
+
+@param aWindow The window to perform the function on.
+@return Flags to describe what extra work needed doing.
+@see CWindowElement::CleanUpPlacedElements
+*/
+TInt CWindowElementSet::CleanUpPlacedElements(const CWsClientWindow& aWindow, TInt aGcDrawingCount)
+ {
+ TInt index;
+ TInt error = FindEntry(aWindow,index);
+ if (error < 0)
+ {
+ WS_ASSERT_DEBUG(0,EWsPanicNoWindowElement);
+ return error;
+ }
+ TInt returnFlags = iElements[index]->CleanUpPlacedElements(iScene, aGcDrawingCount);
+
+ if (!iElements[index]->iBackgroundElement.iElement && iElements[index]->iPlacedElements.Count() == 0)
+ { //remove window entry
+ DestroyWindowElementEntry(index);
+ }
+ else
+ {
+ if (returnFlags&CWindowElement::EResort)
+ { //need to sort elements
+ //find front most visible element in window behind, invoke sort by z order
+ if (index == 0)
+ { //this element is backmost window
+ iElements[index]->MoveToAboveGivenElement(iScene,NULL);
+ }
+ else
+ { //place infront of highest element behind
+ if (iElements[index-1]->iPlacedElements.Count() == 0)
+ { //top element of element behind must be the background element
+ iElements[index]->MoveToAboveGivenElement(iScene,iElements[index-1]->iBackgroundElement.iElement);
+ }
+ else
+ { //top element of element behind must be highest placed element
+ TInt placedCount = iElements[index-1]->iPlacedElements.Count();
+ iElements[index]->MoveToAboveGivenElement(iScene,iElements[index-1]->iPlacedElements[placedCount-1].iElement);
+ }
+ }
+ }
+ }
+ if (returnFlags&CWindowElement::EFailed)
+ { //visible elements may have been deleted, error to suggest a full window redraw
+ return KErrGeneral;
+ }
+ return returnFlags;
+ }
+
+/** Counts how many elements there are in the set.
+
+@return The number of elements in the set.
+*/
+TInt CWindowElementSet::Count() const
+ {
+ return iElements.Count();
+ }
+
+/** Returns the background attributes for the specified window
+
+@param aWindow The window to perform the function on.
+@return The background surface attributes. If the window has no elementset entry, returns NULL.
+*/
+TBackgroundAttributes* CWindowElementSet::FindBackgroundElement(const CWsClientWindow& aWindow)
+ {
+ TInt index;
+ TInt err = FindEntry(aWindow, index);
+
+ if (err != KErrNotFound)
+ {
+ return &(iElements[index]->iBackgroundElement);
+ }
+ return NULL;
+ }
+
+/** Returns the contents of the element data associated with the input window.
+If this method is successful, then neither pointer will be NULL.
+
+@return standard symbian error code.
+@param aWindow window to find
+@param aBackAttr backgroud surface attributes associated with the window
+@param aPlacedAttr array of placed surface attributes associated with the window.
+*/
+TInt CWindowElementSet::FindElements( CWsClientWindow const &aWindow,
+ TBackgroundAttributes const * & aBackAttr,
+ RArray<class TPlacedAttributes> const * & aPlacedAttr )
+ {
+ TInt index;
+
+ TInt err = FindEntry(aWindow, index);
+// __ASSERT_DEBUG(err != KErrNotFound, Panic(EWsPanicNoWindowElement));
+
+// return *iElements[index].iElement;
+ if (err >= KErrNone)
+ {
+ aBackAttr=&iElements[index]->iBackgroundElement;
+ aPlacedAttr=&iElements[index]->iPlacedElements;
+ }
+ else
+ {
+ aBackAttr=NULL;
+ aPlacedAttr=NULL;
+ }
+ return err;
+
+ }
+
+/** Registers the surface with the compositor.
+@param aSurface The surface id to register.
+@return KErrNone if successful, KErrNoMemory if registration fails due to low
+memory, KErrNotSupported if the surface is not compatible with
+this compositor or KErrBadHandle if the given surface ID does not
+represent a valid surface. KErrArgument is returned if the
+surface does not have both dimensions less than 32 767 pixels.
+*/
+TInt CWindowElementSet::RegisterSurface(const TSurfaceId& aSurface)
+ {
+
+ return iScene.RegisterSurface(aSurface);
+ }
+
+/** Unregisters the surface with the compositor.
+
+@param aSurface The surface id to register.
+@return KErrNone if successful. KErrInUse if the surface is
+used by a layer or layers. KErrBadHandle if the surface
+is not currently registered. KErrArgument if
+the surface ID is a NULL ID.
+*/
+
+void CWindowElementSet::UnregisterSurface(const TSurfaceId& aSurface)
+ {
+
+ TInt returnCode = iScene.UnregisterSurface(aSurface);
+ __ASSERT_DEBUG((returnCode==KErrNone || returnCode==KErrInUse || returnCode==KErrBadHandle), Panic(EWsPanicSceneErrorIgnored));
+ }
+
+/** Sorts the array elements into the same order as the windows are in the
+hierarchy. Use after window hierarchy has been modified, to update the scene
+order to match.
+@return EFalse if element order unchanged, ETrue if order may have changed.
+*/
+TBool CWindowElementSet::SortByZOrder()
+ {
+ if (iElements.Count() < 2)
+ {
+ // Early out for the very common cases where there are zero or one
+ // elements, which cannot therefore be out of order.
+ return EFalse;
+ }
+
+ // The approach being used is to first just sort the array, then update the
+ // scene order afterwards. This is simple to code and since there are not
+ // expected to be many elements, it should be perfectly good enough.
+
+ TLinearOrder<CWindowElement> order(WindowOrder);
+ iElements.Sort(order);
+
+ TBool orderChanged = EFalse;
+ MWsElement* below;
+ TInt elementCount = iElements.Count();
+ for (TInt index = 0; index < elementCount; index++)
+ {
+ if (index == 0)
+ {
+ below = NULL;
+ }
+ else
+ {
+ //Find highest element in window below
+ TInt placedCount = iElements[index-1]->iPlacedElements.Count();
+ if (placedCount > 0)
+ {
+ below = iElements[index-1]->iPlacedElements[placedCount-1].iElement;
+ }
+ else
+ { //below = above = background surface
+ below = iElements[index-1]->iBackgroundElement.iElement;
+ }
+ }
+ //Find lowest element in above window element
+ MWsElement* above;
+ if (iElements[index]->iBackgroundElement.iElement != NULL)
+ { //use background element
+ above = iElements[index]->iBackgroundElement.iElement; //background element will be bottom
+ }
+ else //use bottom element of placed surfaces
+ {
+ //above = iElements[index]->iPlacedElements[iElements[index]->iPlacedElements.Count()-1].iElement; //first or last placed element is bottom?
+ above = iElements[index]->iPlacedElements[0].iElement;
+ }
+ if (above->ElementBelow() != below)
+ {
+ //CALL below window element function to move all elements above 'below'
+ iElements[index]->MoveToAboveGivenElement(iScene, below);
+ orderChanged = ETrue;
+ }
+ }
+ return orderChanged;
+ }
+
+/** Processes the specified windows placed elements, for when windows visibility is changed.
+If the placed elements are no longer visible, they are removed.
+
+@param aWindow The window to call the function on.
+@return Positive if any elements have been removed, zero if not, or errorcode.
+@see CWindowElement::SetVisibleRegion
+*/
+TInt CWindowElementSet::SetVisibleRegion(CWsClientWindow& aWindow)
+ {
+ TInt index;
+ TInt find = FindEntry(aWindow,index);
+ WS_ASSERT_DEBUG(find>=KErrNone,EWsPanicNoWindowElement);
+ TBool ret = iElements[index]->SetVisibleRegion(aWindow.VisibleRegion(), iScene);
+
+ if (!iElements[index]->iBackgroundElement.iElement && iElements[index]->iPlacedElements.Count() == 0)
+ {
+ DestroyWindowElementEntry(index);
+ }
+ return ret;
+ }
+
+/** Updates the specified windows elements extent, either from a window movement or a change in window size
+
+@param aWindow The window to call the function on.
+@param aOffset The movement of the window. If NULL then the window has changed size.
+@see CWindowElement::UpdateElementExtent
+*/
+void CWindowElementSet::UpdateElementExtent(const CWsClientWindow& aWindow, const TPoint* aOffset)
+ {
+ FindElement(aWindow)->UpdateElementExtent(aOffset);
+ }
+
+/** Method to fill in a TSurfaceConfiguration from a scene element.
+
+@param aConfiguration Surface configuration to fill in.
+@param aElement Element to get information from.
+@return Once multiple versions of TSurfaceConfiguration are available, KErrNotSupported if configuration supplied is too small.
+*/
+TInt CWindowElementSet::GetConfiguration(TSurfaceConfiguration& aConfiguration,MWsElement& aElement)
+ {
+ TSurfaceId tempSurfaceId = aElement.ConnectedSurface();
+ aConfiguration.SetSurfaceId(tempSurfaceId);
+
+ //Convert and copy orientation
+ aConfiguration.SetOrientation(ElementToGcRotation(aElement.SourceRotation()));
+
+ //Convert and copy flip
+ TBool flip = aElement.SourceFlipping();
+ aConfiguration.SetFlip(flip);
+
+ //Convert and copy viewport
+ TRect tempViewport;
+ aElement.GetSourceRectangle(tempViewport);
+ aConfiguration.SetViewport(tempViewport);
+ TRect tempExtent;
+ aElement.GetDestinationRectangle(tempExtent);
+ aConfiguration.SetExtent(tempExtent);
+ return KErrNone; //Could fail if there are multiple versions of TSurfaceConfiguration
+ }
+
+/** Returns the window element entry for the specified window.
+
+@param aWindow The window to call the function on.
+*/
+CWindowElement* CWindowElementSet::FindElement(const CWsClientWindow& aWindow) const
+ {
+ TInt index;
+ TInt error = FindEntry(aWindow,index);
+ if (error == KErrNone)
+ return iElements[index];
+ WS_ASSERT_DEBUG(EFalse,EWsPanicNoWindowElement);
+ return NULL;
+ }
+
+/** Creates a set of window-element pairs for this scene.
+
+@param aScene To allow access to the scene.
+@param aComposer To allow access to the composer.
+*/
+CWindowElementSet::CWindowElementSet(MWsScene& aScene) :
+ iScene(aScene)
+ {}
+
+/** Searches for the entry in iElements with the given window
+
+@param aWindow The window to find the entry of / where it should be inserted.
+@param aIndex aIndex is set to entry found or the insertion point, respectively.
+@param aLinearSearch ETrue if a linear search of the window element set is required.
+@return KErrNone if found or KErrNotFound.
+*/
+TInt CWindowElementSet::FindEntry(const CWsClientWindow& aWindow, TInt& aIndex, TBool aLinearSearch /*= EFalse*/) const
+ {
+ CWindowElement winelement(aWindow);
+
+ // The array order makes use of the parent pointer, which gets reset during
+ // window shutdown, so if it is clear fall back to a linear search.
+ if (!aWindow.BaseParent() || aLinearSearch)
+ {
+ TIdentityRelation<CWindowElement> match(WindowMatch);
+
+ aIndex = iElements.Find(&winelement, match);
+ return (aIndex == KErrNotFound) ? KErrNotFound : KErrNone;
+ }
+ else
+ {
+ TLinearOrder<CWindowElement> order(WindowOrder);
+ return iElements.FindInOrder(&winelement, aIndex, order);
+ }
+ }
+
+/** Used to find an entry in the set when order cannot be used.
+
+@param aFirst First windowelement to compare.
+@param aSecond Second windowelement to compare.
+@return ETrue if the entries are the same, and EFalse if they are not.
+*/
+TBool CWindowElementSet::WindowMatch(const CWindowElement& aFirst, const CWindowElement& aSecond)
+ {
+ return (&aFirst.iWindow == &aSecond.iWindow);
+ }
+
+
+/** Used to determine the order of entries in the set.
+
+@param aFirst First windowelement to compare.
+@param aSecond Second windowelement to compare.
+@return zero if the entries are the same, a negative value if
+aFirst is behind aSecond or a positive value if aFirst is in front of aSecond.
+*/
+TInt CWindowElementSet::WindowOrder(const CWindowElement& aFirst, const CWindowElement& aSecond)
+ {
+ TInt result = 0;
+
+ if (&aFirst.iWindow != &aSecond.iWindow)
+ {
+ result = aFirst.iWindow.IsInfrontOf(&aSecond.iWindow) ? 1 : -1;
+ }
+
+ return result;
+ }
+
+
+/** Re-sends the extents for all the elements (in this window) to the scene
+ * This allows the renderstage to re-scale those element extents
+ *
+ *
+ **/
+void CWindowElement::ResubmitAllElementExtents()
+ {
+ if (MWsElement* element=iBackgroundElement.iElement)
+ {
+ TRect extent(TRect::EUninitialized);
+ element->GetDestinationRectangle(extent);
+ element->SetDestinationRectangle(extent);
+ }
+ TInt elementCount = iPlacedElements.Count();
+ for (TInt index = 0; index < elementCount; index++)
+ {
+ if (MWsElement* element=iPlacedElements[index].iElement)
+ {
+ TRect extent(TRect::EUninitialized);
+ element->GetDestinationRectangle(extent);
+ element->SetDestinationRectangle(extent);
+ }
+ }
+ }
+
+/** Re-sends the extents for all the elements (in all the windows) to the scene
+ * This allows the renderstage to re-scale those element extents
+ *
+ *
+ **/
+void CWindowElementSet::ResubmitAllElementExtents()
+ {
+ TInt elementCount = iElements.Count();
+ for (TInt index = 0; index < elementCount; index++)
+ {
+ iElements[index]->ResubmitAllElementExtents();
+ }
+ }
+
+//
+// Debug functions
+//
+
+/** Returns background attributes for the specified window index.
+For use with debug client interface.
+
+@param aWin Window index to get the surface attributes from.
+@return Background attributes for the specified window. NULL if the window index is invalid.
+*/
+const TBackgroundAttributes* CWindowElementSet::DebugBackgroundAt(TUint aWin)const
+ {
+ if (aWin>=Count())
+ return NULL;
+ return &iElements[aWin]->iBackgroundElement;
+ }
+
+/** Returns the client window for the specified window index.
+For use with debug client interface.
+
+@param aWin Window index to get the client window from.
+@return Client window for the specified window. NULL if the window index is invalid.
+*/
+const CWsClientWindow* CWindowElementSet::DebugWindowAt(TUint aWin)const
+ {
+ if (aWin>=Count())
+ return NULL;
+ return &iElements[aWin]->iWindow;
+ }
+
+/** Returns how many placed surfaces are on the specified window
+For use with debug client interface.
+
+@param aWin Window index to get the client window from.
+@return Amount of placed surfaces for the specified window index
+*/
+TInt CWindowElementSet::DebugPlacedCountAt(TUint aWin)const
+ {
+ if (aWin>=Count())
+ return -1;
+ return iElements[aWin]->iPlacedElements.Count();
+ }
+
+/** Returns the placed attributes for the specified placed surface index in the
+specified window index.
+For use with debug client interface.
+
+@param aWin Window index to get the client window from.
+@param aPlace Placed surface index to get the placed surface attributes
+@return Placed surface attributes. NULL if either index was invalid.
+*/
+const TPlacedAttributes* CWindowElementSet::DebugPlacedAt(TUint aWin,TUint aPlace)const
+ {
+ if (aWin>=Count())
+ return NULL;
+ if (aPlace>=iElements[aWin]->iPlacedElements.Count())
+ return NULL;
+ return &iElements[aWin]->iPlacedElements[aPlace];
+ }
+
+MWsElement* CWindowElementSet::GetElementFromWindow(const CWsClientWindow& aWindow) const
+ {
+ CWindowElement* windowElement = FindElement(aWindow);
+ if (windowElement)
+ return windowElement->Element();
+ else
+ return NULL;
+ }