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)
197 long allocSize =
sizeof(REGION16_DATA) + (nbItems *
sizeof(
RECTANGLE_16));
198 REGION16_DATA* ret = (REGION16_DATA*)malloc(allocSize);
203 ret->size = allocSize;
204 ret->nbRects = nbItems;
211 WINPR_ASSERT(dst->data);
213 WINPR_ASSERT(src->data);
218 dst->extents = src->extents;
220 if ((dst->data->size > 0) && (dst->data != &empty_region))
223 if (src->data->size == 0)
224 dst->data = &empty_region;
227 dst->data = allocateRegion(src->data->nbRects);
232 CopyMemory(dst->data, src->data, src->data->size);
238 void region16_print(
const REGION16* region)
242 int currentBandY = -1;
243 rects = region16_rects(region, &nbRects);
244 WLog_DBG(TAG,
"nrects=%" PRIu32
"", nbRects);
246 for (UINT32 i = 0; i < nbRects; i++, rects++)
248 if (rects->top != currentBandY)
250 currentBandY = rects->top;
251 WLog_DBG(TAG,
"band %d: ", currentBandY);
254 WLog_DBG(TAG,
"(%" PRIu16
",%" PRIu16
"-%" PRIu16
",%" PRIu16
")", rects->left, rects->top,
255 rects->right, rects->bottom);
260 const RECTANGLE_16* end, UINT16 newTop, UINT16 newBottom,
264 UINT16 refY = src->top;
295 while ((src < end) && (src->top == refY) && (src->right < unionRect->left))
298 dst->bottom = newBottom;
299 dst->right = src->right;
300 dst->left = src->left;
307 startOverlap = unionRect;
308 endOverlap = unionRect;
310 if ((src < end) && (src->top == refY) && (src->left < unionRect->left))
313 while ((src < end) && (src->top == refY) && (src->right < unionRect->right))
318 if ((src < end) && (src->top == refY) && (src->left < unionRect->right))
324 dst->bottom = newBottom;
326 dst->left = startOverlap->left;
327 dst->right = endOverlap->right;
333 while ((src < end) && (src->top == refY))
336 dst->bottom = newBottom;
337 dst->right = src->right;
338 dst->left = src->left;
352 UINT16 refY = band1->top;
355 while ((band1 < endPtr) && (band1->top == refY))
367 int refBand2 = band2->top;
370 while ((band1 < band2Start) && (band2 < endPtr) && (band2->top == refBand2))
372 if ((band1->left != band2->left) || (band1->right != band2->right))
379 if (band1 != band2Start)
382 return (band2 == endPtr) || (band2->top != refBand2);
394 UINT16 refY = band->top;
396 if ((band->top > rect->top) || (rect->bottom > band->bottom))
402 while ((band < endPtr) && (band->top == refY) && (band->left <= rect->left))
404 if (rect->right <= band->right)
413 static BOOL region16_simplify_bands(
REGION16* region)
428 int finalNbRects = 0;
430 finalNbRects = nbRects = region16_n_rects(region);
440 RECTANGLE_16* band2 = next_band(band1, endPtr, &bandItems);
445 if ((band1->bottom == band2->top) && band_match(band1, band2, endPtr))
452 tmp->bottom = band2->bottom;
458 endBand = band2 + bandItems;
459 const size_t toMove = (endPtr - endBand) *
sizeof(
RECTANGLE_16);
462 MoveMemory(band2, endBand, toMove);
464 finalNbRects -= bandItems;
473 if (finalNbRects != nbRects)
475 size_t allocSize =
sizeof(REGION16_DATA) + (finalNbRects *
sizeof(
RECTANGLE_16));
476 REGION16_DATA* data = realloc(region->data, allocSize);
483 region->data = &empty_region;
487 region->data->nbRects = finalNbRects;
488 region->data->size = allocSize;
501 REGION16_DATA* newItems = NULL;
502 REGION16_DATA* tmpItems = NULL;
504 UINT32 usedRects = 0;
505 UINT32 srcNbRects = 0;
506 UINT16 topInterBand = 0;
509 srcExtents = region16_extents(src);
510 dstExtents = region16_extents_noconst(dst);
512 if (!region16_n_rects(src))
515 dst->extents = *rect;
516 dst->data = allocateRegion(1);
521 dstRect = region16_rects_noconst(dst);
522 dstRect->top = rect->top;
523 dstRect->left = rect->left;
524 dstRect->right = rect->right;
525 dstRect->bottom = rect->bottom;
529 newItems = allocateRegion((1ULL + 4ULL * region16_n_rects(src)));
538 if (rect->top < srcExtents->top)
540 dstRect->top = rect->top;
541 dstRect->left = rect->left;
542 dstRect->right = rect->right;
543 dstRect->bottom = MIN(srcExtents->top, rect->bottom);
549 currentBand = region16_rects(src, &srcNbRects);
550 endSrcRect = currentBand + srcNbRects;
552 while (currentBand < endSrcRect)
554 if ((currentBand->bottom <= rect->top) || (rect->bottom <= currentBand->top) ||
555 rectangle_contained_in_band(currentBand, endSrcRect, rect))
571 region16_copy_band_with_union(dstRect, currentBand, endSrcRect, currentBand->top,
572 currentBand->bottom, NULL, &usedRects, &nextBand,
574 topInterBand = rect->top;
600 UINT16 mergeTop = currentBand->top;
601 UINT16 mergeBottom = currentBand->bottom;
604 if (rect->top > currentBand->top)
606 region16_copy_band_with_union(dstRect, currentBand, endSrcRect, currentBand->top,
607 rect->top, NULL, &usedRects, &nextBand, &dstRect);
608 mergeTop = rect->top;
612 if (rect->bottom < currentBand->bottom)
613 mergeBottom = rect->bottom;
615 region16_copy_band_with_union(dstRect, currentBand, endSrcRect, mergeTop, mergeBottom,
616 rect, &usedRects, &nextBand, &dstRect);
619 if (rect->bottom < currentBand->bottom)
621 region16_copy_band_with_union(dstRect, currentBand, endSrcRect, mergeBottom,
622 currentBand->bottom, NULL, &usedRects, &nextBand,
626 topInterBand = currentBand->bottom;
644 if ((nextBand < endSrcRect) && (nextBand->top != currentBand->bottom) &&
645 (rect->bottom > currentBand->bottom) && (rect->top < nextBand->top))
647 dstRect->right = rect->right;
648 dstRect->left = rect->left;
649 dstRect->top = topInterBand;
650 dstRect->bottom = MIN(nextBand->top, rect->bottom);
655 currentBand = nextBand;
659 if (srcExtents->bottom < rect->bottom)
661 dstRect->top = MAX(srcExtents->bottom, rect->top);
662 dstRect->left = rect->left;
663 dstRect->right = rect->right;
664 dstRect->bottom = rect->bottom;
669 if ((src == dst) && (dst->data != &empty_region))
672 dstExtents->top = MIN(rect->top, srcExtents->top);
673 dstExtents->left = MIN(rect->left, srcExtents->left);
674 dstExtents->bottom = MAX(rect->bottom, srcExtents->bottom);
675 dstExtents->right = MAX(rect->right, srcExtents->right);
676 newItems->size =
sizeof(REGION16_DATA) + (usedRects *
sizeof(
RECTANGLE_16));
677 tmpItems = realloc(newItems, newItems->size);
681 dst->data = newItems;
686 dst->data->nbRects = usedRects;
687 return region16_simplify_bands(dst);
697 if (!src || !src->data || !arg2)
700 rect = region16_rects(src, &nbRects);
705 srcExtents = region16_extents(src);
708 return rectangles_intersects(srcExtents, arg2);
710 if (!rectangles_intersects(srcExtents, arg2))
713 for (endPtr = rect + nbRects; (rect < endPtr) && (arg2->bottom > rect->top); rect++)
715 if (rectangles_intersects(rect, arg2))
724 REGION16_DATA* newItems = NULL;
730 UINT32 usedRects = 0;
734 WINPR_ASSERT(src->data);
735 srcPtr = region16_rects(src, &nbRects);
743 srcExtents = region16_extents(src);
747 BOOL intersects = rectangles_intersection(srcExtents, rect, &common);
751 return region16_union_rect(dst, dst, &common);
756 newItems = allocateRegion(nbRects);
763 ZeroMemory(&newExtents,
sizeof(newExtents));
768 for (endPtr = srcPtr + nbRects; (srcPtr < endPtr) && (rect->bottom > srcPtr->top); srcPtr++)
770 if (rectangles_intersection(srcPtr, rect, &common))
776 if (rectangle_is_empty(&newExtents))
786 newExtents.top = MIN(common.top, newExtents.top);
787 newExtents.left = MIN(common.left, newExtents.left);
788 newExtents.bottom = MAX(common.bottom, newExtents.bottom);
789 newExtents.right = MAX(common.right, newExtents.right);
794 newItems->nbRects = usedRects;
795 newItems->size =
sizeof(REGION16_DATA) + (usedRects *
sizeof(
RECTANGLE_16));
797 if ((dst->data->size > 0) && (dst->data != &empty_region))
800 dst->data = realloc(newItems, newItems->size);
808 dst->extents = newExtents;
809 return region16_simplify_bands(dst);
812 void region16_uninit(
REGION16* region)
814 WINPR_ASSERT(region);
818 if ((region->data->size > 0) && (region->data != &empty_region))