os/kernelhwsrv/kernel/eka/euser/us_regn.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32\euser\us_regn.cpp
    15 // 
    16 //
    17 
    18 
    19 #include "us_std.h"
    20 
    21 NONSHARABLE_CLASS(TRectKey) : public TKey
    22 	{
    23 public:
    24 	TRectKey(const TRect *aRectList,const TPoint &aOffset);
    25 	virtual TInt Compare(TInt aLeft,TInt aRight) const;
    26 private:
    27 	const TRect *iRectList;
    28 	TBool iDown;
    29 	TBool iRight;
    30 	};
    31 
    32 NONSHARABLE_CLASS(TRectSwap) : public TSwap
    33 	{
    34 public:
    35 	inline TRectSwap(TRect *aRectList);
    36 	virtual void Swap(TInt aLeft,TInt aRight) const;
    37 private:
    38 	TRect *iRectList;
    39 	};
    40 
    41 inline TRectSwap::TRectSwap(TRect *aRectList)
    42 	{iRectList=aRectList;}
    43 
    44 enum {ERegionBufSize=8};
    45 
    46 EXPORT_C TRegion::TRegion(TInt aAllocedRects)
    47 //
    48 // Constructor.
    49 //
    50 	: iCount(0),iError(EFalse),iAllocedRects(aAllocedRects)
    51 	{}
    52 
    53 
    54 
    55 
    56 EXPORT_C TBool TRegion::IsEmpty() const
    57 /**
    58 Tests whether the region is empty.
    59 
    60 @return True, if the region is empty and its error flag is unset;
    61         false, otherwise.
    62 */
    63 	{
    64 
    65 	return(iCount==0 && !iError);
    66 	}
    67 
    68 
    69 
    70 
    71 #ifndef __REGIONS_MACHINE_CODED__
    72 EXPORT_C TRect TRegion::BoundingRect() const
    73 /**
    74 Gets the minimal rectangle that bounds the entire region.
    75 
    76 @return The region's minimal bounding rectangle.
    77 */
    78 	{
    79 
    80 	TRect bounds;
    81     const TRect *pRect;
    82 	const TRect *pEnd;
    83 	if (iCount>0)
    84 		{
    85 		pRect=RectangleList();
    86 		bounds=(*pRect++);
    87 		for (pEnd=pRect+(iCount-1);pRect<pEnd;pRect++)
    88 			{
    89 			if (pRect->iTl.iX<bounds.iTl.iX)
    90 				bounds.iTl.iX=pRect->iTl.iX;
    91 			if (pRect->iTl.iY<bounds.iTl.iY)
    92 				bounds.iTl.iY=pRect->iTl.iY;
    93 			if (pRect->iBr.iX>bounds.iBr.iX)
    94 				bounds.iBr.iX=pRect->iBr.iX;
    95 			if (pRect->iBr.iY>bounds.iBr.iY)
    96 				bounds.iBr.iY=pRect->iBr.iY;
    97 			}
    98 		}
    99 	return(bounds);
   100 	}	
   101 #endif
   102 
   103 
   104 
   105 
   106 EXPORT_C const TRect &TRegion::operator[](TInt aIndex) const
   107 /**
   108 Gets a rectangle from the region.
   109 
   110 @param aIndex The index of a rectangle within the region's array of rectangles. 
   111               Indexes are relative to zero.
   112               
   113 @return The specified rectangle.              
   114               
   115 @panic USER 81, if aIndex is greater than or equal to the number 
   116                 of rectangles in the region.
   117 */
   118 	{
   119 
   120 	__ASSERT_ALWAYS((TUint)aIndex<(TUint)iCount,Panic(ETRegionOutOfRange));
   121     return(*(RectangleList()+aIndex));
   122     }
   123 
   124 
   125 
   126 
   127 #ifndef __REGIONS_MACHINE_CODED__
   128 EXPORT_C TBool TRegion::IsContainedBy(const TRect &aRect) const
   129 /**
   130 Tests whether the region is fully enclosed within the specified rectangle.
   131 
   132 @param aRect The specified rectangle.
   133  
   134 @return True, if the region is fully enclosed within the rectangle (their sides 
   135         may touch); false, otherwise.
   136 */
   137 	{
   138 
   139     const TRect *pRect1;
   140     const TRect *pEnd1;
   141 	for (pRect1=RectangleList(),pEnd1=pRect1+iCount;pRect1<pEnd1;pRect1++)
   142 		{
   143 		if (pRect1->iTl.iX<aRect.iTl.iX || pRect1->iBr.iX>aRect.iBr.iX || pRect1->iTl.iY<aRect.iTl.iY || pRect1->iBr.iY>aRect.iBr.iY)
   144 			return(EFalse);
   145 		}
   146 	return(ETrue);
   147 	}
   148 
   149 
   150 
   151 
   152 EXPORT_C TBool TRegion::Intersects(const TRect &aRect) const
   153 /**
   154 Tests whether where there is any intersection between this region and the specified rectangle.
   155 
   156 @param aRect The specified rectangle.
   157  
   158 @return True, if there is an intersection; false, otherwise.
   159 */
   160 	{
   161 
   162     const TRect *pRect1;
   163     const TRect *pEnd1;
   164 	for (pRect1=RectangleList(),pEnd1=pRect1+iCount;pRect1<pEnd1;pRect1++)
   165 		{
   166 		if (aRect.Intersects(*pRect1))
   167 			return ETrue;
   168 		}
   169 	return EFalse;
   170 	}
   171 
   172 
   173 
   174 
   175 EXPORT_C void TRegion::Copy(const TRegion &aRegion)
   176 /**
   177 Copies another region to this region.
   178 
   179 The state of the specified region's error flag is also copied.
   180 
   181 @param aRegion The region to be copied.
   182 */
   183 	{
   184 	if (aRegion.iError)
   185 		{
   186 		ForceError();
   187 		}
   188 	else
   189 		{
   190 		const TInt count = aRegion.iCount;
   191 		if (count == 0)
   192 			{ // release memory
   193 			Clear();
   194 			}
   195 		else
   196 			{
   197 			if (iError)
   198 				{
   199 				Clear();
   200 				}
   201 
   202 			if (SetListSize(count))
   203 				{
   204 				iCount = count;
   205 				Mem::Copy(RectangleListW(), aRegion.RectangleList(), sizeof(TRect)*count);
   206 				}
   207 			}
   208 		}
   209 	}
   210 
   211 
   212 
   213 
   214 EXPORT_C void TRegion::Offset(const TPoint &aOffset)
   215 /**
   216 Moves the region by adding a TPoint offset to the co-ordinates of its corners.
   217 	
   218 The size of the region is not changed.
   219 	
   220 @param aOffset The offset by which the region is moved. The region is moved 
   221                horizontally by aOffset.iX pixels and vertically by aOffset.iY pixels.
   222 */
   223  	{
   224 
   225 	TRect *pR=RectangleListW();
   226 	const TRect *pE=pR+iCount;
   227 	while (pR<pE)
   228 		{
   229 		pR->Move(aOffset);
   230 		pR++;
   231 		}
   232 	}
   233 
   234 
   235 
   236 
   237 EXPORT_C void TRegion::Offset(TInt aXoffset,TInt aYoffset)
   238 /**
   239 Moves the region by adding X and Y offsets to the co-ordinates of its corners.
   240 	
   241 The size of the region is not changed.
   242 	
   243 @param aXoffset The number of pixels by which to move the region horizontally. 
   244                 If negative, the region moves leftwards. 
   245 @param aYoffset The number of pixels by which to move the region vertically. 
   246                 If negative, the region moves upwards.
   247 */
   248 	{
   249 
   250 	Offset(TPoint(aXoffset,aYoffset));
   251 	}
   252 
   253 
   254 
   255 
   256 EXPORT_C TBool TRegion::Contains(const TPoint &aPoint) const
   257 /**
   258 Tests whether a point is located within the region.
   259 
   260 If the point is located on the top or left hand side of any rectangle in the 
   261 region, it is considered to be within that rectangle and within the region. 
   262 
   263 If the point is located on the right hand side or bottom of a rectangle, it 
   264 is considered to be outside that rectangle, and may be outside the region.
   265 
   266 @param aPoint The specified point. 
   267 
   268 @return True, if the point is within the region; false, otherwise.
   269 */
   270 	{
   271 	const TRect *pR=RectangleList();
   272 	const TRect *pE=pR+iCount;
   273 	while (pR<pE)
   274 		{
   275 		if (pR->Contains(aPoint))
   276 			return(ETrue);
   277 		pR++;
   278 		}
   279 	return(EFalse);
   280 	}
   281 
   282 
   283 
   284 
   285 EXPORT_C void TRegion::SubRect(const TRect &aRect,TRegion *aSubtractedRegion)
   286 /**
   287 Removes a rectangle from this region.
   288 
   289 If there is no intersection between the rectangle and this region, then this 
   290 region is unaffected. 
   291 
   292 @param aRect             The rectangular area to be removed from this region. 
   293 @param aSubtractedRegion A pointer to a region. If this is supplied, the
   294                          removed rectangle is added to it. By default this
   295                          pointer is NULL.
   296 */
   297 	{
   298 	if (aRect.IsEmpty())
   299 		return;
   300 	TRect *prect=RectangleListW();
   301 	TInt limit=iCount;
   302 	for (TInt index=0;index<limit;)
   303 		{
   304 		if (prect->iBr.iX>aRect.iTl.iX && prect->iBr.iY>aRect.iTl.iY && prect->iTl.iX<aRect.iBr.iX && prect->iTl.iY<aRect.iBr.iY)
   305 			{
   306 			TRect rect(*prect);
   307 			TRect inter(aRect);
   308 			inter.Intersection(*prect);
   309 			DeleteRect(prect);
   310 			if (inter.iBr.iY!=rect.iBr.iY)
   311 				AppendRect(TRect(rect.iTl.iX,inter.iBr.iY,rect.iBr.iX,rect.iBr.iY));
   312 			if (inter.iTl.iY!=rect.iTl.iY)
   313 				AppendRect(TRect(rect.iTl.iX,rect.iTl.iY,rect.iBr.iX,inter.iTl.iY));
   314 			if (inter.iBr.iX!=rect.iBr.iX)
   315 				AppendRect(TRect(inter.iBr.iX,inter.iTl.iY,rect.iBr.iX,inter.iBr.iY));
   316 			if (inter.iTl.iX!=rect.iTl.iX)
   317 				AppendRect(TRect(rect.iTl.iX,inter.iTl.iY,inter.iTl.iX,inter.iBr.iY));
   318 			if (iError)
   319 				break;
   320 			if (aSubtractedRegion!=NULL)
   321 				aSubtractedRegion->AddRect(inter);
   322 			prect=RectangleListW()+index;		// List might have been re-allocated so re-get the pointer
   323 			limit--;
   324 			}
   325 		else
   326 			{
   327 			index++;
   328 			prect++;
   329 			}
   330 		}
   331 	}
   332 
   333 #endif
   334 
   335 
   336 
   337 
   338 /**
   339 Merges a rectangle with this region.
   340 
   341 If requested it looks for a rectangle in the region that covers the new rectangle, if found method returns immediately.
   342 Otherwise, or if an enclosing rectangle is not found, the new aRect is subtracted from all intersecting rectangles,
   343 and then aRect is appended to the region.
   344 
   345 @param aRect             The rectangular area to be added to this region.
   346 @param aCovered          Whether to look for a rectangle in the region that covers the new aRect.
   347 */
   348 void TRegion::MergeRect(const TRect &aRect, TBool aCovered)
   349 	{
   350 	TRect *prect=RectangleListW();
   351 	TInt limit=iCount;
   352 	TInt index=0;
   353 
   354 	while (aCovered && (index < limit) )
   355 		{
   356 		if (prect->iBr.iX<=aRect.iTl.iX || prect->iBr.iY<=aRect.iTl.iY || prect->iTl.iX>=aRect.iBr.iX || prect->iTl.iY>=aRect.iBr.iY)
   357 			{
   358 			index++;
   359 			prect++;
   360 			}
   361 		else
   362 			{
   363 			if (prect->iBr.iX>=aRect.iBr.iX && prect->iBr.iY>=aRect.iBr.iY && prect->iTl.iX<=aRect.iTl.iX && prect->iTl.iY<=aRect.iTl.iY)
   364 				{ // region rectangle covers new aRect
   365 				return;
   366 				}
   367 			break; // let the 2nd loop deal with this intersection
   368 			}
   369 		}
   370 
   371 	while (index < limit)
   372 		{
   373 		if (prect->iBr.iX<=aRect.iTl.iX || prect->iBr.iY<=aRect.iTl.iY || prect->iTl.iX>=aRect.iBr.iX || prect->iTl.iY>=aRect.iBr.iY)
   374 			{
   375 			index++;
   376 			prect++;
   377 			}
   378 		else
   379 			{
   380 			TRect rect(*prect);
   381 			TRect inter(aRect);
   382 			inter.Intersection(*prect);
   383 			DeleteRect(prect);
   384 			if (inter.iBr.iY!=rect.iBr.iY)
   385 				AppendRect(TRect(rect.iTl.iX,inter.iBr.iY,rect.iBr.iX,rect.iBr.iY));
   386 			if (inter.iTl.iY!=rect.iTl.iY)
   387 				AppendRect(TRect(rect.iTl.iX,rect.iTl.iY,rect.iBr.iX,inter.iTl.iY));
   388 			if (inter.iBr.iX!=rect.iBr.iX)
   389 				AppendRect(TRect(inter.iBr.iX,inter.iTl.iY,rect.iBr.iX,inter.iBr.iY));
   390 			if (inter.iTl.iX!=rect.iTl.iX)
   391 				AppendRect(TRect(rect.iTl.iX,inter.iTl.iY,inter.iTl.iX,inter.iBr.iY));
   392 			if (iError)
   393 				return;
   394 			prect=RectangleListW()+index;		// List might have been re-allocated so re-get the pointer
   395 			limit--;
   396 			}
   397 		}
   398 	AppendRect(aRect);
   399 	}
   400 
   401 
   402 
   403 EXPORT_C void TRegion::Union(const TRegion &aRegion)
   404 /**
   405 Replaces this region with the union of it and the specified region.
   406 
   407 Note that if the error flag of either this region or the specified region is
   408 set, then this region is cleared and its error flag is set. This frees up
   409 allocated memory.
   410 
   411 @param aRegion The region to be joined to this region.
   412 */
   413 	{
   414 	if (aRegion.iError)
   415 		{
   416 		ForceError();
   417 		}
   418 	else if (!iError && (aRegion.iCount != 0))
   419 		{
   420 		if (iCount == 0)
   421 			{
   422 			Copy(aRegion);
   423 			}
   424 		else
   425 			{
   426 			RRegionBuf<ERegionBufSize> temp;
   427 			temp.Copy(aRegion);
   428 			if (temp.iCount>iCount)
   429 				{
   430 				temp.AppendRegion(*this);
   431 				Copy(temp);
   432 				}
   433 			else
   434 				{
   435 				AppendRegion(temp);
   436 				}
   437 			temp.Close();
   438 			}
   439 		}
   440 	}
   441 
   442 
   443 
   444 
   445 #ifndef __REGIONS_MACHINE_CODED__
   446 EXPORT_C void TRegion::Intersection(const TRegion &aRegion1,const TRegion &aRegion2)
   447 /**
   448 Replaces this region with the area of intersection between two specified regions.
   449 	
   450 Notes:
   451 	
   452 1. If the error flag of either of the two specified regions is set, then this 
   453    region is cleared and its error flag is set. This frees up allocated memory.
   454 	
   455 2. If this region's error flag is already set, then the function has no effect.
   456 	
   457 @param aRegion1 The first region. 
   458 @param aRegion2 The second region.
   459 */
   460     {
   461 	if (aRegion1.iError || aRegion2.iError)
   462 		ForceError();
   463 	else
   464 		{
   465 		iCount=0;
   466 		const TRect *pRect1,*pEnd1;
   467 		const TRect *pRect2,*pEnd2;
   468 		for (pRect1=aRegion1.RectangleList(),pEnd1=pRect1+aRegion1.iCount;pRect1<pEnd1;pRect1++)
   469 			{
   470 			for (pRect2=aRegion2.RectangleList(),pEnd2=pRect2+aRegion2.iCount;pRect2<pEnd2;pRect2++)
   471 				{
   472 				if (pRect1->iBr.iX>pRect2->iTl.iX && pRect1->iBr.iY>pRect2->iTl.iY && pRect1->iTl.iX<pRect2->iBr.iX && pRect1->iTl.iY<pRect2->iBr.iY)
   473 					{
   474 					TRect rect(*pRect2);
   475 					rect.Intersection(*pRect1);
   476 					AppendRect(rect);
   477 					}
   478 				}
   479 			}
   480 		}
   481 	}
   482 #endif
   483 
   484 
   485 
   486 
   487 EXPORT_C void TRegion::Intersect(const TRegion &aRegion)
   488 /**
   489 Replaces this region with the area of intersection between it and the specified 
   490 region.
   491 
   492 Note that if the error flag of either this region or the specified region is
   493 set, then this region is cleared and its error flag is set. This frees up
   494 allocated memory.
   495 
   496 @param aRegion The region to be intersected with this region.
   497 */
   498 	{
   499 	if (aRegion.iError)
   500 		{
   501 		ForceError();
   502 		}
   503 	else if (!iError && (iCount != 0))
   504 		{
   505 		if (aRegion.iCount == 0)
   506 			{
   507 			Clear();
   508 			}
   509 		else
   510 			{
   511 			RRegionBuf<ERegionBufSize> temp;
   512 			temp.Copy(*this);
   513 			Intersection(temp,aRegion);
   514 			temp.Close();
   515 			}
   516 		}
   517 	}
   518 
   519 
   520 
   521 
   522 EXPORT_C void TRegion::AddRect(const TRect &aRect)
   523 /**
   524 Adds a rectangle to this region.
   525 
   526 Notes:
   527 
   528 1. If this region's error flag is already set, this function has no effect.
   529 
   530 2. If the operation causes the capacity of this region to be exceeded, or if 
   531    memory allocation fails, the region is cleared, freeing up any memory which 
   532    has been allocated; its error flag is also set.
   533 
   534 @param aRect The rectangle to be added to this region.
   535 */
   536 	{
   537 	if (!aRect.IsEmpty() && !iError)
   538 		{
   539 		TBool doAppend = ETrue;
   540 		if (iCount > 0)
   541 			{
   542 			TRect regRect = BoundingRect();
   543 			TRect inter(aRect);
   544 			inter.Intersection(regRect);
   545 
   546 			if (!inter.IsEmpty())
   547 				{
   548 				if ( inter == regRect )
   549 					{ // equivalent to IsContainedBy(aRect)
   550 					iCount=0;
   551 					}
   552 				else
   553 					{
   554 					TBool coversRect = (inter == aRect); // bounding rect of region includes all of aRect?
   555 					MergeRect(aRect, coversRect);
   556 					doAppend = EFalse;
   557 					}
   558 				}
   559 			}
   560 		if (doAppend)
   561 			{
   562 			AppendRect(aRect);
   563 			}
   564 
   565 		// RRegion could have unneeded memory that can be freed
   566 		if (!iError && (iAllocedRects > iCount))
   567 			{
   568 			ShrinkRegion();
   569 			}
   570 		}
   571 	}
   572 
   573 
   574 
   575 
   576 EXPORT_C void TRegion::SubRegion(const TRegion &aRegion,TRegion *aSubtractedRegion)
   577 /**
   578 Removes a region.
   579 
   580 If there is no area of intersection between the two regions, this region is 
   581 unaffected.
   582 
   583 @param aRegion           The region to be removed from this region.
   584                          If aRegion's error flag is set, then this region is
   585                          cleared, freeing up any allocated memory, and the
   586                          error flag is set.
   587 @param aSubtractedRegion If specified, then on return contains the area removed 
   588                          from this region.
   589 */
   590 	{
   591 	SubtractRegion(aRegion, aSubtractedRegion);
   592 
   593 	// RRegion could have unneeded memory that can be freed
   594 	if (!iError && (iAllocedRects > iCount))
   595 		{
   596 		ShrinkRegion();
   597 		}
   598 	}
   599 
   600 
   601 /**
   602 Removes a region.
   603 
   604 If there is no area of intersection between the two regions, this region is 
   605 unaffected.
   606 
   607 @param aRegion           The region to be removed from this region.
   608                          If aRegion's error flag is set, then this region is
   609                          cleared, freeing up any allocated memory, and the
   610                          error flag is set.
   611 @param aSubtractedRegion If specified, then on return contains the area removed 
   612                          from this region.
   613 */
   614 void TRegion::SubtractRegion(const TRegion &aRegion,TRegion *aSubtractedRegion)
   615 	{
   616 	if (!iError)
   617 		{
   618 		if (aRegion.iError)
   619 			{
   620 			ForceError();
   621 			}
   622 		else if (iCount != 0)
   623 			{
   624 			const TRect *pR=aRegion.RectangleList();
   625 			const TRect *pE=pR+aRegion.iCount;
   626 			while (pR<pE && !iError)
   627 				{
   628 				SubRect(*pR++, aSubtractedRegion);
   629 				}
   630 			if (iError && aSubtractedRegion)
   631 				{
   632 				aSubtractedRegion->ForceError();
   633 				}
   634 			}
   635 		}
   636 	}
   637 
   638 
   639 
   640 
   641 #ifndef __REGIONS_MACHINE_CODED__
   642 EXPORT_C void TRegion::ClipRect(const TRect &aRect)
   643 /**
   644 Clips the region to the specified rectangle.
   645 
   646 The resulting region is the area of overlap between the region and the rectangle. 
   647 If there is no overlap, all rectangles within this region are deleted and 
   648 the resulting region is empty.
   649 
   650 @param aRect The rectangle to which this region is to be clipped.
   651 */
   652 	{
   653 
   654 	for (TInt index=0;index<iCount;)
   655 		{
   656 		TRect *r2=RectangleListW()+index;
   657 		if (r2->iTl.iX<aRect.iTl.iX)
   658 			r2->iTl.iX=aRect.iTl.iX;
   659 		if (r2->iTl.iY<aRect.iTl.iY)
   660 			r2->iTl.iY=aRect.iTl.iY;
   661 		if (r2->iBr.iX>aRect.iBr.iX)
   662 			r2->iBr.iX=aRect.iBr.iX;
   663 		if (r2->iBr.iY>aRect.iBr.iY)
   664 			r2->iBr.iY=aRect.iBr.iY;
   665 		if (r2->IsEmpty())
   666 			DeleteRect(r2);
   667 		else
   668 			index++;
   669 		}
   670 	}
   671 #endif
   672 
   673 
   674 
   675 
   676 EXPORT_C void TRegion::Clear()
   677 /**
   678 Clears this region.
   679 
   680 This frees up any memory which has been allocated and unsets the error flag.
   681 */
   682 	{
   683 
   684 	if (iAllocedRects>=0)
   685 		{
   686 		User::Free(((RRegion *)this)->iRectangleList);
   687 		((RRegion *)this)->iRectangleList=NULL;
   688 		iAllocedRects=0;
   689 		}
   690 	iCount=0;
   691 	iError=EFalse;
   692 	}
   693 
   694 
   695 
   696 
   697 
   698 EXPORT_C void TRegion::Tidy()
   699 /**
   700 Merges all rectangles within this region which share an adjacent edge of the 
   701 same length.
   702 
   703 The function subsequently checks for allocated but unused memory, if this memory is
   704 at least as large as the granularity it is released to the system.
   705 */
   706 	{
   707 	TUint doMore = 2; // need 1 pass each of merging vertical & horizontal edges
   708 
   709 	while ( (iCount > 1) && doMore )
   710 		{
   711 		// make rows
   712 		--doMore;
   713 			{
   714 			TRect* pFirst = RectangleListW();
   715 			TRect* pLast = RectangleListW()+iCount-1;
   716 			TRect *pRect1 = pLast;
   717 			for (;pRect1 > pFirst; pRect1--)
   718 				{
   719 				TRect *pRect2 = pRect1-1;
   720 				const TInt top = pRect1->iTl.iY;
   721 				const TInt bottom = pRect1->iBr.iY;
   722 				for (;pRect2 >= pFirst; pRect2--)
   723 					{
   724 					if ( (top == pRect2->iTl.iY) && (bottom == pRect2->iBr.iY) )
   725 						{
   726 						if (pRect1->iBr.iX == pRect2->iTl.iX)
   727 							{
   728 							pRect2->iTl.iX = pRect1->iTl.iX;
   729 							}
   730 						else if (pRect1->iTl.iX == pRect2->iBr.iX)
   731 							{
   732 							pRect2->iBr.iX = pRect1->iBr.iX;
   733 							}
   734 						else
   735 							{
   736 							continue;
   737 							}
   738 						}
   739 					else
   740 						{
   741 						continue;
   742 						}
   743 					// remove merged and move last
   744 					if (pRect1 != pLast)
   745 						{
   746 						*pRect1 = *pLast;
   747 						}
   748 					--iCount;
   749 					--pLast;
   750 					doMore = 1;
   751 					break;
   752 					}
   753 				}
   754 			}
   755 
   756 		// make columns?
   757 		if (doMore)
   758 			{
   759 			--doMore;
   760 			TRect* pFirst = RectangleListW();
   761 			TRect* pLast = RectangleListW()+iCount-1;
   762 			TRect *pRect1 = pLast;
   763 			for (;pRect1 > pFirst; pRect1--)
   764 				{
   765 				TRect *pRect2 = pRect1-1;
   766 				const TInt left = pRect1->iTl.iX;
   767 				const TInt right = pRect1->iBr.iX;
   768 
   769 				for (;pRect2 >= pFirst; pRect2--)
   770 					{
   771 					if ( (left == pRect2->iTl.iX) && (right == pRect2->iBr.iX) )
   772 						{
   773 						if (pRect1->iBr.iY == pRect2->iTl.iY)
   774 							{
   775 							pRect2->iTl.iY = pRect1->iTl.iY;
   776 							}
   777 						else if (pRect1->iTl.iY == pRect2->iBr.iY)
   778 							{
   779 							pRect2->iBr.iY = pRect1->iBr.iY;
   780 							}
   781 						else
   782 							{
   783 							continue;
   784 							}
   785 						}
   786 					else
   787 						{
   788 						continue;
   789 						}
   790 					// remove merged
   791 					if (pRect1 != pLast)
   792 						{
   793 						*pRect1 = *pLast;
   794 						}
   795 					--iCount;
   796 					--pLast;
   797 					doMore = 1;
   798 					break;
   799 					}
   800 				}
   801 			}
   802 		}
   803 
   804 	// free space
   805 	if (iAllocedRects>iCount)
   806 		{
   807 		ShrinkRegion();
   808 		}
   809 	}
   810 
   811 
   812 
   813 EXPORT_C TInt TRegion::Sort()
   814 /**
   815 Sorts the region's array of rectangles according to their vertical position 
   816 on the screen.
   817 
   818 The sort uses the bottom right hand corner co-ordinates of the rectangles.
   819 The co-ordinates of the top and left hand sides are irrelevant 
   820 to the sort operation.
   821 
   822 Higher rectangles take precedence over lower ones. For rectangles at the same 
   823 vertical position, the leftmost takes priority.
   824 
   825 Note that the sort order may need to be different from the default if, for example, 
   826 a region is moved downwards so that lower non-overlapping rectangles need 
   827 to be redrawn (and sorted) before higher ones. In this case, use the second 
   828 overload of this function.
   829 
   830 @return KErrNone, if the operation is successful; KErrGeneral, otherwise.
   831 */
   832 	{
   833 
   834 	return Sort(TPoint(-1,-1));
   835 	}
   836 
   837 
   838 
   839 
   840 EXPORT_C TInt TRegion::Sort(const TPoint &aOffset)
   841 //
   842 // Sort the region for copying to the same display.
   843 //
   844 /**
   845 Sorts the region's array of rectangles according to a specified sort order.
   846 
   847 The sort uses the bottom right hand co-ordinates of the rectangles.
   848 The co-ordinates of the top and left hand sides are irrelevant 
   849 to the sort operation
   850 
   851 The order of the sort is determined by whether the iX and iY members of aOffset 
   852 are positive, or zero or less. If aOffset.iY is greater than zero,
   853 lower rectangles take precedence over higher rectangles in the list order.
   854 Otherwise, higher rectangles take precedence. For rectangles of equal height,
   855 aOffset.iX becomes relevant to the sort.
   856 If is greater than zero, rightmost rectangles
   857 take precedence. Otherwise, leftmost rectangles take precedence.
   858 
   859 Note that the sort order may need to be different from the default if,
   860 for example, a region is moved downwards so that lower non-overlapping
   861 rectangles need to be redrawn (and sorted) before higher ones.
   862 
   863 @param aOffset A point whose iX and iY members determine the order of the 
   864                sort. 
   865 
   866 @return KErrNone, if the operation is successful; KErrGeneral, otherwise.
   867 */
   868 	{
   869 	TRectKey key(RectangleList(),aOffset);
   870 	TRectSwap swap(RectangleListW());
   871 	return(User::QuickSort(iCount,key,swap));
   872 	}
   873 
   874 
   875 
   876 
   877 EXPORT_C TRect *TRegion::RectangleListW()
   878 //
   879 // Return a writeable rectangle list.
   880 //
   881 	{
   882 	if (iAllocedRects>=0)
   883 		return(((RRegion *)this)->iRectangleList);
   884 	else if (iAllocedRects&ERRegionBuf)
   885 		return((TRect *)(this+1));
   886 	return((TRect *)(((RRegion *)this)+1));
   887 	}
   888 
   889 
   890 /** Ensure that the region is big enough to hold aCount rectangles.
   891 
   892 @param aCount number of rectangles the region is expected to hold
   893 @return ETrue if region is big enough, EFalse if fixed size region is too small or alloc failed.
   894 */
   895 TBool TRegion::SetListSize(TInt aCount)
   896 	{
   897 	TInt newAlloc = 0;
   898 	if (iAllocedRects < 0)
   899 		{
   900 		if (aCount > (-(iAllocedRects|ERRegionBuf)))
   901 			{
   902 			if (iAllocedRects & ERRegionBuf)
   903 				{ // TRegionFixed
   904 				ForceError();
   905 				return EFalse;
   906 				}
   907 			// successful alloc will change RRegionBuf into RRegion
   908 			newAlloc = Max(aCount, ((RRegion *)this)->iGranularity);
   909 			}
   910 		}
   911 	else if (aCount > iAllocedRects)
   912 		{
   913 		newAlloc = Max(aCount, iAllocedRects + ((RRegion *)this)->iGranularity);
   914 		}
   915 
   916 	if (newAlloc > 0)
   917 		{
   918 		TRect *newList = (TRect *)User::ReAlloc(((RRegion *)this)->iRectangleList, newAlloc*sizeof(TRect));
   919 		if (newList == NULL)
   920 			{
   921 			ForceError();
   922 			return EFalse;
   923 			}
   924 		((RRegion *)this)->iRectangleList = newList;
   925 		iAllocedRects = newAlloc;
   926 		}
   927 	return ETrue;
   928 	}
   929 
   930 /** Ensure that the region is big enough to hold aCount rectangles.
   931 Any allocation increase is for at least the granularity count of rectangles.
   932 Similar to SetListSize, but always preserves existing iCount rectangles.
   933 
   934 @param aCount number of rectangles the region is expected to hold
   935 @return NULL if region is not big enough, otherwise pointer to the Rect array.
   936 */
   937 TRect* TRegion::ExpandRegion(TInt aCount)
   938 	{
   939 	TRect *prects=NULL;
   940 	if (!iError)
   941 		{
   942 		if (iAllocedRects & ERRegionBuf)
   943 			{							// TRegionFix
   944 			if (aCount > -iAllocedRects)
   945 				{						// Can't expand a TRegionFix
   946 				ForceError();
   947 				return NULL;
   948 				}
   949 			prects=(TRect *)(this+1);
   950 			}
   951 		else if (iAllocedRects < 0)
   952 			{							// RRegionBuf
   953 			prects = (TRect *)(((RRegion *)this)+1);
   954 			if (aCount > (-(iAllocedRects|ERRegionBuf)))
   955 				{
   956 				RRegion *pr = (RRegion *)this;
   957 				TUint newCount = Max(aCount, iCount + pr->iGranularity);
   958 				TRect *newList = (TRect *)User::Alloc(newCount * sizeof(TRect));
   959 				if (newList == NULL)
   960 					{
   961 					ForceError();
   962 					return NULL;
   963 					}
   964 				iAllocedRects = newCount;
   965 				pr->iRectangleList = newList;
   966 				if (iCount > 0)
   967 					{
   968 					Mem::Copy(pr->iRectangleList, prects, sizeof(TRect)*iCount);
   969 					}
   970 				prects = pr->iRectangleList;
   971 				}
   972 			}
   973 		else
   974 			{
   975 			RRegion *pr = (RRegion *)this;
   976 			prects = pr->iRectangleList;
   977 			if (iAllocedRects < aCount)
   978 				{
   979 				TUint newCount = Max(aCount, iAllocedRects + pr->iGranularity);
   980 				prects=(TRect *)User::ReAlloc(prects, newCount*sizeof(TRect));
   981 				if (prects == NULL)
   982 					{
   983 					ForceError();
   984 					return NULL;
   985 					}
   986 				iAllocedRects = newCount;
   987 				pr->iRectangleList = prects;
   988 				}
   989 			}
   990 		}
   991 
   992 	return prects;
   993 	}
   994 
   995 
   996 /**
   997 After an RRegion's iCount has reduced try to release some memory.
   998 Hysteresis rule: reduce allocated memory to iCount, but only if 
   999 the released memory will also be at least the granularity.
  1000 */
  1001 void TRegion::ShrinkRegion()
  1002 	{
  1003 	ASSERT(iAllocedRects > iCount);
  1004 	// must be an RRegion
  1005 	RRegion *pr=(RRegion *)this;
  1006 	if (iAllocedRects >= (iCount + pr->iGranularity) )
  1007 		{
  1008 		TRect *newList = NULL;
  1009 		if (iCount == 0)
  1010 			{
  1011 			User::Free(pr->iRectangleList);
  1012 			}
  1013 		else
  1014 			{
  1015 			newList = (TRect *)User::ReAlloc(pr->iRectangleList, iCount*sizeof(TRect));
  1016 			if (newList == NULL)
  1017 				{
  1018 				ForceError();
  1019 				return;
  1020 				}
  1021 			}
  1022 		iAllocedRects = iCount;
  1023 		pr->iRectangleList = newList;
  1024 		}
  1025 	}
  1026 
  1027 
  1028 void TRegion::AppendRect(const TRect &aRect)
  1029 //
  1030 // Add a rectangle to the list.
  1031 //
  1032 	{
  1033 	TRect *prects = ExpandRegion(iCount+1);
  1034 	if (prects)
  1035 		{
  1036 		*(prects+iCount)=aRect;
  1037 		iCount++;
  1038 		}
  1039 	}
  1040 
  1041 
  1042 #ifndef __REGIONS_MACHINE_CODED__
  1043 
  1044 
  1045 EXPORT_C void TRegion::ForceError()
  1046 /**
  1047 Sets the error flag, and clears the region.
  1048 
  1049 This frees up memory allocated to the region.
  1050 */
  1051 	{
  1052 
  1053 	Clear();
  1054 	iError=ETrue;
  1055 	}
  1056 
  1057 void TRegion::DeleteRect(TRect *aRect)
  1058 //
  1059 // Delete a specific rectangle in the list.
  1060 //
  1061 	{
  1062 
  1063 	iCount--;
  1064 	Mem::Copy(aRect,aRect+1,((TUint8 *)(RectangleList()+iCount))-((TUint8 *)aRect));
  1065 	}
  1066 #endif
  1067 
  1068 void TRegion::AppendRegion(TRegion &aRegion)
  1069 //
  1070 // Append all the rectangles from aRegion to this.
  1071 //
  1072 	{
  1073 	aRegion.SubtractRegion(*this);
  1074 	if (aRegion.iError)
  1075 		{
  1076 		ForceError();
  1077 		}
  1078 	else if (aRegion.iCount > 0)
  1079 		{
  1080 		// alloc enough memory, then memcpy
  1081 		const TInt newCount = iCount + aRegion.iCount;
  1082 		if (ExpandRegion(newCount))
  1083 			{
  1084 			TRect* pDest = RectangleListW() + iCount;
  1085 			const TRect* pSource = aRegion.RectangleList();
  1086 			Mem::Copy(pDest, pSource, aRegion.iCount * sizeof(TRect));
  1087 			iCount = newCount;
  1088 			}
  1089 		}
  1090 	}
  1091 
  1092 
  1093 
  1094 EXPORT_C RRegion::RRegion()
  1095 	: TRegion(0), iGranularity(EDefaultGranularity), iRectangleList(NULL)
  1096 /**
  1097 Default constructor.
  1098 
  1099 Initialises its granularity to five.
  1100 */
  1101 	{}
  1102 
  1103 
  1104 
  1105 
  1106 EXPORT_C RRegion::RRegion(TInt aGran)
  1107 	: TRegion(0), iGranularity(aGran), iRectangleList(NULL)
  1108 /**
  1109 Constructs the object with the specified granularity.
  1110 
  1111 @param aGran The initial value for the region's granularity.
  1112              This value must not be negative.
  1113 */
  1114 	{}
  1115 
  1116 
  1117 
  1118 
  1119 EXPORT_C RRegion::RRegion(const TRect &aRect, TInt aGran)
  1120 	: TRegion(0), iGranularity(aGran), iRectangleList(NULL)
  1121 /**
  1122 Constructs the object with the specified rectangle and granularity.
  1123 
  1124 The resulting region consists of the specified single rectangle.
  1125 
  1126 @param aRect The single rectangle with which to initialise the region 
  1127 @param aGran The initial value for the region's granularity. By default, 
  1128              this is five.
  1129 */
  1130 	{
  1131 
  1132 	if (!aRect.IsEmpty())
  1133 		AppendRect(aRect);
  1134 	}
  1135 
  1136 
  1137 
  1138 
  1139 EXPORT_C RRegion::RRegion(const RRegion &aRegion)
  1140 /**
  1141 Copy constructor.
  1142 
  1143 Constructs a new region from an existing one by performing a bit-wise copy.  Both the new and
  1144 existing regions are left containing pointers to the same data, so Close() must only be called on
  1145 one of them.
  1146 
  1147 Use of this method is not recommended.
  1148 
  1149 @param aRegion The region to be copied.
  1150 */
  1151 	{
  1152 	*this=aRegion;
  1153 	}
  1154 
  1155 
  1156 
  1157 
  1158 EXPORT_C RRegion::RRegion(TInt aBuf, TInt aGran)
  1159 //
  1160 // Constructor.
  1161 //
  1162 	: TRegion(aBuf), iGranularity(aGran), iRectangleList(NULL)
  1163 	{}
  1164 
  1165 
  1166 
  1167 
  1168 EXPORT_C RRegion::RRegion(TInt aCount,TRect* aRectangleList,TInt aGran/*=EDefaultGranularity*/)
  1169 /**
  1170 Constructor that takes ownership of an already created rectangle list.
  1171 
  1172 @param aCount         The number of rectangles in the region.
  1173 @param aRectangleList A pointer to the set of rectangles.
  1174 @param aGran          The region's granularity.
  1175 */
  1176 	: TRegion(aCount), iGranularity(aGran), iRectangleList(aRectangleList)
  1177 	{
  1178 	iCount=aCount;
  1179 	}
  1180 
  1181 
  1182 
  1183 
  1184 EXPORT_C void RRegion::Close()
  1185 /**
  1186 Closes the region.
  1187 
  1188 Frees up any memory which has been allocated, and unsets the error flag, if 
  1189 set. 
  1190 
  1191 The region can be re-used after calling this method.  Its granularity is preserved.
  1192 */
  1193 	{
  1194 
  1195 	Clear();
  1196 	}
  1197 
  1198 
  1199 
  1200 
  1201 EXPORT_C void RRegion::Destroy()
  1202 //
  1203 // Destroy
  1204 //
  1205 /**
  1206 Deletes the region.
  1207 
  1208 Frees all memory.
  1209 
  1210 Note this method will delete the RRegion object and therefore it should not be 
  1211 invoked on RRegion objects that are not allocated on the heap.  RRegion::Close()
  1212 should be used for RRegion objects stored on the stack.
  1213 
  1214 @panic USER 42 if the RRegion object is stored on the stack.
  1215 */
  1216 	{
  1217 
  1218 	Clear();
  1219 	delete this;
  1220 	}
  1221 
  1222 
  1223 
  1224 
  1225 TInt TRectKey::Compare(TInt aLeft,TInt aRight) const
  1226 //
  1227 // Compares two rectangles for partial ordering.
  1228 //
  1229 	{
  1230 
  1231 	if (aLeft==aRight)
  1232 		return(0);
  1233 	const TRect *r1=&iRectList[aLeft];
  1234 	const TRect *r2=&iRectList[aRight];
  1235 	if (r2->iBr.iY<=r1->iTl.iY)
  1236 		return(iDown ? -1 : 1);
  1237 	if (r1->iBr.iY<=r2->iTl.iY)
  1238 		return(iDown ? 1 : -1);
  1239 	if (r2->iBr.iX<=r1->iTl.iX)
  1240 		return(iRight ? -1 : 1);
  1241 	__ASSERT_DEBUG(r1->iBr.iX<=r2->iTl.iX,Panic(ETRegionInvalidRegionInSort));
  1242 	return(iRight ? 1 : -1);
  1243 	}
  1244 
  1245 void TRectSwap::Swap(TInt aLeft,TInt aRight) const
  1246 //
  1247 // Swap two rectangles.
  1248 //
  1249 	{
  1250 
  1251 	TRect tmp(iRectList[aLeft]);
  1252 	iRectList[aLeft]=iRectList[aRight];
  1253 	iRectList[aRight]=tmp;
  1254 	}
  1255 
  1256 TRectKey::TRectKey(const TRect *aRectList,const TPoint &aOffset)
  1257 //
  1258 // Rectangle key constructor
  1259 //
  1260 	{
  1261 
  1262 	iRectList=aRectList;
  1263 	if(aOffset.iX>0)
  1264 		iRight=ETrue;
  1265 	else
  1266 		iRight=EFalse;
  1267 	if(aOffset.iY>0)
  1268 		iDown=ETrue;
  1269 	else
  1270 		iDown=EFalse;
  1271 	}