gdiplus: Add some tests for pathiterator, fix leaks.
[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
414     expectf(-209.6, bounds.X);
415     expectf(-1274.8, bounds.Y);
416     expectf(705.0, bounds.Width);
417     expectf(945.0, bounds.Height);
418 }
419
420 static path_test_t pathpath_path[] = {
421     {600.00, 450.00, PathPointTypeStart, 0, 0}, /*0*/
422     {600.00, 643.30, PathPointTypeBezier, 0, 0}, /*1*/
423     {488.07, 800.00, PathPointTypeBezier, 0, 0}, /*2*/
424     {350.00, 800.00, PathPointTypeBezier, 0, 0}, /*3*/
425     {319.61, 797.40, PathPointTypeStart, 0, 0}, /*4*/
426     {182.56, 773.90, PathPointTypeBezier, 0, 0}, /*5*/
427     {85.07, 599.31, PathPointTypeBezier, 0, 0}, /*6*/
428     {101.85, 407.45, PathPointTypeBezier, 0, 0}, /*7*/
429     {102.54, 399.66, PathPointTypeBezier, 0, 0}, /*8*/
430     {103.40, 391.91, PathPointTypeBezier, 0, 0}, /*9*/
431     {104.46, 384.21, PathPointTypeBezier, 0, 0}, /*10*/
432     {409.92, 110.20, PathPointTypeLine, 0, 0}, /*11*/
433     {543.96, 156.53, PathPointTypeBezier, 0, 0}, /*12*/
434     {625.80, 346.22, PathPointTypeBezier, 0, 0}, /*13*/
435     {592.71, 533.88, PathPointTypeBezier, 0, 0}, /*14*/
436     {592.47, 535.28, PathPointTypeBezier, 0, 0}, /*15*/
437     {592.22, 536.67, PathPointTypeBezier, 0, 0}, /*16*/
438     {591.96, 538.06, PathPointTypeBezier, 0, 0}, /*17*/
439     {319.61, 797.40, PathPointTypeLine, 0, 0}, /*18*/
440     {182.56, 773.90, PathPointTypeBezier, 0, 0}, /*19*/
441     {85.07, 599.31, PathPointTypeBezier, 0, 0}, /*20*/
442     {101.85, 407.45, PathPointTypeBezier, 0, 0}, /*21*/
443     {102.54, 399.66, PathPointTypeBezier, 0, 0}, /*22*/
444     {103.40, 391.91, PathPointTypeBezier, 0, 0}, /*23*/
445     {104.46, 384.21, PathPointTypeBezier, 0, 0} /*24*/
446     };
447
448 static void test_pathpath(void)
449 {
450     GpStatus status;
451     GpPath* path1, *path2;
452
453     GdipCreatePath(FillModeAlternate, &path2);
454     GdipAddPathArc(path2, 100.0, 100.0, 500.0, 700.0, 95.0, 100.0);
455
456     GdipCreatePath(FillModeAlternate, &path1);
457     GdipAddPathArc(path1, 100.0, 100.0, 500.0, 700.0, 0.0, 90.0);
458     status = GdipAddPathPath(path1, path2, FALSE);
459     expect(Ok, status);
460     GdipAddPathArc(path1, 100.0, 100.0, 500.0, 700.0, -80.0, 100.0);
461     status = GdipAddPathPath(path1, path2, TRUE);
462     expect(Ok, status);
463
464     ok_path(path1, pathpath_path, sizeof(pathpath_path)/sizeof(path_test_t), FALSE);
465
466     GdipDeletePath(path1);
467     GdipDeletePath(path2);
468 }
469
470 static path_test_t ellipse_path[] = {
471     {30.00, 125.25, PathPointTypeStart, 0, 0}, /*0*/
472     {30.00, 139.20, PathPointTypeBezier, 0, 0}, /*1*/
473     {25.52, 150.50, PathPointTypeBezier, 0, 0}, /*2*/
474     {20.00, 150.50, PathPointTypeBezier, 0, 0}, /*3*/
475     {14.48, 150.50, PathPointTypeBezier, 0, 0}, /*4*/
476     {10.00, 139.20, PathPointTypeBezier, 0, 0}, /*5*/
477     {10.00, 125.25, PathPointTypeBezier, 0, 0}, /*6*/
478     {10.00, 111.30, PathPointTypeBezier, 0, 0}, /*7*/
479     {14.48, 100.00, PathPointTypeBezier, 0, 0}, /*8*/
480     {20.00, 100.00, PathPointTypeBezier, 0, 0}, /*9*/
481     {25.52, 100.00, PathPointTypeBezier, 0, 0}, /*10*/
482     {30.00, 111.30, PathPointTypeBezier, 0, 0}, /*11*/
483     {30.00, 125.25, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0}, /*12*/
484     {7.00, 11.00, PathPointTypeStart, 0, 0}, /*13*/
485     {13.00, 17.00, PathPointTypeLine, 0, 0}, /*14*/
486     {5.00, 195.00, PathPointTypeStart, 0, 0}, /*15*/
487     {5.00, 192.24, PathPointTypeBezier, 0, 0}, /*16*/
488     {6.12, 190.00, PathPointTypeBezier, 0, 0}, /*17*/
489     {7.50, 190.00, PathPointTypeBezier, 0, 0}, /*18*/
490     {8.88, 190.00, PathPointTypeBezier, 0, 0}, /*19*/
491     {10.00, 192.24, PathPointTypeBezier, 0, 0}, /*20*/
492     {10.00, 195.00, PathPointTypeBezier, 0, 0}, /*21*/
493     {10.00, 197.76, PathPointTypeBezier, 0, 0}, /*22*/
494     {8.88, 200.00, PathPointTypeBezier, 0, 0}, /*23*/
495     {7.50, 200.00, PathPointTypeBezier, 0, 0}, /*24*/
496     {6.12, 200.00, PathPointTypeBezier, 0, 0}, /*25*/
497     {5.00, 197.76, PathPointTypeBezier, 0, 0}, /*26*/
498     {5.00, 195.00, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0}, /*27*/
499     {10.00, 300.50, PathPointTypeStart, 0, 0}, /*28*/
500     {10.00, 300.78, PathPointTypeBezier, 0, 0}, /*29*/
501     {10.00, 301.00, PathPointTypeBezier, 0, 0}, /*30*/
502     {10.00, 301.00, PathPointTypeBezier, 0, 0}, /*31*/
503     {10.00, 301.00, PathPointTypeBezier, 0, 0}, /*32*/
504     {10.00, 300.78, PathPointTypeBezier, 0, 0}, /*33*/
505     {10.00, 300.50, PathPointTypeBezier, 0, 0}, /*34*/
506     {10.00, 300.22, PathPointTypeBezier, 0, 0}, /*35*/
507     {10.00, 300.00, PathPointTypeBezier, 0, 0}, /*36*/
508     {10.00, 300.00, PathPointTypeBezier, 0, 0}, /*37*/
509     {10.00, 300.00, PathPointTypeBezier, 0, 0}, /*38*/
510     {10.00, 300.22, PathPointTypeBezier, 0, 0}, /*39*/
511     {10.00, 300.50, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0} /*40*/
512     };
513
514 static void test_ellipse(void)
515 {
516     GpStatus status;
517     GpPath *path;
518     GpPointF points[2];
519
520     points[0].X = 7.0;
521     points[0].Y = 11.0;
522     points[1].X = 13.0;
523     points[1].Y = 17.0;
524
525     GdipCreatePath(FillModeAlternate, &path);
526     status = GdipAddPathEllipse(path, 10.0, 100.0, 20.0, 50.5);
527     expect(Ok, status);
528     GdipAddPathLine2(path, points, 2);
529     status = GdipAddPathEllipse(path, 10.0, 200.0, -5.0, -10.0);
530     expect(Ok, status);
531     GdipClosePathFigure(path);
532     status = GdipAddPathEllipse(path, 10.0, 300.0, 0.0, 1.0);
533     expect(Ok, status);
534
535     ok_path(path, ellipse_path, sizeof(ellipse_path)/sizeof(path_test_t), FALSE);
536
537     GdipDeletePath(path);
538 }
539
540 static path_test_t linei_path[] = {
541     {5.00, 5.00, PathPointTypeStart, 0, 0}, /*0*/
542     {6.00, 8.00, PathPointTypeLine, 0, 0}, /*1*/
543     {409.92, 110.20, PathPointTypeLine, 0, 0}, /*2*/
544     {543.96, 156.53, PathPointTypeBezier, 0, 0}, /*3*/
545     {625.80, 346.22, PathPointTypeBezier, 0, 0}, /*4*/
546     {592.71, 533.88, PathPointTypeBezier, 0, 0}, /*5*/
547     {592.47, 535.28, PathPointTypeBezier, 0, 0}, /*6*/
548     {592.22, 536.67, PathPointTypeBezier, 0, 0}, /*7*/
549     {591.96, 538.06, PathPointTypeBezier, 0, 0}, /*8*/
550     {15.00, 15.00, PathPointTypeLine, 0, 0}, /*9*/
551     {26.00, 28.00, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*10*/
552     {35.00, 35.00, PathPointTypeStart, 0, 0}, /*11*/
553     {36.00, 38.00, PathPointTypeLine, 0, 0} /*12*/
554     };
555
556 static void test_linei(void)
557 {
558     GpStatus status;
559     GpPath *path;
560     GpPointF points[2];
561
562     points[0].X = 7.0;
563     points[0].Y = 11.0;
564     points[1].X = 13.0;
565     points[1].Y = 17.0;
566
567     GdipCreatePath(FillModeAlternate, &path);
568     status = GdipAddPathLineI(path, 5.0, 5.0, 6.0, 8.0);
569     expect(Ok, status);
570     GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, -80.0, 100.0);
571     status = GdipAddPathLineI(path, 15.0, 15.0, 26.0, 28.0);
572     expect(Ok, status);
573     GdipClosePathFigure(path);
574     status = GdipAddPathLineI(path, 35.0, 35.0, 36.0, 38.0);
575     expect(Ok, status);
576
577     ok_path(path, linei_path, sizeof(linei_path)/sizeof(path_test_t), FALSE);
578
579     GdipDeletePath(path);
580 }
581
582 static path_test_t poly_path[] = {
583     {5.00, 5.00, PathPointTypeStart, 0, 0},   /*1*/
584     {6.00, 8.00, PathPointTypeLine, 0, 0},    /*2*/
585     {0.00,  0.00,  PathPointTypeStart, 0, 0}, /*3*/
586     {10.00, 10.00, PathPointTypeLine, 0, 0},  /*4*/
587     {10.00, 20.00, PathPointTypeLine, 0, 0},  /*5*/
588     {30.00, 10.00, PathPointTypeLine, 0, 0},  /*6*/
589     {20.00, 0.00, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*7*/
590     };
591
592 static void test_polygon(void)
593 {
594     GpStatus status;
595     GpPath *path;
596     GpPointF points[5];
597
598     points[0].X = 0.0;
599     points[0].Y = 0.0;
600     points[1].X = 10.0;
601     points[1].Y = 10.0;
602     points[2].X = 10.0;
603     points[2].Y = 20.0;
604     points[3].X = 30.0;
605     points[3].Y = 10.0;
606     points[4].X = 20.0;
607     points[4].Y = 0.0;
608
609     GdipCreatePath(FillModeAlternate, &path);
610
611     /* NULL args */
612     status = GdipAddPathPolygon(NULL, points, 5);
613     expect(InvalidParameter, status);
614     status = GdipAddPathPolygon(path, NULL, 5);
615     expect(InvalidParameter, status);
616     /* Polygon should have 3 points at least */
617     status = GdipAddPathPolygon(path, points, 2);
618     expect(InvalidParameter, status);
619
620     /* to test how it prolongs not empty path */
621     status = GdipAddPathLine(path, 5.0, 5.0, 6.0, 8.0);
622     expect(Ok, status);
623     status = GdipAddPathPolygon(path, points, 5);
624     expect(Ok, status);
625     /* check resulting path */
626     ok_path(path, poly_path, sizeof(poly_path)/sizeof(path_test_t), FALSE);
627
628     GdipDeletePath(path);
629 }
630
631 static path_test_t rect_path[] = {
632     {5.0, 5.0,       PathPointTypeStart, 0, 0}, /*0*/
633     {105.0, 5.0,     PathPointTypeLine,  0, 0}, /*1*/
634     {105.0, 55.0,    PathPointTypeLine,  0, 0}, /*2*/
635     {5.0, 55.0,      PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*3*/
636
637     {100.0, 50.0,    PathPointTypeStart, 0, 0}, /*4*/
638     {220.0, 50.0,    PathPointTypeLine,  0, 0}, /*5*/
639     {220.0, 80.0,    PathPointTypeLine,  0, 0}, /*6*/
640     {100.0, 80.0,    PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}  /*7*/
641     };
642
643 static void test_rect(void)
644 {
645     GpStatus status;
646     GpPath *path;
647     GpRectF rects[2];
648
649     GdipCreatePath(FillModeAlternate, &path);
650     status = GdipAddPathRectangle(path, 5.0, 5.0, 100.0, 50.0);
651     expect(Ok, status);
652     status = GdipAddPathRectangle(path, 100.0, 50.0, 120.0, 30.0);
653     expect(Ok, status);
654
655     ok_path(path, rect_path, sizeof(rect_path)/sizeof(path_test_t), FALSE);
656
657     GdipDeletePath(path);
658
659     GdipCreatePath(FillModeAlternate, &path);
660
661     rects[0].X      = 5.0;
662     rects[0].Y      = 5.0;
663     rects[0].Width  = 100.0;
664     rects[0].Height = 50.0;
665     rects[1].X      = 100.0;
666     rects[1].Y      = 50.0;
667     rects[1].Width  = 120.0;
668     rects[1].Height = 30.0;
669
670     status = GdipAddPathRectangles(path, (GDIPCONST GpRectF*)&rects, 2);
671     expect(Ok, status);
672
673     ok_path(path, rect_path, sizeof(rect_path)/sizeof(path_test_t), FALSE);
674
675     GdipDeletePath(path);
676 }
677
678 static void test_lastpoint(void)
679 {
680     GpStatus status;
681     GpPath *path;
682     GpPointF ptf;
683
684     GdipCreatePath(FillModeAlternate, &path);
685     status = GdipAddPathRectangle(path, 5.0, 5.0, 100.0, 50.0);
686     expect(Ok, status);
687
688     /* invalid args */
689     status = GdipGetPathLastPoint(NULL, &ptf);
690     expect(InvalidParameter, status);
691     status = GdipGetPathLastPoint(path, NULL);
692     expect(InvalidParameter, status);
693     status = GdipGetPathLastPoint(NULL, NULL);
694     expect(InvalidParameter, status);
695
696     status = GdipGetPathLastPoint(path, &ptf);
697     expect(Ok, status);
698     expect(TRUE, (ptf.X == 5.0) && (ptf.Y == 55.0));
699
700     GdipDeletePath(path);
701 }
702
703 static path_test_t addcurve_path[] = {
704     {0.0, 0.0,   PathPointTypeStart,  0, 0}, /*0*/
705     {3.3, 3.3,   PathPointTypeBezier, 0, 0}, /*1*/
706     {6.7, 3.3,   PathPointTypeBezier, 0, 0}, /*2*/
707     {10.0, 10.0, PathPointTypeBezier, 0, 0}, /*3*/
708     {13.3, 16.7, PathPointTypeBezier, 0, 0}, /*4*/
709     {3.3,  20.0, PathPointTypeBezier, 0, 0}, /*5*/
710     {10.0, 20.0, PathPointTypeBezier, 0, 0}, /*6*/
711     {16.7, 20.0, PathPointTypeBezier, 0, 0}, /*7*/
712     {23.3, 13.3, PathPointTypeBezier, 0, 0}, /*8*/
713     {30.0, 10.0, PathPointTypeBezier, 0, 0}  /*9*/
714     };
715 static path_test_t addcurve_path2[] = {
716     {100.0,120.0,PathPointTypeStart,  0, 0}, /*0*/
717     {123.0,10.0, PathPointTypeLine,   0, 0}, /*1*/
718     {0.0, 0.0,   PathPointTypeLine,   0, 0}, /*2*/
719     {3.3, 3.3,   PathPointTypeBezier, 0, 0}, /*3*/
720     {6.7, 3.3,   PathPointTypeBezier, 0, 0}, /*4*/
721     {10.0, 10.0, PathPointTypeBezier, 0, 0}, /*5*/
722     {13.3, 16.7, PathPointTypeBezier, 0, 0}, /*6*/
723     {3.3,  20.0, PathPointTypeBezier, 0, 0}, /*7*/
724     {10.0, 20.0, PathPointTypeBezier, 0, 0}, /*8*/
725     {16.7, 20.0, PathPointTypeBezier, 0, 0}, /*9*/
726     {23.3, 13.3, PathPointTypeBezier, 0, 0}, /*10*/
727     {30.0, 10.0, PathPointTypeBezier, 0, 0}  /*11*/
728     };
729 static void test_addcurve(void)
730 {
731     GpStatus status;
732     GpPath *path;
733     GpPointF points[4];
734
735     points[0].X = 0.0;
736     points[0].Y = 0.0;
737     points[1].X = 10.0;
738     points[1].Y = 10.0;
739     points[2].X = 10.0;
740     points[2].Y = 20.0;
741     points[3].X = 30.0;
742     points[3].Y = 10.0;
743
744     GdipCreatePath(FillModeAlternate, &path);
745
746     /* NULL args */
747     status = GdipAddPathCurve2(NULL, NULL, 0, 0.0);
748     expect(InvalidParameter, status);
749     status = GdipAddPathCurve2(path, NULL, 0, 0.0);
750     expect(InvalidParameter, status);
751     status = GdipAddPathCurve2(path, points, -1, 0.0);
752     expect(InvalidParameter, status);
753     status = GdipAddPathCurve2(path, points, 1, 1.0);
754     expect(InvalidParameter, status);
755
756     /* add to empty path */
757     status = GdipAddPathCurve2(path, points, 4, 1.0);
758     expect(Ok, status);
759     ok_path(path, addcurve_path, sizeof(addcurve_path)/sizeof(path_test_t), FALSE);
760     GdipDeletePath(path);
761
762     /* add to notempty path and opened figure */
763     GdipCreatePath(FillModeAlternate, &path);
764     GdipAddPathLine(path, 100.0, 120.0, 123.0, 10.0);
765     status = GdipAddPathCurve2(path, points, 4, 1.0);
766     expect(Ok, status);
767     ok_path(path, addcurve_path2, sizeof(addcurve_path2)/sizeof(path_test_t), FALSE);
768     GdipDeletePath(path);
769 }
770
771 static path_test_t addclosedcurve_path[] = {
772     {0.0, 0.0,   PathPointTypeStart,  0, 0}, /*0*/
773     {-6.7, 0.0,  PathPointTypeBezier, 0, 0}, /*1*/
774     {6.7, 3.3,   PathPointTypeBezier, 0, 0}, /*2*/
775     {10.0, 10.0, PathPointTypeBezier, 0, 0}, /*3*/
776     {13.3, 16.7, PathPointTypeBezier, 0, 0}, /*4*/
777     {3.3,  20.0, PathPointTypeBezier, 0, 0}, /*5*/
778     {10.0, 20.0, PathPointTypeBezier, 0, 0}, /*6*/
779     {16.7, 20.0, PathPointTypeBezier, 0, 0}, /*7*/
780     {33.3, 16.7, PathPointTypeBezier, 0, 0}, /*8*/
781     {30.0, 10.0, PathPointTypeBezier, 0, 0}, /*9*/
782     {26.7, 3.3,  PathPointTypeBezier, 0, 0}, /*10*/
783     {6.7,  0.0,  PathPointTypeBezier, 0, 0}, /*11*/
784     {0.0,  0.0,  PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0}  /*12*/
785     };
786 static void test_addclosedcurve(void)
787 {
788     GpStatus status;
789     GpPath *path;
790     GpPointF points[4];
791
792     points[0].X = 0.0;
793     points[0].Y = 0.0;
794     points[1].X = 10.0;
795     points[1].Y = 10.0;
796     points[2].X = 10.0;
797     points[2].Y = 20.0;
798     points[3].X = 30.0;
799     points[3].Y = 10.0;
800
801     GdipCreatePath(FillModeAlternate, &path);
802
803     /* NULL args */
804     status = GdipAddPathClosedCurve2(NULL, NULL, 0, 0.0);
805     expect(InvalidParameter, status);
806     status = GdipAddPathClosedCurve2(path, NULL, 0, 0.0);
807     expect(InvalidParameter, status);
808     status = GdipAddPathClosedCurve2(path, points, -1, 0.0);
809     expect(InvalidParameter, status);
810     status = GdipAddPathClosedCurve2(path, points, 1, 1.0);
811     expect(InvalidParameter, status);
812
813     /* add to empty path */
814     status = GdipAddPathClosedCurve2(path, points, 4, 1.0);
815     expect(Ok, status);
816     ok_path(path, addclosedcurve_path, sizeof(addclosedcurve_path)/sizeof(path_test_t), FALSE);
817     GdipDeletePath(path);
818 }
819
820 static path_test_t reverse_path[] = {
821     {0.0,  20.0, PathPointTypeStart, 0, 0}, /*0*/
822     {25.0, 25.0, PathPointTypeLine,  0, 0}, /*1*/
823     {0.0,  30.0, PathPointTypeLine,  0, 0}, /*2*/
824     {15.0, 35.0, PathPointTypeStart, 0, 0}, /*3*/
825     {0.0,  40.0, PathPointTypeLine,  0, 0}, /*4*/
826     {5.0,  45.0, PathPointTypeLine,  0, 0}, /*5*/
827     {0.0,  50.0, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}  /*6*/
828     };
829
830 static void test_reverse(void)
831 {
832     GpStatus status;
833     GpPath *path;
834     GpPointF pts[7];
835     INT i;
836
837     for(i = 0; i < 7; i++){
838         pts[i].X = i * 5.0 * (REAL)(i % 2);
839         pts[i].Y = 50.0 - i * 5.0;
840     }
841
842     GdipCreatePath(FillModeAlternate, &path);
843
844     /* NULL argument */
845     status = GdipReversePath(NULL);
846     expect(InvalidParameter, status);
847
848     /* empty path */
849     status = GdipReversePath(path);
850     expect(Ok, status);
851
852     GdipAddPathLine2(path, pts, 4);
853     GdipClosePathFigure(path);
854     GdipAddPathLine2(path, &(pts[4]), 3);
855
856     status = GdipReversePath(path);
857     expect(Ok, status);
858     ok_path(path, reverse_path, sizeof(reverse_path)/sizeof(path_test_t), FALSE);
859
860     GdipDeletePath(path);
861 }
862
863 static path_test_t addpie_path[] = {
864     {50.0, 25.0, PathPointTypeStart, 0, 0}, /*0*/
865     {97.2, 33.3, PathPointTypeLine,  0, 0}, /*1*/
866     {91.8, 40.9, PathPointTypeBezier,0, 0}, /*2*/
867     {79.4, 46.8, PathPointTypeBezier,0, 0}, /*3*/
868     {63.9, 49.0, PathPointTypeBezier | PathPointTypeCloseSubpath,  0, 0} /*4*/
869     };
870
871 static void test_addpie(void)
872 {
873     GpStatus status;
874     GpPath *path;
875
876     GdipCreatePath(FillModeAlternate, &path);
877
878     /* NULL argument */
879     status = GdipAddPathPie(NULL, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
880     expect(InvalidParameter, status);
881
882     status = GdipAddPathPie(path, 0.0, 0.0, 100.0, 50.0, 10.0, 50.0);
883     expect(Ok, status);
884     ok_path(path, addpie_path, sizeof(addpie_path)/sizeof(path_test_t), FALSE);
885
886     GdipDeletePath(path);
887 }
888
889 static path_test_t flattenellipse_path[] = {
890     {100.0, 25.0,PathPointTypeStart, 0, 0}, /*0*/
891     {99.0, 30.0, PathPointTypeLine,  0, 0}, /*1*/
892     {96.0, 34.8, PathPointTypeLine,  0, 0}, /*2*/
893     {91.5, 39.0, PathPointTypeLine,  0, 0}, /*3*/
894     {85.5, 42.8, PathPointTypeLine,  0, 0}, /*4*/
895     {69.5, 48.0, PathPointTypeLine,  0, 1}, /*5*/
896     {50.0, 50.0, PathPointTypeLine,  0, 1}, /*6*/
897     {30.5, 48.0, PathPointTypeLine,  0, 1}, /*7*/
898     {14.8, 42.8, PathPointTypeLine,  0, 1}, /*8*/
899     {8.5,  39.0, PathPointTypeLine,  0, 1}, /*9*/
900     {4.0,  34.8, PathPointTypeLine,  0, 1}, /*10*/
901     {1.0,  30.0, PathPointTypeLine,  0, 1}, /*11*/
902     {0.0,  25.0, PathPointTypeLine,  0, 1}, /*12*/
903     {1.0,  20.0, PathPointTypeLine,  0, 1}, /*13*/
904     {4.0,  15.3, PathPointTypeLine,  0, 1}, /*14*/
905     {8.5,  11.0, PathPointTypeLine,  0, 1}, /*15*/
906     {14.8, 7.3,  PathPointTypeLine,  0, 1}, /*16*/
907     {30.5, 2.0,  PathPointTypeLine,  0, 1}, /*17*/
908     {50.0, 0.0,  PathPointTypeLine,  0, 1}, /*18*/
909     {69.5, 2.0,  PathPointTypeLine,  0, 1}, /*19*/
910     {85.5, 7.3,  PathPointTypeLine,  0, 1}, /*20*/
911     {91.5, 11.0, PathPointTypeLine,  0, 1}, /*21*/
912     {96.0, 15.3, PathPointTypeLine,  0, 1}, /*22*/
913     {99.0, 20.0, PathPointTypeLine,  0, 1}, /*23*/
914     {100.0,25.0, PathPointTypeLine | PathPointTypeCloseSubpath,  0, 1}  /*24*/
915     };
916
917 static path_test_t flattenarc_path[] = {
918     {100.0, 25.0,PathPointTypeStart, 0, 0}, /*0*/
919     {99.0, 30.0, PathPointTypeLine,  0, 0}, /*1*/
920     {96.0, 34.8, PathPointTypeLine,  0, 0}, /*2*/
921     {91.5, 39.0, PathPointTypeLine,  0, 0}, /*3*/
922     {85.5, 42.8, PathPointTypeLine,  0, 0}, /*4*/
923     {69.5, 48.0, PathPointTypeLine,  0, 1}, /*5*/
924     {50.0, 50.0, PathPointTypeLine,  0, 1}  /*6*/
925     };
926
927 static path_test_t flattenquater_path[] = {
928     {100.0, 50.0,PathPointTypeStart, 0, 0}, /*0*/
929     {99.0, 60.0, PathPointTypeLine,  0, 0}, /*1*/
930     {96.0, 69.5, PathPointTypeLine,  0, 0}, /*2*/
931     {91.5, 78.0, PathPointTypeLine,  0, 0}, /*3*/
932     {85.5, 85.5, PathPointTypeLine,  0, 0}, /*4*/
933     {78.0, 91.5, PathPointTypeLine,  0, 0}, /*5*/
934     {69.5, 96.0, PathPointTypeLine,  0, 0}, /*6*/
935     {60.0, 99.0, PathPointTypeLine,  0, 0}, /*7*/
936     {50.0, 100.0,PathPointTypeLine,  0, 0}  /*8*/
937     };
938
939 static void test_flatten(void)
940 {
941     GpStatus status;
942     GpPath *path;
943     GpMatrix *m;
944
945     status = GdipCreatePath(FillModeAlternate, &path);
946     expect(Ok, status);
947     status = GdipCreateMatrix(&m);
948     expect(Ok, status);
949
950     /* NULL arguments */
951     status = GdipFlattenPath(NULL, NULL, 0.0);
952     expect(InvalidParameter, status);
953     status = GdipFlattenPath(NULL, m, 0.0);
954     expect(InvalidParameter, status);
955
956     /* flatten empty path */
957     status = GdipFlattenPath(path, NULL, 1.0);
958     expect(Ok, status);
959
960     status = GdipAddPathEllipse(path, 0.0, 0.0, 100.0, 50.0);
961     expect(Ok, status);
962
963     status = GdipFlattenPath(path, NULL, 1.0);
964     expect(Ok, status);
965     ok_path(path, flattenellipse_path, sizeof(flattenellipse_path)/sizeof(path_test_t), TRUE);
966
967     status = GdipResetPath(path);
968     expect(Ok, status);
969     status = GdipAddPathArc(path, 0.0, 0.0, 100.0, 50.0, 0.0, 90.0);
970     expect(Ok, status);
971     status = GdipFlattenPath(path, NULL, 1.0);
972     expect(Ok, status);
973     ok_path(path, flattenarc_path, sizeof(flattenarc_path)/sizeof(path_test_t), TRUE);
974
975     /* easy case - quater of a full circle */
976     status = GdipResetPath(path);
977     expect(Ok, status);
978     status = GdipAddPathArc(path, 0.0, 0.0, 100.0, 100.0, 0.0, 90.0);
979     expect(Ok, status);
980     status = GdipFlattenPath(path, NULL, 1.0);
981     expect(Ok, status);
982     ok_path(path, flattenquater_path, sizeof(flattenquater_path)/sizeof(path_test_t), FALSE);
983
984     GdipDeleteMatrix(m);
985     GdipDeletePath(path);
986 }
987
988 START_TEST(graphicspath)
989 {
990     struct GdiplusStartupInput gdiplusStartupInput;
991     ULONG_PTR gdiplusToken;
992
993     gdiplusStartupInput.GdiplusVersion              = 1;
994     gdiplusStartupInput.DebugEventCallback          = NULL;
995     gdiplusStartupInput.SuppressBackgroundThread    = 0;
996     gdiplusStartupInput.SuppressExternalCodecs      = 0;
997
998     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
999
1000     test_constructor_destructor();
1001     test_getpathdata();
1002     test_line2();
1003     test_arc();
1004     test_worldbounds();
1005     test_pathpath();
1006     test_ellipse();
1007     test_linei();
1008     test_rect();
1009     test_polygon();
1010     test_lastpoint();
1011     test_addcurve();
1012     test_addclosedcurve();
1013     test_reverse();
1014     test_addpie();
1015     test_flatten();
1016
1017     GdiplusShutdown(gdiplusToken);
1018 }