windowing/windowserver/nga/SERVER/regionextend.cpp
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nga/SERVER/regionextend.cpp	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,336 @@
+// 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:
+//
+
+#include <e32def.h>
+#include "regionextend.h"
+
+//Only call this if certain neither rectangle is empty.
+//Region rectangles are always non-empty
+inline /*static*/
+TRegionExtend::TOverlapFlags TestDifferenceNotEmpty(const TRect& aThis,const TRect& aThat)
+	{
+	struct SubAdd
+	{
+		inline static TRegionExtend::TOverlapFlags Conv(TInt delta)
+			{	//returns sub, exact or add for delta of each edge pair
+				//neg --> +1	//pos --> +2	//zero ==> 0	
+				return TRegionExtend::TOverlapFlags(	
+						((delta>>31)&1)	+(((-delta)>>30)&2)		);
+			}
+	};
+	//could use SubAdd for this if...
+	if (	aThis.iTl.iX>=aThat.iBr.iX
+		||	aThis.iTl.iY>=aThat.iBr.iY
+		||					aThat.iTl.iX>=aThis.iBr.iX
+		||					aThat.iTl.iY>=aThis.iBr.iY
+	)
+		return TRegionExtend::TOverlapFlags(TRegionExtend::EDiffers|TRegionExtend::ENoIntersect);
+
+	TInt subAdd=(	SubAdd::Conv(aThis.iTl.iX-aThat.iTl.iX)
+					|	SubAdd::Conv(aThis.iTl.iY-aThat.iTl.iY)
+					|	SubAdd::Conv(aThat.iBr.iX-aThis.iBr.iX)
+					|	SubAdd::Conv(aThat.iBr.iY-aThis.iBr.iY)
+				);
+	return 
+	TRegionExtend::TOverlapFlags(subAdd);
+	}
+
+/**	Calc total area of a list of non-intersecting rectangles (ie a region)
+ * 	@param	aThisRects	the array of rectangles
+ * 	@param	aThisCount	the number in the array
+ */
+inline TUint RectListArea(const TRect* aThisRects,TInt aThisCount)
+	{
+	TInt thisArea=0;
+	for (TInt stepThis=aThisCount-1;stepThis>=0;stepThis--)
+		{
+		TSize size=aThisRects[stepThis].Size();
+		__ASSERT_DEBUG((size.iWidth|size.iHeight)<32768,User::Panic(_L("TRegionExtend"),4003));
+		thisArea+=size.iWidth*size.iHeight;
+		}
+	return thisArea;
+	}
+/**	Returns the result code flag based on the calculated intersection of two areas
+ * 	The intersection is always less than or equal to this and that.
+ * 	@param 	aThisArea		Start area
+ * 	@param	aIntersectArea	Intersection
+ * 	@param	aThatArea		Final area
+ * 	@return
+ * 		-	EDiffers 	if both this and that differ from intersect 
+ * 		-	EExact		if both this and that are same as intersect
+ * 		-	ESub		if only that is same as intersect, so this is bigger
+ * 		-	EAdd		if only this is same as intersect, so that is bigger
+ * 		
+ **/
+inline TRegionExtend::TOverlapFlags AreaDiffResults(TUint aThisArea,TUint aIntersectArea,TUint aThatArea)
+	{
+	if (aThisArea>aIntersectArea)
+		if (aThatArea>aIntersectArea)
+			return TRegionExtend::EDiffers;
+		else
+			return TRegionExtend::ESub;
+	else
+		if (aThatArea>aIntersectArea)
+			return TRegionExtend::EAdd;
+		else
+			return TRegionExtend::EExact;
+	}
+/**	Calculates the intersection area of one rectangle with an array of non intersecting rectangles
+ * 	It is presumed that the caller will loop through all the cells of a target region,
+ * 	repeating this call for a source region, so we can add an extra optimisation 
+ * 	to avoid revisiting any source rectangles that have been consumed completely in later passes.
+ * 	The simplest test is that the source cell is wholy inside the target rect.
+ * 	The simplest record is a bit field, but that only works up to 32 elements, then will not optimise further elements.
+ * 	@param	aThisCount 			num elements in rect array
+ * 	@param	aThisRects			array of rectangles
+ * 	@param	aThatRect			intersecting rectangle
+ * 	@param	aOptimiseThisBits	record of elements of rect aray that have been fully consumed
+ * 	@return	total intersection area
+ **/
+inline TUint TestDifferenceRegionInnerLoop(TInt aThisCount,const TRect* aThisRects,TRect& aThatRect,TUint& aOptimiseThisBits)
+	{
+	TUint intersectArea=0;
+	for (TInt stepThis=aThisCount-1,bit=1;stepThis>=0;stepThis--,bit<<=1)
+		{
+		if (!(aOptimiseThisBits&bit))
+			{
+			const TRect& thisRect=aThisRects[stepThis];
+			TRegionExtend::TOverlapFlags flags=TestDifferenceNotEmpty(thisRect,aThatRect);
+			if (!(flags&TRegionExtend::ENoIntersect))
+				{
+				if (!(flags&TRegionExtend::EAdd))
+					{	//Skip rest of inner loop if a containing rect is found
+					TSize size=aThatRect.Size();
+					intersectArea+=size.iWidth*size.iHeight;
+					if (!(flags&TRegionExtend::ESub))	//equal rects...
+						{	//skip this cell for rest of outer loop if a contains rect is found
+						aOptimiseThisBits|=bit;
+						}
+					break;	//this cell contains the target rect so don't bother checking any more
+					}
+				else
+					if (!(flags&TRegionExtend::ESub))
+						{	//skip this cell for rest of outer loop if a contains rect is found
+						aOptimiseThisBits|=bit;
+						TSize size=thisRect.Size();
+						intersectArea+=size.iWidth*size.iHeight;
+						}
+					else
+						{
+						TRect intersect=thisRect;
+						intersect.Intersection(aThatRect);
+						TSize size=intersect.Size();
+						intersectArea+=size.iWidth*size.iHeight;
+						}
+				}
+			}
+		}
+	return intersectArea;
+	}
+/** Avoids the use of a temp region by performing area calc on the fly.
+ * If both regions are empty then EOverlapNoIntersect only is returned.
+ * @param	aThat	target region
+ * @return	flags from TOverlapFlags enumeration
+ * 		-	EExact			=0 if rgions are exactly identical
+ * 		-	ESub			Flagged if some rectangles are removed converting current region to that target
+ * 		-	EAdd			Flagged if some rectangles are added converting current region to that target
+ * 		- 	ENoIntersect	if there is no common region between the current region and that target
+ * 		-	EErrorRegion	One of the regions is signalling CheckError()
+ **/
+TRegionExtend::TOverlapFlags	TRegionExtend::TestDifference(const TRegion& aThat)const
+	{
+	TInt intersectArea=0;
+	TInt thisArea=0;
+	TInt thatArea=0;
+	const TRect* thisRects=RectangleList();
+	const TRect* thatRects=aThat.RectangleList();
+	TInt thatCount=aThat.Count();
+	TInt thisCount=Count();
+	
+	if (CheckError()||aThat.CheckError())
+		return EErrorRegion;
+	if (thisCount==0)
+		if (thatCount==0)
+			return ENoIntersect;
+		else
+			return TOverlapFlags(ENoIntersect|EAdd);
+	//both regions are populated. How big is the intersection?
+	//The following optimisation bit is that 
+	//if any rect is fully contained by a rect in the opposite region 
+	//then further compares against that rect are skipped. For this, inner loop is skipped immediately
+	//Can track the first 32 rects of aThat. The remainder won't benefit from the optimisation
+	TUint optimiseThisBits=0;	
+	for (TInt stepThat=thatCount-1;stepThat>=0;stepThat--)
+		{
+		TRect thatRect=thatRects[stepThat];
+		intersectArea+=TestDifferenceRegionInnerLoop(thisCount,thisRects,thatRect,optimiseThisBits);
+		}
+	if (intersectArea==0)
+		if (thatCount==0)
+			return TOverlapFlags(ENoIntersect|ESub);
+		else
+			return 	TOverlapFlags(ENoIntersect|EAdd|ESub);
+	thatArea=RectListArea(thatRects,thatCount);
+	thisArea=RectListArea(thisRects,thisCount);
+	return AreaDiffResults( thisArea, intersectArea, thatArea );
+	}
+
+/** Avoids the use of a temp region by performing area calc on the fly.
+ * This version further optimises the process by avoiding the client having to re-origin either region.
+  * If both regions are empty then EOverlapNoIntersect only is returned.
+ * @param	aThat	target region
+ * @return	flags from TOverlapFlags enumeration
+ * 		-	EExact			=0 if rgions are exactly identical
+ * 		-	ESub			Flagged if some rectangles are removed converting current region to that target
+ * 		-	EAdd			Flagged if some rectangles are added converting current region to that target
+ * 		- 	ENoIntersect	if there is no common region between the current region and that target
+ * 		-	EErrorRegion	One of the regions is signalling CheckError()
+ **/
+TRegionExtend::TOverlapFlags	TRegionExtend::TestDifference(const TRegion& aThat,TPoint aOffsetToThat)const
+	{
+	TInt intersectArea=0;
+	TInt thisArea=0;
+	TInt thatArea=0;
+	const TRect* thisRects=RectangleList();
+	const TRect* thatRects=aThat.RectangleList();
+	TInt thatCount=aThat.Count();
+	TInt thisCount=Count();
+	
+	if (CheckError()||aThat.CheckError())
+		return EErrorRegion;
+	if (thisCount==0)
+		if (thatCount==0)
+			return ENoIntersect;
+		else
+			return TOverlapFlags(ENoIntersect|EAdd);
+	//both regions are populated. How big is the intersection?
+	//The following optimisation bit is that 
+	//if any rect is fully contained by a rect in the opposite region 
+	//then further compares against that rect are skipped. For this, inner loop is skipped immediately
+	//Can track the first 32 rects of aThat. The remainder won't benefit from the optimisation
+	TUint optimiseThisBits=0;	
+	for (TInt stepThat=thatCount-1;stepThat>=0;stepThat--)
+		{
+		TRect thatRect=thatRects[stepThat];
+		thatRect.Move(-aOffsetToThat.iX,-aOffsetToThat.iY);	//this line is the only difference, but the next lump has a lot of parameters...
+		intersectArea+=TestDifferenceRegionInnerLoop(thisCount,thisRects,thatRect,optimiseThisBits);
+		}
+	if (intersectArea==0)
+		if (thatCount==0)
+			return TOverlapFlags(ENoIntersect|ESub);
+		else
+			return 	TOverlapFlags(ENoIntersect|EAdd|ESub);
+	
+	thatArea=RectListArea(thatRects,thatCount);
+	thisArea=RectListArea(thisRects,thisCount);
+	return AreaDiffResults( thisArea, intersectArea, thatArea );
+	}
+
+/** This returns the same comparrison flags between two rectangles.
+ *	Note that a zero return means exact intersection... 
+ *  Intended as an internal method, but there doesn't seem to be a useful public alternative.
+ * 	@param  aThis	source rectangle
+ *	@param	aThat	target rectangle
+ * 	@return	flags from TOverlapFlags enumeration
+ * 		-	EExact			=0 if rgions are exactly identical
+ * 		-	ESub			Flagged if some rectangles are removed converting this source rectangle to that target
+ * 		-	EAdd			Flagged if some rectangles are added converting this source rectangle to that target
+ * 		- 	ENoIntersect	if there is no common region between this source rectangle and that target
+ **/
+TRegionExtend::TOverlapFlags TRegionExtend::TestDifference(const TRect& aThis,const TRect& aThat)
+	{
+	if (aThis.IsEmpty())
+		if (aThat.IsEmpty())
+			return ENoIntersect;
+		else
+			return TOverlapFlags(EAdd|ENoIntersect);
+	else
+		if (aThat.IsEmpty())
+			return TOverlapFlags(ESub|ENoIntersect);
+	return TestDifferenceNotEmpty(aThis,aThat);
+	}	
+
+
+/** Returns total area of the region
+ * 	@return total area
+ **/
+TUint	TRegionExtend::Area()const
+{ 
+return RectListArea(RectangleList(),Count());
+}
+
+/** Avoids the use of a temp region by performing area calc on the fly.
+ * If both are empty then EOverlapNoIntersect only is returned.
+ * @param	aThat	target rectangle
+ * @return	flags from TOverlapFlags enumeration
+ * 		-	EExact			=0 if region exactly fills rectangle
+ * 		-	ESub			Flagged if some rectangles are removed converting current region to that target
+ * 		-	EAdd			Flagged if some rectangles are added converting current region to that target
+ * 		- 	ENoIntersect	if there is no common region between the current region and that target
+ * 		-	EErrorRegion	One of the region is signalling CheckError()
+ **/
+TRegionExtend::TOverlapFlags	TRegionExtend::TestDifference(const TRect& aThat)const
+	{
+	TInt intersectArea=0;
+	const TRect* thisRects=RectangleList();
+	TInt thisCount=Count();
+	
+	if (aThat.IsEmpty())
+		if (thisCount==0)
+			return ENoIntersect;
+		else
+			return TOverlapFlags(ENoIntersect|ESub);
+	if (CheckError())
+		return EErrorRegion;
+	TInt output=ENoIntersect;
+	for (TInt stepThis=thisCount-1,bit=1;stepThis>=0;stepThis--,bit+=bit)
+		{
+		TOverlapFlags flags=TestDifferenceNotEmpty(thisRects[stepThis],aThat);
+		if (!(flags&ENoIntersect))
+			{
+			if (!(flags&EAdd))		//the target rect does not add anything to this region element
+				{	//Skip rest of inner loop if a containing rect is found
+				if ((flags&ESub)||thisCount>1)
+					return ESub;	//the region element is bigger or there are more region elements
+				else
+					return EExact;
+				}
+			else
+				{
+				TRect intersect=thisRects[stepThis];
+				intersect.Intersection(aThat);
+				TSize size=intersect.Size();
+				__ASSERT_DEBUG((size.iWidth|size.iHeight)<32768,User::Panic(_L("TRegionExtend"),1003));
+				intersectArea+=size.iWidth*size.iHeight;
+				
+				}
+			output&=~ENoIntersect;
+			}
+		output|=(flags&ESub);
+		}
+	if (intersectArea==0)
+		{
+		return TOverlapFlags(output|EAdd);
+		}
+	TSize size=aThat.Size();
+	__ASSERT_DEBUG((size.iWidth|size.iHeight)<32768,User::Panic(_L("TRegionExtend"),2003));
+	TInt thatArea=size.iWidth*size.iHeight;
+	if (thatArea>intersectArea)
+		return TOverlapFlags(output|EAdd);
+	else
+		return TOverlapFlags(output);
+	}
+	
+