FreeRDP
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 
40 static char* gdi_rect_str(char* buffer, size_t size, const HGDI_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 
53 static char* gdi_regn_str(char* buffer, size_t size, const HGDI_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 
77 HGDI_RGN gdi_CreateRectRgn(INT32 nLeftRect, INT32 nTopRect, INT32 nRightRect, INT32 nBottomRect)
78 {
79  INT64 w = 0;
80  INT64 h = 0;
81  HGDI_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 = (HGDI_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 
116 HGDI_RECT gdi_CreateRect(INT32 xLeft, INT32 yTop, INT32 xRight, INT32 yBottom)
117 {
118  HGDI_RECT hRect = NULL;
119 
120  if (xLeft > xRight)
121  return NULL;
122  if (yTop > yBottom)
123  return NULL;
124 
125  hRect = (HGDI_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 
144 BOOL gdi_RectToRgn(const HGDI_RECT rect, HGDI_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 
180 BOOL gdi_CRectToRgn(INT32 left, INT32 top, INT32 right, INT32 bottom, HGDI_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 
218 BOOL gdi_RectToCRgn(const HGDI_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 
258 BOOL 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 
292 BOOL gdi_RgnToRect(const HGDI_RGN rgn, HGDI_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 
325 BOOL gdi_CRgnToRect(INT64 x, INT64 y, INT32 w, INT32 h, HGDI_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 
371 BOOL gdi_RgnToCRect(const HGDI_RGN rgn, INT32* left, INT32* top, INT32* right, INT32* bottom)
372 {
373  BOOL rc = TRUE;
374  if ((rgn->w < 0) || (rgn->h < 0))
375  {
376  char buffer[256];
377  WLog_ERR(TAG, "Can not create region %s", gdi_regn_str(buffer, sizeof(buffer), rgn));
378  rc = FALSE;
379  }
380 
381  *left = rgn->x;
382  *top = rgn->y;
383  *right = rgn->x + rgn->w - 1;
384  *bottom = rgn->y + rgn->h - 1;
385 
386  return rc;
387 }
388 
401 INLINE BOOL gdi_CRgnToCRect(INT32 x, INT32 y, INT32 w, INT32 h, INT32* left, INT32* top,
402  INT32* right, INT32* bottom)
403 {
404  BOOL rc = TRUE;
405  *left = x;
406  *top = y;
407  *right = 0;
408 
409  if (w > 0)
410  *right = x + w - 1;
411  else
412  {
413  WLog_ERR(TAG, "Invalid width");
414  rc = FALSE;
415  }
416 
417  *bottom = 0;
418 
419  if (h > 0)
420  *bottom = y + h - 1;
421  else
422  {
423  WLog_ERR(TAG, "Invalid height");
424  rc = FALSE;
425  }
426 
427  return rc;
428 }
429 
441 INLINE BOOL gdi_CopyOverlap(INT32 x, INT32 y, INT32 width, INT32 height, INT32 srcx, INT32 srcy)
442 {
443  GDI_RECT dst;
444  GDI_RECT src;
445  gdi_CRgnToRect(x, y, width, height, &dst);
446  gdi_CRgnToRect(srcx, srcy, width, height, &src);
447 
448  if (dst.right < src.left)
449  return FALSE;
450  if (dst.left > src.right)
451  return FALSE;
452  if (dst.bottom < src.top)
453  return FALSE;
454  if (dst.top > src.bottom)
455  return FALSE;
456  return TRUE;
457 }
458 
472 INLINE BOOL gdi_SetRect(HGDI_RECT rc, INT32 xLeft, INT32 yTop, INT32 xRight, INT32 yBottom)
473 {
474  if (!rc)
475  return FALSE;
476  if (xLeft > xRight)
477  return FALSE;
478  if (yTop > yBottom)
479  return FALSE;
480 
481  rc->left = xLeft;
482  rc->top = yTop;
483  rc->right = xRight;
484  rc->bottom = yBottom;
485  return TRUE;
486 }
487 
498 INLINE BOOL gdi_SetRgn(HGDI_RGN hRgn, INT32 nXLeft, INT32 nYLeft, INT32 nWidth, INT32 nHeight)
499 {
500  if (!hRgn)
501  return FALSE;
502 
503  if ((nWidth < 0) || (nHeight < 0))
504  return FALSE;
505 
506  hRgn->x = nXLeft;
507  hRgn->y = nYLeft;
508  hRgn->w = nWidth;
509  hRgn->h = nHeight;
510  hRgn->null = FALSE;
511  return TRUE;
512 }
513 
524 INLINE BOOL gdi_SetRectRgn(HGDI_RGN hRgn, INT32 nLeftRect, INT32 nTopRect, INT32 nRightRect,
525  INT32 nBottomRect)
526 {
527  if (!gdi_CRectToRgn(nLeftRect, nTopRect, nRightRect, nBottomRect, hRgn))
528  return FALSE;
529  hRgn->null = FALSE;
530  return TRUE;
531 }
532 
542 INLINE BOOL gdi_EqualRgn(const HGDI_RGN hSrcRgn1, const HGDI_RGN hSrcRgn2)
543 {
544  if ((hSrcRgn1->x == hSrcRgn2->x) && (hSrcRgn1->y == hSrcRgn2->y) &&
545  (hSrcRgn1->w == hSrcRgn2->w) && (hSrcRgn1->h == hSrcRgn2->h))
546  {
547  return TRUE;
548  }
549 
550  return FALSE;
551 }
552 
562 INLINE BOOL gdi_CopyRect(HGDI_RECT dst, const HGDI_RECT src)
563 {
564  if (!dst || !src)
565  return FALSE;
566 
567  dst->left = src->left;
568  dst->top = src->top;
569  dst->right = src->right;
570  dst->bottom = src->bottom;
571  return TRUE;
572 }
573 
583 INLINE BOOL gdi_PtInRect(const HGDI_RECT rc, INT32 x, INT32 y)
584 {
585  /*
586  * points on the left and top sides are considered in,
587  * while points on the right and bottom sides are considered out
588  */
589  if ((x >= rc->left) && (x <= rc->right))
590  {
591  if ((y >= rc->top) && (y <= rc->bottom))
592  {
593  return TRUE;
594  }
595  }
596 
597  return FALSE;
598 }
599 
611 INLINE BOOL gdi_InvalidateRegion(HGDI_DC hdc, INT32 x, INT32 y, INT32 w, INT32 h)
612 {
613  GDI_RECT inv;
614  GDI_RECT rgn;
615  HGDI_RGN invalid = NULL;
616  HGDI_RGN cinvalid = NULL;
617 
618  if (!hdc->hwnd)
619  return TRUE;
620 
621  if (!hdc->hwnd->invalid)
622  return TRUE;
623 
624  if (w == 0 || h == 0)
625  return TRUE;
626 
627  cinvalid = hdc->hwnd->cinvalid;
628 
629  if ((hdc->hwnd->ninvalid + 1) > (INT64)hdc->hwnd->count)
630  {
631  HGDI_RGN new_rgn = NULL;
632  size_t new_cnt = 2ULL * hdc->hwnd->count;
633  if (new_cnt > UINT32_MAX)
634  return FALSE;
635 
636  new_rgn = (HGDI_RGN)realloc(cinvalid, sizeof(GDI_RGN) * new_cnt);
637 
638  if (!new_rgn)
639  return FALSE;
640 
641  hdc->hwnd->count = (UINT32)new_cnt;
642  cinvalid = new_rgn;
643  }
644 
645  gdi_SetRgn(&cinvalid[hdc->hwnd->ninvalid++], x, y, w, h);
646  hdc->hwnd->cinvalid = cinvalid;
647  invalid = hdc->hwnd->invalid;
648 
649  if (invalid->null)
650  {
651  invalid->x = x;
652  invalid->y = y;
653  invalid->w = w;
654  invalid->h = h;
655  invalid->null = FALSE;
656  return TRUE;
657  }
658 
659  gdi_CRgnToRect(x, y, w, h, &rgn);
660  gdi_RgnToRect(invalid, &inv);
661 
662  if (rgn.left < inv.left)
663  inv.left = rgn.left;
664 
665  if (rgn.top < inv.top)
666  inv.top = rgn.top;
667 
668  if (rgn.right > inv.right)
669  inv.right = rgn.right;
670 
671  if (rgn.bottom > inv.bottom)
672  inv.bottom = rgn.bottom;
673 
674  gdi_RectToRgn(&inv, invalid);
675  return TRUE;
676 }