[GDIPLUS_WINETEST] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / modules / rostests / winetests / gdiplus / matrix.c
1 /*
2 * Unit test suite for matrices
3 *
4 * Copyright (C) 2007 Google (Evan Stade)
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 <math.h>
22 #include <limits.h>
23
24 #include "objbase.h"
25 #include "gdiplus.h"
26 #include "wine/test.h"
27
28 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
29 #define expectf(expected, got) ok(fabs(expected - got) < 0.0001, "Expected %.2f, got %.2f\n", expected, got)
30
31 static BOOL compare_float(float f, float g, unsigned int ulps)
32 {
33 int x = *(int *)&f;
34 int y = *(int *)&g;
35
36 if (x < 0)
37 x = INT_MIN - x;
38 if (y < 0)
39 y = INT_MIN - y;
40
41 if (abs(x - y) > ulps)
42 return FALSE;
43
44 return TRUE;
45 }
46
47 static void test_constructor_destructor(void)
48 {
49 GpStatus status;
50 GpMatrix *matrix = NULL;
51
52 status = GdipCreateMatrix2(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, &matrix);
53 expect(Ok, status);
54 ok(matrix != NULL, "Expected matrix to be initialized\n");
55
56 status = GdipDeleteMatrix(NULL);
57 expect(InvalidParameter, status);
58
59 status = GdipDeleteMatrix(matrix);
60 expect(Ok, status);
61 }
62
63 typedef struct{
64 REAL X;
65 REAL Y;
66 } real_point;
67
68 static real_point transform_points[] = {
69 {1000.00, 2600.00}, /*0*/
70 {855.00, 2390.00}, /*1*/
71 {700.00, 2200.00}, /*2*/
72 {565.00, 1970.00}, /*3*/
73 {400.00, 1800.00}, /*4*/
74 {275.00, 1550.00}, /*5*/
75 {100.00, 1400.00}, /*6*/
76 {-15.00, 1130.00}, /*7*/
77 {-200.00, 1000.00}, /*8*/
78 {-305.00, 710.00} /*9*/
79 };
80
81 static void test_transform(void)
82 {
83 GpStatus status;
84 GpMatrix *matrix = NULL;
85 GpPointF pts[10];
86 INT i;
87 BOOL match;
88
89 for(i = 0; i < 10; i ++){
90 pts[i].X = i * 5.0 * (REAL)(i % 2);
91 pts[i].Y = 50.0 - i * 5.0;
92 }
93
94 GdipCreateMatrix2(1.0, -2.0, 30.0, 40.0, -500.0, 600.0, &matrix);
95
96 status = GdipTransformMatrixPoints(matrix, pts, 0);
97 expect(InvalidParameter, status);
98
99 status = GdipTransformMatrixPoints(matrix, pts, 10);
100 expect(Ok, status);
101
102 for(i = 0; i < 10; i ++){
103 match = fabs(transform_points[i].X - pts[i].X) < 2.0
104 && fabs(transform_points[i].Y - pts[i].Y) < 2.0;
105
106 ok(match, "Expected #%d to be (%.2f, %.2f) but got (%.2f, %.2f)\n", i,
107 transform_points[i].X, transform_points[i].Y, pts[i].X, pts[i].Y);
108 }
109
110 GdipDeleteMatrix(matrix);
111 }
112
113 static void test_isinvertible(void)
114 {
115 GpStatus status;
116 GpMatrix *matrix = NULL;
117 BOOL result;
118
119 /* NULL arguments */
120 status = GdipIsMatrixInvertible(NULL, &result);
121 expect(InvalidParameter, status);
122 status = GdipIsMatrixInvertible((GpMatrix*)0xdeadbeef, NULL);
123 expect(InvalidParameter, status);
124 status = GdipIsMatrixInvertible(NULL, NULL);
125 expect(InvalidParameter, status);
126
127 /* invertible */
128 GdipCreateMatrix2(1.0, 1.2, 2.3, -1.0, 2.0, 3.0, &matrix);
129 status = GdipIsMatrixInvertible(matrix, &result);
130 expect(Ok, status);
131 expect(TRUE, result);
132 GdipDeleteMatrix(matrix);
133
134 /* noninvertible */
135 GdipCreateMatrix2(2.0, -1.0, 6.0, -3.0, 2.2, 3.0, &matrix);
136 status = GdipIsMatrixInvertible(matrix, &result);
137 expect(Ok, status);
138 expect(FALSE, result);
139 GdipDeleteMatrix(matrix);
140 }
141
142 static void test_invert(void)
143 {
144 GpStatus status;
145 GpMatrix *matrix = NULL;
146 GpMatrix *inverted = NULL;
147 BOOL equal = FALSE;
148 REAL elems[6];
149
150 /* NULL */
151 status = GdipInvertMatrix(NULL);
152 expect(InvalidParameter, status);
153
154 /* noninvertible */
155 GdipCreateMatrix2(2.0, -1.0, 6.0, -3.0, 2.2, 3.0, &matrix);
156 status = GdipInvertMatrix(matrix);
157 expect(InvalidParameter, status);
158 GdipDeleteMatrix(matrix);
159
160 /* invertible */
161 GdipCreateMatrix2(3.0, -2.0, 5.0, 2.0, 6.0, 3.0, &matrix);
162 status = GdipInvertMatrix(matrix);
163 expect(Ok, status);
164 GdipCreateMatrix2(2.0/16.0, 2.0/16.0, -5.0/16.0, 3.0/16.0, 3.0/16.0, -21.0/16.0, &inverted);
165 GdipIsMatrixEqual(matrix, inverted, &equal);
166 expect(TRUE, equal);
167 GdipDeleteMatrix(matrix);
168
169 GdipCreateMatrix2(0.0006, 0, 0, 0.0006, 400, 400, &matrix);
170 status = GdipInvertMatrix(matrix);
171 expect(Ok, status);
172 status = GdipGetMatrixElements(matrix, elems);
173 expect(Ok, status);
174 ok(compare_float(elems[0], 1666.666504, 1), "elems[0] = %.10g\n", elems[0]);
175 ok(compare_float(elems[1], 0, 0), "elems[1] = %.10g\n", elems[1]);
176 ok(compare_float(elems[2], 0, 0), "elems[2] = %.10g\n", elems[2]);
177 ok(compare_float(elems[3], 1666.666504, 1), "elems[3] = %.10g\n", elems[3]);
178 ok(compare_float(elems[4], -666666.6875, 1), "elems[4] = %.10g\n", elems[4]);
179 ok(compare_float(elems[5], -666666.6875, 1), "elems[5] = %.10g\n", elems[5]);
180
181 GdipDeleteMatrix(inverted);
182 GdipDeleteMatrix(matrix);
183 }
184
185 static void test_shear(void)
186 {
187 GpStatus status;
188 GpMatrix *matrix = NULL;
189 GpMatrix *sheared = NULL;
190 BOOL equal;
191
192 /* NULL */
193 status = GdipShearMatrix(NULL, 0.0, 0.0, MatrixOrderPrepend);
194 expect(InvalidParameter, status);
195
196 /* X only shearing, MatrixOrderPrepend */
197 GdipCreateMatrix2(1.0, 2.0, 4.0, -1.0, 6.0, 3.0, &matrix);
198 status = GdipShearMatrix(matrix, 1.5, 0.0, MatrixOrderPrepend);
199 expect(Ok, status);
200 GdipCreateMatrix2(1.0, 2.0, 5.5, 2.0, 6.0, 3.0, &sheared);
201 GdipIsMatrixEqual(matrix, sheared, &equal);
202 expect(TRUE, equal);
203 GdipDeleteMatrix(sheared);
204 GdipDeleteMatrix(matrix);
205
206 /* X only shearing, MatrixOrderAppend */
207 GdipCreateMatrix2(1.0, 2.0, 4.0, -1.0, 6.0, 3.0, &matrix);
208 status = GdipShearMatrix(matrix, 1.5, 0.0, MatrixOrderAppend);
209 expect(Ok, status);
210 GdipCreateMatrix2(4.0, 2.0, 2.5, -1.0, 10.5, 3.0, &sheared);
211 GdipIsMatrixEqual(matrix, sheared, &equal);
212 expect(TRUE, equal);
213 GdipDeleteMatrix(sheared);
214 GdipDeleteMatrix(matrix);
215
216 /* Y only shearing, MatrixOrderPrepend */
217 GdipCreateMatrix2(1.0, 2.0, 4.0, -1.0, 6.0, 3.0, &matrix);
218 status = GdipShearMatrix(matrix, 0.0, 1.5, MatrixOrderPrepend);
219 expect(Ok, status);
220 GdipCreateMatrix2(7.0, 0.5, 4.0, -1.0, 6.0, 3.0, &sheared);
221 GdipIsMatrixEqual(matrix, sheared, &equal);
222 expect(TRUE, equal);
223 GdipDeleteMatrix(sheared);
224 GdipDeleteMatrix(matrix);
225
226 /* Y only shearing, MatrixOrderAppend */
227 GdipCreateMatrix2(1.0, 2.0, 4.0, -1.0, 6.0, 3.0, &matrix);
228 status = GdipShearMatrix(matrix, 0.0, 1.5, MatrixOrderAppend);
229 expect(Ok, status);
230 GdipCreateMatrix2(1.0, 3.5, 4.0, 5.0, 6.0, 12.0, &sheared);
231 GdipIsMatrixEqual(matrix, sheared, &equal);
232 expect(TRUE, equal);
233 GdipDeleteMatrix(sheared);
234 GdipDeleteMatrix(matrix);
235
236 /* X,Y shearing, MatrixOrderPrepend */
237 GdipCreateMatrix2(1.0, 2.0, 4.0, -1.0, 6.0, 3.0, &matrix);
238 status = GdipShearMatrix(matrix, 4.0, 1.5, MatrixOrderPrepend);
239 expect(Ok, status);
240 GdipCreateMatrix2(7.0, 0.5, 8.0, 7.0, 6.0, 3.0, &sheared);
241 GdipIsMatrixEqual(matrix, sheared, &equal);
242 expect(TRUE, equal);
243 GdipDeleteMatrix(sheared);
244 GdipDeleteMatrix(matrix);
245
246 /* X,Y shearing, MatrixOrderAppend */
247 GdipCreateMatrix2(1.0, 2.0, 4.0, -1.0, 6.0, 3.0, &matrix);
248 status = GdipShearMatrix(matrix, 4.0, 1.5, MatrixOrderAppend);
249 expect(Ok, status);
250 GdipCreateMatrix2(9.0, 3.5, 0.0, 5.0, 18.0, 12.0, &sheared);
251 GdipIsMatrixEqual(matrix, sheared, &equal);
252 expect(TRUE, equal);
253 GdipDeleteMatrix(sheared);
254 GdipDeleteMatrix(matrix);
255 }
256
257 static void test_constructor3(void)
258 {
259 /* MSDN is on crack. GdipCreateMatrix3 makes a matrix that transforms the
260 * corners of the given rectangle to the three points given. */
261 GpMatrix *matrix;
262 REAL values[6];
263 GpRectF rc;
264 GpPointF pt[3];
265 GpStatus stat;
266
267 rc.X = 10;
268 rc.Y = 10;
269 rc.Width = 10;
270 rc.Height = 10;
271
272 pt[0].X = 10;
273 pt[0].Y = 10;
274 pt[1].X = 20;
275 pt[1].Y = 10;
276 pt[2].X = 10;
277 pt[2].Y = 20;
278
279 stat = GdipCreateMatrix3(&rc, pt, &matrix);
280 expect(Ok, stat);
281
282 stat = GdipGetMatrixElements(matrix, values);
283 expect(Ok, stat);
284
285 expectf(1.0, values[0]);
286 expectf(0.0, values[1]);
287 expectf(0.0, values[2]);
288 expectf(1.0, values[3]);
289 expectf(0.0, values[4]);
290 expectf(0.0, values[5]);
291
292 GdipDeleteMatrix(matrix);
293
294 pt[0].X = 20;
295 pt[0].Y = 10;
296 pt[1].X = 40;
297 pt[1].Y = 10;
298 pt[2].X = 20;
299 pt[2].Y = 20;
300
301 stat = GdipCreateMatrix3(&rc, pt, &matrix);
302 expect(Ok, stat);
303
304 stat = GdipGetMatrixElements(matrix, values);
305 expect(Ok, stat);
306
307 expectf(2.0, values[0]);
308 expectf(0.0, values[1]);
309 expectf(0.0, values[2]);
310 expectf(1.0, values[3]);
311 expectf(0.0, values[4]);
312 expectf(0.0, values[5]);
313
314 GdipDeleteMatrix(matrix);
315
316 pt[0].X = 10;
317 pt[0].Y = 20;
318 pt[1].X = 20;
319 pt[1].Y = 30;
320 pt[2].X = 10;
321 pt[2].Y = 30;
322
323 stat = GdipCreateMatrix3(&rc, pt, &matrix);
324 expect(Ok, stat);
325
326 stat = GdipGetMatrixElements(matrix, values);
327 expect(Ok, stat);
328
329 expectf(1.0, values[0]);
330 expectf(1.0, values[1]);
331 expectf(0.0, values[2]);
332 expectf(1.0, values[3]);
333 expectf(0.0, values[4]);
334 expectf(0.0, values[5]);
335
336 GdipDeleteMatrix(matrix);
337 }
338
339 static void test_isidentity(void)
340 {
341 GpMatrix *matrix;
342 GpStatus stat;
343 BOOL result;
344
345 stat = GdipIsMatrixIdentity(NULL, NULL);
346 expect(InvalidParameter, stat);
347
348 stat = GdipIsMatrixIdentity(NULL, &result);
349 expect(InvalidParameter, stat);
350
351 stat = GdipCreateMatrix2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, &matrix);
352 expect(Ok, stat);
353
354 stat = GdipIsMatrixIdentity(matrix, NULL);
355 expect(InvalidParameter, stat);
356
357 result = FALSE;
358 stat = GdipIsMatrixIdentity(matrix, &result);
359 expect(Ok, stat);
360 ok(!!result, "got %d\n", result);
361
362 stat = GdipSetMatrixElements(matrix, 1.0, 0.0, 0.0, 1.0, 0.1, 0.0);
363 expect(Ok, stat);
364
365 result = TRUE;
366 stat = GdipIsMatrixIdentity(matrix, &result);
367 expect(Ok, stat);
368 ok(!result, "got %d\n", result);
369
370 GdipDeleteMatrix(matrix);
371 }
372
373 START_TEST(matrix)
374 {
375 struct GdiplusStartupInput gdiplusStartupInput;
376 ULONG_PTR gdiplusToken;
377 HMODULE hmsvcrt;
378 int (CDECL * _controlfp_s)(unsigned int *cur, unsigned int newval, unsigned int mask);
379
380 /* Enable all FP exceptions except _EM_INEXACT, which gdi32 can trigger */
381 hmsvcrt = LoadLibraryA("msvcrt");
382 _controlfp_s = (void*)GetProcAddress(hmsvcrt, "_controlfp_s");
383 if (_controlfp_s) _controlfp_s(0, 0, 0x0008001e);
384
385 gdiplusStartupInput.GdiplusVersion = 1;
386 gdiplusStartupInput.DebugEventCallback = NULL;
387 gdiplusStartupInput.SuppressBackgroundThread = 0;
388 gdiplusStartupInput.SuppressExternalCodecs = 0;
389
390 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
391
392 test_constructor_destructor();
393 test_transform();
394 test_isinvertible();
395 test_invert();
396 test_shear();
397 test_constructor3();
398 test_isidentity();
399
400 GdiplusShutdown(gdiplusToken);
401 }