FreeRDP
Loading...
Searching...
No Matches
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 nullptr;
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 nullptr;
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 = nullptr;
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 nullptr;
92 }
93 hRgn = (GDI_RGN*)calloc(1, sizeof(GDI_RGN));
94
95 if (!hRgn)
96 return nullptr;
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 = nullptr;
119
120 if (xLeft > xRight)
121 return nullptr;
122 if (yTop > yBottom)
123 return nullptr;
124
125 hRect = (GDI_RECT*)calloc(1, sizeof(GDI_RECT));
126
127 if (!hRect)
128 return nullptr;
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 WINPR_ASSERT(rect);
147 WINPR_ASSERT(rgn);
148
149 BOOL rc = TRUE;
150 INT64 w = rect->right - rect->left + 1ll;
151 INT64 h = rect->bottom - rect->top + 1ll;
152
153 if ((w < 0) || (h < 0) || (w > INT32_MAX) || (h > INT32_MAX))
154 {
155 WLog_ERR(TAG,
156 "Can not create region top/left=%" PRId32 "x%" PRId32 "-bottom/right=%" PRId32
157 "x%" PRId32,
158 rect->top, rect->left, rect->bottom, rect->right);
159 w = 0;
160 h = 0;
161 rc = FALSE;
162 }
163
164 rgn->x = rect->left;
165 rgn->y = rect->top;
166 rgn->w = (INT32)w;
167 rgn->h = (INT32)h;
168
169 return rc;
170}
171
181BOOL gdi_CRectToRgn(INT32 left, INT32 top, INT32 right, INT32 bottom, GDI_RGN* rgn)
182{
183 BOOL rc = TRUE;
184 INT64 w = 0;
185 INT64 h = 0;
186 w = right - left + 1ll;
187 h = bottom - top + 1ll;
188
189 if (!rgn)
190 return FALSE;
191
192 if ((w < 0) || (h < 0) || (w > INT32_MAX) || (h > INT32_MAX))
193 {
194 WLog_ERR(TAG,
195 "Can not create region top/left=%" PRId32 "x%" PRId32 "-bottom/right=%" PRId32
196 "x%" PRId32,
197 top, left, bottom, right);
198 w = 0;
199 h = 0;
200 rc = FALSE;
201 }
202
203 rgn->x = left;
204 rgn->y = top;
205 rgn->w = (INT32)w;
206 rgn->h = (INT32)h;
207 return rc;
208}
209
219BOOL gdi_RectToCRgn(const GDI_RECT* rect, INT32* x, INT32* y, INT32* w, INT32* h)
220{
221 BOOL rc = TRUE;
222 *x = rect->left;
223 *y = rect->top;
224 INT64 tmp = rect->right - rect->left + 1;
225 if ((tmp < 0) || (tmp > INT32_MAX))
226 {
227 char buffer[256];
228 WLog_ERR(TAG, "rectangle invalid %s", gdi_rect_str(buffer, sizeof(buffer), rect));
229 *w = 0;
230 rc = FALSE;
231 }
232 else
233 *w = (INT32)tmp;
234 tmp = rect->bottom - rect->top + 1;
235 if ((tmp < 0) || (tmp > INT32_MAX))
236 {
237 char buffer[256];
238 WLog_ERR(TAG, "rectangle invalid %s", gdi_rect_str(buffer, sizeof(buffer), rect));
239 *h = 0;
240 rc = FALSE;
241 }
242 else
243 *h = (INT32)tmp;
244 return rc;
245}
246
259BOOL gdi_CRectToCRgn(INT32 left, INT32 top, INT32 right, INT32 bottom, INT32* x, INT32* y, INT32* w,
260 INT32* h)
261{
262 INT64 wl = 0;
263 INT64 hl = 0;
264 BOOL rc = TRUE;
265 wl = right - left + 1ll;
266 hl = bottom - top + 1ll;
267
268 if ((left > right) || (top > bottom) || (wl <= 0) || (hl <= 0) || (wl > INT32_MAX) ||
269 (hl > INT32_MAX))
270 {
271 WLog_ERR(TAG,
272 "Can not create region top/left=%" PRId32 "x%" PRId32 "-bottom/right=%" PRId32
273 "x%" PRId32,
274 top, left, bottom, right);
275 wl = 0;
276 hl = 0;
277 rc = FALSE;
278 }
279
280 *x = left;
281 *y = top;
282 *w = (INT32)wl;
283 *h = (INT32)hl;
284 return rc;
285}
286
293BOOL gdi_RgnToRect(const GDI_RGN* rgn, GDI_RECT* rect)
294{
295 INT64 r = 0;
296 INT64 b = 0;
297 BOOL rc = TRUE;
298 r = rgn->x + rgn->w - 1ll;
299 b = rgn->y + rgn->h - 1ll;
300
301 if ((r < INT32_MIN) || (r > INT32_MAX) || (b < INT32_MIN) || (b > INT32_MAX))
302 {
303 char buffer[256];
304 WLog_ERR(TAG, "Can not create region %s", gdi_regn_str(buffer, sizeof(buffer), rgn));
305 r = rgn->x;
306 b = rgn->y;
307 rc = FALSE;
308 }
309 rect->left = rgn->x;
310 rect->top = rgn->y;
311 rect->right = (INT32)r;
312 rect->bottom = (INT32)b;
313
314 return rc;
315}
316
326BOOL gdi_CRgnToRect(INT64 x, INT64 y, INT32 w, INT32 h, GDI_RECT* rect)
327{
328 BOOL invalid = FALSE;
329 const INT64 r = x + w - 1;
330 const INT64 b = y + h - 1;
331 WINPR_ASSERT(x <= INT32_MAX);
332 WINPR_ASSERT(y <= INT32_MAX);
333 WINPR_ASSERT(r <= INT32_MAX);
334 WINPR_ASSERT(b <= INT32_MAX);
335 rect->left = (x > 0) ? (INT32)x : 0;
336 rect->top = (y > 0) ? (INT32)y : 0;
337 rect->right = rect->left;
338 rect->bottom = rect->top;
339
340 if ((w <= 0) || (h <= 0))
341 invalid = TRUE;
342
343 if (r > 0)
344 rect->right = (INT32)r;
345 else
346 invalid = TRUE;
347
348 if (b > 0)
349 rect->bottom = (INT32)b;
350 else
351 invalid = TRUE;
352
353 if (invalid)
354 {
355 WLog_DBG(TAG, "Invisible rectangle %" PRId64 "x%" PRId64 "-%" PRId64 "x%" PRId64, x, y, r,
356 b);
357 return FALSE;
358 }
359
360 return TRUE;
361}
362
372BOOL gdi_RgnToCRect(const GDI_RGN* rgn, INT32* left, INT32* top, INT32* right, INT32* bottom)
373{
374 BOOL rc = TRUE;
375
376 WINPR_ASSERT(rgn);
377 if ((rgn->w < 0) || (rgn->h < 0))
378 {
379 char buffer[256];
380 WLog_ERR(TAG, "Can not create region %s", gdi_regn_str(buffer, sizeof(buffer), rgn));
381 rc = FALSE;
382 }
383
384 *left = rgn->x;
385 *top = rgn->y;
386 *right = rgn->x + rgn->w - 1;
387 *bottom = rgn->y + rgn->h - 1;
388
389 return rc;
390}
391
404BOOL gdi_CRgnToCRect(INT32 x, INT32 y, INT32 w, INT32 h, INT32* left, INT32* top, INT32* right,
405 INT32* bottom)
406{
407 BOOL rc = TRUE;
408 *left = x;
409 *top = y;
410 *right = 0;
411
412 if (w > 0)
413 *right = x + w - 1;
414 else
415 {
416 WLog_ERR(TAG, "Invalid width");
417 rc = FALSE;
418 }
419
420 *bottom = 0;
421
422 if (h > 0)
423 *bottom = y + h - 1;
424 else
425 {
426 WLog_ERR(TAG, "Invalid height");
427 rc = FALSE;
428 }
429
430 return rc;
431}
432
444inline BOOL gdi_CopyOverlap(INT32 x, INT32 y, INT32 width, INT32 height, INT32 srcx, INT32 srcy)
445{
446 GDI_RECT dst;
447 GDI_RECT src;
448 if (!gdi_CRgnToRect(x, y, width, height, &dst))
449 return FALSE;
450 if (!gdi_CRgnToRect(srcx, srcy, width, height, &src))
451 return FALSE;
452
453 if (dst.right < src.left)
454 return FALSE;
455 if (dst.left > src.right)
456 return FALSE;
457 if (dst.bottom < src.top)
458 return FALSE;
459 if (dst.top > src.bottom)
460 return FALSE;
461 return TRUE;
462}
463
477inline BOOL gdi_SetRect(GDI_RECT* rc, INT32 xLeft, INT32 yTop, INT32 xRight, INT32 yBottom)
478{
479 if (!rc)
480 return FALSE;
481 if (xLeft > xRight)
482 return FALSE;
483 if (yTop > yBottom)
484 return FALSE;
485
486 rc->left = xLeft;
487 rc->top = yTop;
488 rc->right = xRight;
489 rc->bottom = yBottom;
490 return TRUE;
491}
492
503inline BOOL gdi_SetRgn(GDI_RGN* hRgn, INT32 nXLeft, INT32 nYLeft, INT32 nWidth, INT32 nHeight)
504{
505 if (!hRgn)
506 return FALSE;
507
508 if ((nWidth < 0) || (nHeight < 0))
509 return FALSE;
510
511 hRgn->x = nXLeft;
512 hRgn->y = nYLeft;
513 hRgn->w = nWidth;
514 hRgn->h = nHeight;
515 hRgn->null = FALSE;
516 return TRUE;
517}
518
529inline BOOL gdi_SetRectRgn(GDI_RGN* hRgn, INT32 nLeftRect, INT32 nTopRect, INT32 nRightRect,
530 INT32 nBottomRect)
531{
532 if (!gdi_CRectToRgn(nLeftRect, nTopRect, nRightRect, nBottomRect, hRgn))
533 return FALSE;
534 hRgn->null = FALSE;
535 return TRUE;
536}
537
547inline BOOL gdi_EqualRgn(const GDI_RGN* hSrcRgn1, const GDI_RGN* hSrcRgn2)
548{
549 WINPR_ASSERT(hSrcRgn1);
550 WINPR_ASSERT(hSrcRgn2);
551 return ((hSrcRgn1->x == hSrcRgn2->x) && (hSrcRgn1->y == hSrcRgn2->y) &&
552 (hSrcRgn1->w == hSrcRgn2->w) && (hSrcRgn1->h == hSrcRgn2->h));
553}
554
564inline BOOL gdi_CopyRect(GDI_RECT* dst, const GDI_RECT* src)
565{
566 if (!dst || !src)
567 return FALSE;
568
569 dst->left = src->left;
570 dst->top = src->top;
571 dst->right = src->right;
572 dst->bottom = src->bottom;
573 return TRUE;
574}
575
585inline BOOL gdi_PtInRect(const GDI_RECT* rc, INT32 x, INT32 y)
586{
587 /*
588 * points on the left and top sides are considered in,
589 * while points on the right and bottom sides are considered out
590 */
591 if ((x >= rc->left) && (x <= rc->right))
592 {
593 if ((y >= rc->top) && (y <= rc->bottom))
594 {
595 return TRUE;
596 }
597 }
598
599 return FALSE;
600}
601
613inline BOOL gdi_InvalidateRegion(HGDI_DC hdc, INT32 x, INT32 y, INT32 w, INT32 h)
614{
615 GDI_RECT inv;
616 GDI_RECT rgn;
617 GDI_RGN* invalid = nullptr;
618 GDI_RGN* cinvalid = nullptr;
619
620 if (!hdc->hwnd)
621 return TRUE;
622
623 if (!hdc->hwnd->invalid)
624 return TRUE;
625
626 if (w == 0 || h == 0)
627 return TRUE;
628
629 cinvalid = hdc->hwnd->cinvalid;
630
631 if ((hdc->hwnd->ninvalid + 1) > (INT64)hdc->hwnd->count)
632 {
633 GDI_RGN* new_rgn = nullptr;
634 size_t new_cnt = 2ULL * hdc->hwnd->count;
635 if (new_cnt > UINT32_MAX)
636 return FALSE;
637
638 new_rgn = (GDI_RGN*)realloc(cinvalid, sizeof(GDI_RGN) * new_cnt);
639
640 if (!new_rgn)
641 return FALSE;
642
643 hdc->hwnd->count = (UINT32)new_cnt;
644 cinvalid = new_rgn;
645 }
646
647 hdc->hwnd->cinvalid = cinvalid;
648 invalid = hdc->hwnd->invalid;
649
650 if (!gdi_SetRgn(&cinvalid[hdc->hwnd->ninvalid++], x, y, w, h))
651 return FALSE;
652
653 if (!gdi_CRgnToRect(x, y, w, h, &rgn))
654 {
655 invalid->x = 0;
656 invalid->y = 0;
657 invalid->w = 0;
658 invalid->h = 0;
659 invalid->null = TRUE;
660 return TRUE;
661 }
662
663 if (invalid->null)
664 {
665 invalid->x = x;
666 invalid->y = y;
667 invalid->w = w;
668 invalid->h = h;
669 invalid->null = FALSE;
670 return TRUE;
671 }
672
673 if (!gdi_RgnToRect(invalid, &inv))
674 return FALSE;
675
676 if (rgn.left < inv.left)
677 inv.left = rgn.left;
678
679 if (rgn.top < inv.top)
680 inv.top = rgn.top;
681
682 if (rgn.right > inv.right)
683 inv.right = rgn.right;
684
685 if (rgn.bottom > inv.bottom)
686 inv.bottom = rgn.bottom;
687
688 return gdi_RectToRgn(&inv, invalid);
689}