22 #include <winpr/assert.h>
23 #include <winpr/memory.h>
24 #include <freerdp/log.h>
25 #include <freerdp/codec/region.h>
27 #define TAG FREERDP_TAG("codec")
71 struct S_REGION16_DATA
77 static REGION16_DATA empty_region = { 0, 0 };
82 ZeroMemory(region,
sizeof(
REGION16));
83 region->data = &empty_region;
86 int region16_n_rects(
const REGION16* region)
89 WINPR_ASSERT(region->data);
90 WINPR_ASSERT(region->data->nbRects <= INT32_MAX);
91 return (
int)region->data->nbRects;
96 REGION16_DATA* data = NULL;
111 WINPR_ASSERT(data->nbRects <= UINT32_MAX);
112 *nbRects = (UINT32)data->nbRects;
120 REGION16_DATA* data = NULL;
134 return ®ion->extents;
142 return ®ion->extents;
150 return ((rect->left >= rect->right) || (rect->top >= rect->bottom)) ? TRUE : FALSE;
153 BOOL region16_is_empty(
const REGION16* region)
155 WINPR_ASSERT(region);
156 WINPR_ASSERT(region->data);
157 return (region->data->nbRects == 0);
162 return ((r1->left == r2->left) && (r1->top == r2->top) && (r1->right == r2->right) &&
163 (r1->bottom == r2->bottom))
171 return rectangles_intersection(r1, r2, &tmp);
176 dst->left = MAX(r1->left, r2->left);
177 dst->right = MIN(r1->right, r2->right);
178 dst->top = MAX(r1->top, r2->top);
179 dst->bottom = MIN(r1->bottom, r2->bottom);
180 return (dst->left < dst->right) && (dst->top < dst->bottom);
183 void region16_clear(
REGION16* region)
185 WINPR_ASSERT(region);
186 WINPR_ASSERT(region->data);
188 if ((region->data->size > 0) && (region->data != &empty_region))
191 region->data = &empty_region;
192 ZeroMemory(®ion->extents,
sizeof(region->extents));
195 static INLINE REGION16_DATA* allocateRegion(
long nbItems)
198 sizeof(REGION16_DATA) + (WINPR_ASSERTING_INT_CAST(
size_t, nbItems) *
sizeof(
RECTANGLE_16));
199 REGION16_DATA* ret = (REGION16_DATA*)malloc(allocSize);
204 ret->size = WINPR_ASSERTING_INT_CAST(
long, allocSize);
205 ret->nbRects = nbItems;
212 WINPR_ASSERT(dst->data);
214 WINPR_ASSERT(src->data);
219 dst->extents = src->extents;
221 if ((dst->data->size > 0) && (dst->data != &empty_region))
224 if (src->data->size == 0)
225 dst->data = &empty_region;
228 dst->data = allocateRegion(src->data->nbRects);
233 CopyMemory(dst->data, src->data, WINPR_ASSERTING_INT_CAST(
size_t, src->data->size));
239 void region16_print(
const REGION16* region)
243 int currentBandY = -1;
244 rects = region16_rects(region, &nbRects);
245 WLog_DBG(TAG,
"nrects=%" PRIu32
"", nbRects);
247 for (UINT32 i = 0; i < nbRects; i++, rects++)
249 if (rects->top != currentBandY)
251 currentBandY = rects->top;
252 WLog_DBG(TAG,
"band %d: ", currentBandY);
255 WLog_DBG(TAG,
"(%" PRIu16
",%" PRIu16
"-%" PRIu16
",%" PRIu16
")", rects->left, rects->top,
256 rects->right, rects->bottom);
261 const RECTANGLE_16* end, UINT16 newTop, UINT16 newBottom,
265 UINT16 refY = src->top;
296 while ((src < end) && (src->top == refY) && (src->right < unionRect->left))
299 dst->bottom = newBottom;
300 dst->right = src->right;
301 dst->left = src->left;
308 startOverlap = unionRect;
309 endOverlap = unionRect;
311 if ((src < end) && (src->top == refY) && (src->left < unionRect->left))
314 while ((src < end) && (src->top == refY) && (src->right < unionRect->right))
319 if ((src < end) && (src->top == refY) && (src->left < unionRect->right))
325 dst->bottom = newBottom;
327 dst->left = startOverlap->left;
328 dst->right = endOverlap->right;
334 while ((src < end) && (src->top == refY))
337 dst->bottom = newBottom;
338 dst->right = src->right;
339 dst->left = src->left;
353 UINT16 refY = band1->top;
356 while ((band1 < endPtr) && (band1->top == refY))
368 int refBand2 = band2->top;
371 while ((band1 < band2Start) && (band2 < endPtr) && (band2->top == refBand2))
373 if ((band1->left != band2->left) || (band1->right != band2->right))
380 if (band1 != band2Start)
383 return (band2 == endPtr) || (band2->top != refBand2);
395 UINT16 refY = band->top;
397 if ((band->top > rect->top) || (rect->bottom > band->bottom))
403 while ((band < endPtr) && (band->top == refY) && (band->left <= rect->left))
405 if (rect->right <= band->right)
414 static BOOL region16_simplify_bands(
REGION16* region)
429 int finalNbRects = 0;
431 finalNbRects = nbRects = region16_n_rects(region);
441 RECTANGLE_16* band2 = next_band(band1, endPtr, &bandItems);
446 if ((band1->bottom == band2->top) && band_match(band1, band2, endPtr))
453 tmp->bottom = band2->bottom;
459 endBand = band2 + bandItems;
460 const size_t toMove =
461 WINPR_ASSERTING_INT_CAST(
size_t, (endPtr - endBand)) *
sizeof(
RECTANGLE_16);
464 MoveMemory(band2, endBand, toMove);
466 finalNbRects -= bandItems;
475 if (finalNbRects != nbRects)
477 size_t allocSize =
sizeof(REGION16_DATA) +
478 (WINPR_ASSERTING_INT_CAST(
size_t, finalNbRects) *
sizeof(
RECTANGLE_16));
479 REGION16_DATA* data = realloc(region->data, allocSize);
486 region->data = &empty_region;
490 region->data->nbRects = finalNbRects;
491 region->data->size = WINPR_ASSERTING_INT_CAST(
long, allocSize);
504 REGION16_DATA* newItems = NULL;
505 REGION16_DATA* tmpItems = NULL;
507 UINT32 usedRects = 0;
508 UINT32 srcNbRects = 0;
509 UINT16 topInterBand = 0;
512 srcExtents = region16_extents(src);
513 dstExtents = region16_extents_noconst(dst);
515 if (!region16_n_rects(src))
518 dst->extents = *rect;
519 dst->data = allocateRegion(1);
524 dstRect = region16_rects_noconst(dst);
525 dstRect->top = rect->top;
526 dstRect->left = rect->left;
527 dstRect->right = rect->right;
528 dstRect->bottom = rect->bottom;
532 newItems = allocateRegion((1L + 4L * region16_n_rects(src)));
541 if (rect->top < srcExtents->top)
543 dstRect->top = rect->top;
544 dstRect->left = rect->left;
545 dstRect->right = rect->right;
546 dstRect->bottom = MIN(srcExtents->top, rect->bottom);
552 currentBand = region16_rects(src, &srcNbRects);
553 endSrcRect = currentBand + srcNbRects;
555 while (currentBand < endSrcRect)
557 if ((currentBand->bottom <= rect->top) || (rect->bottom <= currentBand->top) ||
558 rectangle_contained_in_band(currentBand, endSrcRect, rect))
574 region16_copy_band_with_union(dstRect, currentBand, endSrcRect, currentBand->top,
575 currentBand->bottom, NULL, &usedRects, &nextBand,
577 topInterBand = rect->top;
603 UINT16 mergeTop = currentBand->top;
604 UINT16 mergeBottom = currentBand->bottom;
607 if (rect->top > currentBand->top)
609 region16_copy_band_with_union(dstRect, currentBand, endSrcRect, currentBand->top,
610 rect->top, NULL, &usedRects, &nextBand, &dstRect);
611 mergeTop = rect->top;
615 if (rect->bottom < currentBand->bottom)
616 mergeBottom = rect->bottom;
618 region16_copy_band_with_union(dstRect, currentBand, endSrcRect, mergeTop, mergeBottom,
619 rect, &usedRects, &nextBand, &dstRect);
622 if (rect->bottom < currentBand->bottom)
624 region16_copy_band_with_union(dstRect, currentBand, endSrcRect, mergeBottom,
625 currentBand->bottom, NULL, &usedRects, &nextBand,
629 topInterBand = currentBand->bottom;
647 if ((nextBand < endSrcRect) && (nextBand->top != currentBand->bottom) &&
648 (rect->bottom > currentBand->bottom) && (rect->top < nextBand->top))
650 dstRect->right = rect->right;
651 dstRect->left = rect->left;
652 dstRect->top = topInterBand;
653 dstRect->bottom = MIN(nextBand->top, rect->bottom);
658 currentBand = nextBand;
662 if (srcExtents->bottom < rect->bottom)
664 dstRect->top = MAX(srcExtents->bottom, rect->top);
665 dstRect->left = rect->left;
666 dstRect->right = rect->right;
667 dstRect->bottom = rect->bottom;
672 if ((src == dst) && (dst->data != &empty_region))
675 dstExtents->top = MIN(rect->top, srcExtents->top);
676 dstExtents->left = MIN(rect->left, srcExtents->left);
677 dstExtents->bottom = MAX(rect->bottom, srcExtents->bottom);
678 dstExtents->right = MAX(rect->right, srcExtents->right);
680 WINPR_ASSERTING_INT_CAST(
long,
sizeof(REGION16_DATA) + (usedRects *
sizeof(
RECTANGLE_16)));
681 if (newItems->size != 0)
682 tmpItems = realloc(newItems, WINPR_ASSERTING_INT_CAST(
size_t, newItems->size));
687 dst->data = newItems;
692 dst->data->nbRects = usedRects;
693 return region16_simplify_bands(dst);
703 if (!src || !src->data || !arg2)
706 rect = region16_rects(src, &nbRects);
711 srcExtents = region16_extents(src);
714 return rectangles_intersects(srcExtents, arg2);
716 if (!rectangles_intersects(srcExtents, arg2))
719 for (endPtr = rect + nbRects; (rect < endPtr) && (arg2->bottom > rect->top); rect++)
721 if (rectangles_intersects(rect, arg2))
730 REGION16_DATA* newItems = NULL;
736 UINT32 usedRects = 0;
740 WINPR_ASSERT(src->data);
741 srcPtr = region16_rects(src, &nbRects);
749 srcExtents = region16_extents(src);
753 BOOL intersects = rectangles_intersection(srcExtents, rect, &common);
757 return region16_union_rect(dst, dst, &common);
762 newItems = allocateRegion(nbRects);
769 ZeroMemory(&newExtents,
sizeof(newExtents));
774 for (endPtr = srcPtr + nbRects; (srcPtr < endPtr) && (rect->bottom > srcPtr->top); srcPtr++)
776 if (rectangles_intersection(srcPtr, rect, &common))
782 if (rectangle_is_empty(&newExtents))
792 newExtents.top = MIN(common.top, newExtents.top);
793 newExtents.left = MIN(common.left, newExtents.left);
794 newExtents.bottom = MAX(common.bottom, newExtents.bottom);
795 newExtents.right = MAX(common.right, newExtents.right);
800 newItems->nbRects = usedRects;
802 WINPR_ASSERTING_INT_CAST(
long,
sizeof(REGION16_DATA) + (usedRects *
sizeof(
RECTANGLE_16)));
804 if ((dst->data->size > 0) && (dst->data != &empty_region))
807 dst->data = realloc(newItems, WINPR_ASSERTING_INT_CAST(
size_t, newItems->size));
815 dst->extents = newExtents;
816 return region16_simplify_bands(dst);
819 void region16_uninit(
REGION16* region)
821 WINPR_ASSERT(region);
825 if ((region->data->size > 0) && (region->data != &empty_region))