gdi32: Add a couple of SetGraphicsMode/SetWorldTransform tests, make them pass under...
[wine] / dlls / gdi32 / tests / mapping.c
1 /*
2  * Unit tests for mapping functions
3  *
4  * Copyright (c) 2005 Huw Davies
5  * Copyright (c) 2008 Dmitry  Timoshkov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <assert.h>
23 #include <stdio.h>
24 #include <math.h>
25
26 #include "wine/test.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winerror.h"
31
32 #define rough_match(got, expected) (abs((got) - (expected)) <= 5)
33
34 #define expect_LPtoDP(_hdc, _x, _y) \
35 { \
36     POINT _pt = { 1000, 1000 }; \
37     LPtoDP(_hdc, &_pt, 1); \
38     ok(rough_match(_pt.x, _x), "expected x %d, got %d\n", (_x), _pt.x); \
39     ok(rough_match(_pt.y, _y), "expected y %d, got %d\n", (_y), _pt.y); \
40 }
41
42 #define expect_world_trasform(_hdc, _em11, _em22) \
43 { \
44     BOOL _ret; \
45     XFORM _xform; \
46     SetLastError(0xdeadbeef); \
47     _ret = GetWorldTransform(_hdc, &_xform); \
48     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) \
49     { \
50         ok(_ret, "GetWorldTransform error %u\n", GetLastError()); \
51         ok(_xform.eM11 == (_em11), "expected %f, got %f\n", (_em11), _xform.eM11); \
52         ok(_xform.eM12 == 0.0, "expected 0.0, got %f\n", _xform.eM12); \
53         ok(_xform.eM21 == 0.0, "expected 0.0, got %f\n", _xform.eM21); \
54         ok(_xform.eM22 == (_em22), "expected %f, got %f\n", (_em22), _xform.eM22); \
55         ok(_xform.eDx == 0.0, "expected 0.0, got %f\n", _xform.eDx); \
56         ok(_xform.eDy == 0.0, "expected 0.0, got %f\n", _xform.eDy); \
57     } \
58 }
59
60 #define expect_dc_ext(_func, _hdc, _cx, _cy) \
61 { \
62     BOOL _ret; \
63     SIZE _size; \
64     SetLastError(0xdeadbeef); \
65     _ret = _func(_hdc, &_size); \
66     ok(_ret, #_func " error %u\n", GetLastError()); \
67     ok(_size.cx == (_cx), "expected cx %d, got %d\n", (_cx), _size.cx); \
68     ok(_size.cy == (_cy), "expected cy %d, got %d\n", (_cy), _size.cy); \
69 }
70
71 #define expect_viewport_ext(_hdc, _cx, _cy) expect_dc_ext(GetViewportExtEx, _hdc, _cx, _cy)
72 #define expect_window_ext(_hdc, _cx, _cy)  expect_dc_ext(GetWindowExtEx, _hdc, _cx, _cy)
73
74 static void test_world_transform(void)
75 {
76     BOOL is_win9x;
77     HDC hdc;
78     INT ret, size_cx, size_cy, res_x, res_y, dpi_x, dpi_y;
79     XFORM xform;
80     SIZE size;
81
82     SetLastError(0xdeadbeef);
83     GetWorldTransform(0, NULL);
84     is_win9x = GetLastError() == ERROR_CALL_NOT_IMPLEMENTED;
85
86     hdc = CreateCompatibleDC(0);
87
88     xform.eM11 = 1.0f;
89     xform.eM12 = 0.0f;
90     xform.eM21 = 0.0f;
91     xform.eM22 = 1.0f;
92     xform.eDx = 0.0f;
93     xform.eDy = 0.0f;
94     ret = SetWorldTransform(hdc, &xform);
95     ok(!ret, "SetWorldTransform should fail in GM_COMPATIBLE mode\n");
96
97     size_cx = GetDeviceCaps(hdc, HORZSIZE);
98     size_cy = GetDeviceCaps(hdc, VERTSIZE);
99     res_x = GetDeviceCaps(hdc, HORZRES);
100     res_y = GetDeviceCaps(hdc, VERTRES);
101     dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
102     dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
103     trace("dc size %d x %d, resolution %d x %d dpi %d x %d\n",
104           size_cx, size_cy, res_x, res_y, dpi_x, dpi_y );
105
106     expect_viewport_ext(hdc, 1, 1);
107     expect_window_ext(hdc, 1, 1);
108     expect_world_trasform(hdc, 1.0, 1.0);
109     expect_LPtoDP(hdc, 1000, 1000);
110
111     SetLastError(0xdeadbeef);
112     ret = SetMapMode(hdc, MM_LOMETRIC);
113     ok(ret == MM_TEXT, "expected MM_TEXT, got %d\n", ret);
114
115     if (is_win9x)
116     {
117         expect_viewport_ext(hdc, dpi_x, dpi_y);
118         expect_window_ext(hdc, 254, -254);
119     }
120     else
121     {
122         expect_viewport_ext(hdc, res_x, -res_y);
123         ok( GetWindowExtEx( hdc, &size ), "GetWindowExtEx failed\n" );
124         ok( size.cx == size_cx * 10 ||
125             size.cx == MulDiv( res_x, 254, dpi_x ),  /* Vista uses a more precise method */
126             "expected cx %d or %d, got %d\n", size_cx * 10, MulDiv( res_x, 254, dpi_x ), size.cx );
127         ok( size.cy == size_cy * 10 ||
128             size.cy == MulDiv( res_y, 254, dpi_y ),  /* Vista uses a more precise method */
129             "expected cy %d or %d, got %d\n", size_cy * 10, MulDiv( res_y, 254, dpi_y ), size.cy );
130     }
131     expect_world_trasform(hdc, 1.0, 1.0);
132     expect_LPtoDP(hdc, MulDiv(1000 / 10, res_x, size_cx), -MulDiv(1000 / 10, res_y, size_cy));
133
134     SetLastError(0xdeadbeef);
135     ret = SetMapMode(hdc, MM_TEXT);
136     ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d\n", ret);
137
138     expect_viewport_ext(hdc, 1, 1);
139     expect_window_ext(hdc, 1, 1);
140     expect_world_trasform(hdc, 1.0, 1.0);
141     expect_LPtoDP(hdc, 1000, 1000);
142
143     ret = SetGraphicsMode(hdc, GM_ADVANCED);
144     if (!ret)
145     {
146         DeleteDC(hdc);
147         skip("GM_ADVANCED is not supported on this platform\n");
148         return;
149     }
150
151     expect_viewport_ext(hdc, 1, 1);
152     expect_window_ext(hdc, 1, 1);
153     expect_world_trasform(hdc, 1.0, 1.0);
154     expect_LPtoDP(hdc, 1000, 1000);
155
156     /* The transform must conform to (eM11 * eM22 != eM12 * eM21) requirement */
157     xform.eM11 = 1.0f;
158     xform.eM12 = 2.0f;
159     xform.eM21 = 1.0f;
160     xform.eM22 = 2.0f;
161     xform.eDx = 0.0f;
162     xform.eDy = 0.0f;
163     ret = SetWorldTransform(hdc, &xform);
164     ok(!ret, "SetWorldTransform should fail with an invalid xform\n");
165
166     xform.eM11 = 20.0f;
167     xform.eM12 = 0.0f;
168     xform.eM21 = 0.0f;
169     xform.eM22 = 20.0f;
170     xform.eDx = 0.0f;
171     xform.eDy = 0.0f;
172     SetLastError(0xdeadbeef);
173     ret = SetWorldTransform(hdc, &xform);
174     ok(ret, "SetWorldTransform error %u\n", GetLastError());
175
176     expect_viewport_ext(hdc, 1, 1);
177     expect_window_ext(hdc, 1, 1);
178     expect_world_trasform(hdc, 20.0, 20.0);
179     expect_LPtoDP(hdc, 20000, 20000);
180
181     SetLastError(0xdeadbeef);
182     ret = SetMapMode(hdc, MM_LOMETRIC);
183     ok(ret == MM_TEXT, "expected MM_TEXT, got %d\n", ret);
184
185     expect_viewport_ext(hdc, res_x, -res_y);
186     ok( GetWindowExtEx( hdc, &size ), "GetWindowExtEx failed\n" );
187     ok( size.cx == size_cx * 10 ||
188         size.cx == MulDiv( res_x, 254, dpi_x ),  /* Vista uses a more precise method */
189         "expected cx %d or %d, got %d\n", size_cx * 10, MulDiv( res_x, 254, dpi_x ), size.cx );
190     ok( size.cy == size_cy * 10 ||
191         size.cy == MulDiv( res_y, 254, dpi_y ),  /* Vista uses a more precise method */
192         "expected cy %d or %d, got %d\n", size_cy * 10, MulDiv( res_y, 254, dpi_y ), size.cy );
193     expect_world_trasform(hdc, 20.0, 20.0);
194     expect_LPtoDP(hdc, MulDiv(20000, res_x, size.cx), -MulDiv(20000, res_y, size.cy));
195
196     SetLastError(0xdeadbeef);
197     ret = SetMapMode(hdc, MM_TEXT);
198     ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d\n", ret);
199
200     expect_viewport_ext(hdc, 1, 1);
201     expect_window_ext(hdc, 1, 1);
202     expect_world_trasform(hdc, 20.0, 20.0);
203     expect_LPtoDP(hdc, 20000, 20000);
204
205     ret = SetGraphicsMode(hdc, GM_COMPATIBLE);
206     ok(ret, "SetGraphicsMode(GM_COMPATIBLE) should not fail if DC has't an identity transform\n");
207     ret = GetGraphicsMode(hdc);
208     ok(ret == GM_COMPATIBLE, "expected GM_COMPATIBLE, got %d\n", ret);
209
210     expect_viewport_ext(hdc, 1, 1);
211     expect_window_ext(hdc, 1, 1);
212     expect_world_trasform(hdc, 20.0, 20.0);
213     expect_LPtoDP(hdc, 20000, 20000);
214
215     DeleteDC(hdc);
216 }
217
218 static void test_modify_world_transform(void)
219 {
220     HDC hdc = GetDC(0);
221     int ret;
222
223     ret = SetGraphicsMode(hdc, GM_ADVANCED);
224     if(!ret) /* running in win9x so quit */
225     {
226         ReleaseDC(0, hdc);
227         skip("GM_ADVANCED is not supported on this platform\n");
228         return;
229     }
230
231     ret = ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
232     ok(ret, "ret = %d\n", ret);
233
234     ret = ModifyWorldTransform(hdc, NULL, MWT_LEFTMULTIPLY);
235     ok(!ret, "ret = %d\n", ret);
236
237     ret = ModifyWorldTransform(hdc, NULL, MWT_RIGHTMULTIPLY);
238     ok(!ret, "ret = %d\n", ret);
239
240     ReleaseDC(0, hdc);
241 }
242
243 static void test_SetWindowExt(HDC hdc, LONG cx, LONG cy, LONG expected_vp_cx, LONG expected_vp_cy)
244 {
245     SIZE windowExt, viewportExt;
246     POINT windowOrg, windowOrgAfter, viewportOrg, viewportOrgAfter;
247
248     GetWindowOrgEx(hdc, &windowOrg);
249     GetViewportOrgEx(hdc, &viewportOrg);
250
251     SetWindowExtEx(hdc, cx, cy, NULL);
252     GetWindowExtEx(hdc, &windowExt);
253     ok(windowExt.cx == cx && windowExt.cy == cy,
254        "Window extension: Expected %dx%d, got %dx%d\n",
255        cx, cy, windowExt.cx, windowExt.cy);
256
257     GetViewportExtEx(hdc, &viewportExt);
258     ok(rough_match(viewportExt.cx, expected_vp_cx) && rough_match(viewportExt.cy, expected_vp_cy),
259         "Viewport extents have not been properly adjusted: Expected %dx%d, got %dx%d\n",
260         expected_vp_cx, expected_vp_cy, viewportExt.cx, viewportExt.cy);
261
262     GetWindowOrgEx(hdc, &windowOrgAfter);
263     ok(windowOrg.x == windowOrgAfter.x && windowOrg.y == windowOrgAfter.y,
264         "Window origin changed from (%d,%d) to (%d,%d)\n",
265         windowOrg.x, windowOrg.y, windowOrgAfter.x, windowOrgAfter.y);
266
267     GetViewportOrgEx(hdc, &viewportOrgAfter);
268     ok(viewportOrg.x == viewportOrgAfter.x && viewportOrg.y == viewportOrgAfter.y,
269         "Viewport origin changed from (%d,%d) to (%d,%d)\n",
270         viewportOrg.x, viewportOrg.y, viewportOrgAfter.x, viewportOrgAfter.y);
271 }
272
273 static void test_SetViewportExt(HDC hdc, LONG cx, LONG cy, LONG expected_vp_cx, LONG expected_vp_cy)
274 {
275     SIZE windowExt, windowExtAfter, viewportExt;
276     POINT windowOrg, windowOrgAfter, viewportOrg, viewportOrgAfter;
277
278     GetWindowOrgEx(hdc, &windowOrg);
279     GetViewportOrgEx(hdc, &viewportOrg);
280     GetWindowExtEx(hdc, &windowExt);
281
282     SetViewportExtEx(hdc, cx, cy, NULL);
283     GetViewportExtEx(hdc, &viewportExt);
284     ok(rough_match(viewportExt.cx, expected_vp_cx) && rough_match(viewportExt.cy, expected_vp_cy),
285         "Viewport extents have not been properly adjusted: Expected %dx%d, got %dx%d\n",
286         expected_vp_cx, expected_vp_cy, viewportExt.cx, viewportExt.cy);
287
288     GetWindowExtEx(hdc, &windowExtAfter);
289     ok(windowExt.cx == windowExtAfter.cx && windowExt.cy == windowExtAfter.cy,
290        "Window extension changed from %dx%d to %dx%d\n",
291        windowExt.cx, windowExt.cy, windowExtAfter.cx, windowExtAfter.cy);
292
293     GetWindowOrgEx(hdc, &windowOrgAfter);
294     ok(windowOrg.x == windowOrgAfter.x && windowOrg.y == windowOrgAfter.y,
295         "Window origin changed from (%d,%d) to (%d,%d)\n",
296         windowOrg.x, windowOrg.y, windowOrgAfter.x, windowOrgAfter.y);
297
298     GetViewportOrgEx(hdc, &viewportOrgAfter);
299     ok(viewportOrg.x == viewportOrgAfter.x && viewportOrg.y == viewportOrgAfter.y,
300         "Viewport origin changed from (%d,%d) to (%d,%d)\n",
301         viewportOrg.x, viewportOrg.y, viewportOrgAfter.x, viewportOrgAfter.y);
302 }
303
304 static void test_isotropic_mapping(void)
305 {
306     SIZE win, vp;
307     HDC hdc = GetDC(0);
308     
309     SetMapMode(hdc, MM_ISOTROPIC);
310     
311     /* MM_ISOTROPIC is set up like MM_LOMETRIC.
312        Initial values after SetMapMode():
313        (1 inch = 25.4 mm)
314        
315                        Windows 9x:               Windows NT:
316        Window Ext:     254 x -254                HORZSIZE*10 x VERTSIZE*10
317        Viewport Ext:   LOGPIXELSX x LOGPIXELSY   HORZRES x -VERTRES
318        
319        To test without rounding errors, we have to use multiples of
320        these values!
321      */
322     
323     GetWindowExtEx(hdc, &win);
324     GetViewportExtEx(hdc, &vp);
325     
326     test_SetViewportExt(hdc, 10 * vp.cx, 10 * vp.cy, 10 * vp.cx, 10 * vp.cy);
327     test_SetWindowExt(hdc, win.cx, win.cy, 10 * vp.cx, 10 * vp.cy);
328     test_SetWindowExt(hdc, 2 * win.cx, win.cy, 10 * vp.cx, 5 * vp.cy);
329     test_SetWindowExt(hdc, win.cx, win.cy, 5 * vp.cx, 5 * vp.cy);
330     test_SetViewportExt(hdc, 4 * vp.cx, 2 * vp.cy, 2 * vp.cx, 2 * vp.cy);
331     test_SetViewportExt(hdc, vp.cx, 2 * vp.cy, vp.cx, vp.cy);
332     test_SetViewportExt(hdc, 2 * vp.cx, 2 * vp.cy, 2 * vp.cx, 2 * vp.cy);
333     test_SetViewportExt(hdc, 4 * vp.cx, 2 * vp.cy, 2 * vp.cx, 2 * vp.cy);
334     test_SetWindowExt(hdc, 4 * win.cx, 2 * win.cy, 2 * vp.cx, vp.cy);
335     test_SetViewportExt(hdc, -2 * vp.cx, -4 * vp.cy, -2 * vp.cx, -vp.cy);
336     test_SetViewportExt(hdc, -2 * vp.cx, -1 * vp.cy, -2 * vp.cx, -vp.cy);    
337     test_SetWindowExt(hdc, -4 * win.cx, -2 * win.cy, -2 * vp.cx, -vp.cy);
338     test_SetWindowExt(hdc, 4 * win.cx, -4 * win.cy, -vp.cx, -vp.cy);
339     
340     ReleaseDC(0, hdc);
341 }
342
343 START_TEST(mapping)
344 {
345     test_modify_world_transform();
346     test_world_transform();
347     test_isotropic_mapping();
348 }