gdiplus: Fix parameter order in expect() calls.
[wine] / dlls / gdiplus / tests / graphicspath.c
1 /*
2  * Unit test suite for paths
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 "windows.h"
22 #include "gdiplus.h"
23 #include "wine/test.h"
24 #include <math.h>
25
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)
29
30 static void stringify_point_type(PathPointType type, char * name)
31 {
32     *name = '\0';
33
34     switch(type & PathPointTypePathTypeMask){
35         case PathPointTypeStart:
36             strcat(name, "PathPointTypeStart");
37             break;
38         case PathPointTypeLine:
39             strcat(name, "PathPointTypeLine");
40             break;
41         case PathPointTypeBezier:
42             strcat(name, "PathPointTypeBezier");
43             break;
44         default:
45             strcat(name, "Unknown type");
46             return;
47     }
48
49     type &= ~PathPointTypePathTypeMask;
50     if(type & ~((PathPointTypePathMarker | PathPointTypeCloseSubpath))){
51         *name = '\0';
52         strcat(name, "Unknown type");
53         return;
54     }
55
56     if(type & PathPointTypePathMarker)
57         strcat(name, " | PathPointTypePathMarker");
58     if(type & PathPointTypeCloseSubpath)
59         strcat(name, " | PathPointTypeCloseSubpath");
60 }
61
62 /* this helper structure and function modeled after gdi path.c test */
63 typedef struct
64 {
65     REAL X, Y;
66     BYTE type;
67
68     /* How many extra entries before this one only on wine
69      * but not on native? */
70     int wine_only_entries_preceding;
71
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. */
75     int todo;
76 } path_test_t;
77
78 static void ok_path(GpPath* path, const path_test_t *expected, INT expected_size, BOOL todo_size)
79 {
80     BYTE * types;
81     INT size, idx = 0, eidx = 0, numskip;
82     GpPointF * points;
83     char ename[POINT_TYPE_MAX_LEN], name[POINT_TYPE_MAX_LEN];
84
85     if(GdipGetPointCount(path, &size) != Ok){
86         skip("Cannot perform path comparisons due to failure to retrieve path.\n");
87         return;
88     }
89
90     if(todo_size) todo_wine
91         ok(size == expected_size, "Path size %d does not match expected size %d\n",
92             size, expected_size);
93     else
94         ok(size == expected_size, "Path size %d does not match expected size %d\n",
95             size, expected_size);
96
97     points = HeapAlloc(GetProcessHeap(), 0, size * sizeof(GpPointF));
98     types = HeapAlloc(GetProcessHeap(), 0, size);
99
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");
102         goto end;
103     }
104
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;
112
113         stringify_point_type(expected[eidx].type, ename);
114         stringify_point_type(types[idx], name);
115
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);
120         else
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);
124
125         if (match || expected[eidx].todo != 2)
126             idx++;
127         if (match || !numskip--)
128             numskip = expected[++eidx].wine_only_entries_preceding;
129     }
130
131 end:
132     HeapFree(GetProcessHeap(), 0, types);
133     HeapFree(GetProcessHeap(), 0, points);
134 }
135
136 static void test_constructor_destructor(void)
137 {
138     GpStatus status;
139     GpPath* path = NULL;
140
141     status = GdipCreatePath(FillModeAlternate, &path);
142     expect(Ok, status);
143     ok(path != NULL, "Expected path to be initialized\n");
144
145     status = GdipDeletePath(NULL);
146     expect(InvalidParameter, status);
147
148     status = GdipDeletePath(path);
149     expect(Ok, status);
150 }
151
152 static void test_getpathdata(void)
153 {
154     GpPath *path;
155     GpPathData data;
156     GpStatus status;
157     INT count;
158
159     GdipCreatePath(FillModeAlternate, &path);
160     status = GdipAddPathLine(path, 5.0, 5.0, 100.0, 50.0);
161     expect(Ok, status);
162
163     /* Prepare storage. Made by wrapper class. */
164     status = GdipGetPointCount(path, &count);
165     expect(Ok, status);
166
167     data.Count  = 2;
168     data.Types  = GdipAlloc(sizeof(BYTE) * count);
169     data.Points = GdipAlloc(sizeof(PointF) * count);
170
171     status = GdipGetPathData(path, &data);
172     expect(Ok, status);
173     expect((data.Points[0].X == 5.0) && (data.Points[0].Y == 5.0) &&
174            (data.Points[1].X == 100.0) && (data.Points[1].Y == 50.0), TRUE);
175     expect((data.Types[0] == PathPointTypeStart) && (data.Types[1] == PathPointTypeLine), TRUE);
176
177     GdipFree(data.Points);
178     GdipFree(data.Types);
179     GdipDeletePath(path);
180 }
181
182 static path_test_t line2_path[] = {
183     {0.0, 50.0, PathPointTypeStart, 0, 0}, /*0*/
184     {5.0, 45.0, PathPointTypeLine, 0, 0}, /*1*/
185     {0.0, 40.0, PathPointTypeLine, 0, 0}, /*2*/
186     {15.0, 35.0, PathPointTypeLine, 0, 0}, /*3*/
187     {0.0, 30.0, PathPointTypeLine, 0, 0}, /*4*/
188     {25.0, 25.0, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*5*/
189     {0.0, 20.0, PathPointTypeStart, 0, 0}, /*6*/
190     {35.0, 15.0, PathPointTypeLine, 0, 0}, /*7*/
191     {0.0, 10.0, PathPointTypeLine, 0, 0} /*8*/
192     };
193
194 static void test_line2(void)
195 {
196     GpStatus status;
197     GpPath* path;
198     int i;
199     GpPointF line2_points[9];
200
201     for(i = 0; i < 9; i ++){
202         line2_points[i].X = i * 5.0 * (REAL)(i % 2);
203         line2_points[i].Y = 50.0 - i * 5.0;
204     }
205
206     GdipCreatePath(FillModeAlternate, &path);
207     status = GdipAddPathLine2(path, line2_points, 3);
208     expect(Ok, status);
209     status = GdipAddPathLine2(path, &(line2_points[3]), 3);
210     expect(Ok, status);
211     status = GdipClosePathFigure(path);
212     expect(Ok, status);
213     status = GdipAddPathLine2(path, &(line2_points[6]), 3);
214     expect(Ok, status);
215
216     ok_path(path, line2_path, sizeof(line2_path)/sizeof(path_test_t), FALSE);
217
218     GdipDeletePath(path);
219 }
220
221 static path_test_t arc_path[] = {
222     {600.0, 450.0, PathPointTypeStart, 0, 0}, /*0*/
223     {600.0, 643.3, PathPointTypeBezier, 0, 0}, /*1*/
224     {488.1, 800.0, PathPointTypeBezier, 0, 0}, /*2*/
225     {350.0, 800.0, PathPointTypeBezier, 0, 0}, /*3*/
226     {600.0, 450.0, PathPointTypeLine, 0, 0}, /*4*/
227     {600.0, 643.3, PathPointTypeBezier, 0, 0}, /*5*/
228     {488.1, 800.0, PathPointTypeBezier, 0, 0}, /*6*/
229     {350.0, 800.0, PathPointTypeBezier, 0, 0}, /*7*/
230     {329.8, 800.0, PathPointTypeBezier, 0, 0}, /*8*/
231     {309.7, 796.6, PathPointTypeBezier, 0, 0}, /*9*/
232     {290.1, 789.8, PathPointTypeBezier, 0, 0}, /*10*/
233     {409.9, 110.2, PathPointTypeLine, 0, 0}, /*11*/
234     {544.0, 156.5, PathPointTypeBezier, 0, 0}, /*12*/
235     {625.8, 346.2, PathPointTypeBezier, 0, 0}, /*13*/
236     {592.7, 533.9, PathPointTypeBezier, 0, 0}, /*14*/
237     {592.5, 535.3, PathPointTypeBezier, 0, 0}, /*15*/
238     {592.2, 536.7, PathPointTypeBezier, 0, 0}, /*16*/
239     {592.0, 538.1, PathPointTypeBezier, 0, 0}, /*17*/
240     {409.9, 789.8, PathPointTypeLine, 0, 0}, /*18*/
241     {544.0, 743.5, PathPointTypeBezier, 0, 0}, /*19*/
242     {625.8, 553.8, PathPointTypeBezier, 0, 0}, /*20*/
243     {592.7, 366.1, PathPointTypeBezier, 0, 0}, /*21*/
244     {592.5, 364.7, PathPointTypeBezier, 0, 0}, /*22*/
245     {592.2, 363.3, PathPointTypeBezier, 0, 0}, /*23*/
246     {592.0, 361.9, PathPointTypeBezier, 0, 0}, /*24*/
247     {540.4, 676.9, PathPointTypeLine, 0, 0}, /*25*/
248     {629.9, 529.7, PathPointTypeBezier, 0, 0}, /*26*/
249     {617.2, 308.8, PathPointTypeBezier, 0, 0}, /*27*/
250     {512.1, 183.5, PathPointTypeBezier, 0, 0}, /*28*/
251     {406.9, 58.2, PathPointTypeBezier, 0, 0}, /*29*/
252     {249.1, 75.9, PathPointTypeBezier, 0, 0}, /*30*/
253     {159.6, 223.1, PathPointTypeBezier, 0, 0}, /*31*/
254     {70.1, 370.3, PathPointTypeBezier, 0, 0}, /*32*/
255     {82.8, 591.2, PathPointTypeBezier, 0, 0}, /*33*/
256     {187.9, 716.5, PathPointTypeBezier, 0, 0}, /*34*/
257     {293.1, 841.8, PathPointTypeBezier, 0, 0}, /*35*/
258     {450.9, 824.1, PathPointTypeBezier, 0, 0}, /*36*/
259     {540.4, 676.9, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 1} /*37*/
260     };
261
262 static void test_arc(void)
263 {
264     GpStatus status;
265     GpPath* path;
266
267     GdipCreatePath(FillModeAlternate, &path);
268     /* Exactly 90 degrees */
269     status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 90.0);
270     expect(Ok, status);
271     /* Over 90 degrees */
272     status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
273     expect(Ok, status);
274     /* Negative start angle */
275     status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, -80.0, 100.0);
276     expect(Ok, status);
277     /* Negative sweep angle */
278     status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 80.0, -100.0);
279     expect(Ok, status);
280     /* More than a full revolution */
281     status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 50.0, -400.0);
282     expect(Ok, status);
283     /* 0 sweep angle */
284     status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 50.0, 0.0);
285     expect(Ok, status);
286
287     ok_path(path, arc_path, sizeof(arc_path)/sizeof(path_test_t), FALSE);
288
289     GdipDeletePath(path);
290 }
291
292 static void test_worldbounds(void)
293 {
294     GpStatus status;
295     GpPath *path;
296     GpPen *pen;
297     GpMatrix *matrix;
298     GpRectF bounds;
299     GpPointF line2_points[10];
300     int i;
301
302     for(i = 0; i < 10; i ++){
303         line2_points[i].X = 200.0 + i * 50.0 * (i % 2);
304         line2_points[i].Y = 200.0 + i * 50.0 * !(i % 2);
305     }
306     GdipCreatePen1((ARGB)0xdeadbeef, 20.0, UnitWorld, &pen);
307     GdipSetPenEndCap(pen, LineCapSquareAnchor);
308     GdipCreateMatrix2(1.5, 0.0, 1.0, 1.2, 10.4, 10.2, &matrix);
309
310     GdipCreatePath(FillModeAlternate, &path);
311     GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
312     GdipAddPathLine2(path, &(line2_points[0]), 10);
313     status = GdipGetPathWorldBounds(path, &bounds, NULL, NULL);
314     expect(Ok, status);
315     GdipDeletePath(path);
316
317     expectf(200.0, bounds.X);
318     expectf(200.0, bounds.Y);
319     expectf(450.0, bounds.Width);
320     expectf(600.0, bounds.Height);
321
322     GdipCreatePath(FillModeAlternate, &path);
323     GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
324     GdipAddPathLine2(path, &(line2_points[0]), 10);
325     status = GdipGetPathWorldBounds(path, &bounds, matrix, NULL);
326     expect(Ok, status);
327     GdipDeletePath(path);
328
329     expectf(510.4, bounds.X);
330     expectf(250.2, bounds.Y);
331     expectf(1275.0, bounds.Width);
332     expectf(720.0, bounds.Height);
333
334     GdipCreatePath(FillModeAlternate, &path);
335     GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
336     GdipAddPathLine2(path, &(line2_points[0]), 10);
337     status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
338     expect(Ok, status);
339     GdipDeletePath(path);
340
341     expectf(100.0, bounds.X);
342     expectf(100.0, bounds.Y);
343     expectf(650.0, bounds.Width);
344     expectf(800.0, bounds.Height);
345
346     GdipCreatePath(FillModeAlternate, &path);
347     GdipAddPathLine2(path, &(line2_points[0]), 2);
348     status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
349     expect(Ok, status);
350     GdipDeletePath(path);
351
352     expectf(156.0, bounds.X);
353     expectf(156.0, bounds.Y);
354     expectf(138.0, bounds.Width);
355     expectf(88.0, bounds.Height);
356
357     line2_points[2].X = 2 * line2_points[1].X - line2_points[0].X;
358     line2_points[2].Y = 2 * line2_points[1].Y - line2_points[0].Y;
359
360     GdipCreatePath(FillModeAlternate, &path);
361     GdipAddPathLine2(path, &(line2_points[0]), 3);
362     status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
363     expect(Ok, status);
364     GdipDeletePath(path);
365
366     expectf(100.0, bounds.X);
367     expectf(100.0, bounds.Y);
368     expectf(300.0, bounds.Width);
369     expectf(200.0, bounds.Height);
370
371     GdipCreatePath(FillModeAlternate, &path);
372     GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 45.0, 20.0);
373     status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
374     expect(Ok, status);
375     GdipDeletePath(path);
376
377     expectf(386.7, bounds.X);
378     expectf(553.4, bounds.Y);
379     expectf(266.8, bounds.Width);
380     expectf(289.6, bounds.Height);
381
382     GdipCreatePath(FillModeAlternate, &path);
383     status = GdipGetPathWorldBounds(path, &bounds, matrix, pen);
384     expect(Ok, status);
385     GdipDeletePath(path);
386
387     expectf(0.0, bounds.X);
388     expectf(0.0, bounds.Y);
389     expectf(0.0, bounds.Width);
390     expectf(0.0, bounds.Height);
391
392     GdipCreatePath(FillModeAlternate, &path);
393     GdipAddPathLine2(path, &(line2_points[0]), 2);
394     status = GdipGetPathWorldBounds(path, &bounds, matrix, pen);
395     expect(Ok, status);
396     GdipDeletePath(path);
397
398     todo_wine{
399         expectf(427.9, bounds.X);
400         expectf(167.7, bounds.Y);
401         expectf(239.9, bounds.Width);
402         expectf(164.9, bounds.Height);
403     }
404
405     GdipDeleteMatrix(matrix);
406     GdipCreateMatrix2(0.9, -0.5, -0.5, -1.2, 10.4, 10.2, &matrix);
407     GdipCreatePath(FillModeAlternate, &path);
408     GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
409     GdipAddPathLine2(path, &(line2_points[0]), 10);
410     status = GdipGetPathWorldBounds(path, &bounds, matrix, NULL);
411     expect(Ok, status);
412     GdipDeletePath(path);
413     GdipDeleteMatrix(matrix);
414
415     expectf(-209.6, bounds.X);
416     expectf(-1274.8, bounds.Y);
417     expectf(705.0, bounds.Width);
418     expectf(945.0, bounds.Height);
419
420     GdipDeletePen(pen);
421 }
422
423 static path_test_t pathpath_path[] = {
424     {600.00, 450.00, PathPointTypeStart, 0, 0}, /*0*/
425     {600.00, 643.30, PathPointTypeBezier, 0, 0}, /*1*/
426     {488.07, 800.00, PathPointTypeBezier, 0, 0}, /*2*/
427     {350.00, 800.00, PathPointTypeBezier, 0, 0}, /*3*/
428     {319.61, 797.40, PathPointTypeStart, 0, 0}, /*4*/
429     {182.56, 773.90, PathPointTypeBezier, 0, 0}, /*5*/
430     {85.07, 599.31, PathPointTypeBezier, 0, 0}, /*6*/
431     {101.85, 407.45, PathPointTypeBezier, 0, 0}, /*7*/
432     {102.54, 399.66, PathPointTypeBezier, 0, 0}, /*8*/
433     {103.40, 391.91, PathPointTypeBezier, 0, 0}, /*9*/
434     {104.46, 384.21, PathPointTypeBezier, 0, 0}, /*10*/
435     {409.92, 110.20, PathPointTypeLine, 0, 0}, /*11*/
436     {543.96, 156.53, PathPointTypeBezier, 0, 0}, /*12*/
437     {625.80, 346.22, PathPointTypeBezier, 0, 0}, /*13*/
438     {592.71, 533.88, PathPointTypeBezier, 0, 0}, /*14*/
439     {592.47, 535.28, PathPointTypeBezier, 0, 0}, /*15*/
440     {592.22, 536.67, PathPointTypeBezier, 0, 0}, /*16*/
441     {591.96, 538.06, PathPointTypeBezier, 0, 0}, /*17*/
442     {319.61, 797.40, PathPointTypeLine, 0, 0}, /*18*/
443     {182.56, 773.90, PathPointTypeBezier, 0, 0}, /*19*/
444     {85.07, 599.31, PathPointTypeBezier, 0, 0}, /*20*/
445     {101.85, 407.45, PathPointTypeBezier, 0, 0}, /*21*/
446     {102.54, 399.66, PathPointTypeBezier, 0, 0}, /*22*/
447     {103.40, 391.91, PathPointTypeBezier, 0, 0}, /*23*/
448     {104.46, 384.21, PathPointTypeBezier, 0, 0} /*24*/
449     };
450
451 static void test_pathpath(void)
452 {
453     GpStatus status;
454     GpPath* path1, *path2;
455
456     GdipCreatePath(FillModeAlternate, &path2);
457     GdipAddPathArc(path2, 100.0, 100.0, 500.0, 700.0, 95.0, 100.0);
458
459     GdipCreatePath(FillModeAlternate, &path1);
460     GdipAddPathArc(path1, 100.0, 100.0, 500.0, 700.0, 0.0, 90.0);
461     status = GdipAddPathPath(path1, path2, FALSE);
462     expect(Ok, status);
463     GdipAddPathArc(path1, 100.0, 100.0, 500.0, 700.0, -80.0, 100.0);
464     status = GdipAddPathPath(path1, path2, TRUE);
465     expect(Ok, status);
466
467     ok_path(path1, pathpath_path, sizeof(pathpath_path)/sizeof(path_test_t), FALSE);
468
469     GdipDeletePath(path1);
470     GdipDeletePath(path2);
471 }
472
473 static path_test_t ellipse_path[] = {
474     {30.00, 125.25, PathPointTypeStart, 0, 0}, /*0*/
475     {30.00, 139.20, PathPointTypeBezier, 0, 0}, /*1*/
476     {25.52, 150.50, PathPointTypeBezier, 0, 0}, /*2*/
477     {20.00, 150.50, PathPointTypeBezier, 0, 0}, /*3*/
478     {14.48, 150.50, PathPointTypeBezier, 0, 0}, /*4*/
479     {10.00, 139.20, PathPointTypeBezier, 0, 0}, /*5*/
480     {10.00, 125.25, PathPointTypeBezier, 0, 0}, /*6*/
481     {10.00, 111.30, PathPointTypeBezier, 0, 0}, /*7*/
482     {14.48, 100.00, PathPointTypeBezier, 0, 0}, /*8*/
483     {20.00, 100.00, PathPointTypeBezier, 0, 0}, /*9*/
484     {25.52, 100.00, PathPointTypeBezier, 0, 0}, /*10*/
485     {30.00, 111.30, PathPointTypeBezier, 0, 0}, /*11*/
486     {30.00, 125.25, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0}, /*12*/
487     {7.00, 11.00, PathPointTypeStart, 0, 0}, /*13*/
488     {13.00, 17.00, PathPointTypeLine, 0, 0}, /*14*/
489     {5.00, 195.00, PathPointTypeStart, 0, 0}, /*15*/
490     {5.00, 192.24, PathPointTypeBezier, 0, 0}, /*16*/
491     {6.12, 190.00, PathPointTypeBezier, 0, 0}, /*17*/
492     {7.50, 190.00, PathPointTypeBezier, 0, 0}, /*18*/
493     {8.88, 190.00, PathPointTypeBezier, 0, 0}, /*19*/
494     {10.00, 192.24, PathPointTypeBezier, 0, 0}, /*20*/
495     {10.00, 195.00, PathPointTypeBezier, 0, 0}, /*21*/
496     {10.00, 197.76, PathPointTypeBezier, 0, 0}, /*22*/
497     {8.88, 200.00, PathPointTypeBezier, 0, 0}, /*23*/
498     {7.50, 200.00, PathPointTypeBezier, 0, 0}, /*24*/
499     {6.12, 200.00, PathPointTypeBezier, 0, 0}, /*25*/
500     {5.00, 197.76, PathPointTypeBezier, 0, 0}, /*26*/
501     {5.00, 195.00, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0}, /*27*/
502     {10.00, 300.50, PathPointTypeStart, 0, 0}, /*28*/
503     {10.00, 300.78, PathPointTypeBezier, 0, 0}, /*29*/
504     {10.00, 301.00, PathPointTypeBezier, 0, 0}, /*30*/
505     {10.00, 301.00, PathPointTypeBezier, 0, 0}, /*31*/
506     {10.00, 301.00, PathPointTypeBezier, 0, 0}, /*32*/
507     {10.00, 300.78, PathPointTypeBezier, 0, 0}, /*33*/
508     {10.00, 300.50, PathPointTypeBezier, 0, 0}, /*34*/
509     {10.00, 300.22, PathPointTypeBezier, 0, 0}, /*35*/
510     {10.00, 300.00, PathPointTypeBezier, 0, 0}, /*36*/
511     {10.00, 300.00, PathPointTypeBezier, 0, 0}, /*37*/
512     {10.00, 300.00, PathPointTypeBezier, 0, 0}, /*38*/
513     {10.00, 300.22, PathPointTypeBezier, 0, 0}, /*39*/
514     {10.00, 300.50, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0} /*40*/
515     };
516
517 static void test_ellipse(void)
518 {
519     GpStatus status;
520     GpPath *path;
521     GpPointF points[2];
522
523     points[0].X = 7.0;
524     points[0].Y = 11.0;
525     points[1].X = 13.0;
526     points[1].Y = 17.0;
527
528     GdipCreatePath(FillModeAlternate, &path);
529     status = GdipAddPathEllipse(path, 10.0, 100.0, 20.0, 50.5);
530     expect(Ok, status);
531     GdipAddPathLine2(path, points, 2);
532     status = GdipAddPathEllipse(path, 10.0, 200.0, -5.0, -10.0);
533     expect(Ok, status);
534     GdipClosePathFigure(path);
535     status = GdipAddPathEllipse(path, 10.0, 300.0, 0.0, 1.0);
536     expect(Ok, status);
537
538     ok_path(path, ellipse_path, sizeof(ellipse_path)/sizeof(path_test_t), FALSE);
539
540     GdipDeletePath(path);
541 }
542
543 static path_test_t linei_path[] = {
544     {5.00, 5.00, PathPointTypeStart, 0, 0}, /*0*/
545     {6.00, 8.00, PathPointTypeLine, 0, 0}, /*1*/
546     {409.92, 110.20, PathPointTypeLine, 0, 0}, /*2*/
547     {543.96, 156.53, PathPointTypeBezier, 0, 0}, /*3*/
548     {625.80, 346.22, PathPointTypeBezier, 0, 0}, /*4*/
549     {592.71, 533.88, PathPointTypeBezier, 0, 0}, /*5*/
550     {592.47, 535.28, PathPointTypeBezier, 0, 0}, /*6*/
551     {592.22, 536.67, PathPointTypeBezier, 0, 0}, /*7*/
552     {591.96, 538.06, PathPointTypeBezier, 0, 0}, /*8*/
553     {15.00, 15.00, PathPointTypeLine, 0, 0}, /*9*/
554     {26.00, 28.00, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*10*/
555     {35.00, 35.00, PathPointTypeStart, 0, 0}, /*11*/
556     {36.00, 38.00, PathPointTypeLine, 0, 0} /*12*/
557     };
558
559 static void test_linei(void)
560 {
561     GpStatus status;
562     GpPath *path;
563
564     GdipCreatePath(FillModeAlternate, &path);
565     status = GdipAddPathLineI(path, 5.0, 5.0, 6.0, 8.0);
566     expect(Ok, status);
567     GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, -80.0, 100.0);
568     status = GdipAddPathLineI(path, 15.0, 15.0, 26.0, 28.0);
569     expect(Ok, status);
570     GdipClosePathFigure(path);
571     status = GdipAddPathLineI(path, 35.0, 35.0, 36.0, 38.0);
572     expect(Ok, status);
573
574     ok_path(path, linei_path, sizeof(linei_path)/sizeof(path_test_t), FALSE);
575
576     GdipDeletePath(path);
577 }
578
579 static path_test_t poly_path[] = {
580     {5.00, 5.00, PathPointTypeStart, 0, 0},   /*1*/
581     {6.00, 8.00, PathPointTypeLine, 0, 0},    /*2*/
582     {0.00,  0.00,  PathPointTypeStart, 0, 0}, /*3*/
583     {10.00, 10.00, PathPointTypeLine, 0, 0},  /*4*/
584     {10.00, 20.00, PathPointTypeLine, 0, 0},  /*5*/
585     {30.00, 10.00, PathPointTypeLine, 0, 0},  /*6*/
586     {20.00, 0.00, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*7*/
587     };
588
589 static void test_polygon(void)
590 {
591     GpStatus status;
592     GpPath *path;
593     GpPointF points[5];
594
595     points[0].X = 0.0;
596     points[0].Y = 0.0;
597     points[1].X = 10.0;
598     points[1].Y = 10.0;
599     points[2].X = 10.0;
600     points[2].Y = 20.0;
601     points[3].X = 30.0;
602     points[3].Y = 10.0;
603     points[4].X = 20.0;
604     points[4].Y = 0.0;
605
606     GdipCreatePath(FillModeAlternate, &path);
607
608     /* NULL args */
609     status = GdipAddPathPolygon(NULL, points, 5);
610     expect(InvalidParameter, status);
611     status = GdipAddPathPolygon(path, NULL, 5);
612     expect(InvalidParameter, status);
613     /* Polygon should have 3 points at least */
614     status = GdipAddPathPolygon(path, points, 2);
615     expect(InvalidParameter, status);
616
617     /* to test how it prolongs not empty path */
618     status = GdipAddPathLine(path, 5.0, 5.0, 6.0, 8.0);
619     expect(Ok, status);
620     status = GdipAddPathPolygon(path, points, 5);
621     expect(Ok, status);
622     /* check resulting path */
623     ok_path(path, poly_path, sizeof(poly_path)/sizeof(path_test_t), FALSE);
624
625     GdipDeletePath(path);
626 }
627
628 static path_test_t rect_path[] = {
629     {5.0, 5.0,       PathPointTypeStart, 0, 0}, /*0*/
630     {105.0, 5.0,     PathPointTypeLine,  0, 0}, /*1*/
631     {105.0, 55.0,    PathPointTypeLine,  0, 0}, /*2*/
632     {5.0, 55.0,      PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*3*/
633
634     {100.0, 50.0,    PathPointTypeStart, 0, 0}, /*4*/
635     {220.0, 50.0,    PathPointTypeLine,  0, 0}, /*5*/
636     {220.0, 80.0,    PathPointTypeLine,  0, 0}, /*6*/
637     {100.0, 80.0,    PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}  /*7*/
638     };
639
640 static void test_rect(void)
641 {
642     GpStatus status;
643     GpPath *path;
644     GpRectF rects[2];
645
646     GdipCreatePath(FillModeAlternate, &path);
647     status = GdipAddPathRectangle(path, 5.0, 5.0, 100.0, 50.0);
648     expect(Ok, status);
649     status = GdipAddPathRectangle(path, 100.0, 50.0, 120.0, 30.0);
650     expect(Ok, status);
651
652     ok_path(path, rect_path, sizeof(rect_path)/sizeof(path_test_t), FALSE);
653
654     GdipDeletePath(path);
655
656     GdipCreatePath(FillModeAlternate, &path);
657
658     rects[0].X      = 5.0;
659     rects[0].Y      = 5.0;
660     rects[0].Width  = 100.0;
661     rects[0].Height = 50.0;
662     rects[1].X      = 100.0;
663     rects[1].Y      = 50.0;
664     rects[1].Width  = 120.0;
665     rects[1].Height = 30.0;
666
667     status = GdipAddPathRectangles(path, (GDIPCONST GpRectF*)&rects, 2);
668     expect(Ok, status);
669
670     ok_path(path, rect_path, sizeof(rect_path)/sizeof(path_test_t), FALSE);
671
672     GdipDeletePath(path);
673 }
674
675 static void test_lastpoint(void)
676 {
677     GpStatus status;
678     GpPath *path;
679     GpPointF ptf;
680
681     GdipCreatePath(FillModeAlternate, &path);
682     status = GdipAddPathRectangle(path, 5.0, 5.0, 100.0, 50.0);
683     expect(Ok, status);
684
685     /* invalid args */
686     status = GdipGetPathLastPoint(NULL, &ptf);
687     expect(InvalidParameter, status);
688     status = GdipGetPathLastPoint(path, NULL);
689     expect(InvalidParameter, status);
690     status = GdipGetPathLastPoint(NULL, NULL);
691     expect(InvalidParameter, status);
692
693     status = GdipGetPathLastPoint(path, &ptf);
694     expect(Ok, status);
695     expect(TRUE, (ptf.X == 5.0) && (ptf.Y == 55.0));
696
697     GdipDeletePath(path);
698 }
699
700 static path_test_t addcurve_path[] = {
701     {0.0, 0.0,   PathPointTypeStart,  0, 0}, /*0*/
702     {3.3, 3.3,   PathPointTypeBezier, 0, 0}, /*1*/
703     {6.7, 3.3,   PathPointTypeBezier, 0, 0}, /*2*/
704     {10.0, 10.0, PathPointTypeBezier, 0, 0}, /*3*/
705     {13.3, 16.7, PathPointTypeBezier, 0, 0}, /*4*/
706     {3.3,  20.0, PathPointTypeBezier, 0, 0}, /*5*/
707     {10.0, 20.0, PathPointTypeBezier, 0, 0}, /*6*/
708     {16.7, 20.0, PathPointTypeBezier, 0, 0}, /*7*/
709     {23.3, 13.3, PathPointTypeBezier, 0, 0}, /*8*/
710     {30.0, 10.0, PathPointTypeBezier, 0, 0}  /*9*/
711     };
712 static path_test_t addcurve_path2[] = {
713     {100.0,120.0,PathPointTypeStart,  0, 0}, /*0*/
714     {123.0,10.0, PathPointTypeLine,   0, 0}, /*1*/
715     {0.0, 0.0,   PathPointTypeLine,   0, 0}, /*2*/
716     {3.3, 3.3,   PathPointTypeBezier, 0, 0}, /*3*/
717     {6.7, 3.3,   PathPointTypeBezier, 0, 0}, /*4*/
718     {10.0, 10.0, PathPointTypeBezier, 0, 0}, /*5*/
719     {13.3, 16.7, PathPointTypeBezier, 0, 0}, /*6*/
720     {3.3,  20.0, PathPointTypeBezier, 0, 0}, /*7*/
721     {10.0, 20.0, PathPointTypeBezier, 0, 0}, /*8*/
722     {16.7, 20.0, PathPointTypeBezier, 0, 0}, /*9*/
723     {23.3, 13.3, PathPointTypeBezier, 0, 0}, /*10*/
724     {30.0, 10.0, PathPointTypeBezier, 0, 0}  /*11*/
725     };
726 static path_test_t addcurve_path3[] = {
727     {10.0, 10.0, PathPointTypeStart,  0, 0}, /*0*/
728     {13.3, 16.7, PathPointTypeBezier, 0, 1}, /*1*/
729     {3.3,  20.0, PathPointTypeBezier, 0, 0}, /*2*/
730     {10.0, 20.0, PathPointTypeBezier, 0, 0}, /*3*/
731     {16.7, 20.0, PathPointTypeBezier, 0, 0}, /*4*/
732     {23.3, 13.3, PathPointTypeBezier, 0, 0}, /*5*/
733     {30.0, 10.0, PathPointTypeBezier, 0, 0}  /*6*/
734     };
735 static void test_addcurve(void)
736 {
737     GpStatus status;
738     GpPath *path;
739     GpPointF points[4];
740
741     points[0].X = 0.0;
742     points[0].Y = 0.0;
743     points[1].X = 10.0;
744     points[1].Y = 10.0;
745     points[2].X = 10.0;
746     points[2].Y = 20.0;
747     points[3].X = 30.0;
748     points[3].Y = 10.0;
749
750     GdipCreatePath(FillModeAlternate, &path);
751
752     /* NULL args */
753     status = GdipAddPathCurve2(NULL, NULL, 0, 0.0);
754     expect(InvalidParameter, status);
755     status = GdipAddPathCurve2(path, NULL, 0, 0.0);
756     expect(InvalidParameter, status);
757     status = GdipAddPathCurve2(path, points, -1, 0.0);
758     expect(InvalidParameter, status);
759     status = GdipAddPathCurve2(path, points, 1, 1.0);
760     expect(InvalidParameter, status);
761
762     /* add to empty path */
763     status = GdipAddPathCurve2(path, points, 4, 1.0);
764     expect(Ok, status);
765     ok_path(path, addcurve_path, sizeof(addcurve_path)/sizeof(path_test_t), FALSE);
766     GdipDeletePath(path);
767
768     /* add to notempty path and opened figure */
769     GdipCreatePath(FillModeAlternate, &path);
770     GdipAddPathLine(path, 100.0, 120.0, 123.0, 10.0);
771     status = GdipAddPathCurve2(path, points, 4, 1.0);
772     expect(Ok, status);
773     ok_path(path, addcurve_path2, sizeof(addcurve_path2)/sizeof(path_test_t), FALSE);
774
775     /* NULL args */
776     GdipResetPath(path);
777     status = GdipAddPathCurve3(NULL, NULL, 0, 0, 0, 0.0);
778     expect(InvalidParameter, status);
779     status = GdipAddPathCurve3(path, NULL, 0, 0, 0, 0.0);
780     expect(InvalidParameter, status);
781     /* wrong count, offset.. */
782     status = GdipAddPathCurve3(path, points, 0, 0, 0, 0.0);
783     expect(InvalidParameter, status);
784     status = GdipAddPathCurve3(path, points, 4, 0, 0, 0.0);
785     expect(InvalidParameter, status);
786     status = GdipAddPathCurve3(path, points, 4, 0, 4, 0.0);
787     expect(InvalidParameter, status);
788     status = GdipAddPathCurve3(path, points, 4, 1, 3, 0.0);
789     expect(InvalidParameter, status);
790     status = GdipAddPathCurve3(path, points, 4, 1, 0, 0.0);
791     expect(InvalidParameter, status);
792     status = GdipAddPathCurve3(path, points, 4, 3, 1, 0.0);
793     expect(InvalidParameter, status);
794
795     /* use all points */
796     status = GdipAddPathCurve3(path, points, 4, 0, 3, 1.0);
797     expect(Ok, status);
798     ok_path(path, addcurve_path, sizeof(addcurve_path)/sizeof(path_test_t), FALSE);
799     GdipResetPath(path);
800
801     status = GdipAddPathCurve3(path, points, 4, 1, 2, 1.0);
802     expect(Ok, status);
803     ok_path(path, addcurve_path3, sizeof(addcurve_path3)/sizeof(path_test_t), FALSE);
804
805     GdipDeletePath(path);
806 }
807
808 static path_test_t addclosedcurve_path[] = {
809     {0.0, 0.0,   PathPointTypeStart,  0, 0}, /*0*/
810     {-6.7, 0.0,  PathPointTypeBezier, 0, 0}, /*1*/
811     {6.7, 3.3,   PathPointTypeBezier, 0, 0}, /*2*/
812     {10.0, 10.0, PathPointTypeBezier, 0, 0}, /*3*/
813     {13.3, 16.7, PathPointTypeBezier, 0, 0}, /*4*/
814     {3.3,  20.0, PathPointTypeBezier, 0, 0}, /*5*/
815     {10.0, 20.0, PathPointTypeBezier, 0, 0}, /*6*/
816     {16.7, 20.0, PathPointTypeBezier, 0, 0}, /*7*/
817     {33.3, 16.7, PathPointTypeBezier, 0, 0}, /*8*/
818     {30.0, 10.0, PathPointTypeBezier, 0, 0}, /*9*/
819     {26.7, 3.3,  PathPointTypeBezier, 0, 0}, /*10*/
820     {6.7,  0.0,  PathPointTypeBezier, 0, 0}, /*11*/
821     {0.0,  0.0,  PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0}  /*12*/
822     };
823 static void test_addclosedcurve(void)
824 {
825     GpStatus status;
826     GpPath *path;
827     GpPointF points[4];
828
829     points[0].X = 0.0;
830     points[0].Y = 0.0;
831     points[1].X = 10.0;
832     points[1].Y = 10.0;
833     points[2].X = 10.0;
834     points[2].Y = 20.0;
835     points[3].X = 30.0;
836     points[3].Y = 10.0;
837
838     GdipCreatePath(FillModeAlternate, &path);
839
840     /* NULL args */
841     status = GdipAddPathClosedCurve2(NULL, NULL, 0, 0.0);
842     expect(InvalidParameter, status);
843     status = GdipAddPathClosedCurve2(path, NULL, 0, 0.0);
844     expect(InvalidParameter, status);
845     status = GdipAddPathClosedCurve2(path, points, -1, 0.0);
846     expect(InvalidParameter, status);
847     status = GdipAddPathClosedCurve2(path, points, 1, 1.0);
848     expect(InvalidParameter, status);
849
850     /* add to empty path */
851     status = GdipAddPathClosedCurve2(path, points, 4, 1.0);
852     expect(Ok, status);
853     ok_path(path, addclosedcurve_path, sizeof(addclosedcurve_path)/sizeof(path_test_t), FALSE);
854     GdipDeletePath(path);
855 }
856
857 static path_test_t reverse_path[] = {
858     {0.0,  20.0, PathPointTypeStart, 0, 0}, /*0*/
859     {25.0, 25.0, PathPointTypeLine,  0, 0}, /*1*/
860     {0.0,  30.0, PathPointTypeLine,  0, 0}, /*2*/
861     {15.0, 35.0, PathPointTypeStart, 0, 0}, /*3*/
862     {0.0,  40.0, PathPointTypeLine,  0, 0}, /*4*/
863     {5.0,  45.0, PathPointTypeLine,  0, 0}, /*5*/
864     {0.0,  50.0, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}  /*6*/
865     };
866
867 static void test_reverse(void)
868 {
869     GpStatus status;
870     GpPath *path;
871     GpPointF pts[7];
872     INT i;
873
874     for(i = 0; i < 7; i++){
875         pts[i].X = i * 5.0 * (REAL)(i % 2);
876         pts[i].Y = 50.0 - i * 5.0;
877     }
878
879     GdipCreatePath(FillModeAlternate, &path);
880
881     /* NULL argument */
882     status = GdipReversePath(NULL);
883     expect(InvalidParameter, status);
884
885     /* empty path */
886     status = GdipReversePath(path);
887     expect(Ok, status);
888
889     GdipAddPathLine2(path, pts, 4);
890     GdipClosePathFigure(path);
891     GdipAddPathLine2(path, &(pts[4]), 3);
892
893     status = GdipReversePath(path);
894     expect(Ok, status);
895     ok_path(path, reverse_path, sizeof(reverse_path)/sizeof(path_test_t), FALSE);
896
897     GdipDeletePath(path);
898 }
899
900 static path_test_t addpie_path[] = {
901     {50.0, 25.0, PathPointTypeStart, 0, 0}, /*0*/
902     {97.2, 33.3, PathPointTypeLine,  0, 0}, /*1*/
903     {91.8, 40.9, PathPointTypeBezier,0, 0}, /*2*/
904     {79.4, 46.8, PathPointTypeBezier,0, 0}, /*3*/
905     {63.9, 49.0, PathPointTypeBezier | PathPointTypeCloseSubpath,  0, 0} /*4*/
906     };
907 static path_test_t addpie_path2[] = {
908     {0.0, 30.0, PathPointTypeStart | PathPointTypeCloseSubpath, 0, 0} /*0*/
909     };
910 static path_test_t addpie_path3[] = {
911     {30.0, 0.0, PathPointTypeStart | PathPointTypeCloseSubpath, 0, 0} /*0*/
912     };
913 static void test_addpie(void)
914 {
915     GpStatus status;
916     GpPath *path;
917
918     GdipCreatePath(FillModeAlternate, &path);
919
920     /* NULL argument */
921     status = GdipAddPathPie(NULL, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
922     expect(InvalidParameter, status);
923
924     status = GdipAddPathPie(path, 0.0, 0.0, 100.0, 50.0, 10.0, 50.0);
925     expect(Ok, status);
926     ok_path(path, addpie_path, sizeof(addpie_path)/sizeof(path_test_t), FALSE);
927     status = GdipResetPath(path);
928     expect(Ok, status);
929
930     /* zero width base ellipse */
931     status = GdipAddPathPie(path, 0.0, 0.0, 0.0, 60.0, -90.0, 24.0);
932     expect(InvalidParameter, status);
933     ok_path(path, addpie_path2, sizeof(addpie_path2)/sizeof(path_test_t), FALSE);
934     status = GdipResetPath(path);
935     expect(Ok, status);
936
937     /* zero height base ellipse */
938     status = GdipAddPathPie(path, 0.0, 0.0, 60.0, 0.0 , -90.0, 24.0);
939     expect(InvalidParameter, status);
940     ok_path(path, addpie_path3, sizeof(addpie_path3)/sizeof(path_test_t), FALSE);
941
942     GdipDeletePath(path);
943 }
944
945 static path_test_t flattenellipse_path[] = {
946     {100.0, 25.0,PathPointTypeStart, 0, 0}, /*0*/
947     {99.0, 30.0, PathPointTypeLine,  0, 0}, /*1*/
948     {96.0, 34.8, PathPointTypeLine,  0, 0}, /*2*/
949     {91.5, 39.0, PathPointTypeLine,  0, 0}, /*3*/
950     {85.5, 42.8, PathPointTypeLine,  0, 0}, /*4*/
951     {69.5, 48.0, PathPointTypeLine,  0, 1}, /*5*/
952     {50.0, 50.0, PathPointTypeLine,  0, 1}, /*6*/
953     {30.5, 48.0, PathPointTypeLine,  0, 1}, /*7*/
954     {14.8, 42.8, PathPointTypeLine,  0, 1}, /*8*/
955     {8.5,  39.0, PathPointTypeLine,  0, 1}, /*9*/
956     {4.0,  34.8, PathPointTypeLine,  0, 1}, /*10*/
957     {1.0,  30.0, PathPointTypeLine,  0, 1}, /*11*/
958     {0.0,  25.0, PathPointTypeLine,  0, 1}, /*12*/
959     {1.0,  20.0, PathPointTypeLine,  0, 1}, /*13*/
960     {4.0,  15.3, PathPointTypeLine,  0, 1}, /*14*/
961     {8.5,  11.0, PathPointTypeLine,  0, 1}, /*15*/
962     {14.8, 7.3,  PathPointTypeLine,  0, 1}, /*16*/
963     {30.5, 2.0,  PathPointTypeLine,  0, 1}, /*17*/
964     {50.0, 0.0,  PathPointTypeLine,  0, 1}, /*18*/
965     {69.5, 2.0,  PathPointTypeLine,  0, 1}, /*19*/
966     {85.5, 7.3,  PathPointTypeLine,  0, 1}, /*20*/
967     {91.5, 11.0, PathPointTypeLine,  0, 1}, /*21*/
968     {96.0, 15.3, PathPointTypeLine,  0, 1}, /*22*/
969     {99.0, 20.0, PathPointTypeLine,  0, 1}, /*23*/
970     {100.0,25.0, PathPointTypeLine | PathPointTypeCloseSubpath,  0, 1}  /*24*/
971     };
972
973 static path_test_t flattenline_path[] = {
974     {5.0, 10.0,PathPointTypeStart, 0, 0}, /*0*/
975     {50.0, 100.0, PathPointTypeLine,  0, 0} /*1*/
976     };
977
978 static path_test_t flattenarc_path[] = {
979     {100.0, 25.0,PathPointTypeStart, 0, 0}, /*0*/
980     {99.0, 30.0, PathPointTypeLine,  0, 0}, /*1*/
981     {96.0, 34.8, PathPointTypeLine,  0, 0}, /*2*/
982     {91.5, 39.0, PathPointTypeLine,  0, 0}, /*3*/
983     {85.5, 42.8, PathPointTypeLine,  0, 0}, /*4*/
984     {69.5, 48.0, PathPointTypeLine,  0, 1}, /*5*/
985     {50.0, 50.0, PathPointTypeLine,  0, 1}  /*6*/
986     };
987
988 static path_test_t flattenquater_path[] = {
989     {100.0, 50.0,PathPointTypeStart, 0, 0}, /*0*/
990     {99.0, 60.0, PathPointTypeLine,  0, 0}, /*1*/
991     {96.0, 69.5, PathPointTypeLine,  0, 0}, /*2*/
992     {91.5, 78.0, PathPointTypeLine,  0, 0}, /*3*/
993     {85.5, 85.5, PathPointTypeLine,  0, 0}, /*4*/
994     {78.0, 91.5, PathPointTypeLine,  0, 0}, /*5*/
995     {69.5, 96.0, PathPointTypeLine,  0, 0}, /*6*/
996     {60.0, 99.0, PathPointTypeLine,  0, 0}, /*7*/
997     {50.0, 100.0,PathPointTypeLine,  0, 0}  /*8*/
998     };
999
1000 static void test_flatten(void)
1001 {
1002     GpStatus status;
1003     GpPath *path;
1004     GpMatrix *m;
1005
1006     status = GdipCreatePath(FillModeAlternate, &path);
1007     expect(Ok, status);
1008     status = GdipCreateMatrix(&m);
1009     expect(Ok, status);
1010
1011     /* NULL arguments */
1012     status = GdipFlattenPath(NULL, NULL, 0.0);
1013     expect(InvalidParameter, status);
1014     status = GdipFlattenPath(NULL, m, 0.0);
1015     expect(InvalidParameter, status);
1016
1017     /* flatten empty path */
1018     status = GdipFlattenPath(path, NULL, 1.0);
1019     expect(Ok, status);
1020
1021     status = GdipAddPathEllipse(path, 0.0, 0.0, 100.0, 50.0);
1022     expect(Ok, status);
1023
1024     status = GdipFlattenPath(path, NULL, 1.0);
1025     expect(Ok, status);
1026     ok_path(path, flattenellipse_path, sizeof(flattenellipse_path)/sizeof(path_test_t), TRUE);
1027
1028     status = GdipResetPath(path);
1029     expect(Ok, status);
1030     status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 100.0);
1031     expect(Ok, status);
1032     status = GdipFlattenPath(path, NULL, 1.0);
1033     expect(Ok, status);
1034     ok_path(path, flattenline_path, sizeof(flattenline_path)/sizeof(path_test_t), FALSE);
1035
1036     status = GdipResetPath(path);
1037     expect(Ok, status);
1038     status = GdipAddPathArc(path, 0.0, 0.0, 100.0, 50.0, 0.0, 90.0);
1039     expect(Ok, status);
1040     status = GdipFlattenPath(path, NULL, 1.0);
1041     expect(Ok, status);
1042     ok_path(path, flattenarc_path, sizeof(flattenarc_path)/sizeof(path_test_t), TRUE);
1043
1044     /* easy case - quater of a full circle */
1045     status = GdipResetPath(path);
1046     expect(Ok, status);
1047     status = GdipAddPathArc(path, 0.0, 0.0, 100.0, 100.0, 0.0, 90.0);
1048     expect(Ok, status);
1049     status = GdipFlattenPath(path, NULL, 1.0);
1050     expect(Ok, status);
1051     ok_path(path, flattenquater_path, sizeof(flattenquater_path)/sizeof(path_test_t), FALSE);
1052
1053     GdipDeleteMatrix(m);
1054     GdipDeletePath(path);
1055 }
1056
1057 static void test_isvisible(void)
1058 {
1059     GpPath *path;
1060     GpGraphics *graphics = NULL;
1061     HDC hdc = GetDC(0);
1062     BOOL result;
1063     GpStatus status;
1064
1065     status = GdipCreateFromHDC(hdc, &graphics);
1066     expect(Ok, status);
1067     status = GdipCreatePath(FillModeAlternate, &path);
1068     expect(Ok, status);
1069
1070     /* NULL */
1071     status = GdipIsVisiblePathPoint(NULL, 0.0, 0.0, NULL, NULL);
1072     expect(InvalidParameter, status);
1073     status = GdipIsVisiblePathPoint(path, 0.0, 0.0, NULL, NULL);
1074     expect(InvalidParameter, status);
1075     status = GdipIsVisiblePathPoint(path, 0.0, 0.0, NULL, NULL);
1076     expect(InvalidParameter, status);
1077     status = GdipIsVisiblePathPoint(path, 0.0, 0.0, graphics, NULL);
1078     expect(InvalidParameter, status);
1079
1080     /* empty path */
1081     result = TRUE;
1082     status = GdipIsVisiblePathPoint(path, 0.0, 0.0, NULL, &result);
1083     expect(Ok, status);
1084     expect(FALSE, result);
1085     /* rect */
1086     status = GdipAddPathRectangle(path, 0.0, 0.0, 10.0, 10.0);
1087     expect(Ok, status);
1088     result = FALSE;
1089     status = GdipIsVisiblePathPoint(path, 0.0, 0.0, NULL, &result);
1090     expect(Ok, status);
1091     expect(TRUE, result);
1092     result = TRUE;
1093     status = GdipIsVisiblePathPoint(path, 11.0, 11.0, NULL, &result);
1094     expect(Ok, status);
1095     expect(FALSE, result);
1096     /* not affected by clipping */
1097     status = GdipSetClipRect(graphics, 5.0, 5.0, 5.0, 5.0, CombineModeReplace);
1098     expect(Ok, status);
1099     result = FALSE;
1100     status = GdipIsVisiblePathPoint(path, 0.0, 0.0, graphics, &result);
1101     expect(Ok, status);
1102     expect(TRUE, result);
1103
1104     GdipDeletePath(path);
1105     GdipDeleteGraphics(graphics);
1106     ReleaseDC(0, hdc);
1107 }
1108
1109 static void test_empty_rect(void)
1110 {
1111     GpPath *path;
1112     GpStatus status;
1113     BOOL result;
1114
1115     status = GdipCreatePath(FillModeAlternate, &path);
1116     expect(Ok, status);
1117
1118     status = GdipAddPathRectangle(path, 0.0, 0.0, -5.0, 5.0);
1119     expect(Ok, status);
1120
1121     status = GdipIsVisiblePathPoint(path, -2.0, 2.0, NULL, &result);
1122     expect(Ok, status);
1123     expect(FALSE, status);
1124
1125     status = GdipAddPathRectangle(path, 0.0, 0.0, 5.0, -5.0);
1126     expect(Ok, status);
1127
1128     status = GdipAddPathRectangle(path, 0.0, 0.0, 0.0, 5.0);
1129     expect(Ok, status);
1130
1131     status = GdipAddPathRectangle(path, 0.0, 0.0, 5.0, 0.0);
1132     expect(Ok, status);
1133
1134     GdipDeletePath(path);
1135 }
1136
1137 START_TEST(graphicspath)
1138 {
1139     struct GdiplusStartupInput gdiplusStartupInput;
1140     ULONG_PTR gdiplusToken;
1141
1142     gdiplusStartupInput.GdiplusVersion              = 1;
1143     gdiplusStartupInput.DebugEventCallback          = NULL;
1144     gdiplusStartupInput.SuppressBackgroundThread    = 0;
1145     gdiplusStartupInput.SuppressExternalCodecs      = 0;
1146
1147     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
1148
1149     test_constructor_destructor();
1150     test_getpathdata();
1151     test_line2();
1152     test_arc();
1153     test_worldbounds();
1154     test_pathpath();
1155     test_ellipse();
1156     test_linei();
1157     test_rect();
1158     test_polygon();
1159     test_lastpoint();
1160     test_addcurve();
1161     test_addclosedcurve();
1162     test_reverse();
1163     test_addpie();
1164     test_flatten();
1165     test_isvisible();
1166     test_empty_rect();
1167
1168     GdiplusShutdown(gdiplusToken);
1169 }