ole32: Check source pointer in StringFromGUID2.
[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 path_test_t addcurve_path3[] = {
730     {10.0, 10.0, PathPointTypeStart,  0, 0}, /*0*/
731     {13.3, 16.7, PathPointTypeBezier, 0, 1}, /*1*/
732     {3.3,  20.0, PathPointTypeBezier, 0, 0}, /*2*/
733     {10.0, 20.0, PathPointTypeBezier, 0, 0}, /*3*/
734     {16.7, 20.0, PathPointTypeBezier, 0, 0}, /*4*/
735     {23.3, 13.3, PathPointTypeBezier, 0, 0}, /*5*/
736     {30.0, 10.0, PathPointTypeBezier, 0, 0}  /*6*/
737     };
738 static void test_addcurve(void)
739 {
740     GpStatus status;
741     GpPath *path;
742     GpPointF points[4];
743
744     points[0].X = 0.0;
745     points[0].Y = 0.0;
746     points[1].X = 10.0;
747     points[1].Y = 10.0;
748     points[2].X = 10.0;
749     points[2].Y = 20.0;
750     points[3].X = 30.0;
751     points[3].Y = 10.0;
752
753     GdipCreatePath(FillModeAlternate, &path);
754
755     /* NULL args */
756     status = GdipAddPathCurve2(NULL, NULL, 0, 0.0);
757     expect(InvalidParameter, status);
758     status = GdipAddPathCurve2(path, NULL, 0, 0.0);
759     expect(InvalidParameter, status);
760     status = GdipAddPathCurve2(path, points, -1, 0.0);
761     expect(InvalidParameter, status);
762     status = GdipAddPathCurve2(path, points, 1, 1.0);
763     expect(InvalidParameter, status);
764
765     /* add to empty path */
766     status = GdipAddPathCurve2(path, points, 4, 1.0);
767     expect(Ok, status);
768     ok_path(path, addcurve_path, sizeof(addcurve_path)/sizeof(path_test_t), FALSE);
769     GdipDeletePath(path);
770
771     /* add to notempty path and opened figure */
772     GdipCreatePath(FillModeAlternate, &path);
773     GdipAddPathLine(path, 100.0, 120.0, 123.0, 10.0);
774     status = GdipAddPathCurve2(path, points, 4, 1.0);
775     expect(Ok, status);
776     ok_path(path, addcurve_path2, sizeof(addcurve_path2)/sizeof(path_test_t), FALSE);
777
778     /* NULL args */
779     GdipResetPath(path);
780     status = GdipAddPathCurve3(NULL, NULL, 0, 0, 0, 0.0);
781     expect(InvalidParameter, status);
782     status = GdipAddPathCurve3(path, NULL, 0, 0, 0, 0.0);
783     expect(InvalidParameter, status);
784     /* wrong count, offset.. */
785     status = GdipAddPathCurve3(path, points, 0, 0, 0, 0.0);
786     expect(InvalidParameter, status);
787     status = GdipAddPathCurve3(path, points, 4, 0, 0, 0.0);
788     expect(InvalidParameter, status);
789     status = GdipAddPathCurve3(path, points, 4, 0, 4, 0.0);
790     expect(InvalidParameter, status);
791     status = GdipAddPathCurve3(path, points, 4, 1, 3, 0.0);
792     expect(InvalidParameter, status);
793     status = GdipAddPathCurve3(path, points, 4, 1, 0, 0.0);
794     expect(InvalidParameter, status);
795     status = GdipAddPathCurve3(path, points, 4, 3, 1, 0.0);
796     expect(InvalidParameter, status);
797
798     /* use all points */
799     status = GdipAddPathCurve3(path, points, 4, 0, 3, 1.0);
800     expect(Ok, status);
801     ok_path(path, addcurve_path, sizeof(addcurve_path)/sizeof(path_test_t), FALSE);
802     GdipResetPath(path);
803
804     status = GdipAddPathCurve3(path, points, 4, 1, 2, 1.0);
805     expect(Ok, status);
806     ok_path(path, addcurve_path3, sizeof(addcurve_path3)/sizeof(path_test_t), FALSE);
807
808     GdipDeletePath(path);
809 }
810
811 static path_test_t addclosedcurve_path[] = {
812     {0.0, 0.0,   PathPointTypeStart,  0, 0}, /*0*/
813     {-6.7, 0.0,  PathPointTypeBezier, 0, 0}, /*1*/
814     {6.7, 3.3,   PathPointTypeBezier, 0, 0}, /*2*/
815     {10.0, 10.0, PathPointTypeBezier, 0, 0}, /*3*/
816     {13.3, 16.7, PathPointTypeBezier, 0, 0}, /*4*/
817     {3.3,  20.0, PathPointTypeBezier, 0, 0}, /*5*/
818     {10.0, 20.0, PathPointTypeBezier, 0, 0}, /*6*/
819     {16.7, 20.0, PathPointTypeBezier, 0, 0}, /*7*/
820     {33.3, 16.7, PathPointTypeBezier, 0, 0}, /*8*/
821     {30.0, 10.0, PathPointTypeBezier, 0, 0}, /*9*/
822     {26.7, 3.3,  PathPointTypeBezier, 0, 0}, /*10*/
823     {6.7,  0.0,  PathPointTypeBezier, 0, 0}, /*11*/
824     {0.0,  0.0,  PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0}  /*12*/
825     };
826 static void test_addclosedcurve(void)
827 {
828     GpStatus status;
829     GpPath *path;
830     GpPointF points[4];
831
832     points[0].X = 0.0;
833     points[0].Y = 0.0;
834     points[1].X = 10.0;
835     points[1].Y = 10.0;
836     points[2].X = 10.0;
837     points[2].Y = 20.0;
838     points[3].X = 30.0;
839     points[3].Y = 10.0;
840
841     GdipCreatePath(FillModeAlternate, &path);
842
843     /* NULL args */
844     status = GdipAddPathClosedCurve2(NULL, NULL, 0, 0.0);
845     expect(InvalidParameter, status);
846     status = GdipAddPathClosedCurve2(path, NULL, 0, 0.0);
847     expect(InvalidParameter, status);
848     status = GdipAddPathClosedCurve2(path, points, -1, 0.0);
849     expect(InvalidParameter, status);
850     status = GdipAddPathClosedCurve2(path, points, 1, 1.0);
851     expect(InvalidParameter, status);
852
853     /* add to empty path */
854     status = GdipAddPathClosedCurve2(path, points, 4, 1.0);
855     expect(Ok, status);
856     ok_path(path, addclosedcurve_path, sizeof(addclosedcurve_path)/sizeof(path_test_t), FALSE);
857     GdipDeletePath(path);
858 }
859
860 static path_test_t reverse_path[] = {
861     {0.0,  20.0, PathPointTypeStart, 0, 0}, /*0*/
862     {25.0, 25.0, PathPointTypeLine,  0, 0}, /*1*/
863     {0.0,  30.0, PathPointTypeLine,  0, 0}, /*2*/
864     {15.0, 35.0, PathPointTypeStart, 0, 0}, /*3*/
865     {0.0,  40.0, PathPointTypeLine,  0, 0}, /*4*/
866     {5.0,  45.0, PathPointTypeLine,  0, 0}, /*5*/
867     {0.0,  50.0, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}  /*6*/
868     };
869
870 static void test_reverse(void)
871 {
872     GpStatus status;
873     GpPath *path;
874     GpPointF pts[7];
875     INT i;
876
877     for(i = 0; i < 7; i++){
878         pts[i].X = i * 5.0 * (REAL)(i % 2);
879         pts[i].Y = 50.0 - i * 5.0;
880     }
881
882     GdipCreatePath(FillModeAlternate, &path);
883
884     /* NULL argument */
885     status = GdipReversePath(NULL);
886     expect(InvalidParameter, status);
887
888     /* empty path */
889     status = GdipReversePath(path);
890     expect(Ok, status);
891
892     GdipAddPathLine2(path, pts, 4);
893     GdipClosePathFigure(path);
894     GdipAddPathLine2(path, &(pts[4]), 3);
895
896     status = GdipReversePath(path);
897     expect(Ok, status);
898     ok_path(path, reverse_path, sizeof(reverse_path)/sizeof(path_test_t), FALSE);
899
900     GdipDeletePath(path);
901 }
902
903 static path_test_t addpie_path[] = {
904     {50.0, 25.0, PathPointTypeStart, 0, 0}, /*0*/
905     {97.2, 33.3, PathPointTypeLine,  0, 0}, /*1*/
906     {91.8, 40.9, PathPointTypeBezier,0, 0}, /*2*/
907     {79.4, 46.8, PathPointTypeBezier,0, 0}, /*3*/
908     {63.9, 49.0, PathPointTypeBezier | PathPointTypeCloseSubpath,  0, 0} /*4*/
909     };
910 static path_test_t addpie_path2[] = {
911     {0.0, 30.0, PathPointTypeStart | PathPointTypeCloseSubpath, 0, 0} /*0*/
912     };
913 static path_test_t addpie_path3[] = {
914     {30.0, 0.0, PathPointTypeStart | PathPointTypeCloseSubpath, 0, 0} /*0*/
915     };
916 static void test_addpie(void)
917 {
918     GpStatus status;
919     GpPath *path;
920
921     GdipCreatePath(FillModeAlternate, &path);
922
923     /* NULL argument */
924     status = GdipAddPathPie(NULL, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
925     expect(InvalidParameter, status);
926
927     status = GdipAddPathPie(path, 0.0, 0.0, 100.0, 50.0, 10.0, 50.0);
928     expect(Ok, status);
929     ok_path(path, addpie_path, sizeof(addpie_path)/sizeof(path_test_t), FALSE);
930     status = GdipResetPath(path);
931     expect(Ok, status);
932
933     /* zero width base ellipse */
934     status = GdipAddPathPie(path, 0.0, 0.0, 0.0, 60.0, -90.0, 24.0);
935     expect(InvalidParameter, status);
936     ok_path(path, addpie_path2, sizeof(addpie_path2)/sizeof(path_test_t), FALSE);
937     status = GdipResetPath(path);
938     expect(Ok, status);
939
940     /* zero height base ellipse */
941     status = GdipAddPathPie(path, 0.0, 0.0, 60.0, 0.0 , -90.0, 24.0);
942     expect(InvalidParameter, status);
943     ok_path(path, addpie_path3, sizeof(addpie_path3)/sizeof(path_test_t), FALSE);
944
945     GdipDeletePath(path);
946 }
947
948 static path_test_t flattenellipse_path[] = {
949     {100.0, 25.0,PathPointTypeStart, 0, 0}, /*0*/
950     {99.0, 30.0, PathPointTypeLine,  0, 0}, /*1*/
951     {96.0, 34.8, PathPointTypeLine,  0, 0}, /*2*/
952     {91.5, 39.0, PathPointTypeLine,  0, 0}, /*3*/
953     {85.5, 42.8, PathPointTypeLine,  0, 0}, /*4*/
954     {69.5, 48.0, PathPointTypeLine,  0, 1}, /*5*/
955     {50.0, 50.0, PathPointTypeLine,  0, 1}, /*6*/
956     {30.5, 48.0, PathPointTypeLine,  0, 1}, /*7*/
957     {14.8, 42.8, PathPointTypeLine,  0, 1}, /*8*/
958     {8.5,  39.0, PathPointTypeLine,  0, 1}, /*9*/
959     {4.0,  34.8, PathPointTypeLine,  0, 1}, /*10*/
960     {1.0,  30.0, PathPointTypeLine,  0, 1}, /*11*/
961     {0.0,  25.0, PathPointTypeLine,  0, 1}, /*12*/
962     {1.0,  20.0, PathPointTypeLine,  0, 1}, /*13*/
963     {4.0,  15.3, PathPointTypeLine,  0, 1}, /*14*/
964     {8.5,  11.0, PathPointTypeLine,  0, 1}, /*15*/
965     {14.8, 7.3,  PathPointTypeLine,  0, 1}, /*16*/
966     {30.5, 2.0,  PathPointTypeLine,  0, 1}, /*17*/
967     {50.0, 0.0,  PathPointTypeLine,  0, 1}, /*18*/
968     {69.5, 2.0,  PathPointTypeLine,  0, 1}, /*19*/
969     {85.5, 7.3,  PathPointTypeLine,  0, 1}, /*20*/
970     {91.5, 11.0, PathPointTypeLine,  0, 1}, /*21*/
971     {96.0, 15.3, PathPointTypeLine,  0, 1}, /*22*/
972     {99.0, 20.0, PathPointTypeLine,  0, 1}, /*23*/
973     {100.0,25.0, PathPointTypeLine | PathPointTypeCloseSubpath,  0, 1}  /*24*/
974     };
975
976 static path_test_t flattenline_path[] = {
977     {5.0, 10.0,PathPointTypeStart, 0, 0}, /*0*/
978     {50.0, 100.0, PathPointTypeLine,  0, 0} /*1*/
979     };
980
981 static path_test_t flattenarc_path[] = {
982     {100.0, 25.0,PathPointTypeStart, 0, 0}, /*0*/
983     {99.0, 30.0, PathPointTypeLine,  0, 0}, /*1*/
984     {96.0, 34.8, PathPointTypeLine,  0, 0}, /*2*/
985     {91.5, 39.0, PathPointTypeLine,  0, 0}, /*3*/
986     {85.5, 42.8, PathPointTypeLine,  0, 0}, /*4*/
987     {69.5, 48.0, PathPointTypeLine,  0, 1}, /*5*/
988     {50.0, 50.0, PathPointTypeLine,  0, 1}  /*6*/
989     };
990
991 static path_test_t flattenquater_path[] = {
992     {100.0, 50.0,PathPointTypeStart, 0, 0}, /*0*/
993     {99.0, 60.0, PathPointTypeLine,  0, 0}, /*1*/
994     {96.0, 69.5, PathPointTypeLine,  0, 0}, /*2*/
995     {91.5, 78.0, PathPointTypeLine,  0, 0}, /*3*/
996     {85.5, 85.5, PathPointTypeLine,  0, 0}, /*4*/
997     {78.0, 91.5, PathPointTypeLine,  0, 0}, /*5*/
998     {69.5, 96.0, PathPointTypeLine,  0, 0}, /*6*/
999     {60.0, 99.0, PathPointTypeLine,  0, 0}, /*7*/
1000     {50.0, 100.0,PathPointTypeLine,  0, 0}  /*8*/
1001     };
1002
1003 static void test_flatten(void)
1004 {
1005     GpStatus status;
1006     GpPath *path;
1007     GpMatrix *m;
1008
1009     status = GdipCreatePath(FillModeAlternate, &path);
1010     expect(Ok, status);
1011     status = GdipCreateMatrix(&m);
1012     expect(Ok, status);
1013
1014     /* NULL arguments */
1015     status = GdipFlattenPath(NULL, NULL, 0.0);
1016     expect(InvalidParameter, status);
1017     status = GdipFlattenPath(NULL, m, 0.0);
1018     expect(InvalidParameter, status);
1019
1020     /* flatten empty path */
1021     status = GdipFlattenPath(path, NULL, 1.0);
1022     expect(Ok, status);
1023
1024     status = GdipAddPathEllipse(path, 0.0, 0.0, 100.0, 50.0);
1025     expect(Ok, status);
1026
1027     status = GdipFlattenPath(path, NULL, 1.0);
1028     expect(Ok, status);
1029     ok_path(path, flattenellipse_path, sizeof(flattenellipse_path)/sizeof(path_test_t), TRUE);
1030
1031     status = GdipResetPath(path);
1032     expect(Ok, status);
1033     status = GdipAddPathLine(path, 5.0, 10.0, 50.0, 100.0);
1034     expect(Ok, status);
1035     status = GdipFlattenPath(path, NULL, 1.0);
1036     expect(Ok, status);
1037     ok_path(path, flattenline_path, sizeof(flattenline_path)/sizeof(path_test_t), FALSE);
1038
1039     status = GdipResetPath(path);
1040     expect(Ok, status);
1041     status = GdipAddPathArc(path, 0.0, 0.0, 100.0, 50.0, 0.0, 90.0);
1042     expect(Ok, status);
1043     status = GdipFlattenPath(path, NULL, 1.0);
1044     expect(Ok, status);
1045     ok_path(path, flattenarc_path, sizeof(flattenarc_path)/sizeof(path_test_t), TRUE);
1046
1047     /* easy case - quater of a full circle */
1048     status = GdipResetPath(path);
1049     expect(Ok, status);
1050     status = GdipAddPathArc(path, 0.0, 0.0, 100.0, 100.0, 0.0, 90.0);
1051     expect(Ok, status);
1052     status = GdipFlattenPath(path, NULL, 1.0);
1053     expect(Ok, status);
1054     ok_path(path, flattenquater_path, sizeof(flattenquater_path)/sizeof(path_test_t), FALSE);
1055
1056     GdipDeleteMatrix(m);
1057     GdipDeletePath(path);
1058 }
1059
1060 static void test_isvisible(void)
1061 {
1062     GpPath *path;
1063     GpGraphics *graphics = NULL;
1064     HDC hdc = GetDC(0);
1065     BOOL result;
1066     GpStatus status;
1067
1068     status = GdipCreateFromHDC(hdc, &graphics);
1069     expect(Ok, status);
1070     status = GdipCreatePath(FillModeAlternate, &path);
1071     expect(Ok, status);
1072
1073     /* NULL */
1074     status = GdipIsVisiblePathPoint(NULL, 0.0, 0.0, NULL, NULL);
1075     expect(InvalidParameter, status);
1076     status = GdipIsVisiblePathPoint(path, 0.0, 0.0, NULL, NULL);
1077     expect(InvalidParameter, status);
1078     status = GdipIsVisiblePathPoint(path, 0.0, 0.0, NULL, NULL);
1079     expect(InvalidParameter, status);
1080     status = GdipIsVisiblePathPoint(path, 0.0, 0.0, graphics, NULL);
1081     expect(InvalidParameter, status);
1082
1083     /* empty path */
1084     result = TRUE;
1085     status = GdipIsVisiblePathPoint(path, 0.0, 0.0, NULL, &result);
1086     expect(Ok, status);
1087     expect(FALSE, result);
1088     /* rect */
1089     status = GdipAddPathRectangle(path, 0.0, 0.0, 10.0, 10.0);
1090     expect(Ok, status);
1091     result = FALSE;
1092     status = GdipIsVisiblePathPoint(path, 0.0, 0.0, NULL, &result);
1093     expect(Ok, status);
1094     expect(TRUE, result);
1095     result = TRUE;
1096     status = GdipIsVisiblePathPoint(path, 11.0, 11.0, NULL, &result);
1097     expect(Ok, status);
1098     expect(FALSE, result);
1099     /* not affected by clipping */
1100     status = GdipSetClipRect(graphics, 5.0, 5.0, 5.0, 5.0, CombineModeReplace);
1101     expect(Ok, status);
1102     result = FALSE;
1103     status = GdipIsVisiblePathPoint(path, 0.0, 0.0, graphics, &result);
1104     expect(Ok, status);
1105     expect(TRUE, result);
1106
1107     GdipDeletePath(path);
1108     GdipDeleteGraphics(graphics);
1109     ReleaseDC(0, hdc);
1110 }
1111
1112 START_TEST(graphicspath)
1113 {
1114     struct GdiplusStartupInput gdiplusStartupInput;
1115     ULONG_PTR gdiplusToken;
1116
1117     gdiplusStartupInput.GdiplusVersion              = 1;
1118     gdiplusStartupInput.DebugEventCallback          = NULL;
1119     gdiplusStartupInput.SuppressBackgroundThread    = 0;
1120     gdiplusStartupInput.SuppressExternalCodecs      = 0;
1121
1122     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
1123
1124     test_constructor_destructor();
1125     test_getpathdata();
1126     test_line2();
1127     test_arc();
1128     test_worldbounds();
1129     test_pathpath();
1130     test_ellipse();
1131     test_linei();
1132     test_rect();
1133     test_polygon();
1134     test_lastpoint();
1135     test_addcurve();
1136     test_addclosedcurve();
1137     test_reverse();
1138     test_addpie();
1139     test_flatten();
1140     test_isvisible();
1141
1142     GdiplusShutdown(gdiplusToken);
1143 }