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")
81 const REGION16 empty = WINPR_C_ARRAY_INIT;
85int region16_n_rects(
const REGION16* region)
91 return WINPR_ASSERTING_INT_CAST(
int, region->data->nbRects);
102 REGION16_DATA* data = region->data;
107 *nbRects = WINPR_ASSERTING_INT_CAST(UINT32, data->nbRects);
114 WINPR_ASSERT(region);
116 REGION16_DATA* data = region->data;
129 return ®ion->extents;
137 return ®ion->extents;
147 return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
150BOOL region16_is_empty(
const REGION16* region)
152 WINPR_ASSERT(region);
155 return (region->data->nbRects == 0);
163 return ((r1->left == r2->left) && (r1->top == r2->top) && (r1->right == r2->right) &&
164 (r1->bottom == r2->bottom));
170 return rectangles_intersection(r1, r2, &tmp);
179 dst->left = MAX(r1->left, r2->left);
180 dst->right = MIN(r1->right, r2->right);
181 dst->top = MAX(r1->top, r2->top);
182 dst->bottom = MIN(r1->bottom, r2->bottom);
183 return (dst->left < dst->right) && (dst->top < dst->bottom);
186const char* rectangle_to_string(
const RECTANGLE_16* rect,
char* buffer,
size_t length)
188 if (!buffer || (length < 2))
191 (void)_snprintf(buffer, length - 1,
"{ nullptr }");
193 (
void)_snprintf(buffer, length - 1,
"{%" PRIu16
"x%" PRIu16
"-%" PRIu16
"x%" PRIu16
"}",
194 rect->left, rect->top, rect->right, rect->bottom);
215static void freeRegion(REGION16_DATA* data)
222void region16_clear(
REGION16* region)
224 WINPR_ASSERT(region);
226 freeRegion(region->data);
227 region->data =
nullptr;
230 region->extents = empty;
233WINPR_ATTR_MALLOC(freeRegion, 1)
235static REGION16_DATA* allocateRegion(
size_t nbItems)
237 REGION16_DATA* data = calloc(1,
sizeof(REGION16_DATA));
251 data->nbRects = nbItems;
255static inline RECTANGLE_16* nextRect(REGION16_DATA* data,
size_t index)
258 if (index + 1 > data->nbRects)
268 rects[index] = empty;
269 data->nbRects = index + 1;
272 return &data->rects[index];
275static BOOL resizeRegion(
REGION16* region,
size_t nbItems)
277 WINPR_ASSERT(region);
280 freeRegion(region->data);
281 region->data =
nullptr;
287 region->data = allocateRegion(nbItems);
288 return region->data !=
nullptr;
294 free(region->data->rects);
295 region->data->nbRects = 0;
296 region->data->rects =
nullptr;
300 for (
size_t x = region->data->nbRects; x < nbItems; x++)
305 region->data->rects = rects;
306 region->data->nbRects = nbItems;
315 freeRegion(dst->data);
318 if (src->data && (src->data->nbRects > 0))
320 dst->data = allocateRegion(src->data->nbRects);
321 if (!dst->data || !dst->data->rects)
323 memcpy(dst->data->rects, src->data->rects, dst->data->nbRects *
sizeof(
RECTANGLE_16));
336 dst->extents = src->extents;
338 return region16_copy_data(dst, src);
341void region16_print(
const REGION16* region)
344 int currentBandY = -1;
345 const RECTANGLE_16* rects = region16_rects(region, &nbRects);
347 WLog_DBG(TAG,
"nrects=%" PRIu32
"", nbRects);
349 for (UINT32 i = 0; i < nbRects; i++)
353 if (rect->top != currentBandY)
355 currentBandY = rect->top;
356 WLog_DBG(TAG,
"band %d: ", currentBandY);
359 WLog_DBG(TAG,
"(%" PRIu16
",%" PRIu16
"-%" PRIu16
",%" PRIu16
")", rect->left, rect->top,
360 rect->right, rect->bottom);
364char* region16_to_string(
const REGION16* region)
367 return _strdup(
"REGION16{nullptr}");
370 const RECTANGLE_16* rects = region16_rects(region, &nbRects);
374 winpr_asprintf(&str, &slen,
"REGION16{nrects=%" PRIu32
" [", nbRects);
376 UINT16 currentBandY = 0;
377 for (UINT32 i = 0; i < nbRects; i++)
381 if (rect->top != currentBandY)
383 currentBandY = rect->top;
385 winpr_asprintf(&tmp, &slen,
"%sband %" PRIu16
":", str, currentBandY);
390 char buffer[64] = WINPR_C_ARRAY_INIT;
392 winpr_asprintf(&tmp, &slen,
"%s, %s", str,
393 rectangle_to_string(rect, buffer,
sizeof(buffer)));
399 winpr_asprintf(&tmp, &slen,
"%s]}", str);
404static BOOL region16_copy_band_with_union(REGION16_DATA* region,
const RECTANGLE_16* src,
405 const RECTANGLE_16* end, UINT16 newTop, UINT16 newBottom,
409 WINPR_ASSERT(region);
412 WINPR_ASSERT(dstCounter);
414 UINT16 refY = src->top;
443 while ((src < end) && (src->top == refY) && (src->right < unionRect->left))
449 dst->bottom = newBottom;
450 dst->right = src->right;
451 dst->left = src->left;
459 if ((src < end) && (src->top == refY) && (src->left < unionRect->left))
462 while ((src < end) && (src->top == refY) && (src->right < unionRect->right))
467 if ((src < end) && (src->top == refY) && (src->left < unionRect->right))
477 dst->bottom = newBottom;
479 dst->left = startOverlap->left;
480 dst->right = endOverlap->right;
485 while ((src < end) && (src->top == refY))
492 dst->bottom = newBottom;
493 dst->right = src->right;
494 dst->left = src->left;
507 WINPR_ASSERT(endPtr);
508 WINPR_ASSERT(nbItems);
510 UINT16 refY = band1->top;
513 while ((band1 < endPtr) && (band1->top == refY))
525 int refBand2 = band2->top;
528 while ((band1 < band2Start) && (band2 < endPtr) && (band2->top == refBand2))
530 if ((band1->left != band2->left) || (band1->right != band2->right))
537 if (band1 != band2Start)
540 return (band2 == endPtr) || (band2->top != refBand2);
553 WINPR_ASSERT(endPtr);
556 UINT16 refY = band->top;
558 if ((band->top > rect->top) || (rect->bottom > band->bottom))
564 while ((band < endPtr) && (band->top == refY) && (band->left <= rect->left))
566 if (rect->right <= band->right)
575static BOOL region16_simplify_bands(
REGION16* region)
589 const int nbRects = region16_n_rects(region);
590 int finalNbRects = nbRects;
601 RECTANGLE_16* band2 = next_band(band1, endPtr, &bandItems);
606 if ((band1->bottom == band2->top) && band_match(band1, band2, endPtr))
613 tmp->bottom = band2->bottom;
620 const size_t toMove =
621 WINPR_ASSERTING_INT_CAST(
size_t, (endPtr - endBand)) *
sizeof(
RECTANGLE_16);
624 MoveMemory(band2, endBand, toMove);
626 finalNbRects -= bandItems;
635 if (finalNbRects != nbRects)
637 if (!resizeRegion(region, WINPR_ASSERTING_INT_CAST(
size_t, finalNbRects)))
647 UINT32 srcNbRects = 0;
648 UINT16 topInterBand = 0;
653 RECTANGLE_16* dstExtents = region16_extents_noconst(dst);
655 const int nrSrcRects = region16_n_rects(src);
659 dst->extents = *rect;
661 if (!resizeRegion(dst, 1))
665 WINPR_ASSERT(dstRect);
667 dstRect->top = rect->top;
668 dstRect->left = rect->left;
669 dstRect->right = rect->right;
670 dstRect->bottom = rect->bottom;
671 dst->data->nbRects = 1;
675 REGION16_DATA* newItems = allocateRegion(WINPR_ASSERTING_INT_CAST(
size_t, nrSrcRects + 1));
680 UINT32 usedRects = 0;
683 if (rect->top < srcExtents->top)
685 RECTANGLE_16* dstRect = nextRect(newItems, usedRects++);
689 dstRect->top = rect->top;
690 dstRect->left = rect->left;
691 dstRect->right = rect->right;
692 dstRect->bottom = MIN(srcExtents->top, rect->bottom);
696 const RECTANGLE_16* currentBand = region16_rects(src, &srcNbRects);
697 const RECTANGLE_16* endSrcRect = currentBand + srcNbRects;
699 while (currentBand < endSrcRect)
701 if ((currentBand->bottom <= rect->top) || (rect->bottom <= currentBand->top) ||
702 rectangle_contained_in_band(currentBand, endSrcRect, rect))
718 if (!region16_copy_band_with_union(newItems, currentBand, endSrcRect, currentBand->top,
719 currentBand->bottom,
nullptr, &usedRects, &nextBand))
721 topInterBand = rect->top;
747 UINT16 mergeTop = currentBand->top;
748 UINT16 mergeBottom = currentBand->bottom;
751 if (rect->top > currentBand->top)
753 if (!region16_copy_band_with_union(newItems, currentBand, endSrcRect,
754 currentBand->top, rect->top,
nullptr, &usedRects,
757 mergeTop = rect->top;
761 if (rect->bottom < currentBand->bottom)
762 mergeBottom = rect->bottom;
764 if (!region16_copy_band_with_union(newItems, currentBand, endSrcRect, mergeTop,
765 mergeBottom, rect, &usedRects, &nextBand))
769 if (rect->bottom < currentBand->bottom)
771 if (!region16_copy_band_with_union(newItems, currentBand, endSrcRect, mergeBottom,
772 currentBand->bottom,
nullptr, &usedRects,
777 topInterBand = currentBand->bottom;
795 if ((nextBand < endSrcRect) && (nextBand->top != currentBand->bottom) &&
796 (rect->bottom > currentBand->bottom) && (rect->top < nextBand->top))
798 RECTANGLE_16* dstRect = nextRect(newItems, usedRects++);
802 dstRect->right = rect->right;
803 dstRect->left = rect->left;
804 dstRect->top = topInterBand;
805 dstRect->bottom = MIN(nextBand->top, rect->bottom);
808 currentBand = nextBand;
812 if (srcExtents->bottom < rect->bottom)
814 RECTANGLE_16* dstRect = nextRect(newItems, usedRects++);
818 dstRect->top = MAX(srcExtents->bottom, rect->top);
819 dstRect->left = rect->left;
820 dstRect->right = rect->right;
821 dstRect->bottom = rect->bottom;
824 dstExtents->top = MIN(rect->top, srcExtents->top);
825 dstExtents->left = MIN(rect->left, srcExtents->left);
826 dstExtents->bottom = MAX(rect->bottom, srcExtents->bottom);
827 dstExtents->right = MAX(rect->right, srcExtents->right);
829 newItems->nbRects = usedRects;
830 freeRegion(dst->data);
831 dst->data = newItems;
833 return region16_simplify_bands(dst);
841 if (!src || !src->data || !arg2)
844 const RECTANGLE_16* rect = region16_rects(src, &nbRects);
852 return rectangles_intersects(srcExtents, arg2);
854 if (!rectangles_intersects(srcExtents, arg2))
857 for (endPtr = rect + nbRects; (rect < endPtr) && (arg2->bottom > rect->top); rect++)
859 if (rectangles_intersects(rect, arg2))
875 const RECTANGLE_16* srcPtr = region16_rects(src, &nbRects);
887 BOOL intersects = rectangles_intersection(srcExtents, rect, &common);
891 return region16_union_rect(dst, dst, &common);
896 REGION16_DATA* newItems = allocateRegion(nbRects);
902 UINT32 usedRects = 0;
908 for (endPtr = srcPtr + nbRects; (srcPtr < endPtr) && (rect->bottom > srcPtr->top); srcPtr++)
910 if (usedRects > nbRects)
912 freeRegion(newItems);
916 if (rectangles_intersection(srcPtr, rect, &common))
922 if (rectangle_is_empty(&newExtents))
932 newExtents.top = MIN(common.top, newExtents.top);
933 newExtents.left = MIN(common.left, newExtents.left);
934 newExtents.bottom = MAX(common.bottom, newExtents.bottom);
935 newExtents.right = MAX(common.right, newExtents.right);
940 newItems->nbRects = usedRects;
942 freeRegion(dst->data);
943 dst->data = newItems;
944 dst->extents = newExtents;
945 return region16_simplify_bands(dst);
948void region16_uninit(
REGION16* region)
950 WINPR_ASSERT(region);
952 freeRegion(region->data);
953 region->data =
nullptr;