Sync trunk r40500
[reactos.git] / rostests / winetests / gdiplus / 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
219 static path_test_t arc_path[] = {
220 {600.0, 450.0, PathPointTypeStart, 0, 0}, /*0*/
221 {600.0, 643.3, PathPointTypeBezier, 0, 0}, /*1*/
222 {488.1, 800.0, PathPointTypeBezier, 0, 0}, /*2*/
223 {350.0, 800.0, PathPointTypeBezier, 0, 0}, /*3*/
224 {600.0, 450.0, PathPointTypeLine, 0, 0}, /*4*/
225 {600.0, 643.3, PathPointTypeBezier, 0, 0}, /*5*/
226 {488.1, 800.0, PathPointTypeBezier, 0, 0}, /*6*/
227 {350.0, 800.0, PathPointTypeBezier, 0, 0}, /*7*/
228 {329.8, 800.0, PathPointTypeBezier, 0, 0}, /*8*/
229 {309.7, 796.6, PathPointTypeBezier, 0, 0}, /*9*/
230 {290.1, 789.8, PathPointTypeBezier, 0, 0}, /*10*/
231 {409.9, 110.2, PathPointTypeLine, 0, 0}, /*11*/
232 {544.0, 156.5, PathPointTypeBezier, 0, 0}, /*12*/
233 {625.8, 346.2, PathPointTypeBezier, 0, 0}, /*13*/
234 {592.7, 533.9, PathPointTypeBezier, 0, 0}, /*14*/
235 {592.5, 535.3, PathPointTypeBezier, 0, 0}, /*15*/
236 {592.2, 536.7, PathPointTypeBezier, 0, 0}, /*16*/
237 {592.0, 538.1, PathPointTypeBezier, 0, 0}, /*17*/
238 {409.9, 789.8, PathPointTypeLine, 0, 0}, /*18*/
239 {544.0, 743.5, PathPointTypeBezier, 0, 0}, /*19*/
240 {625.8, 553.8, PathPointTypeBezier, 0, 0}, /*20*/
241 {592.7, 366.1, PathPointTypeBezier, 0, 0}, /*21*/
242 {592.5, 364.7, PathPointTypeBezier, 0, 0}, /*22*/
243 {592.2, 363.3, PathPointTypeBezier, 0, 0}, /*23*/
244 {592.0, 361.9, PathPointTypeBezier, 0, 0}, /*24*/
245 {540.4, 676.9, PathPointTypeLine, 0, 0}, /*25*/
246 {629.9, 529.7, PathPointTypeBezier, 0, 0}, /*26*/
247 {617.2, 308.8, PathPointTypeBezier, 0, 0}, /*27*/
248 {512.1, 183.5, PathPointTypeBezier, 0, 0}, /*28*/
249 {406.9, 58.2, PathPointTypeBezier, 0, 0}, /*29*/
250 {249.1, 75.9, PathPointTypeBezier, 0, 0}, /*30*/
251 {159.6, 223.1, PathPointTypeBezier, 0, 0}, /*31*/
252 {70.1, 370.3, PathPointTypeBezier, 0, 0}, /*32*/
253 {82.8, 591.2, PathPointTypeBezier, 0, 0}, /*33*/
254 {187.9, 716.5, PathPointTypeBezier, 0, 0}, /*34*/
255 {293.1, 841.8, PathPointTypeBezier, 0, 0}, /*35*/
256 {450.9, 824.1, PathPointTypeBezier, 0, 0}, /*36*/
257 {540.4, 676.9, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 1} /*37*/
258 };
259
260 static void test_arc(void)
261 {
262 GpStatus status;
263 GpPath* path;
264
265 GdipCreatePath(FillModeAlternate, &path);
266 /* Exactly 90 degrees */
267 status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 90.0);
268 expect(Ok, status);
269 /* Over 90 degrees */
270 status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
271 expect(Ok, status);
272 /* Negative start angle */
273 status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, -80.0, 100.0);
274 expect(Ok, status);
275 /* Negative sweep angle */
276 status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 80.0, -100.0);
277 expect(Ok, status);
278 /* More than a full revolution */
279 status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 50.0, -400.0);
280 expect(Ok, status);
281 /* 0 sweep angle */
282 status = GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 50.0, 0.0);
283 expect(Ok, status);
284
285 ok_path(path, arc_path, sizeof(arc_path)/sizeof(path_test_t), FALSE);
286 }
287
288 static void test_worldbounds(void)
289 {
290 GpStatus status;
291 GpPath *path;
292 GpPen *pen;
293 GpMatrix *matrix;
294 GpRectF bounds;
295 GpPointF line2_points[10];
296 int i;
297
298 for(i = 0; i < 10; i ++){
299 line2_points[i].X = 200.0 + i * 50.0 * (i % 2);
300 line2_points[i].Y = 200.0 + i * 50.0 * !(i % 2);
301 }
302 GdipCreatePen1((ARGB)0xdeadbeef, 20.0, UnitWorld, &pen);
303 GdipSetPenEndCap(pen, LineCapSquareAnchor);
304 GdipCreateMatrix2(1.5, 0.0, 1.0, 1.2, 10.4, 10.2, &matrix);
305
306 GdipCreatePath(FillModeAlternate, &path);
307 GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
308 GdipAddPathLine2(path, &(line2_points[0]), 10);
309 status = GdipGetPathWorldBounds(path, &bounds, NULL, NULL);
310 expect(Ok, status);
311 GdipDeletePath(path);
312
313 expectf(200.0, bounds.X);
314 expectf(200.0, bounds.Y);
315 expectf(450.0, bounds.Width);
316 expectf(600.0, bounds.Height);
317
318 GdipCreatePath(FillModeAlternate, &path);
319 GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
320 GdipAddPathLine2(path, &(line2_points[0]), 10);
321 status = GdipGetPathWorldBounds(path, &bounds, matrix, NULL);
322 expect(Ok, status);
323 GdipDeletePath(path);
324
325 expectf(510.4, bounds.X);
326 expectf(250.2, bounds.Y);
327 expectf(1275.0, bounds.Width);
328 expectf(720.0, bounds.Height);
329
330 GdipCreatePath(FillModeAlternate, &path);
331 GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
332 GdipAddPathLine2(path, &(line2_points[0]), 10);
333 status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
334 expect(Ok, status);
335 GdipDeletePath(path);
336
337 expectf(100.0, bounds.X);
338 expectf(100.0, bounds.Y);
339 expectf(650.0, bounds.Width);
340 expectf(800.0, bounds.Height);
341
342 GdipCreatePath(FillModeAlternate, &path);
343 GdipAddPathLine2(path, &(line2_points[0]), 2);
344 status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
345 expect(Ok, status);
346 GdipDeletePath(path);
347
348 expectf(156.0, bounds.X);
349 expectf(156.0, bounds.Y);
350 expectf(138.0, bounds.Width);
351 expectf(88.0, bounds.Height);
352
353 line2_points[2].X = 2 * line2_points[1].X - line2_points[0].X;
354 line2_points[2].Y = 2 * line2_points[1].Y - line2_points[0].Y;
355
356 GdipCreatePath(FillModeAlternate, &path);
357 GdipAddPathLine2(path, &(line2_points[0]), 3);
358 status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
359 expect(Ok, status);
360 GdipDeletePath(path);
361
362 expectf(100.0, bounds.X);
363 expectf(100.0, bounds.Y);
364 expectf(300.0, bounds.Width);
365 expectf(200.0, bounds.Height);
366
367 GdipCreatePath(FillModeAlternate, &path);
368 GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 45.0, 20.0);
369 status = GdipGetPathWorldBounds(path, &bounds, NULL, pen);
370 expect(Ok, status);
371 GdipDeletePath(path);
372
373 expectf(386.7, bounds.X);
374 expectf(553.4, bounds.Y);
375 expectf(266.8, bounds.Width);
376 expectf(289.6, bounds.Height);
377
378 GdipCreatePath(FillModeAlternate, &path);
379 status = GdipGetPathWorldBounds(path, &bounds, matrix, pen);
380 expect(Ok, status);
381 GdipDeletePath(path);
382
383 expectf(0.0, bounds.X);
384 expectf(0.0, bounds.Y);
385 expectf(0.0, bounds.Width);
386 expectf(0.0, bounds.Height);
387
388 GdipCreatePath(FillModeAlternate, &path);
389 GdipAddPathLine2(path, &(line2_points[0]), 2);
390 status = GdipGetPathWorldBounds(path, &bounds, matrix, pen);
391 expect(Ok, status);
392 GdipDeletePath(path);
393
394 todo_wine{
395 expectf(427.9, bounds.X);
396 expectf(167.7, bounds.Y);
397 expectf(239.9, bounds.Width);
398 expectf(164.9, bounds.Height);
399 }
400
401 GdipDeleteMatrix(matrix);
402 GdipCreateMatrix2(0.9, -0.5, -0.5, -1.2, 10.4, 10.2, &matrix);
403 GdipCreatePath(FillModeAlternate, &path);
404 GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, 0.0, 100.0);
405 GdipAddPathLine2(path, &(line2_points[0]), 10);
406 status = GdipGetPathWorldBounds(path, &bounds, matrix, NULL);
407 expect(Ok, status);
408 GdipDeletePath(path);
409
410 expectf(-209.6, bounds.X);
411 expectf(-1274.8, bounds.Y);
412 expectf(705.0, bounds.Width);
413 expectf(945.0, bounds.Height);
414 }
415
416 static path_test_t pathpath_path[] = {
417 {600.00, 450.00, PathPointTypeStart, 0, 0}, /*0*/
418 {600.00, 643.30, PathPointTypeBezier, 0, 0}, /*1*/
419 {488.07, 800.00, PathPointTypeBezier, 0, 0}, /*2*/
420 {350.00, 800.00, PathPointTypeBezier, 0, 0}, /*3*/
421 {319.61, 797.40, PathPointTypeStart, 0, 0}, /*4*/
422 {182.56, 773.90, PathPointTypeBezier, 0, 0}, /*5*/
423 {85.07, 599.31, PathPointTypeBezier, 0, 0}, /*6*/
424 {101.85, 407.45, PathPointTypeBezier, 0, 0}, /*7*/
425 {102.54, 399.66, PathPointTypeBezier, 0, 0}, /*8*/
426 {103.40, 391.91, PathPointTypeBezier, 0, 0}, /*9*/
427 {104.46, 384.21, PathPointTypeBezier, 0, 0}, /*10*/
428 {409.92, 110.20, PathPointTypeLine, 0, 0}, /*11*/
429 {543.96, 156.53, PathPointTypeBezier, 0, 0}, /*12*/
430 {625.80, 346.22, PathPointTypeBezier, 0, 0}, /*13*/
431 {592.71, 533.88, PathPointTypeBezier, 0, 0}, /*14*/
432 {592.47, 535.28, PathPointTypeBezier, 0, 0}, /*15*/
433 {592.22, 536.67, PathPointTypeBezier, 0, 0}, /*16*/
434 {591.96, 538.06, PathPointTypeBezier, 0, 0}, /*17*/
435 {319.61, 797.40, PathPointTypeLine, 0, 0}, /*18*/
436 {182.56, 773.90, PathPointTypeBezier, 0, 0}, /*19*/
437 {85.07, 599.31, PathPointTypeBezier, 0, 0}, /*20*/
438 {101.85, 407.45, PathPointTypeBezier, 0, 0}, /*21*/
439 {102.54, 399.66, PathPointTypeBezier, 0, 0}, /*22*/
440 {103.40, 391.91, PathPointTypeBezier, 0, 0}, /*23*/
441 {104.46, 384.21, PathPointTypeBezier, 0, 0} /*24*/
442 };
443
444 static void test_pathpath(void)
445 {
446 GpStatus status;
447 GpPath* path1, *path2;
448
449 GdipCreatePath(FillModeAlternate, &path2);
450 GdipAddPathArc(path2, 100.0, 100.0, 500.0, 700.0, 95.0, 100.0);
451
452 GdipCreatePath(FillModeAlternate, &path1);
453 GdipAddPathArc(path1, 100.0, 100.0, 500.0, 700.0, 0.0, 90.0);
454 status = GdipAddPathPath(path1, path2, FALSE);
455 expect(Ok, status);
456 GdipAddPathArc(path1, 100.0, 100.0, 500.0, 700.0, -80.0, 100.0);
457 status = GdipAddPathPath(path1, path2, TRUE);
458 expect(Ok, status);
459
460 ok_path(path1, pathpath_path, sizeof(pathpath_path)/sizeof(path_test_t), FALSE);
461
462 GdipDeletePath(path1);
463 GdipDeletePath(path2);
464 }
465
466 static path_test_t ellipse_path[] = {
467 {30.00, 125.25, PathPointTypeStart, 0, 0}, /*0*/
468 {30.00, 139.20, PathPointTypeBezier, 0, 0}, /*1*/
469 {25.52, 150.50, PathPointTypeBezier, 0, 0}, /*2*/
470 {20.00, 150.50, PathPointTypeBezier, 0, 0}, /*3*/
471 {14.48, 150.50, PathPointTypeBezier, 0, 0}, /*4*/
472 {10.00, 139.20, PathPointTypeBezier, 0, 0}, /*5*/
473 {10.00, 125.25, PathPointTypeBezier, 0, 0}, /*6*/
474 {10.00, 111.30, PathPointTypeBezier, 0, 0}, /*7*/
475 {14.48, 100.00, PathPointTypeBezier, 0, 0}, /*8*/
476 {20.00, 100.00, PathPointTypeBezier, 0, 0}, /*9*/
477 {25.52, 100.00, PathPointTypeBezier, 0, 0}, /*10*/
478 {30.00, 111.30, PathPointTypeBezier, 0, 0}, /*11*/
479 {30.00, 125.25, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0}, /*12*/
480 {7.00, 11.00, PathPointTypeStart, 0, 0}, /*13*/
481 {13.00, 17.00, PathPointTypeLine, 0, 0}, /*14*/
482 {5.00, 195.00, PathPointTypeStart, 0, 0}, /*15*/
483 {5.00, 192.24, PathPointTypeBezier, 0, 0}, /*16*/
484 {6.12, 190.00, PathPointTypeBezier, 0, 0}, /*17*/
485 {7.50, 190.00, PathPointTypeBezier, 0, 0}, /*18*/
486 {8.88, 190.00, PathPointTypeBezier, 0, 0}, /*19*/
487 {10.00, 192.24, PathPointTypeBezier, 0, 0}, /*20*/
488 {10.00, 195.00, PathPointTypeBezier, 0, 0}, /*21*/
489 {10.00, 197.76, PathPointTypeBezier, 0, 0}, /*22*/
490 {8.88, 200.00, PathPointTypeBezier, 0, 0}, /*23*/
491 {7.50, 200.00, PathPointTypeBezier, 0, 0}, /*24*/
492 {6.12, 200.00, PathPointTypeBezier, 0, 0}, /*25*/
493 {5.00, 197.76, PathPointTypeBezier, 0, 0}, /*26*/
494 {5.00, 195.00, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0}, /*27*/
495 {10.00, 300.50, PathPointTypeStart, 0, 0}, /*28*/
496 {10.00, 300.78, PathPointTypeBezier, 0, 0}, /*29*/
497 {10.00, 301.00, PathPointTypeBezier, 0, 0}, /*30*/
498 {10.00, 301.00, PathPointTypeBezier, 0, 0}, /*31*/
499 {10.00, 301.00, PathPointTypeBezier, 0, 0}, /*32*/
500 {10.00, 300.78, PathPointTypeBezier, 0, 0}, /*33*/
501 {10.00, 300.50, PathPointTypeBezier, 0, 0}, /*34*/
502 {10.00, 300.22, PathPointTypeBezier, 0, 0}, /*35*/
503 {10.00, 300.00, PathPointTypeBezier, 0, 0}, /*36*/
504 {10.00, 300.00, PathPointTypeBezier, 0, 0}, /*37*/
505 {10.00, 300.00, PathPointTypeBezier, 0, 0}, /*38*/
506 {10.00, 300.22, PathPointTypeBezier, 0, 0}, /*39*/
507 {10.00, 300.50, PathPointTypeBezier | PathPointTypeCloseSubpath, 0, 0} /*40*/
508 };
509
510 static void test_ellipse(void)
511 {
512 GpStatus status;
513 GpPath *path;
514 GpPointF points[2];
515
516 points[0].X = 7.0;
517 points[0].Y = 11.0;
518 points[1].X = 13.0;
519 points[1].Y = 17.0;
520
521 GdipCreatePath(FillModeAlternate, &path);
522 status = GdipAddPathEllipse(path, 10.0, 100.0, 20.0, 50.5);
523 expect(Ok, status);
524 GdipAddPathLine2(path, points, 2);
525 status = GdipAddPathEllipse(path, 10.0, 200.0, -5.0, -10.0);
526 expect(Ok, status);
527 GdipClosePathFigure(path);
528 status = GdipAddPathEllipse(path, 10.0, 300.0, 0.0, 1.0);
529 expect(Ok, status);
530
531 ok_path(path, ellipse_path, sizeof(ellipse_path)/sizeof(path_test_t), FALSE);
532
533 GdipDeletePath(path);
534 }
535
536 static path_test_t linei_path[] = {
537 {5.00, 5.00, PathPointTypeStart, 0, 0}, /*0*/
538 {6.00, 8.00, PathPointTypeLine, 0, 0}, /*1*/
539 {409.92, 110.20, PathPointTypeLine, 0, 0}, /*2*/
540 {543.96, 156.53, PathPointTypeBezier, 0, 0}, /*3*/
541 {625.80, 346.22, PathPointTypeBezier, 0, 0}, /*4*/
542 {592.71, 533.88, PathPointTypeBezier, 0, 0}, /*5*/
543 {592.47, 535.28, PathPointTypeBezier, 0, 0}, /*6*/
544 {592.22, 536.67, PathPointTypeBezier, 0, 0}, /*7*/
545 {591.96, 538.06, PathPointTypeBezier, 0, 0}, /*8*/
546 {15.00, 15.00, PathPointTypeLine, 0, 0}, /*9*/
547 {26.00, 28.00, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*10*/
548 {35.00, 35.00, PathPointTypeStart, 0, 0}, /*11*/
549 {36.00, 38.00, PathPointTypeLine, 0, 0} /*12*/
550 };
551
552 static void test_linei(void)
553 {
554 GpStatus status;
555 GpPath *path;
556 GpPointF points[2];
557
558 points[0].X = 7.0;
559 points[0].Y = 11.0;
560 points[1].X = 13.0;
561 points[1].Y = 17.0;
562
563 GdipCreatePath(FillModeAlternate, &path);
564 status = GdipAddPathLineI(path, 5.0, 5.0, 6.0, 8.0);
565 expect(Ok, status);
566 GdipAddPathArc(path, 100.0, 100.0, 500.0, 700.0, -80.0, 100.0);
567 status = GdipAddPathLineI(path, 15.0, 15.0, 26.0, 28.0);
568 expect(Ok, status);
569 GdipClosePathFigure(path);
570 status = GdipAddPathLineI(path, 35.0, 35.0, 36.0, 38.0);
571 expect(Ok, status);
572
573 ok_path(path, linei_path, sizeof(linei_path)/sizeof(path_test_t), FALSE);
574
575 GdipDeletePath(path);
576 }
577
578 static path_test_t poly_path[] = {
579 {5.00, 5.00, PathPointTypeStart, 0, 0}, /*1*/
580 {6.00, 8.00, PathPointTypeLine, 0, 0}, /*2*/
581 {0.00, 0.00, PathPointTypeStart, 0, 0}, /*3*/
582 {10.00, 10.00, PathPointTypeLine, 0, 0}, /*4*/
583 {10.00, 20.00, PathPointTypeLine, 0, 0}, /*5*/
584 {30.00, 10.00, PathPointTypeLine, 0, 0}, /*6*/
585 {20.00, 0.00, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*7*/
586 };
587
588 static void test_polygon(void)
589 {
590 GpStatus status;
591 GpPath *path;
592 GpPointF points[5];
593
594 points[0].X = 0.0;
595 points[0].Y = 0.0;
596 points[1].X = 10.0;
597 points[1].Y = 10.0;
598 points[2].X = 10.0;
599 points[2].Y = 20.0;
600 points[3].X = 30.0;
601 points[3].Y = 10.0;
602 points[4].X = 20.0;
603 points[4].Y = 0.0;
604
605 GdipCreatePath(FillModeAlternate, &path);
606
607 /* NULL args */
608 status = GdipAddPathPolygon(NULL, points, 5);
609 expect(InvalidParameter, status);
610 status = GdipAddPathPolygon(path, NULL, 5);
611 expect(InvalidParameter, status);
612 /* Polygon should have 3 points at least */
613 status = GdipAddPathPolygon(path, points, 2);
614 expect(InvalidParameter, status);
615
616 /* to test how it prolongs not empty path */
617 status = GdipAddPathLine(path, 5.0, 5.0, 6.0, 8.0);
618 expect(Ok, status);
619 status = GdipAddPathPolygon(path, points, 5);
620 expect(Ok, status);
621 /* check resulting path */
622 ok_path(path, poly_path, sizeof(poly_path)/sizeof(path_test_t), FALSE);
623
624 GdipDeletePath(path);
625 }
626
627 static path_test_t rect_path[] = {
628 {5.0, 5.0, PathPointTypeStart, 0, 0}, /*0*/
629 {105.0, 5.0, PathPointTypeLine, 0, 0}, /*1*/
630 {105.0, 55.0, PathPointTypeLine, 0, 0}, /*2*/
631 {5.0, 55.0, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0}, /*3*/
632
633 {100.0, 50.0, PathPointTypeStart, 0, 0}, /*4*/
634 {220.0, 50.0, PathPointTypeLine, 0, 0}, /*5*/
635 {220.0, 80.0, PathPointTypeLine, 0, 0}, /*6*/
636 {100.0, 80.0, PathPointTypeLine | PathPointTypeCloseSubpath, 0, 0} /*7*/
637 };
638
639 static void test_rect(void)
640 {
641 GpStatus status;
642 GpPath *path;
643 GpRectF rects[2];
644
645 GdipCreatePath(FillModeAlternate, &path);
646 status = GdipAddPathRectangle(path, 5.0, 5.0, 100.0, 50.0);
647 expect(Ok, status);
648 status = GdipAddPathRectangle(path, 100.0, 50.0, 120.0, 30.0);
649 expect(Ok, status);
650
651 ok_path(path, rect_path, sizeof(rect_path)/sizeof(path_test_t), FALSE);
652
653 GdipDeletePath(path);
654
655 GdipCreatePath(FillModeAlternate, &path);
656
657 rects[0].X = 5.0;
658 rects[0].Y = 5.0;
659 rects[0].Width = 100.0;
660 rects[0].Height = 50.0;
661 rects[1].X = 100.0;
662 rects[1].Y = 50.0;
663 rects[1].Width = 120.0;
664 rects[1].Height = 30.0;
665
666 status = GdipAddPathRectangles(path, (GDIPCONST GpRectF*)&rects, 2);
667 expect(Ok, status);
668
669 ok_path(path, rect_path, sizeof(rect_path)/sizeof(path_test_t), FALSE);
670
671 GdipDeletePath(path);
672 }
673
674 static void test_lastpoint(void)
675 {
676 GpStatus status;
677 GpPath *path;
678 GpPointF ptf;
679
680 GdipCreatePath(FillModeAlternate, &path);
681 status = GdipAddPathRectangle(path, 5.0, 5.0, 100.0, 50.0);
682 expect(Ok, status);
683
684 /* invalid args */
685 status = GdipGetPathLastPoint(NULL, &ptf);
686 expect(InvalidParameter, status);
687 status = GdipGetPathLastPoint(path, NULL);
688 expect(InvalidParameter, status);
689 status = GdipGetPathLastPoint(NULL, NULL);
690 expect(InvalidParameter, status);
691
692 status = GdipGetPathLastPoint(path, &ptf);
693 expect(Ok, status);
694 expect(TRUE, (ptf.X == 5.0) && (ptf.Y == 55.0));
695
696 GdipDeletePath(path);
697 }
698
699 START_TEST(graphicspath)
700 {
701 struct GdiplusStartupInput gdiplusStartupInput;
702 ULONG_PTR gdiplusToken;
703
704 gdiplusStartupInput.GdiplusVersion = 1;
705 gdiplusStartupInput.DebugEventCallback = NULL;
706 gdiplusStartupInput.SuppressBackgroundThread = 0;
707 gdiplusStartupInput.SuppressExternalCodecs = 0;
708
709 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
710
711 test_constructor_destructor();
712 test_getpathdata();
713 test_line2();
714 test_arc();
715 test_worldbounds();
716 test_pathpath();
717 test_ellipse();
718 test_linei();
719 test_rect();
720 test_polygon();
721 test_lastpoint();
722
723 GdiplusShutdown(gdiplusToken);
724 }