gdiplus/tests: Added GdipAddPathLineI test.
[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 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*/
162     };
163
164 static void test_line2(void)
165 {
166     GpStatus status;
167     GpPath* path;
168     int i;
169     GpPointF line2_points[9];
170
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;
174     }
175
176     GdipCreatePath(FillModeAlternate, &path);
177     status = GdipAddPathLine2(path, line2_points, 3);
178     expect(Ok, status);
179     status = GdipAddPathLine2(path, &(line2_points[3]), 3);
180     expect(Ok, status);
181     status = GdipClosePathFigure(path);
182     expect(Ok, status);
183     status = GdipAddPathLine2(path, &(line2_points[6]), 3);
184     expect(Ok, status);
185
186     ok_path(path, line2_path, sizeof(line2_path)/sizeof(path_test_t), FALSE);
187 }
188
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*/
228     };
229
230 static void test_arc(void)
231 {
232     GpStatus status;
233     GpPath* path;
234
235     GdipCreatePath(FillModeAlternate, &path);
236     /* Exactly 90 degrees */
237     status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 90.0);
238     expect(Ok, status);
239     /* Over 90 degrees */
240     status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
241     expect(Ok, status);
242     /* Negative start angle */
243     status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, -80.0, 100.0);
244     expect(Ok, status);
245     /* Negative sweep angle */
246     status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 80.0, -100.0);
247     expect(Ok, status);
248     /* More than a full revolution */
249     status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 50.0, -400.0);
250     expect(Ok, status);
251     /* 0 sweep angle */
252     status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 50.0, 0.0);
253     expect(Ok, status);
254
255     ok_path(path, arc_path, sizeof(arc_path)/sizeof(path_test_t), FALSE);
256 }
257
258 static void test_worldbounds(void)
259 {
260     GpStatus status;
261     GpPath *path;
262     GpPen *pen;
263     GpMatrix *matrix;
264     GpRectF bounds;
265     GpPointF line2_points[10];
266     int i;
267
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);
271     }
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);
275
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);
280     expect(Ok, status);
281     GdipDeletePath(path);
282
283     expectf(200.0, bounds.X);
284     expectf(200.0, bounds.Y);
285     expectf(450.0, bounds.Width);
286     expectf(600.0, bounds.Height);
287
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);
292     expect(Ok, status);
293     GdipDeletePath(path);
294
295     expectf(510.4, bounds.X);
296     expectf(250.2, bounds.Y);
297     expectf(1275.0, bounds.Width);
298     expectf(720.0, bounds.Height);
299
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);
304     expect(Ok, status);
305     GdipDeletePath(path);
306
307     expectf(100.0, bounds.X);
308     expectf(100.0, bounds.Y);
309     expectf(650.0, bounds.Width);
310     expectf(800.0, bounds.Height);
311
312     GdipCreatePath(FillModeAlternate, &path);
313     GdipAddPathLine2(path, &(line2_points[0]), 2);
314     status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
315     expect(Ok, status);
316     GdipDeletePath(path);
317
318     expectf(156.0, bounds.X);
319     expectf(156.0, bounds.Y);
320     expectf(138.0, bounds.Width);
321     expectf(88.0, bounds.Height);
322
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;
325
326     GdipCreatePath(FillModeAlternate, &path);
327     GdipAddPathLine2(path, &(line2_points[0]), 3);
328     status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
329     expect(Ok, status);
330     GdipDeletePath(path);
331
332     expectf(100.0, bounds.X);
333     expectf(100.0, bounds.Y);
334     expectf(300.0, bounds.Width);
335     expectf(200.0, bounds.Height);
336
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);
340     expect(Ok, status);
341     GdipDeletePath(path);
342
343     expectf(386.7, bounds.X);
344     expectf(553.4, bounds.Y);
345     expectf(266.8, bounds.Width);
346     expectf(289.6, bounds.Height);
347
348     GdipCreatePath(FillModeAlternate, &path);
349     status = GdipGetPathWorldBounds(path, &bounds, matrix, pen);
350     expect(Ok, status);
351     GdipDeletePath(path);
352
353     expectf(0.0, bounds.X);
354     expectf(0.0, bounds.Y);
355     expectf(0.0, bounds.Width);
356     expectf(0.0, bounds.Height);
357
358     GdipCreatePath(FillModeAlternate, &path);
359     GdipAddPathLine2(path, &(line2_points[0]), 2);
360     status = GdipGetPathWorldBounds(path, &bounds, matrix, pen);
361     expect(Ok, status);
362     GdipDeletePath(path);
363
364     todo_wine{
365         expectf(427.9, bounds.X);
366         expectf(167.7, bounds.Y);
367         expectf(239.9, bounds.Width);
368         expectf(164.9, bounds.Height);
369     }
370
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);
377     expect(Ok, status);
378     GdipDeletePath(path);
379
380     expectf(-209.6, bounds.X);
381     expectf(-1274.8, bounds.Y);
382     expectf(705.0, bounds.Width);
383     expectf(945.0, bounds.Height);
384 }
385
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*/
412     };
413
414 static void test_pathpath(void)
415 {
416     GpStatus status;
417     GpPath* path1, *path2;
418
419     GdipCreatePath(FillModeAlternate, &path2);
420     GdipAddPathArc(path2, 100.0, 100.0, 500.0, 700.0, 95.0, 100.0);
421
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);
425     expect(Ok, status);
426     GdipAddPathArc(path1, 100.0, 100.0, 500.0, 700.0, -80.0, 100.0);
427     status = GdipAddPathPath(path1, path2, TRUE);
428     expect(Ok, status);
429
430     ok_path(path1, pathpath_path, sizeof(pathpath_path)/sizeof(path_test_t), FALSE);
431
432     GdipDeletePath(path1);
433     GdipDeletePath(path2);
434 }
435
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, 0}, /*14*/
452     {5.00, 195.00, PathPointTypeStart, 0, 0}, /*15*/
453     {5.00, 192.24, PathPointTypeBezier, 0, 0}, /*16*/
454     {6.12, 190.00, PathPointTypeBezier, 0, 0}, /*17*/
455     {7.50, 190.00, PathPointTypeBezier, 0, 0}, /*18*/
456     {8.88, 190.00, PathPointTypeBezier, 0, 0}, /*19*/
457     {10.00, 192.24, PathPointTypeBezier, 0, 0}, /*20*/
458     {10.00, 195.00, PathPointTypeBezier, 0, 0}, /*21*/
459     {10.00, 197.76, PathPointTypeBezier, 0, 0}, /*22*/
460     {8.88, 200.00, PathPointTypeBezier, 0, 0}, /*23*/
461     {7.50, 200.00, PathPointTypeBezier, 0, 0}, /*24*/
462     {6.12, 200.00, PathPointTypeBezier, 0, 0}, /*25*/
463     {5.00, 197.76, PathPointTypeBezier, 0, 0}, /*26*/
464     {5.00, 195.00, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0}, /*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*/
478     };
479
480 static void test_ellipse(void)
481 {
482     GpStatus status;
483     GpPath *path;
484     GpPointF points[2];
485
486     points[0].X = 7.0;
487     points[0].Y = 11.0;
488     points[1].X = 13.0;
489     points[1].Y = 17.0;
490
491     GdipCreatePath(FillModeAlternate, &path);
492     status = GdipAddPathEllipse(path, 10.0, 100.0, 20.0, 50.5);
493     expect(Ok, status);
494     GdipAddPathLine2(path, points, 2);
495     status = GdipAddPathEllipse(path, 10.0, 200.0, -5.0, -10.0);
496     expect(Ok, status);
497     GdipClosePathFigure(path);
498     status = GdipAddPathEllipse(path, 10.0, 300.0, 0.0, 1.0);
499     expect(Ok, status);
500
501     ok_path(path, ellipse_path, sizeof(ellipse_path)/sizeof(path_test_t), FALSE);
502
503     GdipDeletePath(path);
504 }
505
506 static path_test_t linei_path[] = {
507     {5.00, 5.00, PathPointTypeStart, 0, 0}, /*0*/
508     {6.00, 8.00, PathPointTypeLine, 0, 0}, /*1*/
509     {409.92, 110.20, PathPointTypeLine, 0, 0}, /*2*/
510     {543.96, 156.53, PathPointTypeBezier, 0, 0}, /*3*/
511     {625.80, 346.22, PathPointTypeBezier, 0, 0}, /*4*/
512     {592.71, 533.88, PathPointTypeBezier, 0, 0}, /*5*/
513     {592.47, 535.28, PathPointTypeBezier, 0, 0}, /*6*/
514     {592.22, 536.67, PathPointTypeBezier, 0, 0}, /*7*/
515     {591.96, 538.06, PathPointTypeBezier, 0, 0}, /*8*/
516     {15.00, 15.00, PathPointTypeLine, 0, 0}, /*9*/
517     {26.00, 28.00, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*10*/
518     {35.00, 35.00, PathPointTypeStart, 0, 0}, /*11*/
519     {36.00, 38.00, PathPointTypeLine, 0, 0} /*12*/
520     };
521
522 static void test_linei(void)
523 {
524     GpStatus status;
525     GpPath *path;
526     GpPointF points[2];
527
528     points[0].X = 7.0;
529     points[0].Y = 11.0;
530     points[1].X = 13.0;
531     points[1].Y = 17.0;
532
533     GdipCreatePath(FillModeAlternate, &path);
534     status = GdipAddPathLineI(path, 5.0, 5.0, 6.0, 8.0);
535     expect(Ok, status);
536     GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, -80.0, 100.0);
537     status = GdipAddPathLineI(path, 15.0, 15.0, 26.0, 28.0);
538     expect(Ok, status);
539     GdipClosePathFigure(path);
540     status = GdipAddPathLineI(path, 35.0, 35.0, 36.0, 38.0);
541     expect(Ok, status);
542
543     ok_path(path, linei_path, sizeof(linei_path)/sizeof(path_test_t), FALSE);
544
545     GdipDeletePath(path);
546 }
547
548 START_TEST(graphicspath)
549 {
550     struct GdiplusStartupInput gdiplusStartupInput;
551     ULONG_PTR gdiplusToken;
552
553     gdiplusStartupInput.GdiplusVersion              = 1;
554     gdiplusStartupInput.DebugEventCallback          = NULL;
555     gdiplusStartupInput.SuppressBackgroundThread    = 0;
556     gdiplusStartupInput.SuppressExternalCodecs      = 0;
557
558     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
559
560     test_constructor_destructor();
561     test_line2();
562     test_arc();
563     test_worldbounds();
564     test_pathpath();
565     test_ellipse();
566     test_linei();
567
568     GdiplusShutdown(gdiplusToken);
569 }