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