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