FreeRDP
Loading...
Searching...
No Matches
TestGdiClip.c
1
2#include <freerdp/gdi/gdi.h>
3
4#include <freerdp/gdi/dc.h>
5#include <freerdp/gdi/pen.h>
6#include <freerdp/gdi/region.h>
7#include <freerdp/gdi/bitmap.h>
8
9#include <winpr/crt.h>
10
11#include "line.h"
12#include "brush.h"
13#include "clipping.h"
14
15static bool test_gdi_coords(size_t testNr, HGDI_DC hdc, const GDI_RGN* clip, const GDI_RGN* input,
16 const GDI_RGN* expect)
17{
18 bool rc = false;
19
20 WINPR_ASSERT(hdc);
21 WINPR_ASSERT(input);
22
23 HGDI_RGN rgn1 = gdi_CreateRectRgn(0, 0, 0, 0);
24 HGDI_RGN rgn2 = gdi_CreateRectRgn(0, 0, 0, 0);
25 if (!rgn1 || !rgn2)
26 {
27 (void)fprintf(stderr, "[%s:%" PRIuz "] gdi_CreateRectRgn failed: rgn1=%p, rgn2=%p\n",
28 __func__, testNr, rgn1, rgn2);
29 goto fail;
30 }
31
32 if (!clip)
33 {
34 if (!gdi_SetNullClipRgn(hdc))
35 {
36 (void)fprintf(stderr, "[%s:%" PRIuz "] gdi_SetNullClipRgn failed\n", __func__, testNr);
37 goto fail;
38 }
39 }
40 else if (!gdi_SetClipRgn(hdc, clip->x, clip->y, clip->w, clip->h))
41 {
42 (void)fprintf(stderr, "[%s:%" PRIuz "] gdi_SetClipRgn failed\n", __func__, testNr);
43 goto fail;
44 }
45
46 if (!gdi_SetRgn(rgn1, input->x, input->y, input->w, input->h))
47 {
48 (void)fprintf(stderr, "[%s:%" PRIuz "] gdi_SetRgn (rgn1) failed\n", __func__, testNr);
49 goto fail;
50 }
51
52 if (expect)
53 {
54 if (!gdi_SetRgn(rgn2, expect->x, expect->y, expect->w, expect->h))
55 {
56 (void)fprintf(stderr, "[%s:%" PRIuz "] gdi_SetRgn (rgn2) failed\n", __func__, testNr);
57 goto fail;
58 }
59 }
60
61 const BOOL draw =
62 gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), nullptr, nullptr);
63 if (expect)
64 {
65 if (!draw)
66 {
67 (void)fprintf(stderr,
68 "[%s:%" PRIuz "] gdi_ClipCoords failed: expected TRUE, got FALSE\n",
69 __func__, testNr);
70 goto fail;
71 }
72
73 if (!gdi_EqualRgn(rgn1, rgn2))
74 {
75 char buffer1[64] = WINPR_C_ARRAY_INIT;
76 char buffer2[64] = WINPR_C_ARRAY_INIT;
77 (void)fprintf(stderr, "[%s:%" PRIuz "] gdi_EqualRgn failed: expected %s, got %s\n",
78 __func__, testNr, buffer1, buffer2);
79 goto fail;
80 }
81 }
82 else
83 {
84 if (draw)
85 {
86 (void)fprintf(stderr,
87 "[%s:%" PRIuz "] gdi_ClipCoords failed: expected FALSE, got TRUE\n",
88 __func__, testNr);
89 goto fail;
90 }
91 }
92
93 rc = true;
94
95fail:
96 gdi_DeleteObject((HGDIOBJECT)rgn1);
97 gdi_DeleteObject((HGDIOBJECT)rgn2);
98 return rc;
99}
100
101static int test_gdi_ClipCoords(void)
102{
103 int rc = -1;
104 HGDI_DC hdc = nullptr;
105 HGDI_BITMAP bmp = nullptr;
106 const UINT32 format = PIXEL_FORMAT_ARGB32;
107
108 if (!(hdc = gdi_GetDC()))
109 {
110 printf("failed to get gdi device context\n");
111 return -1;
112 }
113
114 hdc->format = format;
115 bmp = gdi_CreateBitmapEx(1024, 768, PIXEL_FORMAT_XRGB32, 0, nullptr, nullptr);
116 if (!bmp)
117 return -1;
118 gdi_SelectObject(hdc, (HGDIOBJECT)bmp);
119 if (!gdi_SetNullClipRgn(hdc))
120 return -1;
121
122 struct testcase_t
123 {
124 const GDI_RGN* clip;
125 const GDI_RGN* in;
126 const GDI_RGN* expect;
127 };
128
129 const GDI_RGN rgn0x0_1x768 = { 0, 0, 0, 1, 768, FALSE };
130 const GDI_RGN rgn0x0_1024x1 = { 0, 0, 0, 1024, 1, FALSE };
131 const GDI_RGN rgn0x0_1024x768 = { 0, 0, 0, 1024, 768, FALSE };
132 const GDI_RGN rgn20x20_0x0 = { 0, 20, 20, 0, 0, FALSE };
133 const GDI_RGN rgn20x20_100x100 = { 0, 20, 20, 100, 100, FALSE };
134 const GDI_RGN rgn100x300_250x100 = { 0, 100, 300, 250, 100, FALSE };
135 const GDI_RGN rgn100x300_300x100 = { 0, 100, 300, 300, 100, FALSE };
136 const GDI_RGN rgn300x20_100x100 = { 0, 300, 20, 100, 100, FALSE };
137 const GDI_RGN rgn300x100_300x300 = { 0, 300, 100, 300, 300, FALSE };
138 const GDI_RGN rgn300x300_50x100 = { 0, 300, 300, 50, 100, FALSE };
139 const GDI_RGN rgn300x300_100x100 = { 0, 300, 300, 100, 100, FALSE };
140 const GDI_RGN rgn300x300_300x100 = { 0, 300, 300, 300, 100, FALSE };
141 const GDI_RGN rgn300x300_300x200 = { 0, 300, 300, 100, 200, FALSE };
142 const GDI_RGN rgn300x420_100x100 = { 0, 300, 420, 100, 100, FALSE };
143 const GDI_RGN rgn350x300_50x100 = { 0, 350, 300, 50, 100, FALSE };
144 const GDI_RGN rgn350x300_200x100 = { 0, 350, 300, 200, 100, FALSE };
145 const GDI_RGN rgn420x420_100x100 = { 0, 420, 420, 100, 100, FALSE };
146
147 const struct testcase_t testcases[] = {
148 /* null clipping region */
149 { nullptr, &rgn20x20_100x100, &rgn20x20_100x100 },
150 /* empty region, nothing to draw */
151 { nullptr, &rgn20x20_0x0, nullptr },
152 /* region only covers first column */
153 { nullptr, &rgn0x0_1x768, &rgn0x0_1x768 },
154 /* region only covers first row */
155 { nullptr, &rgn0x0_1024x1, &rgn0x0_1024x1 },
156 /* region all inside clipping region */
157 { &rgn0x0_1024x768, &rgn20x20_100x100, &rgn20x20_100x100 },
158 /* region all outside clipping region, on the left */
159 { &rgn300x300_100x100, &rgn20x20_100x100, nullptr },
160 /* region all outside clipping region, on the right */
161 { &rgn300x300_100x100, &rgn420x420_100x100, nullptr },
162 /* region all outside clipping region, on top */
163 { &rgn300x300_100x100, &rgn300x20_100x100, nullptr },
164 /* region all outside clipping region, at the bottom */
165 { &rgn300x300_100x100, &rgn300x420_100x100, nullptr },
166 /* left outside, right = clip, top = clip, bottom = clip */
167 { &rgn300x300_100x100, &rgn100x300_300x100, &rgn300x300_100x100 },
168 /* left outside, right inside, top = clip, bottom = clip */
169 { &rgn300x300_100x100, &rgn100x300_250x100, &rgn300x300_50x100 },
170 /* left = clip, right outside, top = clip, bottom = clip */
171 { &rgn300x300_100x100, &rgn300x300_300x100, &rgn300x300_100x100 },
172 /* left inside, right outside, top = clip, bottom = clip */
173 { &rgn300x300_100x100, &rgn350x300_200x100, &rgn350x300_50x100 },
174 /* top outside, bottom = clip, left = clip, right = clip */
175 { &rgn300x300_100x100, &rgn300x100_300x300, &rgn300x300_100x100 },
176 /* top = clip, bottom outside, left = clip, right = clip */
177 { &rgn300x300_100x100, &rgn300x300_300x200, &rgn300x300_100x100 },
178 /* top = clip, bottom = clip, top = clip, bottom = clip */
179 { &rgn300x300_100x100, &rgn300x300_100x100, &rgn300x300_100x100 }
180 };
181
182 for (size_t x = 0; x < ARRAYSIZE(testcases); x++)
183 {
184 const struct testcase_t* cur = &testcases[x];
185 if (!test_gdi_coords(x, hdc, cur->clip, cur->in, cur->expect))
186 goto fail;
187 }
188
189 rc = 0;
190fail:
191 gdi_DeleteObject((HGDIOBJECT)bmp);
192 gdi_DeleteDC(hdc);
193 return rc;
194}
195
196/* A bitmap that is only one pixel wide or high must still clip */
197static int test_gdi_ClipCoordsSmallBitmap(void)
198{
199 const GDI_RGN rgn0x0_64x64 = { 0, 0, 0, 64, 64, FALSE };
200 const GDI_RGN rgn0x0_1x64 = { 0, 0, 0, 1, 64, FALSE };
201 const GDI_RGN rgn0x0_64x1 = { 0, 0, 0, 64, 1, FALSE };
202 const GDI_RGN* sizes[] = { &rgn0x0_1x64, &rgn0x0_64x1 };
203
204 for (size_t x = 0; x < ARRAYSIZE(sizes); x++)
205 {
206 const GDI_RGN* cur = sizes[x];
207 const UINT32 w = WINPR_ASSERTING_INT_CAST(UINT32, cur->w);
208 const UINT32 h = WINPR_ASSERTING_INT_CAST(UINT32, cur->h);
209 bool rc = false;
210 HGDI_DC hdc = gdi_GetDC();
211 if (!hdc)
212 return -1;
213
214 hdc->format = PIXEL_FORMAT_XRGB32;
215 HGDI_BITMAP bmp = gdi_CreateBitmapEx(w, h, hdc->format, 0, nullptr, nullptr);
216 if (bmp)
217 {
218 gdi_SelectObject(hdc, (HGDIOBJECT)bmp);
219 rc = test_gdi_coords(x, hdc, nullptr, &rgn0x0_64x64, cur) &&
220 test_gdi_coords(x, hdc, &rgn0x0_64x64, &rgn0x0_64x64, cur);
221 }
222
223 gdi_DeleteObject((HGDIOBJECT)bmp);
224 gdi_DeleteDC(hdc);
225 if (!rc)
226 return -1;
227 }
228
229 return 0;
230}
231
232static int test_gdi_InvalidateRegion(void)
233{
234 int rc = -1;
235 HGDI_DC hdc = nullptr;
236 HGDI_RGN rgn1 = nullptr;
237 HGDI_RGN rgn2 = nullptr;
238 HGDI_RGN invalid = nullptr;
239 HGDI_BITMAP bmp = nullptr;
240 HGDI_PEN pen = nullptr;
241 const UINT32 format = PIXEL_FORMAT_XRGB32;
242
243 if (!(hdc = gdi_GetDC()))
244 {
245 printf("failed to get gdi device context\n");
246 return -1;
247 }
248
249 hdc->format = format;
250 bmp = gdi_CreateBitmapEx(1024, 768, PIXEL_FORMAT_XRGB32, 0, nullptr, nullptr);
251 if (!bmp)
252 goto fail;
253 gdi_SelectObject(hdc, (HGDIOBJECT)bmp);
254 if (!gdi_SetNullClipRgn(hdc))
255 goto fail;
256 hdc->hwnd = (HGDI_WND)calloc(1, sizeof(GDI_WND));
257 if (!hdc->hwnd)
258 goto fail;
259 hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0);
260 if (!hdc->hwnd->invalid)
261 goto fail;
262 hdc->hwnd->invalid->null = TRUE;
263 invalid = hdc->hwnd->invalid;
264 hdc->hwnd->count = 16;
265 hdc->hwnd->cinvalid = (HGDI_RGN)calloc(hdc->hwnd->count, sizeof(GDI_RGN));
266 rgn1 = gdi_CreateRectRgn(0, 0, 0, 0);
267 rgn2 = gdi_CreateRectRgn(0, 0, 0, 0);
268 rgn1->null = TRUE;
269 rgn2->null = TRUE;
270 /* no previous invalid region */
271 invalid->null = TRUE;
272 if (!gdi_SetRgn(rgn1, 300, 300, 100, 100))
273 goto fail;
274 if (!gdi_SetRgn(rgn2, 300, 300, 100, 100))
275 goto fail;
276 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
277 goto fail;
278
279 if (!gdi_EqualRgn(invalid, rgn2))
280 goto fail;
281
282 /* region same as invalid region */
283 if (!gdi_SetRgn(invalid, 300, 300, 100, 100))
284 goto fail;
285 if (!gdi_SetRgn(rgn1, 300, 300, 100, 100))
286 goto fail;
287 if (!gdi_SetRgn(rgn2, 300, 300, 100, 100))
288 goto fail;
289 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
290 goto fail;
291
292 if (!gdi_EqualRgn(invalid, rgn2))
293 goto fail;
294
295 /* left outside */
296 if (!gdi_SetRgn(invalid, 300, 300, 100, 100))
297 goto fail;
298 if (!gdi_SetRgn(rgn1, 100, 300, 300, 100))
299 goto fail;
300 if (!gdi_SetRgn(rgn2, 100, 300, 300, 100))
301 goto fail;
302 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
303 goto fail;
304
305 if (!gdi_EqualRgn(invalid, rgn2))
306 goto fail;
307
308 /* right outside */
309 if (!gdi_SetRgn(invalid, 300, 300, 100, 100))
310 goto fail;
311 if (!gdi_SetRgn(rgn1, 300, 300, 300, 100))
312 goto fail;
313 if (!gdi_SetRgn(rgn2, 300, 300, 300, 100))
314 goto fail;
315 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
316 goto fail;
317
318 if (!gdi_EqualRgn(invalid, rgn2))
319 goto fail;
320
321 /* top outside */
322 if (!gdi_SetRgn(invalid, 300, 300, 100, 100))
323 goto fail;
324 if (!gdi_SetRgn(rgn1, 300, 100, 100, 300))
325 goto fail;
326 if (!gdi_SetRgn(rgn2, 300, 100, 100, 300))
327 goto fail;
328 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
329 goto fail;
330
331 if (!gdi_EqualRgn(invalid, rgn2))
332 goto fail;
333
334 /* bottom outside */
335 if (!gdi_SetRgn(invalid, 300, 300, 100, 100))
336 goto fail;
337 if (!gdi_SetRgn(rgn1, 300, 300, 100, 300))
338 goto fail;
339 if (!gdi_SetRgn(rgn2, 300, 300, 100, 300))
340 goto fail;
341 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
342 goto fail;
343
344 if (!gdi_EqualRgn(invalid, rgn2))
345 goto fail;
346
347 /* left outside, right outside */
348 if (!gdi_SetRgn(invalid, 300, 300, 100, 100))
349 goto fail;
350 if (!gdi_SetRgn(rgn1, 100, 300, 600, 300))
351 goto fail;
352 if (!gdi_SetRgn(rgn2, 100, 300, 600, 300))
353 goto fail;
354 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
355 goto fail;
356
357 if (!gdi_EqualRgn(invalid, rgn2))
358 goto fail;
359
360 /* top outside, bottom outside */
361 if (!gdi_SetRgn(invalid, 300, 300, 100, 100))
362 goto fail;
363 if (!gdi_SetRgn(rgn1, 300, 100, 100, 500))
364 goto fail;
365 if (!gdi_SetRgn(rgn2, 300, 100, 100, 500))
366 goto fail;
367 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
368 goto fail;
369
370 if (!gdi_EqualRgn(invalid, rgn2))
371 goto fail;
372
373 /* all outside, left */
374 if (!gdi_SetRgn(invalid, 300, 300, 100, 100))
375 goto fail;
376 if (!gdi_SetRgn(rgn1, 100, 300, 100, 100))
377 goto fail;
378 if (!gdi_SetRgn(rgn2, 100, 300, 300, 100))
379 goto fail;
380 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
381 goto fail;
382
383 if (!gdi_EqualRgn(invalid, rgn2))
384 goto fail;
385
386 /* all outside, right */
387 if (!gdi_SetRgn(invalid, 300, 300, 100, 100))
388 goto fail;
389 if (!gdi_SetRgn(rgn1, 700, 300, 100, 100))
390 goto fail;
391 if (!gdi_SetRgn(rgn2, 300, 300, 500, 100))
392 goto fail;
393 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
394 goto fail;
395
396 if (!gdi_EqualRgn(invalid, rgn2))
397 goto fail;
398
399 /* all outside, top */
400 if (!gdi_SetRgn(invalid, 300, 300, 100, 100))
401 goto fail;
402 if (!gdi_SetRgn(rgn1, 300, 100, 100, 100))
403 goto fail;
404 if (!gdi_SetRgn(rgn2, 300, 100, 100, 300))
405 goto fail;
406 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
407 goto fail;
408
409 if (!gdi_EqualRgn(invalid, rgn2))
410 goto fail;
411
412 /* all outside, bottom */
413 if (!gdi_SetRgn(invalid, 300, 300, 100, 100))
414 goto fail;
415 if (!gdi_SetRgn(rgn1, 300, 500, 100, 100))
416 goto fail;
417 if (!gdi_SetRgn(rgn2, 300, 300, 100, 300))
418 goto fail;
419 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
420 goto fail;
421
422 if (!gdi_EqualRgn(invalid, rgn2))
423 goto fail;
424
425 /* all outside */
426 if (!gdi_SetRgn(invalid, 300, 300, 100, 100))
427 goto fail;
428 if (!gdi_SetRgn(rgn1, 100, 100, 600, 600))
429 goto fail;
430 if (!gdi_SetRgn(rgn2, 100, 100, 600, 600))
431 goto fail;
432 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
433 goto fail;
434
435 if (!gdi_EqualRgn(invalid, rgn2))
436 goto fail;
437
438 /* everything */
439 if (!gdi_SetRgn(invalid, 300, 300, 100, 100))
440 goto fail;
441 if (!gdi_SetRgn(rgn1, 0, 0, 1024, 768))
442 goto fail;
443 if (!gdi_SetRgn(rgn2, 0, 0, 1024, 768))
444 goto fail;
445 if (!gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h))
446 goto fail;
447
448 if (!gdi_EqualRgn(invalid, rgn2))
449 goto fail;
450
451 /* a rejected region is not added to the list */
452 hdc->hwnd->ninvalid = 0;
453 if (!gdi_InvalidateRegion(hdc, 2024, 10, -1000, 11))
454 goto fail;
455 if (!gdi_InvalidateRegion(hdc, 10, 2024, 11, -1000))
456 goto fail;
457 if (hdc->hwnd->ninvalid != 0)
458 goto fail;
459
460 pen = gdi_CreatePen(GDI_PS_SOLID, 1, 0, format, nullptr);
461 if (!pen)
462 goto fail;
463 gdi_SelectObject(hdc, (HGDIOBJECT)pen);
464 if (!gdi_MoveToEx(hdc, 2024, 10, nullptr))
465 goto fail;
466 if (!gdi_LineTo(hdc, 2124, 20))
467 goto fail;
468 if (hdc->hwnd->ninvalid != 0)
469 goto fail;
470
471 rc = 0;
472fail:
473 gdi_DeleteObject((HGDIOBJECT)rgn1);
474 gdi_DeleteObject((HGDIOBJECT)rgn2);
475 gdi_DeleteObject((HGDIOBJECT)bmp);
476 gdi_DeleteObject((HGDIOBJECT)pen);
477 gdi_DeleteDC(hdc);
478 return rc;
479}
480
481int TestGdiClip(int argc, char* argv[])
482{
483 WINPR_UNUSED(argc);
484 WINPR_UNUSED(argv);
485 (void)fprintf(stderr, "test_gdi_ClipCoords()\n");
486
487 if (test_gdi_ClipCoords() < 0)
488 return -1;
489
490 (void)fprintf(stderr, "test_gdi_ClipCoordsSmallBitmap()\n");
491
492 if (test_gdi_ClipCoordsSmallBitmap() < 0)
493 return -1;
494
495 (void)fprintf(stderr, "test_gdi_InvalidateRegion()\n");
496
497 if (test_gdi_InvalidateRegion() < 0)
498 return -1;
499
500 return 0;
501}