FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
gdi/region.c
1
22#include <freerdp/config.h>
23
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27
28#include <winpr/wtypes.h>
29
30#include <freerdp/api.h>
31#include <freerdp/freerdp.h>
32#include <freerdp/gdi/gdi.h>
33
34#include <freerdp/gdi/region.h>
35
36#include <freerdp/log.h>
37
38#define TAG FREERDP_TAG("gdi.region")
39
40static char* gdi_rect_str(char* buffer, size_t size, const GDI_RECT* rect)
41{
42 if (!buffer || (size < 1) || !rect)
43 return NULL;
44
45 (void)_snprintf(buffer, size - 1,
46 "[top/left=%" PRId32 "x%" PRId32 "-bottom/right%" PRId32 "x%" PRId32 "]",
47 rect->top, rect->left, rect->bottom, rect->right);
48 buffer[size - 1] = '\0';
49
50 return buffer;
51}
52
53static char* gdi_regn_str(char* buffer, size_t size, const GDI_RGN* rgn)
54{
55 if (!buffer || (size < 1) || !rgn)
56 return NULL;
57
58 (void)_snprintf(buffer, size - 1, "[%" PRId32 "x%" PRId32 "-%" PRId32 "x%" PRId32 "]", rgn->x,
59 rgn->y, rgn->w, rgn->h);
60 buffer[size - 1] = '\0';
61
62 return buffer;
63}
64
77GDI_RGN* gdi_CreateRectRgn(INT32 nLeftRect, INT32 nTopRect, INT32 nRightRect, INT32 nBottomRect)
78{
79 INT64 w = 0;
80 INT64 h = 0;
81 GDI_RGN* hRgn = NULL;
82
83 w = nRightRect - nLeftRect + 1ll;
84 h = nBottomRect - nTopRect + 1ll;
85 if ((w < 0) || (h < 0) || (w > INT32_MAX) || (h > INT32_MAX))
86 {
87 WLog_ERR(TAG,
88 "Can not create region top/left=%" PRId32 "x%" PRId32 "-bottom/right=%" PRId32
89 "x%" PRId32,
90 nTopRect, nLeftRect, nBottomRect, nRightRect);
91 return NULL;
92 }
93 hRgn = (GDI_RGN*)calloc(1, sizeof(GDI_RGN));
94
95 if (!hRgn)
96 return NULL;
97
98 hRgn->objectType = GDIOBJECT_REGION;
99 hRgn->x = nLeftRect;
100 hRgn->y = nTopRect;
101 hRgn->w = (INT32)w;
102 hRgn->h = (INT32)h;
103 hRgn->null = FALSE;
104 return hRgn;
105}
106
116GDI_RECT* gdi_CreateRect(INT32 xLeft, INT32 yTop, INT32 xRight, INT32 yBottom)
117{
118 GDI_RECT* hRect = NULL;
119
120 if (xLeft > xRight)
121 return NULL;
122 if (yTop > yBottom)
123 return NULL;
124
125 hRect = (GDI_RECT*)calloc(1, sizeof(GDI_RECT));
126
127 if (!hRect)
128 return NULL;
129
130 hRect->objectType = GDIOBJECT_RECT;
131 hRect->left = xLeft;
132 hRect->top = yTop;
133 hRect->right = xRight;
134 hRect->bottom = yBottom;
135 return hRect;
136}
137
144BOOL gdi_RectToRgn(const GDI_RECT* rect, GDI_RGN* rgn)
145{
146 BOOL rc = TRUE;
147 INT64 w = 0;
148 INT64 h = 0;
149 w = rect->right - rect->left + 1ll;
150 h = rect->bottom - rect->top + 1ll;
151
152 if ((w < 0) || (h < 0) || (w > INT32_MAX) || (h > INT32_MAX))
153 {
154 WLog_ERR(TAG,
155 "Can not create region top/left=%" PRId32 "x%" PRId32 "-bottom/right=%" PRId32
156 "x%" PRId32,
157 rect->top, rect->left, rect->bottom, rect->right);
158 w = 0;
159 h = 0;
160 rc = FALSE;
161 }
162
163 rgn->x = rect->left;
164 rgn->y = rect->top;
165 rgn->w = (INT32)w;
166 rgn->h = (INT32)h;
167
168 return rc;
169}
170
180BOOL gdi_CRectToRgn(INT32 left, INT32 top, INT32 right, INT32 bottom, GDI_RGN* rgn)
181{
182 BOOL rc = TRUE;
183 INT64 w = 0;
184 INT64 h = 0;
185 w = right - left + 1ll;
186 h = bottom - top + 1ll;
187
188 if (!rgn)
189 return FALSE;
190
191 if ((w < 0) || (h < 0) || (w > INT32_MAX) || (h > INT32_MAX))
192 {
193 WLog_ERR(TAG,
194 "Can not create region top/left=%" PRId32 "x%" PRId32 "-bottom/right=%" PRId32
195 "x%" PRId32,
196 top, left, bottom, right);
197 w = 0;
198 h = 0;
199 rc = FALSE;
200 }
201
202 rgn->x = left;
203 rgn->y = top;
204 rgn->w = (INT32)w;
205 rgn->h = (INT32)h;
206 return rc;
207}
208
218BOOL gdi_RectToCRgn(const GDI_RECT* rect, INT32* x, INT32* y, INT32* w, INT32* h)
219{
220 BOOL rc = TRUE;
221 *x = rect->left;
222 *y = rect->top;
223 INT64 tmp = rect->right - rect->left + 1;
224 if ((tmp < 0) || (tmp > INT32_MAX))
225 {
226 char buffer[256];
227 WLog_ERR(TAG, "rectangle invalid %s", gdi_rect_str(buffer, sizeof(buffer), rect));
228 *w = 0;
229 rc = FALSE;
230 }
231 else
232 *w = (INT32)tmp;
233 tmp = rect->bottom - rect->top + 1;
234 if ((tmp < 0) || (tmp > INT32_MAX))
235 {
236 char buffer[256];
237 WLog_ERR(TAG, "rectangle invalid %s", gdi_rect_str(buffer, sizeof(buffer), rect));
238 *h = 0;
239 rc = FALSE;
240 }
241 else
242 *h = (INT32)tmp;
243 return rc;
244}
245
258BOOL gdi_CRectToCRgn(INT32 left, INT32 top, INT32 right, INT32 bottom, INT32* x, INT32* y, INT32* w,
259 INT32* h)
260{
261 INT64 wl = 0;
262 INT64 hl = 0;
263 BOOL rc = TRUE;
264 wl = right - left + 1ll;
265 hl = bottom - top + 1ll;
266
267 if ((left > right) || (top > bottom) || (wl <= 0) || (hl <= 0) || (wl > INT32_MAX) ||
268 (hl > INT32_MAX))
269 {
270 WLog_ERR(TAG,
271 "Can not create region top/left=%" PRId32 "x%" PRId32 "-bottom/right=%" PRId32
272 "x%" PRId32,
273 top, left, bottom, right);
274 wl = 0;
275 hl = 0;
276 rc = FALSE;
277 }
278
279 *x = left;
280 *y = top;
281 *w = (INT32)wl;
282 *h = (INT32)hl;
283 return rc;
284}
285
292BOOL gdi_RgnToRect(const GDI_RGN* rgn, GDI_RECT* rect)
293{
294 INT64 r = 0;
295 INT64 b = 0;
296 BOOL rc = TRUE;
297 r = rgn->x + rgn->w - 1ll;
298 b = rgn->y + rgn->h - 1ll;
299
300 if ((r < INT32_MIN) || (r > INT32_MAX) || (b < INT32_MIN) || (b > INT32_MAX))
301 {
302 char buffer[256];
303 WLog_ERR(TAG, "Can not create region %s", gdi_regn_str(buffer, sizeof(buffer), rgn));
304 r = rgn->x;
305 b = rgn->y;
306 rc = FALSE;
307 }
308 rect->left = rgn->x;
309 rect->top = rgn->y;
310 rect->right = (INT32)r;
311 rect->bottom = (INT32)b;
312
313 return rc;
314}
315
325BOOL gdi_CRgnToRect(INT64 x, INT64 y, INT32 w, INT32 h, GDI_RECT* rect)
326{
327 BOOL invalid = FALSE;
328 const INT64 r = x + w - 1;
329 const INT64 b = y + h - 1;
330 WINPR_ASSERT(x <= INT32_MAX);
331 WINPR_ASSERT(y <= INT32_MAX);
332 WINPR_ASSERT(r <= INT32_MAX);
333 WINPR_ASSERT(b <= INT32_MAX);
334 rect->left = (x > 0) ? (INT32)x : 0;
335 rect->top = (y > 0) ? (INT32)y : 0;
336 rect->right = rect->left;
337 rect->bottom = rect->top;
338
339 if ((w <= 0) || (h <= 0))
340 invalid = TRUE;
341
342 if (r > 0)
343 rect->right = (INT32)r;
344 else
345 invalid = TRUE;
346
347 if (b > 0)
348 rect->bottom = (INT32)b;
349 else
350 invalid = TRUE;
351
352 if (invalid)
353 {
354 WLog_DBG(TAG, "Invisible rectangle %" PRId64 "x%" PRId64 "-%" PRId64 "x%" PRId64, x, y, r,
355 b);
356 return FALSE;
357 }
358
359 return TRUE;
360}
361
371BOOL gdi_RgnToCRect(const GDI_RGN* rgn, INT32* left, INT32* top, INT32* right, INT32* bottom)
372{
373 BOOL rc = TRUE;
374
375 WINPR_ASSERT(rgn);
376 if ((rgn->w < 0) || (rgn->h < 0))
377 {
378 char buffer[256];
379 WLog_ERR(TAG, "Can not create region %s", gdi_regn_str(buffer, sizeof(buffer), rgn));
380 rc = FALSE;
381 }
382
383 *left = rgn->x;
384 *top = rgn->y;
385 *right = rgn->x + rgn->w - 1;
386 *bottom = rgn->y + rgn->h - 1;
387
388 return rc;
389}
390
403BOOL gdi_CRgnToCRect(INT32 x, INT32 y, INT32 w, INT32 h, INT32* left, INT32* top, INT32* right,
404 INT32* bottom)
405{
406 BOOL rc = TRUE;
407 *left = x;
408 *top = y;
409 *right = 0;
410
411 if (w > 0)
412 *right = x + w - 1;
413 else
414 {
415 WLog_ERR(TAG, "Invalid width");
416 rc = FALSE;
417 }
418
419 *bottom = 0;
420
421 if (h > 0)
422 *bottom = y + h - 1;
423 else
424 {
425 WLog_ERR(TAG, "Invalid height");
426 rc = FALSE;
427 }
428
429 return rc;
430}
431
443INLINE BOOL gdi_CopyOverlap(INT32 x, INT32 y, INT32 width, INT32 height, INT32 srcx, INT32 srcy)
444{
445 GDI_RECT dst;
446 GDI_RECT src;
447 gdi_CRgnToRect(x, y, width, height, &dst);
448 gdi_CRgnToRect(srcx, srcy, width, height, &src);
449
450 if (dst.right < src.left)
451 return FALSE;
452 if (dst.left > src.right)
453 return FALSE;
454 if (dst.bottom < src.top)
455 return FALSE;
456 if (dst.top > src.bottom)
457 return FALSE;
458 return TRUE;
459}
460
474INLINE BOOL gdi_SetRect(GDI_RECT* rc, INT32 xLeft, INT32 yTop, INT32 xRight, INT32 yBottom)
475{
476 if (!rc)
477 return FALSE;
478 if (xLeft > xRight)
479 return FALSE;
480 if (yTop > yBottom)
481 return FALSE;
482
483 rc->left = xLeft;
484 rc->top = yTop;
485 rc->right = xRight;
486 rc->bottom = yBottom;
487 return TRUE;
488}
489
500INLINE BOOL gdi_SetRgn(GDI_RGN* hRgn, INT32 nXLeft, INT32 nYLeft, INT32 nWidth, INT32 nHeight)
501{
502 if (!hRgn)
503 return FALSE;
504
505 if ((nWidth < 0) || (nHeight < 0))
506 return FALSE;
507
508 hRgn->x = nXLeft;
509 hRgn->y = nYLeft;
510 hRgn->w = nWidth;
511 hRgn->h = nHeight;
512 hRgn->null = FALSE;
513 return TRUE;
514}
515
526INLINE BOOL gdi_SetRectRgn(GDI_RGN* hRgn, INT32 nLeftRect, INT32 nTopRect, INT32 nRightRect,
527 INT32 nBottomRect)
528{
529 if (!gdi_CRectToRgn(nLeftRect, nTopRect, nRightRect, nBottomRect, hRgn))
530 return FALSE;
531 hRgn->null = FALSE;
532 return TRUE;
533}
534
544INLINE BOOL gdi_EqualRgn(const GDI_RGN* hSrcRgn1, const GDI_RGN* hSrcRgn2)
545{
546 WINPR_ASSERT(hSrcRgn1);
547 WINPR_ASSERT(hSrcRgn2);
548 if ((hSrcRgn1->x == hSrcRgn2->x) && (hSrcRgn1->y == hSrcRgn2->y) &&
549 (hSrcRgn1->w == hSrcRgn2->w) && (hSrcRgn1->h == hSrcRgn2->h))
550 {
551 return TRUE;
552 }
553
554 return FALSE;
555}
556
566INLINE BOOL gdi_CopyRect(GDI_RECT* dst, const GDI_RECT* src)
567{
568 if (!dst || !src)
569 return FALSE;
570
571 dst->left = src->left;
572 dst->top = src->top;
573 dst->right = src->right;
574 dst->bottom = src->bottom;
575 return TRUE;
576}
577
587INLINE BOOL gdi_PtInRect(const GDI_RECT* rc, INT32 x, INT32 y)
588{
589 /*
590 * points on the left and top sides are considered in,
591 * while points on the right and bottom sides are considered out
592 */
593 if ((x >= rc->left) && (x <= rc->right))
594 {
595 if ((y >= rc->top) && (y <= rc->bottom))
596 {
597 return TRUE;
598 }
599 }
600
601 return FALSE;
602}
603
615INLINE BOOL gdi_InvalidateRegion(HGDI_DC hdc, INT32 x, INT32 y, INT32 w, INT32 h)
616{
617 GDI_RECT inv;
618 GDI_RECT rgn;
619 GDI_RGN* invalid = NULL;
620 GDI_RGN* cinvalid = NULL;
621
622 if (!hdc->hwnd)
623 return TRUE;
624
625 if (!hdc->hwnd->invalid)
626 return TRUE;
627
628 if (w == 0 || h == 0)
629 return TRUE;
630
631 cinvalid = hdc->hwnd->cinvalid;
632
633 if ((hdc->hwnd->ninvalid + 1) > (INT64)hdc->hwnd->count)
634 {
635 GDI_RGN* new_rgn = NULL;
636 size_t new_cnt = 2ULL * hdc->hwnd->count;
637 if (new_cnt > UINT32_MAX)
638 return FALSE;
639
640 new_rgn = (GDI_RGN*)realloc(cinvalid, sizeof(GDI_RGN) * new_cnt);
641
642 if (!new_rgn)
643 return FALSE;
644
645 hdc->hwnd->count = (UINT32)new_cnt;
646 cinvalid = new_rgn;
647 }
648
649 gdi_SetRgn(&cinvalid[hdc->hwnd->ninvalid++], x, y, w, h);
650 hdc->hwnd->cinvalid = cinvalid;
651 invalid = hdc->hwnd->invalid;
652
653 if (invalid->null)
654 {
655 invalid->x = x;
656 invalid->y = y;
657 invalid->w = w;
658 invalid->h = h;
659 invalid->null = FALSE;
660 return TRUE;
661 }
662
663 gdi_CRgnToRect(x, y, w, h, &rgn);
664 gdi_RgnToRect(invalid, &inv);
665
666 if (rgn.left < inv.left)
667 inv.left = rgn.left;
668
669 if (rgn.top < inv.top)
670 inv.top = rgn.top;
671
672 if (rgn.right > inv.right)
673 inv.right = rgn.right;
674
675 if (rgn.bottom > inv.bottom)
676 inv.bottom = rgn.bottom;
677
678 gdi_RectToRgn(&inv, invalid);
679 return TRUE;
680}