FreeRDP
Loading...
Searching...
No Matches
codec/region.c
1
22#include <winpr/assert.h>
23#include <winpr/memory.h>
24#include <freerdp/log.h>
25#include <freerdp/codec/region.h>
26
27#define TAG FREERDP_TAG("codec")
28
29/*
30 * The functions in this file implement the Region abstraction largely inspired from
31 * pixman library. The following comment is taken from the pixman code.
32 *
33 * A Region is simply a set of disjoint(non-overlapping) rectangles, plus an
34 * "extent" rectangle which is the smallest single rectangle that contains all
35 * the non-overlapping rectangles.
36 *
37 * A Region is implemented as a "y-x-banded" array of rectangles. This array
38 * imposes two degrees of order. First, all rectangles are sorted by top side
39 * y coordinate first (y1), and then by left side x coordinate (x1).
40 *
41 * Furthermore, the rectangles are grouped into "bands". Each rectangle in a
42 * band has the same top y coordinate (y1), and each has the same bottom y
43 * coordinate (y2). Thus all rectangles in a band differ only in their left
44 * and right side (x1 and x2). Bands are implicit in the array of rectangles:
45 * there is no separate list of band start pointers.
46 *
47 * The y-x band representation does not minimize rectangles. In particular,
48 * if a rectangle vertically crosses a band (the rectangle has scanlines in
49 * the y1 to y2 area spanned by the band), then the rectangle may be broken
50 * down into two or more smaller rectangles stacked one atop the other.
51 *
52 * ----------- -----------
53 * | | | | band 0
54 * | | -------- ----------- --------
55 * | | | | in y-x banded | | | | band 1
56 * | | | | form is | | | |
57 * ----------- | | ----------- --------
58 * | | | | band 2
59 * -------- --------
60 *
61 * An added constraint on the rectangles is that they must cover as much
62 * horizontal area as possible: no two rectangles within a band are allowed
63 * to touch.
64 *
65 * Whenever possible, bands will be merged together to cover a greater vertical
66 * distance (and thus reduce the number of rectangles). Two bands can be merged
67 * only if the bottom of one touches the top of the other and they have
68 * rectangles in the same places (of the same width, of course).
69 */
70
71struct S_REGION16_DATA
72{
73 size_t nbRects;
74 RECTANGLE_16* rects;
75};
76
77void region16_init(REGION16* region)
78{
79 WINPR_ASSERT(region);
80
81 const REGION16 empty = { 0 };
82 *region = empty;
83}
84
85int region16_n_rects(const REGION16* region)
86{
87 WINPR_ASSERT(region);
88 if (!region->data)
89 return 0;
90
91 return WINPR_ASSERTING_INT_CAST(int, region->data->nbRects);
92}
93
94const RECTANGLE_16* region16_rects(const REGION16* region, UINT32* nbRects)
95{
96 if (nbRects)
97 *nbRects = 0;
98
99 if (!region)
100 return NULL;
101
102 REGION16_DATA* data = region->data;
103 if (!data)
104 return NULL;
105
106 if (nbRects)
107 *nbRects = WINPR_ASSERTING_INT_CAST(UINT32, data->nbRects);
108
109 return data->rects;
110}
111
112static inline RECTANGLE_16* region16_rects_noconst(REGION16* region)
113{
114 WINPR_ASSERT(region);
115
116 REGION16_DATA* data = region->data;
117
118 if (!data)
119 return NULL;
120
121 return data->rects;
122}
123
124const RECTANGLE_16* region16_extents(const REGION16* region)
125{
126 if (!region)
127 return NULL;
128
129 return &region->extents;
130}
131
132static RECTANGLE_16* region16_extents_noconst(REGION16* region)
133{
134 if (!region)
135 return NULL;
136
137 return &region->extents;
138}
139
140BOOL rectangle_is_empty(const RECTANGLE_16* rect)
141{
142 WINPR_ASSERT(rect);
143
144 /* A rectangle with width <= 0 or height <= 0 should be regarded
145 * as empty.
146 */
147 return ((rect->left >= rect->right) || (rect->top >= rect->bottom)) ? TRUE : FALSE;
148}
149
150BOOL region16_is_empty(const REGION16* region)
151{
152 WINPR_ASSERT(region);
153 if (!region->data)
154 return TRUE;
155 return (region->data->nbRects == 0);
156}
157
158BOOL rectangles_equal(const RECTANGLE_16* r1, const RECTANGLE_16* r2)
159{
160 WINPR_ASSERT(r1);
161 WINPR_ASSERT(r2);
162
163 return ((r1->left == r2->left) && (r1->top == r2->top) && (r1->right == r2->right) &&
164 (r1->bottom == r2->bottom))
165 ? TRUE
166 : FALSE;
167}
168
169BOOL rectangles_intersects(const RECTANGLE_16* r1, const RECTANGLE_16* r2)
170{
171 RECTANGLE_16 tmp = { 0 };
172 return rectangles_intersection(r1, r2, &tmp);
173}
174
175BOOL rectangles_intersection(const RECTANGLE_16* r1, const RECTANGLE_16* r2, RECTANGLE_16* dst)
176{
177 WINPR_ASSERT(r1);
178 WINPR_ASSERT(r2);
179 WINPR_ASSERT(dst);
180
181 dst->left = MAX(r1->left, r2->left);
182 dst->right = MIN(r1->right, r2->right);
183 dst->top = MAX(r1->top, r2->top);
184 dst->bottom = MIN(r1->bottom, r2->bottom);
185 return (dst->left < dst->right) && (dst->top < dst->bottom);
186}
187
188static void freeRegion(REGION16_DATA* data)
189{
190 if (data)
191 free(data->rects);
192 free(data);
193}
194
195void region16_clear(REGION16* region)
196{
197 WINPR_ASSERT(region);
198
199 freeRegion(region->data);
200 region->data = NULL;
201
202 const RECTANGLE_16 empty = { 0 };
203 region->extents = empty;
204}
205
206WINPR_ATTR_MALLOC(freeRegion, 1)
207WINPR_ATTR_NODISCARD
208static REGION16_DATA* allocateRegion(size_t nbItems)
209{
210 REGION16_DATA* data = calloc(1, sizeof(REGION16_DATA));
211 if (!data)
212 return NULL;
213
214 if (nbItems > 0)
215 {
216 data->rects = calloc(nbItems, sizeof(RECTANGLE_16));
217 if (!data->rects)
218 {
219 free(data);
220 return NULL;
221 }
222 }
223
224 data->nbRects = nbItems;
225 return data;
226}
227
228static inline RECTANGLE_16* nextRect(REGION16_DATA* data, size_t index)
229{
230 WINPR_ASSERT(data);
231 if (index + 1 > data->nbRects)
232 {
233 RECTANGLE_16* rects = realloc(data->rects, (index + 1) * sizeof(RECTANGLE_16));
234 if (!rects)
235 {
236 freeRegion(data);
237 return NULL;
238 }
239
240 const RECTANGLE_16 empty = { 0 };
241 rects[index] = empty;
242 data->nbRects = index + 1;
243 data->rects = rects;
244 }
245 return &data->rects[index];
246}
247
248static BOOL resizeRegion(REGION16* region, size_t nbItems)
249{
250 WINPR_ASSERT(region);
251 if (nbItems == 0)
252 {
253 freeRegion(region->data);
254 region->data = NULL;
255 return TRUE;
256 }
257
258 if (!region->data)
259 {
260 region->data = allocateRegion(nbItems);
261 return region->data != NULL;
262 }
263
264 RECTANGLE_16* rects = realloc(region->data->rects, nbItems * sizeof(RECTANGLE_16));
265 if (!rects)
266 {
267 free(region->data->rects);
268 region->data->nbRects = 0;
269 region->data->rects = NULL;
270 return FALSE;
271 }
272
273 for (size_t x = region->data->nbRects; x < nbItems; x++)
274 {
275 const RECTANGLE_16 empty = { 0 };
276 rects[x] = empty;
277 }
278 region->data->rects = rects;
279 region->data->nbRects = nbItems;
280 return TRUE;
281}
282
283static inline BOOL region16_copy_data(REGION16* dst, const REGION16* src)
284{
285 WINPR_ASSERT(dst);
286 WINPR_ASSERT(src);
287
288 freeRegion(dst->data);
289 dst->data = NULL;
290
291 if (src->data && (src->data->nbRects > 0))
292 {
293 dst->data = allocateRegion(src->data->nbRects);
294 if (!dst->data || !dst->data->rects)
295 return FALSE;
296 memcpy(dst->data->rects, src->data->rects, dst->data->nbRects * sizeof(RECTANGLE_16));
297 }
298 return TRUE;
299}
300
301BOOL region16_copy(REGION16* dst, const REGION16* src)
302{
303 if (dst == src)
304 return TRUE;
305
306 WINPR_ASSERT(dst);
307 WINPR_ASSERT(src);
308
309 dst->extents = src->extents;
310
311 return region16_copy_data(dst, src);
312}
313
314void region16_print(const REGION16* region)
315{
316 UINT32 nbRects = 0;
317 int currentBandY = -1;
318 const RECTANGLE_16* rects = region16_rects(region, &nbRects);
319
320 WLog_DBG(TAG, "nrects=%" PRIu32 "", nbRects);
321
322 for (UINT32 i = 0; i < nbRects; i++)
323 {
324 const RECTANGLE_16* rect = &rects[i];
325
326 if (rect->top != currentBandY)
327 {
328 currentBandY = rect->top;
329 WLog_DBG(TAG, "band %d: ", currentBandY);
330 }
331
332 WLog_DBG(TAG, "(%" PRIu16 ",%" PRIu16 "-%" PRIu16 ",%" PRIu16 ")", rect->left, rect->top,
333 rect->right, rect->bottom);
334 }
335}
336
337static BOOL region16_copy_band_with_union(REGION16_DATA* region, const RECTANGLE_16* src,
338 const RECTANGLE_16* end, UINT16 newTop, UINT16 newBottom,
339 const RECTANGLE_16* unionRect, UINT32* dstCounter,
340 const RECTANGLE_16** srcPtr)
341{
342 WINPR_ASSERT(region);
343 WINPR_ASSERT(src);
344 WINPR_ASSERT(end);
345 WINPR_ASSERT(dstCounter);
346
347 UINT16 refY = src->top;
348
349 /* merges a band with the given rect
350 * Input:
351 * unionRect
352 * | |
353 * | |
354 * ==============+===============+================================
355 * |Item1| |Item2| |Item3| |Item4| |Item5| Band
356 * ==============+===============+================================
357 * before | overlap | after
358 *
359 * Resulting band:
360 * +-----+ +----------------------+ +-----+
361 * |Item1| | Item2 | |Item3|
362 * +-----+ +----------------------+ +-----+
363 *
364 * We first copy as-is items that are before Item2, the first overlapping
365 * item.
366 * Then we find the last one that overlap unionRect to aggregate Item2, Item3
367 * and Item4 to create Item2.
368 * Finally Item5 is copied as Item3.
369 *
370 * When no unionRect is provided, we skip the two first steps to just copy items
371 */
372
373 if (unionRect)
374 {
375 /* items before unionRect */
376 while ((src < end) && (src->top == refY) && (src->right < unionRect->left))
377 {
378 RECTANGLE_16* dst = nextRect(region, (*dstCounter)++);
379 if (!dst)
380 return FALSE;
381 dst->top = newTop;
382 dst->bottom = newBottom;
383 dst->right = src->right;
384 dst->left = src->left;
385 src++;
386 }
387
388 /* treat items overlapping with unionRect */
389 const RECTANGLE_16* startOverlap = unionRect;
390 const RECTANGLE_16* endOverlap = unionRect;
391
392 if ((src < end) && (src->top == refY) && (src->left < unionRect->left))
393 startOverlap = src;
394
395 while ((src < end) && (src->top == refY) && (src->right < unionRect->right))
396 {
397 src++;
398 }
399
400 if ((src < end) && (src->top == refY) && (src->left < unionRect->right))
401 {
402 endOverlap = src;
403 src++;
404 }
405
406 {
407 RECTANGLE_16* dst = nextRect(region, (*dstCounter)++);
408 if (!dst)
409 return FALSE;
410 dst->bottom = newBottom;
411 dst->top = newTop;
412 dst->left = startOverlap->left;
413 dst->right = endOverlap->right;
414 }
415 }
416
417 /* treat remaining items on the same band */
418 while ((src < end) && (src->top == refY))
419 {
420 RECTANGLE_16* dst = nextRect(region, (*dstCounter)++);
421 if (!dst)
422 return FALSE;
423
424 dst->top = newTop;
425 dst->bottom = newBottom;
426 dst->right = src->right;
427 dst->left = src->left;
428 src++;
429 }
430
431 if (srcPtr)
432 *srcPtr = src;
433
434 return TRUE;
435}
436
437static RECTANGLE_16* next_band(RECTANGLE_16* band1, RECTANGLE_16* endPtr, int* nbItems)
438{
439 WINPR_ASSERT(band1);
440 WINPR_ASSERT(endPtr);
441 WINPR_ASSERT(nbItems);
442
443 UINT16 refY = band1->top;
444 *nbItems = 0;
445
446 while ((band1 < endPtr) && (band1->top == refY))
447 {
448 band1++;
449 *nbItems += 1;
450 }
451
452 return band1;
453}
454
455static BOOL band_match(const RECTANGLE_16* band1, const RECTANGLE_16* band2,
456 const RECTANGLE_16* endPtr)
457{
458 int refBand2 = band2->top;
459 const RECTANGLE_16* band2Start = band2;
460
461 while ((band1 < band2Start) && (band2 < endPtr) && (band2->top == refBand2))
462 {
463 if ((band1->left != band2->left) || (band1->right != band2->right))
464 return FALSE;
465
466 band1++;
467 band2++;
468 }
469
470 if (band1 != band2Start)
471 return FALSE;
472
473 return (band2 == endPtr) || (band2->top != refBand2);
474}
475
482static BOOL rectangle_contained_in_band(const RECTANGLE_16* band, const RECTANGLE_16* endPtr,
483 const RECTANGLE_16* rect)
484{
485 WINPR_ASSERT(band);
486 WINPR_ASSERT(endPtr);
487 WINPR_ASSERT(rect);
488
489 UINT16 refY = band->top;
490
491 if ((band->top > rect->top) || (rect->bottom > band->bottom))
492 return FALSE;
493
494 /* note: as the band is sorted from left to right, once we've seen an item
495 * that is after rect->left we're sure that the result is False.
496 */
497 while ((band < endPtr) && (band->top == refY) && (band->left <= rect->left))
498 {
499 if (rect->right <= band->right)
500 return TRUE;
501
502 band++;
503 }
504
505 return FALSE;
506}
507
508static BOOL region16_simplify_bands(REGION16* region)
509{
522 const int nbRects = region16_n_rects(region);
523 int finalNbRects = nbRects;
524
525 if (nbRects < 2)
526 return TRUE;
527
528 RECTANGLE_16* band1 = region16_rects_noconst(region);
529 RECTANGLE_16* endPtr = band1 + nbRects;
530
531 do
532 {
533 int bandItems = 0;
534 RECTANGLE_16* band2 = next_band(band1, endPtr, &bandItems);
535
536 if (band2 == endPtr)
537 break;
538
539 if ((band1->bottom == band2->top) && band_match(band1, band2, endPtr))
540 {
541 /* adjust the bottom of band1 items */
542 RECTANGLE_16* tmp = band1;
543
544 while (tmp < band2)
545 {
546 tmp->bottom = band2->bottom;
547 tmp++;
548 }
549
550 /* override band2, we don't move band1 pointer as the band after band2
551 * may be merged too */
552 const RECTANGLE_16* endBand = band2 + bandItems;
553 const size_t toMove =
554 WINPR_ASSERTING_INT_CAST(size_t, (endPtr - endBand)) * sizeof(RECTANGLE_16);
555
556 if (toMove)
557 MoveMemory(band2, endBand, toMove);
558
559 finalNbRects -= bandItems;
560 endPtr -= bandItems;
561 }
562 else
563 {
564 band1 = band2;
565 }
566 } while (TRUE);
567
568 if (finalNbRects != nbRects)
569 {
570 if (!resizeRegion(region, WINPR_ASSERTING_INT_CAST(size_t, finalNbRects)))
571 return FALSE;
572 }
573
574 return TRUE;
575}
576
577BOOL region16_union_rect(REGION16* dst, const REGION16* src, const RECTANGLE_16* rect)
578{
579 const RECTANGLE_16* nextBand = NULL;
580 UINT32 srcNbRects = 0;
581 UINT16 topInterBand = 0;
582 WINPR_ASSERT(src);
583 WINPR_ASSERT(dst);
584
585 const RECTANGLE_16* srcExtents = region16_extents(src);
586 RECTANGLE_16* dstExtents = region16_extents_noconst(dst);
587
588 const int nrSrcRects = region16_n_rects(src);
589 if (nrSrcRects == 0)
590 {
591 /* source is empty, so the union is rect */
592 dst->extents = *rect;
593
594 if (!resizeRegion(dst, 1))
595 return FALSE;
596
597 RECTANGLE_16* dstRect = region16_rects_noconst(dst);
598 WINPR_ASSERT(dstRect);
599
600 dstRect->top = rect->top;
601 dstRect->left = rect->left;
602 dstRect->right = rect->right;
603 dstRect->bottom = rect->bottom;
604 dst->data->nbRects = 1;
605 return TRUE;
606 }
607
608 REGION16_DATA* newItems = allocateRegion(WINPR_ASSERTING_INT_CAST(size_t, nrSrcRects + 1));
609
610 if (!newItems)
611 return FALSE;
612
613 UINT32 usedRects = 0;
614
615 /* adds the piece of rect that is on the top of src */
616 if (rect->top < srcExtents->top)
617 {
618 RECTANGLE_16* dstRect = nextRect(newItems, usedRects++);
619 if (!dstRect)
620 return FALSE;
621
622 dstRect->top = rect->top;
623 dstRect->left = rect->left;
624 dstRect->right = rect->right;
625 dstRect->bottom = MIN(srcExtents->top, rect->bottom);
626 }
627
628 /* treat possibly overlapping region */
629 const RECTANGLE_16* currentBand = region16_rects(src, &srcNbRects);
630 const RECTANGLE_16* endSrcRect = currentBand + srcNbRects;
631
632 while (currentBand < endSrcRect)
633 {
634 if ((currentBand->bottom <= rect->top) || (rect->bottom <= currentBand->top) ||
635 rectangle_contained_in_band(currentBand, endSrcRect, rect))
636 {
637 /* no overlap between rect and the band, rect is totally below or totally above
638 * the current band, or rect is already covered by an item of the band.
639 * let's copy all the rectangles from this band
640 +----+
641 | | rect (case 1)
642 +----+
643
644 =================
645 band of srcRect
646 =================
647 +----+
648 | | rect (case 2)
649 +----+
650 */
651 if (!region16_copy_band_with_union(newItems, currentBand, endSrcRect, currentBand->top,
652 currentBand->bottom, NULL, &usedRects, &nextBand))
653 return FALSE;
654 topInterBand = rect->top;
655 }
656 else
657 {
658 /* rect overlaps the band:
659 | | | |
660 ====^=================| |==| |=========================== band
661 | top split | | | |
662 v | 1 | | 2 |
663 ^ | | | | +----+ +----+
664 | merge zone | | | | | | | 4 |
665 v +----+ | | | | +----+
666 ^ | | | 3 |
667 | bottom split | | | |
668 ====v=========================| |==| |===================
669 | | | |
670
671 possible cases:
672 1) no top split, merge zone then a bottom split. The band will be split
673 in two
674 2) not band split, only the merge zone, band merged with rect but not split
675 3) a top split, the merge zone and no bottom split. The band will be split
676 in two
677 4) a top split, the merge zone and also a bottom split. The band will be
678 split in 3, but the coalesce algorithm may merge the created bands
679 */
680 UINT16 mergeTop = currentBand->top;
681 UINT16 mergeBottom = currentBand->bottom;
682
683 /* test if we need a top split, case 3 and 4 */
684 if (rect->top > currentBand->top)
685 {
686 if (!region16_copy_band_with_union(newItems, currentBand, endSrcRect,
687 currentBand->top, rect->top, NULL, &usedRects,
688 &nextBand))
689 return FALSE;
690 mergeTop = rect->top;
691 }
692
693 /* do the merge zone (all cases) */
694 if (rect->bottom < currentBand->bottom)
695 mergeBottom = rect->bottom;
696
697 if (!region16_copy_band_with_union(newItems, currentBand, endSrcRect, mergeTop,
698 mergeBottom, rect, &usedRects, &nextBand))
699 return FALSE;
700
701 /* test if we need a bottom split, case 1 and 4 */
702 if (rect->bottom < currentBand->bottom)
703 {
704 if (!region16_copy_band_with_union(newItems, currentBand, endSrcRect, mergeBottom,
705 currentBand->bottom, NULL, &usedRects,
706 &nextBand))
707 return FALSE;
708 }
709
710 topInterBand = currentBand->bottom;
711 }
712
713 /* test if a piece of rect should be inserted as a new band between
714 * the current band and the next one. band n and n+1 shouldn't touch.
715 *
716 * ==============================================================
717 * band n
718 * +------+ +------+
719 * ===========| rect |====================| |===============
720 * | | +------+ | |
721 * +------+ | rect | | rect |
722 * +------+ | |
723 * =======================================| |================
724 * +------+ band n+1
725 * ===============================================================
726 *
727 */
728 if ((nextBand < endSrcRect) && (nextBand->top != currentBand->bottom) &&
729 (rect->bottom > currentBand->bottom) && (rect->top < nextBand->top))
730 {
731 RECTANGLE_16* dstRect = nextRect(newItems, usedRects++);
732 if (!dstRect)
733 return FALSE;
734
735 dstRect->right = rect->right;
736 dstRect->left = rect->left;
737 dstRect->top = topInterBand;
738 dstRect->bottom = MIN(nextBand->top, rect->bottom);
739 }
740
741 currentBand = nextBand;
742 }
743
744 /* adds the piece of rect that is below src */
745 if (srcExtents->bottom < rect->bottom)
746 {
747 RECTANGLE_16* dstRect = nextRect(newItems, usedRects++);
748 if (!dstRect)
749 return FALSE;
750
751 dstRect->top = MAX(srcExtents->bottom, rect->top);
752 dstRect->left = rect->left;
753 dstRect->right = rect->right;
754 dstRect->bottom = rect->bottom;
755 }
756
757 dstExtents->top = MIN(rect->top, srcExtents->top);
758 dstExtents->left = MIN(rect->left, srcExtents->left);
759 dstExtents->bottom = MAX(rect->bottom, srcExtents->bottom);
760 dstExtents->right = MAX(rect->right, srcExtents->right);
761
762 newItems->nbRects = usedRects;
763 freeRegion(dst->data);
764 dst->data = newItems;
765
766 return region16_simplify_bands(dst);
767}
768
769BOOL region16_intersects_rect(const REGION16* src, const RECTANGLE_16* arg2)
770{
771 const RECTANGLE_16* endPtr = NULL;
772 UINT32 nbRects = 0;
773
774 if (!src || !src->data || !arg2)
775 return FALSE;
776
777 const RECTANGLE_16* rect = region16_rects(src, &nbRects);
778
779 if (!nbRects)
780 return FALSE;
781
782 const RECTANGLE_16* srcExtents = region16_extents(src);
783
784 if (nbRects == 1)
785 return rectangles_intersects(srcExtents, arg2);
786
787 if (!rectangles_intersects(srcExtents, arg2))
788 return FALSE;
789
790 for (endPtr = rect + nbRects; (rect < endPtr) && (arg2->bottom > rect->top); rect++)
791 {
792 if (rectangles_intersects(rect, arg2))
793 return TRUE;
794 }
795
796 return FALSE;
797}
798
799BOOL region16_intersect_rect(REGION16* dst, const REGION16* src, const RECTANGLE_16* rect)
800{
801 const RECTANGLE_16* endPtr = NULL;
802 UINT32 nbRects = 0;
803 RECTANGLE_16 common = { 0 };
804
805 WINPR_ASSERT(dst);
806 WINPR_ASSERT(src);
807
808 const RECTANGLE_16* srcPtr = region16_rects(src, &nbRects);
809
810 if (!nbRects)
811 {
812 region16_clear(dst);
813 return TRUE;
814 }
815
816 const RECTANGLE_16* srcExtents = region16_extents(src);
817
818 if (nbRects == 1)
819 {
820 BOOL intersects = rectangles_intersection(srcExtents, rect, &common);
821 region16_clear(dst);
822
823 if (intersects)
824 return region16_union_rect(dst, dst, &common);
825
826 return TRUE;
827 }
828
829 REGION16_DATA* newItems = allocateRegion(nbRects);
830
831 if (!newItems)
832 return FALSE;
833
834 RECTANGLE_16* dstPtr = newItems->rects;
835 UINT32 usedRects = 0;
836 RECTANGLE_16 newExtents = { 0 };
837
838 /* accumulate intersecting rectangles, the final region16_simplify_bands() will
839 * do all the bad job to recreate correct rectangles
840 */
841 for (endPtr = srcPtr + nbRects; (srcPtr < endPtr) && (rect->bottom > srcPtr->top); srcPtr++)
842 {
843 if (usedRects > nbRects)
844 {
845 freeRegion(newItems);
846 return FALSE;
847 }
848
849 if (rectangles_intersection(srcPtr, rect, &common))
850 {
851 *dstPtr = common;
852 usedRects++;
853 dstPtr++;
854
855 if (rectangle_is_empty(&newExtents))
856 {
857 /* Check if the existing newExtents is empty. If it is empty, use
858 * new common directly. We do not need to check common rectangle
859 * because the rectangles_intersection() ensures that it is not empty.
860 */
861 newExtents = common;
862 }
863 else
864 {
865 newExtents.top = MIN(common.top, newExtents.top);
866 newExtents.left = MIN(common.left, newExtents.left);
867 newExtents.bottom = MAX(common.bottom, newExtents.bottom);
868 newExtents.right = MAX(common.right, newExtents.right);
869 }
870 }
871 }
872
873 newItems->nbRects = usedRects;
874
875 freeRegion(dst->data);
876 dst->data = newItems;
877 dst->extents = newExtents;
878 return region16_simplify_bands(dst);
879}
880
881void region16_uninit(REGION16* region)
882{
883 WINPR_ASSERT(region);
884
885 freeRegion(region->data);
886 region->data = NULL;
887}