|
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 } |