windowing/windowserver/nga/SERVER/regionextend.cpp
author Faisal Memon <faisal.memon@nokia.com>
Thu, 06 May 2010 11:31:11 +0100
branchNewGraphicsArchitecture
changeset 47 48b924ae7197
parent 0 5d03bc08d59c
permissions -rw-r--r--
Applied patch 1, to provide a syborg specific minigui oby file. Need to compare this with the "stripped" version currently in the tree. This supplied version applies for Nokia builds, but need to repeat the test for SF builds to see if pruning is needed, or if the file needs to be device-specific.

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