gdi32/tests: Add test cases for wide pen bounding rectangles.
[wine] / dlls / gdi32 / tests / clipping.c
1 /*
2  * Unit test suite for clipping
3  *
4  * Copyright 2005 Huw Davies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "wine/test.h"
22 #include "winbase.h"
23 #include "wingdi.h"
24 #include "winuser.h"
25
26 static void test_GetRandomRgn(void)
27 {
28     HWND hwnd = CreateWindowExA(0,"BUTTON","test",WS_VISIBLE|WS_POPUP,0,0,100,100,GetDesktopWindow(),0,0,0);
29     HDC hdc;
30     HRGN hrgn = CreateRectRgn(0, 0, 0, 0);
31     int ret;
32     RECT rc, rc2;
33     RECT ret_rc, window_rc;
34
35     ok( hwnd != 0, "CreateWindow failed\n" );
36
37     SetRect(&window_rc, 400, 300, 500, 400);
38     SetWindowPos(hwnd, HWND_TOPMOST, window_rc.left, window_rc.top,
39                  window_rc.right - window_rc.left, window_rc.bottom - window_rc.top, 0 );
40     hdc = GetDC(hwnd);
41
42     ret = GetRandomRgn(hdc, hrgn, 1);
43     ok(ret == 0, "GetRandomRgn rets %d\n", ret);
44     ret = GetRandomRgn(hdc, hrgn, 2);
45     ok(ret == 0, "GetRandomRgn rets %d\n", ret);
46     ret = GetRandomRgn(hdc, hrgn, 3);
47     ok(ret == 0, "GetRandomRgn rets %d\n", ret);
48
49     /* Set a clip region */
50     SetRect(&rc, 20, 20, 80, 80);
51     IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
52
53     ret = GetRandomRgn(hdc, hrgn, 1);
54     ok(ret != 0, "GetRandomRgn rets %d\n", ret);
55     GetRgnBox(hrgn, &ret_rc);
56     ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %d,%d - %d,%d\n",
57        ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
58  
59     ret = GetRandomRgn(hdc, hrgn, 2);
60     ok(ret == 0, "GetRandomRgn rets %d\n", ret);
61
62     ret = GetRandomRgn(hdc, hrgn, 3);
63     ok(ret != 0, "GetRandomRgn rets %d\n", ret);
64     GetRgnBox(hrgn, &ret_rc);
65     ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %d,%d - %d,%d\n",
66        ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
67
68     /* Move the clip to the meta and clear the clip */
69     SetMetaRgn(hdc);
70
71     ret = GetRandomRgn(hdc, hrgn, 1);
72     ok(ret == 0, "GetRandomRgn rets %d\n", ret);
73     ret = GetRandomRgn(hdc, hrgn, 2);
74     ok(ret != 0, "GetRandomRgn rets %d\n", ret);
75     GetRgnBox(hrgn, &ret_rc);
76     ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %d,%d - %d,%d\n",
77        ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
78
79     ret = GetRandomRgn(hdc, hrgn, 3);
80     ok(ret != 0, "GetRandomRgn rets %d\n", ret);
81     GetRgnBox(hrgn, &ret_rc);
82     ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %d,%d - %d,%d\n",
83        ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
84
85     /* Set a new clip (still got the meta) */
86     SetRect(&rc2, 10, 30, 70, 90);
87     IntersectClipRect(hdc, rc2.left, rc2.top, rc2.right, rc2.bottom);
88
89     ret = GetRandomRgn(hdc, hrgn, 1);
90     ok(ret != 0, "GetRandomRgn rets %d\n", ret);
91     GetRgnBox(hrgn, &ret_rc);
92     ok(EqualRect(&rc2, &ret_rc), "GetRandomRgn %d,%d - %d,%d\n",
93        ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
94
95     ret = GetRandomRgn(hdc, hrgn, 2);
96     ok(ret != 0, "GetRandomRgn rets %d\n", ret);
97     GetRgnBox(hrgn, &ret_rc);
98     ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %d,%d - %d,%d\n",
99        ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
100  
101     IntersectRect(&rc2, &rc, &rc2);
102
103     ret = GetRandomRgn(hdc, hrgn, 3);
104     ok(ret != 0, "GetRandomRgn rets %d\n", ret);
105     GetRgnBox(hrgn, &ret_rc);
106     ok(EqualRect(&rc2, &ret_rc), "GetRandomRgn %d,%d - %d,%d\n",
107        ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
108
109
110     ret = GetRandomRgn(hdc, hrgn, SYSRGN);
111     ok(ret != 0, "GetRandomRgn rets %d\n", ret);
112     GetRgnBox(hrgn, &ret_rc);
113     if(GetVersion() & 0x80000000)
114         OffsetRect(&window_rc, -window_rc.left, -window_rc.top);
115     /* the window may be partially obscured so the region may be smaller */
116     IntersectRect( &window_rc, &ret_rc, &ret_rc );
117     ok(EqualRect(&window_rc, &ret_rc) ||
118        broken(IsRectEmpty(&ret_rc)), /* win95 */
119        "GetRandomRgn %d,%d - %d,%d\n",
120        ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
121
122     DeleteObject(hrgn);
123     ReleaseDC(hwnd, hdc);
124     DestroyWindow(hwnd);
125 }
126
127 static void verify_region(HRGN hrgn, const RECT *rc)
128 {
129     union
130     {
131         RGNDATA data;
132         char buf[sizeof(RGNDATAHEADER) + sizeof(RECT)];
133     } rgn;
134     const RECT *rect;
135     DWORD ret;
136
137     ret = GetRegionData(hrgn, 0, NULL);
138     if (IsRectEmpty(rc))
139         ok(ret == sizeof(rgn.data.rdh), "expected sizeof(rdh), got %u\n", ret);
140     else
141         ok(ret == sizeof(rgn.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret);
142
143     if (!ret) return;
144
145     ret = GetRegionData(hrgn, sizeof(rgn), &rgn.data);
146     if (IsRectEmpty(rc))
147         ok(ret == sizeof(rgn.data.rdh), "expected sizeof(rdh), got %u\n", ret);
148     else
149         ok(ret == sizeof(rgn.data.rdh) + sizeof(RECT), "expected sizeof(rgn), got %u\n", ret);
150
151     trace("size %u, type %u, count %u, rgn size %u, bound (%d,%d-%d,%d)\n",
152           rgn.data.rdh.dwSize, rgn.data.rdh.iType,
153           rgn.data.rdh.nCount, rgn.data.rdh.nRgnSize,
154           rgn.data.rdh.rcBound.left, rgn.data.rdh.rcBound.top,
155           rgn.data.rdh.rcBound.right, rgn.data.rdh.rcBound.bottom);
156     if (rgn.data.rdh.nCount != 0)
157     {
158         rect = (const RECT *)rgn.data.Buffer;
159         trace("rect (%d,%d-%d,%d)\n", rect->left, rect->top, rect->right, rect->bottom);
160         ok(EqualRect(rect, rc), "rects don't match\n");
161     }
162
163     ok(rgn.data.rdh.dwSize == sizeof(rgn.data.rdh), "expected sizeof(rdh), got %u\n", rgn.data.rdh.dwSize);
164     ok(rgn.data.rdh.iType == RDH_RECTANGLES, "expected RDH_RECTANGLES, got %u\n", rgn.data.rdh.iType);
165     if (IsRectEmpty(rc))
166     {
167         ok(rgn.data.rdh.nCount == 0, "expected 0, got %u\n", rgn.data.rdh.nCount);
168         ok(rgn.data.rdh.nRgnSize == 0 ||
169            broken(rgn.data.rdh.nRgnSize == 168), /* NT4 */
170            "expected 0, got %u\n", rgn.data.rdh.nRgnSize);
171     }
172     else
173     {
174         ok(rgn.data.rdh.nCount == 1, "expected 1, got %u\n", rgn.data.rdh.nCount);
175         ok(rgn.data.rdh.nRgnSize == sizeof(RECT) ||
176            broken(rgn.data.rdh.nRgnSize == 168), /* NT4 */
177            "expected sizeof(RECT), got %u\n", rgn.data.rdh.nRgnSize);
178     }
179     ok(EqualRect(&rgn.data.rdh.rcBound, rc), "rects don't match\n");
180 }
181
182 static void test_ExtCreateRegion(void)
183 {
184     static const RECT empty_rect;
185     static const RECT rc = { 111, 222, 333, 444 };
186     static const RECT rc_xformed = { 76, 151, 187, 262 };
187     union
188     {
189         RGNDATA data;
190         char buf[sizeof(RGNDATAHEADER) + sizeof(RECT)];
191     } rgn;
192     HRGN hrgn;
193     XFORM xform;
194
195     if (0) /* crashes under Win9x */
196     {
197         SetLastError(0xdeadbeef);
198         hrgn = ExtCreateRegion(NULL, 0, NULL);
199         ok(!hrgn, "ExtCreateRegion should fail\n");
200         ok(GetLastError() == ERROR_INVALID_PARAMETER, "ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
201     }
202
203     rgn.data.rdh.dwSize = 0;
204     rgn.data.rdh.iType = 0;
205     rgn.data.rdh.nCount = 0;
206     rgn.data.rdh.nRgnSize = 0;
207     SetRectEmpty(&rgn.data.rdh.rcBound);
208     memcpy(rgn.data.Buffer, &rc, sizeof(rc));
209
210     SetLastError(0xdeadbeef);
211     hrgn = ExtCreateRegion(NULL, sizeof(rgn), &rgn.data);
212     ok(!hrgn, "ExtCreateRegion should fail\n");
213     ok(GetLastError() == 0xdeadbeef, "0xdeadbeef, got %u\n", GetLastError());
214
215     rgn.data.rdh.dwSize = sizeof(rgn.data.rdh) - 1;
216
217     SetLastError(0xdeadbeef);
218     hrgn = ExtCreateRegion(NULL, sizeof(rgn), &rgn.data);
219     ok(!hrgn, "ExtCreateRegion should fail\n");
220     ok(GetLastError() == 0xdeadbeef, "0xdeadbeef, got %u\n", GetLastError());
221
222     /* although XP doesn't care about the type Win9x does */
223     rgn.data.rdh.iType = RDH_RECTANGLES;
224     rgn.data.rdh.dwSize = sizeof(rgn.data.rdh);
225
226     SetLastError(0xdeadbeef);
227     hrgn = ExtCreateRegion(NULL, sizeof(rgn), &rgn.data);
228     ok(hrgn != 0, "ExtCreateRegion error %u\n", GetLastError());
229     verify_region(hrgn, &empty_rect);
230     DeleteObject(hrgn);
231
232     rgn.data.rdh.nCount = 1;
233     SetRectEmpty(&rgn.data.rdh.rcBound);
234     memcpy(rgn.data.Buffer, &rc, sizeof(rc));
235
236     SetLastError(0xdeadbeef);
237     hrgn = ExtCreateRegion(NULL, sizeof(rgn), &rgn.data);
238     ok(hrgn != 0, "ExtCreateRegion error %u\n", GetLastError());
239     verify_region(hrgn, &rc);
240     DeleteObject(hrgn);
241
242     rgn.data.rdh.dwSize = sizeof(rgn.data.rdh) + 1;
243
244     SetLastError(0xdeadbeef);
245     hrgn = ExtCreateRegion(NULL, 1, &rgn.data);
246     ok(hrgn != 0 ||
247        broken(GetLastError() == 0xdeadbeef), /* NT4 */
248        "ExtCreateRegion error %u\n", GetLastError());
249     if(hrgn)
250     {
251         verify_region(hrgn, &rc);
252         DeleteObject(hrgn);
253     }
254
255     xform.eM11 = 0.5; /* 50% width */
256     xform.eM12 = 0.0;
257     xform.eM21 = 0.0;
258     xform.eM22 = 0.5; /* 50% height */
259     xform.eDx = 20.0;
260     xform.eDy = 40.0;
261
262     rgn.data.rdh.dwSize = sizeof(rgn.data.rdh);
263
264     SetLastError(0xdeadbeef);
265     hrgn = ExtCreateRegion(&xform, sizeof(rgn), &rgn.data);
266     ok(hrgn != 0, "ExtCreateRegion error %u/%x\n", GetLastError(), GetLastError());
267     verify_region(hrgn, &rc_xformed);
268     DeleteObject(hrgn);
269 }
270
271 static void test_GetClipRgn(void)
272 {
273     HDC hdc;
274     HRGN hrgn, hrgn2, hrgn3, hrgn4;
275     int ret;
276
277     /* Test calling GetClipRgn with NULL device context and region handles. */
278     ret = GetClipRgn(NULL, NULL);
279     ok(ret == -1, "Expected GetClipRgn to return -1, got %d\n", ret);
280
281     hdc = GetDC(NULL);
282     ok(hdc != NULL, "Expected GetDC to return a valid device context handle\n");
283
284     /* Test calling GetClipRgn with a valid device context and NULL region. */
285     ret = GetClipRgn(hdc, NULL);
286     ok(ret == 0 ||
287        ret == -1 /* Win9x */,
288        "Expected GetClipRgn to return 0, got %d\n", ret);
289
290     /* Initialize the test regions. */
291     hrgn = CreateRectRgn(100, 100, 100, 100);
292     ok(hrgn != NULL,
293        "Expected CreateRectRgn to return a handle to a new rectangular region\n");
294
295     hrgn2 = CreateRectRgn(1, 2, 3, 4);
296     ok(hrgn2 != NULL,
297        "Expected CreateRectRgn to return a handle to a new rectangular region\n");
298
299     hrgn3 = CreateRectRgn(1, 2, 3, 4);
300     ok(hrgn3 != NULL,
301        "Expected CreateRectRgn to return a handle to a new rectangular region\n");
302
303     hrgn4 = CreateRectRgn(1, 2, 3, 4);
304     ok(hrgn4 != NULL,
305        "Expected CreateRectRgn to return a handle to a new rectangular region\n");
306
307     /* Try getting a clipping region from the device context
308      * when the device context's clipping region isn't set. */
309     ret = GetClipRgn(hdc, hrgn2);
310     ok(ret == 0, "Expected GetClipRgn to return 0, got %d\n", ret);
311
312     /* The region passed to GetClipRgn should be unchanged. */
313     ret = EqualRgn(hrgn2, hrgn3);
314     ok(ret == 1,
315        "Expected EqualRgn to compare the two regions as equal, got %d\n", ret);
316
317     /* Try setting and getting back a clipping region. */
318     ret = SelectClipRgn(hdc, hrgn);
319     ok(ret == NULLREGION,
320        "Expected SelectClipRgn to return NULLREGION, got %d\n", ret);
321
322     /* Passing a NULL region handle when the device context
323      * has a clipping region results in an error. */
324     ret = GetClipRgn(hdc, NULL);
325     ok(ret == -1, "Expected GetClipRgn to return -1, got %d\n", ret);
326
327     ret = GetClipRgn(hdc, hrgn2);
328     ok(ret == 1, "Expected GetClipRgn to return 1, got %d\n", ret);
329
330     ret = EqualRgn(hrgn, hrgn2);
331     ok(ret == 1,
332        "Expected EqualRgn to compare the two regions as equal, got %d\n", ret);
333
334     /* Try unsetting and then query the clipping region. */
335     ret = SelectClipRgn(hdc, NULL);
336     ok(ret == SIMPLEREGION,
337        "Expected SelectClipRgn to return SIMPLEREGION, got %d\n", ret);
338
339     ret = GetClipRgn(hdc, NULL);
340     ok(ret == 0 ||
341        ret == -1 /* Win9x */,
342        "Expected GetClipRgn to return 0, got %d\n", ret);
343
344     ret = GetClipRgn(hdc, hrgn3);
345     ok(ret == 0, "Expected GetClipRgn to return 0, got %d\n", ret);
346
347     ret = EqualRgn(hrgn3, hrgn4);
348     ok(ret == 1,
349        "Expected EqualRgn to compare the two regions as equal, got %d\n", ret);
350
351     DeleteObject(hrgn4);
352     DeleteObject(hrgn3);
353     DeleteObject(hrgn2);
354     DeleteObject(hrgn);
355     ReleaseDC(NULL, hdc);
356 }
357
358 static void test_memory_dc_clipping(void)
359 {
360     HDC hdc;
361     HRGN hrgn, hrgn_empty;
362     HBITMAP hbmp;
363     RECT rc;
364     int ret;
365
366     hdc = CreateCompatibleDC(0);
367     hrgn_empty = CreateRectRgn(0, 0, 0, 0);
368     hrgn = CreateRectRgn(0, 0, 0, 0);
369     hbmp = CreateCompatibleBitmap(hdc, 100, 100);
370
371     ret = GetClipRgn(hdc, hrgn);
372     ok(ret == 0, "expected 0, got %d\n", ret);
373
374     ret = ExtSelectClipRgn(hdc, hrgn_empty, RGN_DIFF);
375     ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
376
377     ret = GetClipRgn(hdc, hrgn);
378     ok(ret == 1, "expected 1, got %d\n", ret);
379
380     ret = GetRgnBox(hrgn, &rc);
381     ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
382     ok(rc.left == 0 && rc.top == 0 && rc.right == 1 && rc.bottom == 1,
383        "expected 0,0-1,1, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
384
385     ret = ExtSelectClipRgn(hdc, 0, RGN_COPY);
386     ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
387
388     ret = GetClipRgn(hdc, hrgn);
389     ok(ret == 0, "expected 0, got %d\n", ret);
390
391     SelectObject(hdc, hbmp);
392
393     ret = ExtSelectClipRgn(hdc, hrgn_empty, RGN_DIFF);
394     ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
395
396     ret = GetClipRgn(hdc, hrgn);
397     ok(ret == 1, "expected 1, got %d\n", ret);
398
399     ret = GetRgnBox(hrgn, &rc);
400     ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
401     ok(rc.left == 0 && rc.top == 0 && rc.right == 100 && rc.bottom == 100,
402        "expected 0,0-100,100, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
403
404     DeleteDC(hdc);
405     DeleteObject(hrgn);
406     DeleteObject(hrgn_empty);
407     DeleteObject(hbmp);
408 }
409
410 static void test_window_dc_clipping(void)
411 {
412     HDC hdc;
413     HRGN hrgn, hrgn_empty;
414     HWND hwnd;
415     RECT rc;
416     int ret, screen_width, screen_height;
417
418     /* Windows versions earlier than Win2k do not support the virtual screen metrics,
419      * so we fall back to the primary screen metrics. */
420     screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
421     if(!screen_width) screen_width = GetSystemMetrics(SM_CXSCREEN);
422     screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
423     if(!screen_height) screen_height = GetSystemMetrics(SM_CYSCREEN);
424
425     trace("screen resolution %d x %d\n", screen_width, screen_height);
426
427     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP,
428                            -100, -100, screen_width * 2, screen_height * 2, 0, 0, 0, NULL);
429     hdc = GetWindowDC(0);
430     hrgn_empty = CreateRectRgn(0, 0, 0, 0);
431     hrgn = CreateRectRgn(0, 0, 0, 0);
432
433     ret = GetClipRgn(hdc, hrgn);
434     ok(ret == 0, "expected 0, got %d\n", ret);
435
436     ret = ExtSelectClipRgn(hdc, hrgn_empty, RGN_DIFF);
437     ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
438
439     ret = GetClipRgn(hdc, hrgn);
440     ok(ret == 1, "expected 1, got %d\n", ret);
441
442     ret = GetRgnBox(hrgn, &rc);
443     ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
444     ok(rc.left == 0 && rc.top == 0 && rc.right == screen_width && rc.bottom == screen_height,
445        "expected 0,0-%d,%d, got %d,%d-%d,%d\n", screen_width, screen_height,
446         rc.left, rc.top, rc.right, rc.bottom);
447
448     ret = ExtSelectClipRgn(hdc, 0, RGN_COPY);
449     ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
450
451     ret = GetClipRgn(hdc, hrgn);
452     ok(ret == 0, "expected 0, got %d\n", ret);
453
454     DeleteDC(hdc);
455     DeleteObject(hrgn);
456     DeleteObject(hrgn_empty);
457     DestroyWindow(hwnd);
458 }
459
460
461 START_TEST(clipping)
462 {
463     test_GetRandomRgn();
464     test_ExtCreateRegion();
465     test_GetClipRgn();
466     test_memory_dc_clipping();
467     test_window_dc_clipping();
468 }