|
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 "Symbian Foundation License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\euser\us_regn.cpp |
|
15 // Optimisation note, it may well be worth machine coding the SubRect() function |
|
16 // this is at the heart of nearly all complex region calculations. |
|
17 // |
|
18 // |
|
19 |
|
20 |
|
21 #include "us_std.h" |
|
22 |
|
23 NONSHARABLE_CLASS(TRectKey) : public TKey |
|
24 { |
|
25 public: |
|
26 TRectKey(const TRect *aRectList,const TPoint &aOffset); |
|
27 virtual TInt Compare(TInt aLeft,TInt aRight) const; |
|
28 private: |
|
29 const TRect *iRectList; |
|
30 TBool iDown; |
|
31 TBool iRight; |
|
32 }; |
|
33 |
|
34 NONSHARABLE_CLASS(TRectSwap) : public TSwap |
|
35 { |
|
36 public: |
|
37 inline TRectSwap(TRect *aRectList); |
|
38 virtual void Swap(TInt aLeft,TInt aRight) const; |
|
39 private: |
|
40 TRect *iRectList; |
|
41 }; |
|
42 |
|
43 inline TRectSwap::TRectSwap(TRect *aRectList) |
|
44 {iRectList=aRectList;} |
|
45 |
|
46 enum {ERegionBufSize=8}; |
|
47 |
|
48 EXPORT_C TRegion::TRegion(TInt aAllocedRects) |
|
49 // |
|
50 // Constructor. |
|
51 // |
|
52 : iCount(0),iError(EFalse),iAllocedRects(aAllocedRects) |
|
53 {} |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 EXPORT_C TBool TRegion::IsEmpty() const |
|
59 /** |
|
60 Tests whether the region is empty. |
|
61 |
|
62 @return True, if the region is empty and its error flag is unset; |
|
63 false, otherwise. |
|
64 */ |
|
65 { |
|
66 |
|
67 return(iCount==0 && !iError); |
|
68 } |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 #ifndef __REGIONS_MACHINE_CODED__ |
|
74 EXPORT_C TRect TRegion::BoundingRect() const |
|
75 /** |
|
76 Gets the minimal rectangle that bounds the entire region. |
|
77 |
|
78 @return The region's minimal bounding rectangle. |
|
79 */ |
|
80 { |
|
81 |
|
82 TRect bounds; |
|
83 const TRect *pRect; |
|
84 const TRect *pEnd; |
|
85 if (iCount>0) |
|
86 { |
|
87 pRect=RectangleList(); |
|
88 bounds=(*pRect++); |
|
89 for (pEnd=pRect+(iCount-1);pRect<pEnd;pRect++) |
|
90 { |
|
91 if (pRect->iTl.iX<bounds.iTl.iX) |
|
92 bounds.iTl.iX=pRect->iTl.iX; |
|
93 if (pRect->iTl.iY<bounds.iTl.iY) |
|
94 bounds.iTl.iY=pRect->iTl.iY; |
|
95 if (pRect->iBr.iX>bounds.iBr.iX) |
|
96 bounds.iBr.iX=pRect->iBr.iX; |
|
97 if (pRect->iBr.iY>bounds.iBr.iY) |
|
98 bounds.iBr.iY=pRect->iBr.iY; |
|
99 } |
|
100 } |
|
101 return(bounds); |
|
102 } |
|
103 #endif |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 EXPORT_C const TRect &TRegion::operator[](TInt aIndex) const |
|
109 /** |
|
110 Gets a rectangle from the region. |
|
111 |
|
112 @param aIndex The index of a rectangle within the region's array of rectangles. |
|
113 Indexes are relative to zero. |
|
114 |
|
115 @return The specified rectangle. |
|
116 |
|
117 @panic USER 81, if aIndex is greater than or equal to the number |
|
118 of rectangles in the region. |
|
119 */ |
|
120 { |
|
121 |
|
122 __ASSERT_ALWAYS((TUint)aIndex<(TUint)iCount,Panic(ETRegionOutOfRange)); |
|
123 return(*(RectangleList()+aIndex)); |
|
124 } |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 #ifndef __REGIONS_MACHINE_CODED__ |
|
130 EXPORT_C TBool TRegion::IsContainedBy(const TRect &aRect) const |
|
131 /** |
|
132 Tests whether the region is fully enclosed within the specified rectangle. |
|
133 |
|
134 @param aRect The specified rectangle. |
|
135 |
|
136 @return True, if the region is fully enclosed within the rectangle (their sides |
|
137 may touch); false, otherwise. |
|
138 */ |
|
139 { |
|
140 |
|
141 const TRect *pRect1; |
|
142 const TRect *pEnd1; |
|
143 for (pRect1=RectangleList(),pEnd1=pRect1+iCount;pRect1<pEnd1;pRect1++) |
|
144 { |
|
145 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) |
|
146 return(EFalse); |
|
147 } |
|
148 return(ETrue); |
|
149 } |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 EXPORT_C TBool TRegion::Intersects(const TRect &aRect) const |
|
155 /** |
|
156 Tests whether where there is any intersection between this region and the specified rectangle. |
|
157 |
|
158 @param aRect The specified rectangle. |
|
159 |
|
160 @return True, if there is an intersection; false, otherwise. |
|
161 */ |
|
162 { |
|
163 |
|
164 const TRect *pRect1; |
|
165 const TRect *pEnd1; |
|
166 for (pRect1=RectangleList(),pEnd1=pRect1+iCount;pRect1<pEnd1;pRect1++) |
|
167 { |
|
168 if (aRect.Intersects(*pRect1)) |
|
169 return ETrue; |
|
170 } |
|
171 return EFalse; |
|
172 } |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 EXPORT_C void TRegion::Copy(const TRegion &aRegion) |
|
178 /** |
|
179 Copies another region to this region. |
|
180 |
|
181 The state of the specified region's error flag is also copied. |
|
182 |
|
183 @param aRegion The region to be copied. |
|
184 */ |
|
185 { |
|
186 |
|
187 if (aRegion.iError) |
|
188 ForceError(); |
|
189 else |
|
190 { |
|
191 if (iError) |
|
192 Clear(); |
|
193 if (SetListSize(aRegion.iCount)) |
|
194 { |
|
195 iCount=aRegion.iCount; |
|
196 Mem::Copy(RectangleListW(), aRegion.RectangleList(), sizeof(TRect)*aRegion.iCount); |
|
197 } |
|
198 } |
|
199 } |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 EXPORT_C void TRegion::Offset(const TPoint &aOffset) |
|
205 /** |
|
206 Moves the region by adding a TPoint offset to the co-ordinates of its corners. |
|
207 |
|
208 The size of the region is not changed. |
|
209 |
|
210 @param aOffset The offset by which the region is moved. The region is moved |
|
211 horizontally by aOffset.iX pixels and vertically by aOffset.iY pixels. |
|
212 */ |
|
213 { |
|
214 |
|
215 TRect *pR=RectangleListW(); |
|
216 const TRect *pE=pR+iCount; |
|
217 while (pR<pE) |
|
218 { |
|
219 pR->Move(aOffset); |
|
220 pR++; |
|
221 } |
|
222 } |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 EXPORT_C void TRegion::Offset(TInt aXoffset,TInt aYoffset) |
|
228 /** |
|
229 Moves the region by adding X and Y offsets to the co-ordinates of its corners. |
|
230 |
|
231 The size of the region is not changed. |
|
232 |
|
233 @param aXoffset The number of pixels by which to move the region horizontally. |
|
234 If negative, the region moves leftwards. |
|
235 @param aYoffset The number of pixels by which to move the region vertically. |
|
236 If negative, the region moves upwards. |
|
237 */ |
|
238 { |
|
239 |
|
240 Offset(TPoint(aXoffset,aYoffset)); |
|
241 } |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 EXPORT_C TBool TRegion::Contains(const TPoint &aPoint) const |
|
247 /** |
|
248 Tests whether a point is located within the region. |
|
249 |
|
250 If the point is located on the top or left hand side of any rectangle in the |
|
251 region, it is considered to be within that rectangle and within the region. |
|
252 |
|
253 If the point is located on the right hand side or bottom of a rectangle, it |
|
254 is considered to be outside that rectangle, and may be outside the region. |
|
255 |
|
256 @param aPoint The specified point. |
|
257 |
|
258 @return True, if the point is within the region; false, otherwise. |
|
259 */ |
|
260 { |
|
261 const TRect *pR=RectangleList(); |
|
262 const TRect *pE=pR+iCount; |
|
263 while (pR<pE) |
|
264 { |
|
265 if (pR->Contains(aPoint)) |
|
266 return(ETrue); |
|
267 pR++; |
|
268 } |
|
269 return(EFalse); |
|
270 } |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 EXPORT_C void TRegion::SubRect(const TRect &aRect,TRegion *aSubtractedRegion) |
|
276 /** |
|
277 Removes a rectangle from this region. |
|
278 |
|
279 If there is no intersection between the rectangle and this region, then this |
|
280 region is unaffected. |
|
281 |
|
282 @param aRect The rectangular area to be removed from this region. |
|
283 @param aSubtractedRegion A pointer to a region. If this is supplied, the |
|
284 removed rectangle is added to it. By default this |
|
285 pointer is NULL. |
|
286 */ |
|
287 { |
|
288 if (aRect.IsEmpty()) |
|
289 return; |
|
290 TRect *prect=RectangleListW(); |
|
291 TInt limit=iCount; |
|
292 for (TInt index=0;index<limit;) |
|
293 { |
|
294 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) |
|
295 { |
|
296 TRect rect(*prect); |
|
297 TRect inter(aRect); |
|
298 inter.Intersection(*prect); |
|
299 DeleteRect(prect); |
|
300 if (inter.iBr.iY!=rect.iBr.iY) |
|
301 AppendRect(TRect(rect.iTl.iX,inter.iBr.iY,rect.iBr.iX,rect.iBr.iY)); |
|
302 if (inter.iTl.iY!=rect.iTl.iY) |
|
303 AppendRect(TRect(rect.iTl.iX,rect.iTl.iY,rect.iBr.iX,inter.iTl.iY)); |
|
304 if (inter.iBr.iX!=rect.iBr.iX) |
|
305 AppendRect(TRect(inter.iBr.iX,inter.iTl.iY,rect.iBr.iX,inter.iBr.iY)); |
|
306 if (inter.iTl.iX!=rect.iTl.iX) |
|
307 AppendRect(TRect(rect.iTl.iX,inter.iTl.iY,inter.iTl.iX,inter.iBr.iY)); |
|
308 if (iError) |
|
309 break; |
|
310 if (aSubtractedRegion!=NULL) |
|
311 aSubtractedRegion->AddRect(inter); |
|
312 prect=RectangleListW()+index; // List might have been re-allocated so re-get the pointer |
|
313 limit--; |
|
314 } |
|
315 else |
|
316 { |
|
317 index++; |
|
318 prect++; |
|
319 } |
|
320 } |
|
321 } |
|
322 #endif |
|
323 |
|
324 |
|
325 |
|
326 |
|
327 EXPORT_C void TRegion::Union(const TRegion &aRegion) |
|
328 /** |
|
329 Replaces this region with the union of it and the specified region. |
|
330 |
|
331 Note that if the error flag of either this region or the specified region is |
|
332 set, then this region is cleared and its error flag is set. This frees up |
|
333 allocated memory. |
|
334 |
|
335 @param aRegion The region to be joined to this region. |
|
336 */ |
|
337 { |
|
338 RRegionBuf<ERegionBufSize> temp; |
|
339 temp.Copy(aRegion); |
|
340 if (temp.iCount>iCount) |
|
341 { |
|
342 temp.AppendRegion(*this); |
|
343 Copy(temp); |
|
344 } |
|
345 else |
|
346 AppendRegion(temp); |
|
347 temp.Close(); |
|
348 } |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 #ifndef __REGIONS_MACHINE_CODED__ |
|
354 EXPORT_C void TRegion::Intersection(const TRegion &aRegion1,const TRegion &aRegion2) |
|
355 /** |
|
356 Replaces this region with the area of intersection between two specified regions. |
|
357 |
|
358 Notes: |
|
359 |
|
360 1. If the error flag of either of the two specified regions is set, then this |
|
361 region is cleared and its error flag is set. This frees up allocated memory. |
|
362 |
|
363 2. If this region's error flag is already set, then the function has no effect. |
|
364 |
|
365 @param aRegion1 The first region. |
|
366 @param aRegion2 The second region. |
|
367 */ |
|
368 { |
|
369 if (aRegion1.iError || aRegion2.iError) |
|
370 ForceError(); |
|
371 else |
|
372 { |
|
373 iCount=0; |
|
374 const TRect *pRect1,*pEnd1; |
|
375 const TRect *pRect2,*pEnd2; |
|
376 for (pRect1=aRegion1.RectangleList(),pEnd1=pRect1+aRegion1.iCount;pRect1<pEnd1;pRect1++) |
|
377 { |
|
378 for (pRect2=aRegion2.RectangleList(),pEnd2=pRect2+aRegion2.iCount;pRect2<pEnd2;pRect2++) |
|
379 { |
|
380 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) |
|
381 { |
|
382 TRect rect(*pRect2); |
|
383 rect.Intersection(*pRect1); |
|
384 AppendRect(rect); |
|
385 } |
|
386 } |
|
387 } |
|
388 } |
|
389 } |
|
390 #endif |
|
391 |
|
392 |
|
393 |
|
394 |
|
395 EXPORT_C void TRegion::Intersect(const TRegion &aRegion) |
|
396 /** |
|
397 Replaces this region with the area of intersection between it and the specified |
|
398 region. |
|
399 |
|
400 Note that if the error flag of either this region or the specified region is |
|
401 set, then this region is cleared and its error flag is set. This frees up |
|
402 allocated memory. |
|
403 |
|
404 @param aRegion The region to be intersected with this region. |
|
405 */ |
|
406 { |
|
407 if (iCount!=0) |
|
408 { |
|
409 RRegionBuf<ERegionBufSize> temp; |
|
410 temp.Copy(*this); |
|
411 Intersection(temp,aRegion); |
|
412 temp.Close(); |
|
413 } |
|
414 } |
|
415 |
|
416 |
|
417 |
|
418 |
|
419 EXPORT_C void TRegion::AddRect(const TRect &aRect) |
|
420 /** |
|
421 Adds a rectangle to this region. |
|
422 |
|
423 Notes: |
|
424 |
|
425 1. If this region's error flag is already set, this function has no effect. |
|
426 |
|
427 2. If the operation causes the capacity of this region to be exceeded, or if |
|
428 memory allocation fails, the region is cleared, freeing up any memory which |
|
429 has been allocated; its error flag is also set. |
|
430 |
|
431 @param aRect The rectangle to be added to this region. |
|
432 */ |
|
433 { |
|
434 |
|
435 if (!aRect.IsEmpty() && !iError) |
|
436 { |
|
437 if (IsContainedBy(aRect)) |
|
438 { |
|
439 iCount=0; |
|
440 AppendRect(aRect); |
|
441 } |
|
442 else |
|
443 { |
|
444 RRegionBuf<ERegionBufSize> temp(aRect); |
|
445 AppendRegion(temp); |
|
446 temp.Close(); |
|
447 } |
|
448 } |
|
449 } |
|
450 |
|
451 |
|
452 |
|
453 |
|
454 EXPORT_C void TRegion::SubRegion(const TRegion &aRegion,TRegion *aSubtractedRegion) |
|
455 /** |
|
456 Removes a region. |
|
457 |
|
458 If there is no area of intersection between the two regions, this region is |
|
459 unaffected. |
|
460 |
|
461 @param aRegion The region to be removed from this region. |
|
462 If aRegion's error flag is set, then this region is |
|
463 cleared, freeing up any allocated memory, and the |
|
464 error flag is set. |
|
465 @param aSubtractedRegion If specified, then on return contains the area removed |
|
466 from this region. |
|
467 */ |
|
468 { |
|
469 if (iCount!=0) |
|
470 { |
|
471 if (aRegion.iError) |
|
472 ForceError(); |
|
473 else |
|
474 { |
|
475 const TRect *pR=aRegion.RectangleList(); |
|
476 const TRect *pE=pR+aRegion.iCount; |
|
477 while (pR<pE && !iError) |
|
478 SubRect(*pR++,aSubtractedRegion); |
|
479 if (iError && aSubtractedRegion) |
|
480 aSubtractedRegion->ForceError(); |
|
481 } |
|
482 } |
|
483 } |
|
484 |
|
485 |
|
486 |
|
487 |
|
488 #ifndef __REGIONS_MACHINE_CODED__ |
|
489 EXPORT_C void TRegion::ClipRect(const TRect &aRect) |
|
490 /** |
|
491 Clips the region to the specified rectangle. |
|
492 |
|
493 The resulting region is the area of overlap between the region and the rectangle. |
|
494 If there is no overlap, all rectangles within this region are deleted and |
|
495 the resulting region is empty. |
|
496 |
|
497 @param aRect The rectangle to which this region is to be clipped. |
|
498 */ |
|
499 { |
|
500 |
|
501 for (TInt index=0;index<iCount;) |
|
502 { |
|
503 TRect *r2=RectangleListW()+index; |
|
504 if (r2->iTl.iX<aRect.iTl.iX) |
|
505 r2->iTl.iX=aRect.iTl.iX; |
|
506 if (r2->iTl.iY<aRect.iTl.iY) |
|
507 r2->iTl.iY=aRect.iTl.iY; |
|
508 if (r2->iBr.iX>aRect.iBr.iX) |
|
509 r2->iBr.iX=aRect.iBr.iX; |
|
510 if (r2->iBr.iY>aRect.iBr.iY) |
|
511 r2->iBr.iY=aRect.iBr.iY; |
|
512 if (r2->IsEmpty()) |
|
513 DeleteRect(r2); |
|
514 else |
|
515 index++; |
|
516 } |
|
517 } |
|
518 #endif |
|
519 |
|
520 |
|
521 |
|
522 |
|
523 EXPORT_C void TRegion::Clear() |
|
524 /** |
|
525 Clears this region. |
|
526 |
|
527 This frees up any memory which has been allocated and unsets the error flag. |
|
528 */ |
|
529 { |
|
530 |
|
531 if (iAllocedRects>=0) |
|
532 { |
|
533 User::Free(((RRegion *)this)->iRectangleList); |
|
534 ((RRegion *)this)->iRectangleList=NULL; |
|
535 iAllocedRects=0; |
|
536 } |
|
537 iCount=0; |
|
538 iError=EFalse; |
|
539 } |
|
540 |
|
541 |
|
542 |
|
543 |
|
544 |
|
545 #ifndef __REGIONS_MACHINE_CODED__ |
|
546 EXPORT_C void TRegion::Tidy() |
|
547 /** |
|
548 Merges all rectangles within this region which share an adjacent edge of the |
|
549 same length. |
|
550 |
|
551 The function subsequently frees up any allocated but unused memory. |
|
552 */ |
|
553 { |
|
554 restart: |
|
555 if (iCount>1) |
|
556 { |
|
557 const TRect *pEnd1=RectangleList()+iCount-1; |
|
558 const TRect *pEnd2=RectangleList()+iCount; |
|
559 TRect *pRect1=RectangleListW(); |
|
560 for (;pRect1<pEnd1;pRect1++) |
|
561 { |
|
562 TRect *pRect2=pRect1+1; |
|
563 for (;pRect2<pEnd2;pRect2++) |
|
564 { |
|
565 if (pRect1->iTl.iX==pRect2->iTl.iX && pRect1->iBr.iX==pRect2->iBr.iX) |
|
566 { |
|
567 if (pRect1->iBr.iY==pRect2->iTl.iY) |
|
568 pRect1->iBr.iY=pRect2->iBr.iY; |
|
569 else if (pRect1->iTl.iY==pRect2->iBr.iY) |
|
570 pRect1->iTl.iY=pRect2->iTl.iY; |
|
571 else |
|
572 continue; |
|
573 } |
|
574 else if (pRect1->iTl.iY==pRect2->iTl.iY && pRect1->iBr.iY==pRect2->iBr.iY) |
|
575 { |
|
576 if (pRect1->iBr.iX==pRect2->iTl.iX) |
|
577 pRect1->iBr.iX=pRect2->iBr.iX; |
|
578 else if (pRect1->iTl.iX==pRect2->iBr.iX) |
|
579 pRect1->iTl.iX=pRect2->iTl.iX; |
|
580 else |
|
581 continue; |
|
582 } |
|
583 else |
|
584 continue; |
|
585 DeleteRect(pRect2); |
|
586 goto restart; |
|
587 } |
|
588 } |
|
589 } |
|
590 if (iAllocedRects>iCount) |
|
591 { |
|
592 TRect *newList=(TRect *)User::ReAlloc(((RRegion *)this)->iRectangleList,iCount*sizeof(TRect)); |
|
593 if (newList!=NULL) |
|
594 { |
|
595 iAllocedRects=iCount; |
|
596 ((RRegion *)this)->iRectangleList=newList; |
|
597 } |
|
598 } |
|
599 } |
|
600 #endif |
|
601 |
|
602 |
|
603 |
|
604 |
|
605 EXPORT_C TInt TRegion::Sort() |
|
606 /** |
|
607 Sorts the region's array of rectangles according to their vertical position |
|
608 on the screen. |
|
609 |
|
610 The sort uses the bottom right hand corner co-ordinates of the rectangles. |
|
611 The co-ordinates of the top and left hand sides are irrelevant |
|
612 to the sort operation. |
|
613 |
|
614 Higher rectangles take precedence over lower ones. For rectangles at the same |
|
615 vertical position, the leftmost takes priority. |
|
616 |
|
617 Note that the sort order may need to be different from the default if, for example, |
|
618 a region is moved downwards so that lower non-overlapping rectangles need |
|
619 to be redrawn (and sorted) before higher ones. In this case, use the second |
|
620 overload of this function. |
|
621 |
|
622 @return KErrNone, if the operation is successful; KErrGeneral, otherwise. |
|
623 */ |
|
624 { |
|
625 |
|
626 return Sort(TPoint(-1,-1)); |
|
627 } |
|
628 |
|
629 |
|
630 |
|
631 |
|
632 EXPORT_C TInt TRegion::Sort(const TPoint &aOffset) |
|
633 // |
|
634 // Sort the region for copying to the same display. |
|
635 // |
|
636 /** |
|
637 Sorts the region's array of rectangles according to a specified sort order. |
|
638 |
|
639 The sort uses the bottom right hand co-ordinates of the rectangles. |
|
640 The co-ordinates of the top and left hand sides are irrelevant |
|
641 to the sort operation |
|
642 |
|
643 The order of the sort is determined by whether the iX and iY members of aOffset |
|
644 are positive, or zero or less. If aOffset.iY is greater than zero, |
|
645 lower rectangles take precedence over higher rectangles in the list order. |
|
646 Otherwise, higher rectangles take precedence. For rectangles of equal height, |
|
647 aOffset.iX becomes relevant to the sort. |
|
648 If is greater than zero, rightmost rectangles |
|
649 take precedence. Otherwise, leftmost rectangles take precedence. |
|
650 |
|
651 Note that the sort order may need to be different from the default if, |
|
652 for example, a region is moved downwards so that lower non-overlapping |
|
653 rectangles need to be redrawn (and sorted) before higher ones. |
|
654 |
|
655 @param aOffset A point whose iX and iY members determine the order of the |
|
656 sort. |
|
657 |
|
658 @return KErrNone, if the operation is successful; KErrGeneral, otherwise. |
|
659 */ |
|
660 { |
|
661 TRectKey key(RectangleList(),aOffset); |
|
662 TRectSwap swap(RectangleListW()); |
|
663 return(User::QuickSort(iCount,key,swap)); |
|
664 } |
|
665 |
|
666 |
|
667 |
|
668 |
|
669 EXPORT_C TRect *TRegion::RectangleListW() |
|
670 // |
|
671 // Return a writeable rectangle list. |
|
672 // |
|
673 { |
|
674 if (iAllocedRects>=0) |
|
675 return(((RRegion *)this)->iRectangleList); |
|
676 else if (iAllocedRects&ERRegionBuf) |
|
677 return((TRect *)(this+1)); |
|
678 return((TRect *)(((RRegion *)this)+1)); |
|
679 } |
|
680 |
|
681 TBool TRegion::SetListSize(TInt aCount) |
|
682 { |
|
683 if (iAllocedRects<0) |
|
684 { |
|
685 if (aCount>(-(iAllocedRects|ERRegionBuf))) |
|
686 { |
|
687 if ((iAllocedRects&ERRegionBuf) || |
|
688 (((RRegion *)this)->iRectangleList= |
|
689 (TRect *)User::Alloc(aCount*sizeof(TRect)))==NULL) |
|
690 { |
|
691 ForceError(); |
|
692 return(EFalse); |
|
693 } |
|
694 iAllocedRects=aCount; |
|
695 } |
|
696 } |
|
697 else if (iAllocedRects<aCount) |
|
698 { |
|
699 TRect *newList=(TRect *)User::ReAlloc(((RRegion *)this)->iRectangleList,aCount*sizeof(TRect)); |
|
700 if (newList==NULL) |
|
701 { |
|
702 ForceError(); |
|
703 return(EFalse); |
|
704 } |
|
705 ((RRegion *)this)->iRectangleList=newList; |
|
706 iAllocedRects=aCount; |
|
707 } |
|
708 return(ETrue); |
|
709 } |
|
710 |
|
711 #ifndef __REGIONS_MACHINE_CODED__ |
|
712 |
|
713 EXPORT_C void TRegion::ForceError() |
|
714 /** |
|
715 Sets the error flag, and clears the region. |
|
716 |
|
717 This frees up memory allocated to the region. |
|
718 */ |
|
719 { |
|
720 |
|
721 Clear(); |
|
722 iError=ETrue; |
|
723 } |
|
724 |
|
725 void TRegion::AppendRect(const TRect &aRect) |
|
726 // |
|
727 // Add a rectangle to the list. |
|
728 // |
|
729 { |
|
730 if (!iError) |
|
731 { |
|
732 TRect *prects=NULL; |
|
733 if (iAllocedRects&ERRegionBuf) |
|
734 { // TRegionFix |
|
735 if (iCount==-iAllocedRects) |
|
736 { // Can't expand a TRegionFix |
|
737 ForceError(); |
|
738 return; |
|
739 } |
|
740 prects=(TRect *)(this+1); |
|
741 } |
|
742 else if (iAllocedRects<0) |
|
743 { // RRegionBuf |
|
744 prects=(TRect *)(((RRegion *)this)+1); |
|
745 if (iCount==(-(iAllocedRects|ERRegionBuf))) |
|
746 { |
|
747 iAllocedRects=iCount+((RRegion *)this)->iGranularity; |
|
748 if ((((RRegion *)this)->iRectangleList=(TRect *)User::Alloc(iAllocedRects*sizeof(TRect)))==NULL) |
|
749 { |
|
750 ForceError(); |
|
751 return; |
|
752 } |
|
753 Mem::Copy(((RRegion *)this)->iRectangleList, prects, sizeof(TRect)*((RRegion *)this)->iGranularity); |
|
754 prects=((RRegion *)this)->iRectangleList; |
|
755 } |
|
756 } |
|
757 else |
|
758 { |
|
759 RRegion *pr=(RRegion *)this; |
|
760 prects=pr->iRectangleList; |
|
761 if (iAllocedRects==iCount) |
|
762 { |
|
763 iAllocedRects+=pr->iGranularity; |
|
764 prects=(TRect *)User::ReAlloc(prects, iAllocedRects*sizeof(TRect)); |
|
765 if (prects==NULL) |
|
766 { |
|
767 ForceError(); |
|
768 return; |
|
769 } |
|
770 pr->iRectangleList=prects; |
|
771 } |
|
772 } |
|
773 *(prects+iCount)=aRect; |
|
774 iCount++; |
|
775 } |
|
776 } |
|
777 |
|
778 void TRegion::DeleteRect(TRect *aRect) |
|
779 // |
|
780 // Delete a specific rectangle in the list. |
|
781 // |
|
782 { |
|
783 |
|
784 iCount--; |
|
785 Mem::Copy(aRect,aRect+1,((TUint8 *)(RectangleList()+iCount))-((TUint8 *)aRect)); |
|
786 } |
|
787 #endif |
|
788 |
|
789 void TRegion::AppendRegion(TRegion &aRegion) |
|
790 // |
|
791 // Append all the rectangles from aRegion to this. |
|
792 // |
|
793 { |
|
794 |
|
795 if (aRegion.iError) |
|
796 ForceError(); |
|
797 else |
|
798 { |
|
799 aRegion.SubRegion(*this); |
|
800 const TRect *pR=aRegion.RectangleList(); |
|
801 const TRect *pE=pR+aRegion.iCount; |
|
802 while (pR<pE) |
|
803 AppendRect(*pR++); |
|
804 } |
|
805 } |
|
806 |
|
807 |
|
808 |
|
809 EXPORT_C RRegion::RRegion() |
|
810 : TRegion(0), iGranularity(EDefaultGranularity), iRectangleList(NULL) |
|
811 /** |
|
812 Default constructor. |
|
813 |
|
814 Initialises its granularity to five. |
|
815 */ |
|
816 {} |
|
817 |
|
818 |
|
819 |
|
820 |
|
821 EXPORT_C RRegion::RRegion(TInt aGran) |
|
822 : TRegion(0), iGranularity(aGran), iRectangleList(NULL) |
|
823 /** |
|
824 Constructs the object with the specified granularity. |
|
825 |
|
826 @param aGran The initial value for the region's granularity. |
|
827 This value must not be negative. |
|
828 */ |
|
829 {} |
|
830 |
|
831 |
|
832 |
|
833 |
|
834 EXPORT_C RRegion::RRegion(const TRect &aRect, TInt aGran) |
|
835 : TRegion(0), iGranularity(aGran), iRectangleList(NULL) |
|
836 /** |
|
837 Constructs the object with the specified rectangle and granularity. |
|
838 |
|
839 The resulting region consists of the specified single rectangle. |
|
840 |
|
841 @param aRect The single rectangle with which to initialise the region |
|
842 @param aGran The initial value for the region's granularity. By default, |
|
843 this is five. |
|
844 */ |
|
845 { |
|
846 |
|
847 if (!aRect.IsEmpty()) |
|
848 AppendRect(aRect); |
|
849 } |
|
850 |
|
851 |
|
852 |
|
853 |
|
854 EXPORT_C RRegion::RRegion(const RRegion &aRegion) |
|
855 /** |
|
856 Copy constructor. |
|
857 |
|
858 Constructs a new region from an existing one by performing a bit-wise copy. Both the new and |
|
859 existing regions are left containing pointers to the same data, so Close() must only be called on |
|
860 one of them. |
|
861 |
|
862 Use of this method is not reccomended. |
|
863 |
|
864 @param aRegion The region to be copied. |
|
865 */ |
|
866 { |
|
867 |
|
868 *this=aRegion; |
|
869 } |
|
870 |
|
871 |
|
872 |
|
873 |
|
874 EXPORT_C RRegion::RRegion(TInt aBuf, TInt aGran) |
|
875 // |
|
876 // Constructor. |
|
877 // |
|
878 : TRegion(aBuf), iGranularity(aGran), iRectangleList(NULL) |
|
879 {} |
|
880 |
|
881 |
|
882 |
|
883 |
|
884 EXPORT_C RRegion::RRegion(TInt aCount,TRect* aRectangleList,TInt aGran/*=EDefaultGranularity*/) |
|
885 /** |
|
886 Constructor that takes ownership of an already created rectangle list. |
|
887 |
|
888 @param aCount The number of rectangles in the region. |
|
889 @param aRectangleList A pointer to the set of rectangles. |
|
890 @param aGran The region's granularity. |
|
891 */ |
|
892 : TRegion(aCount), iGranularity(aGran), iRectangleList(aRectangleList) |
|
893 { |
|
894 iCount=aCount; |
|
895 } |
|
896 |
|
897 |
|
898 |
|
899 |
|
900 EXPORT_C void RRegion::Close() |
|
901 /** |
|
902 Closes the region. |
|
903 |
|
904 Frees up any memory which has been allocated, and unsets the error flag, if |
|
905 set. |
|
906 |
|
907 The region can be re-used after calling this method. Its granularity is preserved. |
|
908 */ |
|
909 { |
|
910 |
|
911 Clear(); |
|
912 } |
|
913 |
|
914 |
|
915 |
|
916 |
|
917 EXPORT_C void RRegion::Destroy() |
|
918 // |
|
919 // Destroy |
|
920 // |
|
921 /** |
|
922 Deletes the region. |
|
923 |
|
924 Frees all memory. |
|
925 |
|
926 Note this method will delete the RRegion object and therefore it should not be |
|
927 invoked on RRegion objects that are not allocated on the heap. RRegion::Close() |
|
928 should be used for RRegion objects stored on the stack. |
|
929 |
|
930 @panic USER 42 if the RRegion object is stored on the stack. |
|
931 */ |
|
932 { |
|
933 |
|
934 Clear(); |
|
935 delete this; |
|
936 } |
|
937 |
|
938 |
|
939 |
|
940 |
|
941 TInt TRectKey::Compare(TInt aLeft,TInt aRight) const |
|
942 // |
|
943 // Compares two rectangles for partial ordering. |
|
944 // |
|
945 { |
|
946 |
|
947 if (aLeft==aRight) |
|
948 return(0); |
|
949 const TRect *r1=&iRectList[aLeft]; |
|
950 const TRect *r2=&iRectList[aRight]; |
|
951 if (r2->iBr.iY<=r1->iTl.iY) |
|
952 return(iDown ? -1 : 1); |
|
953 if (r1->iBr.iY<=r2->iTl.iY) |
|
954 return(iDown ? 1 : -1); |
|
955 if (r2->iBr.iX<=r1->iTl.iX) |
|
956 return(iRight ? -1 : 1); |
|
957 __ASSERT_DEBUG(r1->iBr.iX<=r2->iTl.iX,Panic(ETRegionInvalidRegionInSort)); |
|
958 return(iRight ? 1 : -1); |
|
959 } |
|
960 |
|
961 void TRectSwap::Swap(TInt aLeft,TInt aRight) const |
|
962 // |
|
963 // Swap two rectangles. |
|
964 // |
|
965 { |
|
966 |
|
967 TRect tmp(iRectList[aLeft]); |
|
968 iRectList[aLeft]=iRectList[aRight]; |
|
969 iRectList[aRight]=tmp; |
|
970 } |
|
971 |
|
972 TRectKey::TRectKey(const TRect *aRectList,const TPoint &aOffset) |
|
973 // |
|
974 // Rectangle key constructor |
|
975 // |
|
976 { |
|
977 |
|
978 iRectList=aRectList; |
|
979 if(aOffset.iX>0) |
|
980 iRight=ETrue; |
|
981 else |
|
982 iRight=EFalse; |
|
983 if(aOffset.iY>0) |
|
984 iDown=ETrue; |
|
985 else |
|
986 iDown=EFalse; |
|
987 } |