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 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 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 gdi_CRgnToRect(x, y, width, height, &dst);
449 gdi_CRgnToRect(srcx, srcy, width, height, &src);
450
451 if (dst.right < src.left)
452 return FALSE;
453 if (dst.left > src.right)
454 return FALSE;
455 if (dst.bottom < src.top)
456 return FALSE;
457 if (dst.top > src.bottom)
458 return FALSE;
459 return TRUE;
460}
461
475inline BOOL gdi_SetRect(GDI_RECT* rc, INT32 xLeft, INT32 yTop, INT32 xRight, INT32 yBottom)
476{
477 if (!rc)
478 return FALSE;
479 if (xLeft > xRight)
480 return FALSE;
481 if (yTop > yBottom)
482 return FALSE;
483
484 rc->left = xLeft;
485 rc->top = yTop;
486 rc->right = xRight;
487 rc->bottom = yBottom;
488 return TRUE;
489}
490
501inline BOOL gdi_SetRgn(GDI_RGN* hRgn, INT32 nXLeft, INT32 nYLeft, INT32 nWidth, INT32 nHeight)
502{
503 if (!hRgn)
504 return FALSE;
505
506 if ((nWidth < 0) || (nHeight < 0))
507 return FALSE;
508
509 hRgn->x = nXLeft;
510 hRgn->y = nYLeft;
511 hRgn->w = nWidth;
512 hRgn->h = nHeight;
513 hRgn->null = FALSE;
514 return TRUE;
515}
516
527inline BOOL gdi_SetRectRgn(GDI_RGN* hRgn, INT32 nLeftRect, INT32 nTopRect, INT32 nRightRect,
528 INT32 nBottomRect)
529{
530 if (!gdi_CRectToRgn(nLeftRect, nTopRect, nRightRect, nBottomRect, hRgn))
531 return FALSE;
532 hRgn->null = FALSE;
533 return TRUE;
534}
535
545inline BOOL gdi_EqualRgn(const GDI_RGN* hSrcRgn1, const GDI_RGN* hSrcRgn2)
546{
547 WINPR_ASSERT(hSrcRgn1);
548 WINPR_ASSERT(hSrcRgn2);
549 if ((hSrcRgn1->x == hSrcRgn2->x) && (hSrcRgn1->y == hSrcRgn2->y) &&
550 (hSrcRgn1->w == hSrcRgn2->w) && (hSrcRgn1->h == hSrcRgn2->h))
551 {
552 return TRUE;
553 }
554
555 return FALSE;
556}
557
567inline BOOL gdi_CopyRect(GDI_RECT* dst, const GDI_RECT* src)
568{
569 if (!dst || !src)
570 return FALSE;
571
572 dst->left = src->left;
573 dst->top = src->top;
574 dst->right = src->right;
575 dst->bottom = src->bottom;
576 return TRUE;
577}
578
588inline BOOL gdi_PtInRect(const GDI_RECT* rc, INT32 x, INT32 y)
589{
590 /*
591 * points on the left and top sides are considered in,
592 * while points on the right and bottom sides are considered out
593 */
594 if ((x >= rc->left) && (x <= rc->right))
595 {
596 if ((y >= rc->top) && (y <= rc->bottom))
597 {
598 return TRUE;
599 }
600 }
601
602 return FALSE;
603}
604
616inline BOOL gdi_InvalidateRegion(HGDI_DC hdc, INT32 x, INT32 y, INT32 w, INT32 h)
617{
618 GDI_RECT inv;
619 GDI_RECT rgn;
620 GDI_RGN* invalid = NULL;
621 GDI_RGN* cinvalid = NULL;
622
623 if (!hdc->hwnd)
624 return TRUE;
625
626 if (!hdc->hwnd->invalid)
627 return TRUE;
628
629 if (w == 0 || h == 0)
630 return TRUE;
631
632 cinvalid = hdc->hwnd->cinvalid;
633
634 if ((hdc->hwnd->ninvalid + 1) > (INT64)hdc->hwnd->count)
635 {
636 GDI_RGN* new_rgn = NULL;
637 size_t new_cnt = 2ULL * hdc->hwnd->count;
638 if (new_cnt > UINT32_MAX)
639 return FALSE;
640
641 new_rgn = (GDI_RGN*)realloc(cinvalid, sizeof(GDI_RGN) * new_cnt);
642
643 if (!new_rgn)
644 return FALSE;
645
646 hdc->hwnd->count = (UINT32)new_cnt;
647 cinvalid = new_rgn;
648 }
649
650 gdi_SetRgn(&cinvalid[hdc->hwnd->ninvalid++], x, y, w, h);
651 hdc->hwnd->cinvalid = cinvalid;
652 invalid = hdc->hwnd->invalid;
653
654 if (invalid->null)
655 {
656 invalid->x = x;
657 invalid->y = y;
658 invalid->w = w;
659 invalid->h = h;
660 invalid->null = FALSE;
661 return TRUE;
662 }
663
664 gdi_CRgnToRect(x, y, w, h, &rgn);
665 gdi_RgnToRect(invalid, &inv);
666
667 if (rgn.left < inv.left)
668 inv.left = rgn.left;
669
670 if (rgn.top < inv.top)
671 inv.top = rgn.top;
672
673 if (rgn.right > inv.right)
674 inv.right = rgn.right;
675
676 if (rgn.bottom > inv.bottom)
677 inv.bottom = rgn.bottom;
678
679 gdi_RectToRgn(&inv, invalid);
680 return TRUE;
681}