2 * Unit test suite for paths
4 * Copyright (C) 2007 Google (Evan Stade)
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.
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.
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
23 #include "wine/test.h"
26 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
27 #define expectf(expected, got) ok(fabs(expected - got) < 2.0, "Expected %.2f, got %.2f\n", expected, got)
28 #define POINT_TYPE_MAX_LEN (75)
30 static void stringify_point_type(PathPointType type, char * name)
34 switch(type & PathPointTypePathTypeMask){
35 case PathPointTypeStart:
36 strcat(name, "PathPointTypeStart");
38 case PathPointTypeLine:
39 strcat(name, "PathPointTypeLine");
41 case PathPointTypeBezier:
42 strcat(name, "PathPointTypeBezier");
45 strcat(name, "Unknown type");
49 type &= ~PathPointTypePathTypeMask;
50 if(type & ~((PathPointTypePathMarker | PathPointTypeCloseSubpath))){
52 strcat(name, "Unknown type");
56 if(type & PathPointTypePathMarker)
57 strcat(name, " | PathPointTypePathMarker");
58 if(type & PathPointTypeCloseSubpath)
59 strcat(name, " | PathPointTypeCloseSubpath");
62 /* this helper structure and function modeled after gdi path.c test */
68 /* How many extra entries before this one only on wine
69 * but not on native? */
70 int wine_only_entries_preceding;
72 /* 0 - This entry matches on wine.
73 * 1 - This entry corresponds to a single entry on wine that does not match the native entry.
74 * 2 - This entry is currently skipped on wine but present on native. */
78 static void ok_path(GpPath* path, const path_test_t *expected, INT expected_size, BOOL todo_size)
81 INT size, idx = 0, eidx = 0, numskip;
83 char ename[POINT_TYPE_MAX_LEN], name[POINT_TYPE_MAX_LEN];
85 if(GdipGetPointCount(path, &size) != Ok){
86 skip("Cannot perform path comparisons due to failure to retrieve path.\n");
90 if(todo_size) todo_wine
91 ok(size == expected_size, "Path size %d does not match expected size %d\n",
94 ok(size == expected_size, "Path size %d does not match expected size %d\n",
97 points = HeapAlloc(GetProcessHeap(), 0, size * sizeof(GpPointF));
98 types = HeapAlloc(GetProcessHeap(), 0, size);
100 if(GdipGetPathPoints(path, points, size) != Ok || GdipGetPathTypes(path, types, size) != Ok){
101 skip("Cannot perform path comparisons due to failure to retrieve path.\n");
105 numskip = expected_size ? expected[eidx].wine_only_entries_preceding : 0;
106 while (idx < size && eidx < expected_size){
107 /* We allow a few pixels fudge in matching X and Y coordinates to account for imprecision in
108 * floating point to integer conversion */
109 BOOL match = (types[idx] == expected[eidx].type) &&
110 fabs(points[idx].X - expected[eidx].X) <= 2.0 &&
111 fabs(points[idx].Y - expected[eidx].Y) <= 2.0;
113 stringify_point_type(expected[eidx].type, ename);
114 stringify_point_type(types[idx], name);
116 if (expected[eidx].todo || numskip) todo_wine
117 ok(match, "Expected #%d: %s (%.1f,%.1f) but got %s (%.1f,%.1f)\n", eidx,
118 ename, expected[eidx].X, expected[eidx].Y,
119 name, points[idx].X, points[idx].Y);
121 ok(match, "Expected #%d: %s (%.1f,%.1f) but got %s (%.1f,%.1f)\n", eidx,
122 ename, expected[eidx].X, expected[eidx].Y,
123 name, points[idx].X, points[idx].Y);
125 if (match || expected[eidx].todo != 2)
127 if (match || !numskip--)
128 numskip = expected[++eidx].wine_only_entries_preceding;
132 HeapFree(GetProcessHeap(), 0, types);
133 HeapFree(GetProcessHeap(), 0, points);
136 static void test_constructor_destructor(void)
141 status = GdipCreatePath(FillModeAlternate, &path);
143 ok(path != NULL, "Expected path to be initialized\n");
145 status = GdipDeletePath(NULL);
146 expect(InvalidParameter, status);
148 status = GdipDeletePath(path);
152 static path_test_t line2_path[] = {
153 {0.0, 50.0, PathPointTypeStart, 0, 0}, /*0*/
154 {5.0, 45.0, PathPointTypeLine, 0, 0}, /*1*/
155 {0.0, 40.0, PathPointTypeLine, 0, 0}, /*2*/
156 {15.0, 35.0, PathPointTypeLine, 0, 0}, /*3*/
157 {0.0, 30.0, PathPointTypeLine, 0, 0}, /*4*/
158 {25.0, 25.0, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*5*/
159 {0.0, 20.0, PathPointTypeStart, 0, 0}, /*6*/
160 {35.0, 15.0, PathPointTypeLine, 0, 0}, /*7*/
161 {0.0, 10.0, PathPointTypeLine, 0, 0} /*8*/
164 static void test_line2(void)
169 GpPointF line2_points[9];
171 for(i = 0; i < 9; i ++){
172 line2_points[i].X = i * 5.0 * (REAL)(i % 2);
173 line2_points[i].Y = 50.0 - i * 5.0;
176 GdipCreatePath(FillModeAlternate, &path);
177 status = GdipAddPathLine2(path, line2_points, 3);
179 status = GdipAddPathLine2(path, &(line2_points[3]), 3);
181 status = GdipClosePathFigure(path);
183 status = GdipAddPathLine2(path, &(line2_points[6]), 3);
186 ok_path(path, line2_path, sizeof(line2_path)/sizeof(path_test_t), FALSE);
189 static path_test_t arc_path[] = {
190 {600.0, 450.0, PathPointTypeStart, 0, 0}, /*0*/
191 {600.0, 643.3, PathPointTypeBezier, 0, 0}, /*1*/
192 {488.1, 800.0, PathPointTypeBezier, 0, 0}, /*2*/
193 {350.0, 800.0, PathPointTypeBezier, 0, 0}, /*3*/
194 {600.0, 450.0, PathPointTypeLine, 0, 0}, /*4*/
195 {600.0, 643.3, PathPointTypeBezier, 0, 0}, /*5*/
196 {488.1, 800.0, PathPointTypeBezier, 0, 0}, /*6*/
197 {350.0, 800.0, PathPointTypeBezier, 0, 0}, /*7*/
198 {329.8, 800.0, PathPointTypeBezier, 0, 0}, /*8*/
199 {309.7, 796.6, PathPointTypeBezier, 0, 0}, /*9*/
200 {290.1, 789.8, PathPointTypeBezier, 0, 0}, /*10*/
201 {409.9, 110.2, PathPointTypeLine, 0, 0}, /*11*/
202 {544.0, 156.5, PathPointTypeBezier, 0, 0}, /*12*/
203 {625.8, 346.2, PathPointTypeBezier, 0, 0}, /*13*/
204 {592.7, 533.9, PathPointTypeBezier, 0, 0}, /*14*/
205 {592.5, 535.3, PathPointTypeBezier, 0, 0}, /*15*/
206 {592.2, 536.7, PathPointTypeBezier, 0, 0}, /*16*/
207 {592.0, 538.1, PathPointTypeBezier, 0, 0}, /*17*/
208 {409.9, 789.8, PathPointTypeLine, 0, 0}, /*18*/
209 {544.0, 743.5, PathPointTypeBezier, 0, 0}, /*19*/
210 {625.8, 553.8, PathPointTypeBezier, 0, 0}, /*20*/
211 {592.7, 366.1, PathPointTypeBezier, 0, 0}, /*21*/
212 {592.5, 364.7, PathPointTypeBezier, 0, 0}, /*22*/
213 {592.2, 363.3, PathPointTypeBezier, 0, 0}, /*23*/
214 {592.0, 361.9, PathPointTypeBezier, 0, 0}, /*24*/
215 {540.4, 676.9, PathPointTypeLine, 0, 0}, /*25*/
216 {629.9, 529.7, PathPointTypeBezier, 0, 0}, /*26*/
217 {617.2, 308.8, PathPointTypeBezier, 0, 0}, /*27*/
218 {512.1, 183.5, PathPointTypeBezier, 0, 0}, /*28*/
219 {406.9, 58.2, PathPointTypeBezier, 0, 0}, /*29*/
220 {249.1, 75.9, PathPointTypeBezier, 0, 0}, /*30*/
221 {159.6, 223.1, PathPointTypeBezier, 0, 0}, /*31*/
222 {70.1, 370.3, PathPointTypeBezier, 0, 0}, /*32*/
223 {82.8, 591.2, PathPointTypeBezier, 0, 0}, /*33*/
224 {187.9, 716.5, PathPointTypeBezier, 0, 0}, /*34*/
225 {293.1, 841.8, PathPointTypeBezier, 0, 0}, /*35*/
226 {450.9, 824.1, PathPointTypeBezier, 0, 0}, /*36*/
227 {540.4, 676.9, PathPointTypeBezier, 0, 0} /*37*/
230 static void test_arc(void)
235 GdipCreatePath(FillModeAlternate, &path);
236 /* Exactly 90 degrees */
237 status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 90.0);
239 /* Over 90 degrees */
240 status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
242 /* Negative start angle */
243 status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, -80.0, 100.0);
245 /* Negative sweep angle */
246 status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 80.0, -100.0);
248 /* More than a full revolution */
249 status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 50.0, -400.0);
252 status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 50.0, 0.0);
255 ok_path(path, arc_path, sizeof(arc_path)/sizeof(path_test_t), FALSE);
258 static void test_worldbounds(void)
265 GpPointF line2_points[10];
268 for(i = 0; i < 10; i ++){
269 line2_points[i].X = 200.0 + i * 50.0 * (i % 2);
270 line2_points[i].Y = 200.0 + i * 50.0 * !(i % 2);
272 GdipCreatePen1((ARGB)0xdeadbeef, 20.0, UnitWorld, &pen);
273 GdipSetPenEndCap(pen, LineCapSquareAnchor);
274 GdipCreateMatrix2(1.5, 0.0, 1.0, 1.2, 10.4, 10.2, &matrix);
276 GdipCreatePath(FillModeAlternate, &path);
277 GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
278 GdipAddPathLine2(path, &(line2_points[0]), 10);
279 status = GdipGetPathWorldBounds(path, &bounds, NULL, NULL);
281 GdipDeletePath(path);
283 expectf(200.0, bounds.X);
284 expectf(200.0, bounds.Y);
285 expectf(450.0, bounds.Width);
286 expectf(600.0, bounds.Height);
288 GdipCreatePath(FillModeAlternate, &path);
289 GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
290 GdipAddPathLine2(path, &(line2_points[0]), 10);
291 status = GdipGetPathWorldBounds(path, &bounds, matrix, NULL);
293 GdipDeletePath(path);
295 expectf(510.4, bounds.X);
296 expectf(250.2, bounds.Y);
297 expectf(1275.0, bounds.Width);
298 expectf(720.0, bounds.Height);
300 GdipCreatePath(FillModeAlternate, &path);
301 GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
302 GdipAddPathLine2(path, &(line2_points[0]), 10);
303 status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
305 GdipDeletePath(path);
307 expectf(100.0, bounds.X);
308 expectf(100.0, bounds.Y);
309 expectf(650.0, bounds.Width);
310 expectf(800.0, bounds.Height);
312 GdipCreatePath(FillModeAlternate, &path);
313 GdipAddPathLine2(path, &(line2_points[0]), 2);
314 status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
316 GdipDeletePath(path);
318 expectf(156.0, bounds.X);
319 expectf(156.0, bounds.Y);
320 expectf(138.0, bounds.Width);
321 expectf(88.0, bounds.Height);
323 line2_points[2].X = 2 * line2_points[1].X - line2_points[0].X;
324 line2_points[2].Y = 2 * line2_points[1].Y - line2_points[0].Y;
326 GdipCreatePath(FillModeAlternate, &path);
327 GdipAddPathLine2(path, &(line2_points[0]), 3);
328 status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
330 GdipDeletePath(path);
332 expectf(100.0, bounds.X);
333 expectf(100.0, bounds.Y);
334 expectf(300.0, bounds.Width);
335 expectf(200.0, bounds.Height);
337 GdipCreatePath(FillModeAlternate, &path);
338 GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 45.0, 20.0);
339 status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
341 GdipDeletePath(path);
343 expectf(386.7, bounds.X);
344 expectf(553.4, bounds.Y);
345 expectf(266.8, bounds.Width);
346 expectf(289.6, bounds.Height);
348 GdipCreatePath(FillModeAlternate, &path);
349 status = GdipGetPathWorldBounds(path, &bounds, matrix, pen);
351 GdipDeletePath(path);
353 expectf(0.0, bounds.X);
354 expectf(0.0, bounds.Y);
355 expectf(0.0, bounds.Width);
356 expectf(0.0, bounds.Height);
358 GdipCreatePath(FillModeAlternate, &path);
359 GdipAddPathLine2(path, &(line2_points[0]), 2);
360 status = GdipGetPathWorldBounds(path, &bounds, matrix, pen);
362 GdipDeletePath(path);
365 expectf(427.9, bounds.X);
366 expectf(167.7, bounds.Y);
367 expectf(239.9, bounds.Width);
368 expectf(164.9, bounds.Height);
371 GdipDeleteMatrix(matrix);
372 GdipCreateMatrix2(0.9, -0.5, -0.5, -1.2, 10.4, 10.2, &matrix);
373 GdipCreatePath(FillModeAlternate, &path);
374 GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
375 GdipAddPathLine2(path, &(line2_points[0]), 10);
376 status = GdipGetPathWorldBounds(path, &bounds, matrix, NULL);
378 GdipDeletePath(path);
380 expectf(-209.6, bounds.X);
381 expectf(-1274.8, bounds.Y);
382 expectf(705.0, bounds.Width);
383 expectf(945.0, bounds.Height);
386 static path_test_t pathpath_path[] = {
387 {600.00, 450.00, PathPointTypeStart, 0, 0}, /*0*/
388 {600.00, 643.30, PathPointTypeBezier, 0, 0}, /*1*/
389 {488.07, 800.00, PathPointTypeBezier, 0, 0}, /*2*/
390 {350.00, 800.00, PathPointTypeBezier, 0, 0}, /*3*/
391 {319.61, 797.40, PathPointTypeStart, 0, 0}, /*4*/
392 {182.56, 773.90, PathPointTypeBezier, 0, 0}, /*5*/
393 {85.07, 599.31, PathPointTypeBezier, 0, 0}, /*6*/
394 {101.85, 407.45, PathPointTypeBezier, 0, 0}, /*7*/
395 {102.54, 399.66, PathPointTypeBezier, 0, 0}, /*8*/
396 {103.40, 391.91, PathPointTypeBezier, 0, 0}, /*9*/
397 {104.46, 384.21, PathPointTypeBezier, 0, 0}, /*10*/
398 {409.92, 110.20, PathPointTypeLine, 0, 0}, /*11*/
399 {543.96, 156.53, PathPointTypeBezier, 0, 0}, /*12*/
400 {625.80, 346.22, PathPointTypeBezier, 0, 0}, /*13*/
401 {592.71, 533.88, PathPointTypeBezier, 0, 0}, /*14*/
402 {592.47, 535.28, PathPointTypeBezier, 0, 0}, /*15*/
403 {592.22, 536.67, PathPointTypeBezier, 0, 0}, /*16*/
404 {591.96, 538.06, PathPointTypeBezier, 0, 0}, /*17*/
405 {319.61, 797.40, PathPointTypeLine, 0, 0}, /*18*/
406 {182.56, 773.90, PathPointTypeBezier, 0, 0}, /*19*/
407 {85.07, 599.31, PathPointTypeBezier, 0, 0}, /*20*/
408 {101.85, 407.45, PathPointTypeBezier, 0, 0}, /*21*/
409 {102.54, 399.66, PathPointTypeBezier, 0, 0}, /*22*/
410 {103.40, 391.91, PathPointTypeBezier, 0, 0}, /*23*/
411 {104.46, 384.21, PathPointTypeBezier, 0, 0} /*24*/
414 static void test_pathpath(void)
417 GpPath* path1, *path2;
419 GdipCreatePath(FillModeAlternate, &path2);
420 GdipAddPathArc(path2, 100.0, 100.0, 500.0, 700.0, 95.0, 100.0);
422 GdipCreatePath(FillModeAlternate, &path1);
423 GdipAddPathArc(path1, 100.0, 100.0, 500.0, 700.0, 0.0, 90.0);
424 status = GdipAddPathPath(path1, path2, FALSE);
426 GdipAddPathArc(path1, 100.0, 100.0, 500.0, 700.0, -80.0, 100.0);
427 status = GdipAddPathPath(path1, path2, TRUE);
430 ok_path(path1, pathpath_path, sizeof(pathpath_path)/sizeof(path_test_t), FALSE);
432 GdipDeletePath(path1);
433 GdipDeletePath(path2);
436 static path_test_t ellipse_path[] = {
437 {30.00, 125.25, PathPointTypeStart, 0, 0}, /*0*/
438 {30.00, 139.20, PathPointTypeBezier, 0, 0}, /*1*/
439 {25.52, 150.50, PathPointTypeBezier, 0, 0}, /*2*/
440 {20.00, 150.50, PathPointTypeBezier, 0, 0}, /*3*/
441 {14.48, 150.50, PathPointTypeBezier, 0, 0}, /*4*/
442 {10.00, 139.20, PathPointTypeBezier, 0, 0}, /*5*/
443 {10.00, 125.25, PathPointTypeBezier, 0, 0}, /*6*/
444 {10.00, 111.30, PathPointTypeBezier, 0, 0}, /*7*/
445 {14.48, 100.00, PathPointTypeBezier, 0, 0}, /*8*/
446 {20.00, 100.00, PathPointTypeBezier, 0, 0}, /*9*/
447 {25.52, 100.00, PathPointTypeBezier, 0, 0}, /*10*/
448 {30.00, 111.30, PathPointTypeBezier, 0, 0}, /*11*/
449 {30.00, 125.25, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0}, /*12*/
450 {7.00, 11.00, PathPointTypeStart, 0, 0}, /*13*/
451 {13.00, 17.00, PathPointTypeLine, 0, 1}, /*14*/
452 {5.00, 195.00, PathPointTypeStart, 0, 1}, /*15*/
453 {5.00, 192.24, PathPointTypeBezier, 0, 1}, /*16*/
454 {6.12, 190.00, PathPointTypeBezier, 0, 1}, /*17*/
455 {7.50, 190.00, PathPointTypeBezier, 0, 1}, /*18*/
456 {8.88, 190.00, PathPointTypeBezier, 0, 1}, /*19*/
457 {10.00, 192.24, PathPointTypeBezier, 0, 1}, /*20*/
458 {10.00, 195.00, PathPointTypeBezier, 0, 1}, /*21*/
459 {10.00, 197.76, PathPointTypeBezier, 0, 1}, /*22*/
460 {8.88, 200.00, PathPointTypeBezier, 0, 1}, /*23*/
461 {7.50, 200.00, PathPointTypeBezier, 0, 1}, /*24*/
462 {6.12, 200.00, PathPointTypeBezier, 0, 1}, /*25*/
463 {5.00, 197.76, PathPointTypeBezier, 0, 1}, /*26*/
464 {5.00, 195.00, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 1}, /*27*/
465 {10.00, 300.50, PathPointTypeStart, 0, 0}, /*28*/
466 {10.00, 300.78, PathPointTypeBezier, 0, 0}, /*29*/
467 {10.00, 301.00, PathPointTypeBezier, 0, 0}, /*30*/
468 {10.00, 301.00, PathPointTypeBezier, 0, 0}, /*31*/
469 {10.00, 301.00, PathPointTypeBezier, 0, 0}, /*32*/
470 {10.00, 300.78, PathPointTypeBezier, 0, 0}, /*33*/
471 {10.00, 300.50, PathPointTypeBezier, 0, 0}, /*34*/
472 {10.00, 300.22, PathPointTypeBezier, 0, 0}, /*35*/
473 {10.00, 300.00, PathPointTypeBezier, 0, 0}, /*36*/
474 {10.00, 300.00, PathPointTypeBezier, 0, 0}, /*37*/
475 {10.00, 300.00, PathPointTypeBezier, 0, 0}, /*38*/
476 {10.00, 300.22, PathPointTypeBezier, 0, 0}, /*39*/
477 {10.00, 300.50, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0} /*40*/
480 static void test_ellipse(void)
491 GdipCreatePath(FillModeAlternate, &path);
492 status = GdipAddPathEllipse(path, 10.0, 100.0, 20.0, 50.5);
494 GdipAddPathLine2(path, points, 2);
495 status = GdipAddPathEllipse(path, 10.0, 200.0, -5.0, -10.0);
498 GdipClosePathFigure(path);
499 status = GdipAddPathEllipse(path, 10.0, 300.0, 0.0, 1.0);
502 ok_path(path, ellipse_path, sizeof(ellipse_path)/sizeof(path_test_t), TRUE);
504 GdipDeletePath(path);
507 START_TEST(graphicspath)
509 struct GdiplusStartupInput gdiplusStartupInput;
510 ULONG_PTR gdiplusToken;
512 gdiplusStartupInput.GdiplusVersion = 1;
513 gdiplusStartupInput.DebugEventCallback = NULL;
514 gdiplusStartupInput.SuppressBackgroundThread = 0;
515 gdiplusStartupInput.SuppressExternalCodecs = 0;
517 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
519 test_constructor_destructor();
526 GdiplusShutdown(gdiplusToken);