~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/gdiplus/graphicspath.c

Version: ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Copyright (C) 2007 Google (Evan Stade)
  3  *
  4  * This library is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2.1 of the License, or (at your option) any later version.
  8  *
  9  * This library is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with this library; if not, write to the Free Software
 16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 17  *
 18  */
 19 
 20 #include <stdarg.h>
 21 #include <math.h>
 22 
 23 #include "windef.h"
 24 #include "winbase.h"
 25 #include "winuser.h"
 26 #include "wingdi.h"
 27 
 28 #include "objbase.h"
 29 
 30 #include "gdiplus.h"
 31 #include "gdiplus_private.h"
 32 #include "wine/debug.h"
 33 
 34 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 35 
 36 /* make sure path has enough space for len more points */
 37 static BOOL lengthen_path(GpPath *path, INT len)
 38 {
 39     /* initial allocation */
 40     if(path->datalen == 0){
 41         path->datalen = len * 2;
 42 
 43         path->pathdata.Points = GdipAlloc(path->datalen * sizeof(PointF));
 44         if(!path->pathdata.Points)   return FALSE;
 45 
 46         path->pathdata.Types = GdipAlloc(path->datalen);
 47         if(!path->pathdata.Types){
 48             GdipFree(path->pathdata.Points);
 49             return FALSE;
 50         }
 51     }
 52     /* reallocation, double size of arrays */
 53     else if(path->datalen - path->pathdata.Count < len){
 54         while(path->datalen - path->pathdata.Count < len)
 55             path->datalen *= 2;
 56 
 57         path->pathdata.Points = HeapReAlloc(GetProcessHeap(), 0,
 58             path->pathdata.Points, path->datalen * sizeof(PointF));
 59         if(!path->pathdata.Points)  return FALSE;
 60 
 61         path->pathdata.Types = HeapReAlloc(GetProcessHeap(), 0,
 62             path->pathdata.Types, path->datalen);
 63         if(!path->pathdata.Types)   return FALSE;
 64     }
 65 
 66     return TRUE;
 67 }
 68 
 69 GpStatus WINGDIPAPI GdipAddPathArc(GpPath *path, REAL x1, REAL y1, REAL x2,
 70     REAL y2, REAL startAngle, REAL sweepAngle)
 71 {
 72     INT count, old_count, i;
 73 
 74     if(!path)
 75         return InvalidParameter;
 76 
 77     count = arc2polybezier(NULL, x1, y1, x2, y2, startAngle, sweepAngle);
 78 
 79     if(count == 0)
 80         return Ok;
 81     if(!lengthen_path(path, count))
 82         return OutOfMemory;
 83 
 84     old_count = path->pathdata.Count;
 85     arc2polybezier(&path->pathdata.Points[old_count], x1, y1, x2, y2,
 86                    startAngle, sweepAngle);
 87 
 88     for(i = 0; i < count; i++){
 89         path->pathdata.Types[old_count + i] = PathPointTypeBezier;
 90     }
 91 
 92     path->pathdata.Types[old_count] =
 93         (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
 94     path->newfigure = FALSE;
 95     path->pathdata.Count += count;
 96 
 97     return Ok;
 98 }
 99 
100 GpStatus WINGDIPAPI GdipAddPathArcI(GpPath *path, INT x1, INT y1, INT x2,
101    INT y2, REAL startAngle, REAL sweepAngle)
102 {
103     return GdipAddPathArc(path,(REAL)x1,(REAL)y1,(REAL)x2,(REAL)y2,startAngle,sweepAngle);
104 }
105 
106 GpStatus WINGDIPAPI GdipAddPathBezier(GpPath *path, REAL x1, REAL y1, REAL x2,
107     REAL y2, REAL x3, REAL y3, REAL x4, REAL y4)
108 {
109     INT old_count;
110 
111     if(!path)
112         return InvalidParameter;
113 
114     if(!lengthen_path(path, 4))
115         return OutOfMemory;
116 
117     old_count = path->pathdata.Count;
118 
119     path->pathdata.Points[old_count].X = x1;
120     path->pathdata.Points[old_count].Y = y1;
121     path->pathdata.Points[old_count + 1].X = x2;
122     path->pathdata.Points[old_count + 1].Y = y2;
123     path->pathdata.Points[old_count + 2].X = x3;
124     path->pathdata.Points[old_count + 2].Y = y3;
125     path->pathdata.Points[old_count + 3].X = x4;
126     path->pathdata.Points[old_count + 3].Y = y4;
127 
128     path->pathdata.Types[old_count] =
129         (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
130     path->pathdata.Types[old_count + 1] = PathPointTypeBezier;
131     path->pathdata.Types[old_count + 2] = PathPointTypeBezier;
132     path->pathdata.Types[old_count + 3] = PathPointTypeBezier;
133 
134     path->newfigure = FALSE;
135     path->pathdata.Count += 4;
136 
137     return Ok;
138 }
139 
140 GpStatus WINGDIPAPI GdipAddPathBezierI(GpPath *path, INT x1, INT y1, INT x2,
141     INT y2, INT x3, INT y3, INT x4, INT y4)
142 {
143     return GdipAddPathBezier(path,(REAL)x1,(REAL)y1,(REAL)x2,(REAL)y2,(REAL)x3,(REAL)y3,
144                                   (REAL)x4,(REAL)y4);
145 }
146 
147 GpStatus WINGDIPAPI GdipAddPathBeziers(GpPath *path, GDIPCONST GpPointF *points,
148     INT count)
149 {
150     INT i, old_count;
151 
152     if(!path || !points || ((count - 1) % 3))
153         return InvalidParameter;
154 
155     if(!lengthen_path(path, count))
156         return OutOfMemory;
157 
158     old_count = path->pathdata.Count;
159 
160     for(i = 0; i < count; i++){
161         path->pathdata.Points[old_count + i].X = points[i].X;
162         path->pathdata.Points[old_count + i].Y = points[i].Y;
163         path->pathdata.Types[old_count + i] = PathPointTypeBezier;
164     }
165 
166     path->pathdata.Types[old_count] =
167         (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
168     path->newfigure = FALSE;
169     path->pathdata.Count += count;
170 
171     return Ok;
172 }
173 
174 GpStatus WINGDIPAPI GdipAddPathBeziersI(GpPath *path, GDIPCONST GpPoint *points,
175     INT count)
176 {
177     GpPointF *ptsF;
178     GpStatus ret;
179     INT i;
180 
181     if(!points || ((count - 1) % 3))
182         return InvalidParameter;
183 
184     ptsF = GdipAlloc(sizeof(GpPointF) * count);
185     if(!ptsF)
186         return OutOfMemory;
187 
188     for(i = 0; i < count; i++){
189         ptsF[i].X = (REAL)points[i].X;
190         ptsF[i].Y = (REAL)points[i].Y;
191     }
192 
193     ret = GdipAddPathBeziers(path, ptsF, count);
194     GdipFree(ptsF);
195 
196     return ret;
197 }
198 
199 GpStatus WINGDIPAPI GdipAddPathEllipse(GpPath *path, REAL x, REAL y, REAL width,
200     REAL height)
201 {
202     INT old_count, numpts;
203 
204     if(!path)
205         return InvalidParameter;
206 
207     if(!lengthen_path(path, MAX_ARC_PTS))
208         return OutOfMemory;
209 
210     old_count = path->pathdata.Count;
211     if((numpts = arc2polybezier(&path->pathdata.Points[old_count],  x, y, width,
212                                height, 0.0, 360.0)) != MAX_ARC_PTS){
213         ERR("expected %d points but got %d\n", MAX_ARC_PTS, numpts);
214         return GenericError;
215     }
216 
217     memset(&path->pathdata.Types[old_count + 1], PathPointTypeBezier,
218            MAX_ARC_PTS - 1);
219 
220     /* An ellipse is an intrinsic figure (always is its own subpath). */
221     path->pathdata.Types[old_count] = PathPointTypeStart;
222     path->pathdata.Types[old_count + MAX_ARC_PTS - 1] |= PathPointTypeCloseSubpath;
223     path->newfigure = TRUE;
224     path->pathdata.Count += MAX_ARC_PTS;
225 
226     return Ok;
227 }
228 
229 GpStatus WINGDIPAPI GdipAddPathEllipseI(GpPath *path, INT x, INT y, INT width,
230     INT height)
231 {
232     return GdipAddPathEllipse(path,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
233 }
234 
235 GpStatus WINGDIPAPI GdipAddPathLine2(GpPath *path, GDIPCONST GpPointF *points,
236     INT count)
237 {
238     INT i, old_count;
239 
240     if(!path || !points)
241         return InvalidParameter;
242 
243     if(!lengthen_path(path, count))
244         return OutOfMemory;
245 
246     old_count = path->pathdata.Count;
247 
248     for(i = 0; i < count; i++){
249         path->pathdata.Points[old_count + i].X = points[i].X;
250         path->pathdata.Points[old_count + i].Y = points[i].Y;
251         path->pathdata.Types[old_count + i] = PathPointTypeLine;
252     }
253 
254     if(path->newfigure){
255         path->pathdata.Types[old_count] = PathPointTypeStart;
256         path->newfigure = FALSE;
257     }
258 
259     path->pathdata.Count += count;
260 
261     return Ok;
262 }
263 
264 GpStatus WINGDIPAPI GdipAddPathLine2I(GpPath *path, GDIPCONST GpPoint *points, INT count)
265 {
266     GpPointF *pointsF;
267     INT i;
268     GpStatus stat;
269 
270     if(count <= 0)
271         return InvalidParameter;
272 
273     pointsF = GdipAlloc(sizeof(GpPointF) * count);
274     if(!pointsF)    return OutOfMemory;
275 
276     for(i = 0;i < count; i++){
277         pointsF[i].X = (REAL)points[i].X;
278         pointsF[i].Y = (REAL)points[i].Y;
279     }
280 
281     stat = GdipAddPathLine2(path, pointsF, count);
282 
283     GdipFree(pointsF);
284 
285     return stat;
286 }
287 
288 GpStatus WINGDIPAPI GdipAddPathLine(GpPath *path, REAL x1, REAL y1, REAL x2, REAL y2)
289 {
290     INT old_count;
291 
292     if(!path)
293         return InvalidParameter;
294 
295     if(!lengthen_path(path, 2))
296         return OutOfMemory;
297 
298     old_count = path->pathdata.Count;
299 
300     path->pathdata.Points[old_count].X = x1;
301     path->pathdata.Points[old_count].Y = y1;
302     path->pathdata.Points[old_count + 1].X = x2;
303     path->pathdata.Points[old_count + 1].Y = y2;
304 
305     path->pathdata.Types[old_count] =
306         (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
307     path->pathdata.Types[old_count + 1] = PathPointTypeLine;
308 
309     path->newfigure = FALSE;
310     path->pathdata.Count += 2;
311 
312     return Ok;
313 }
314 
315 GpStatus WINGDIPAPI GdipAddPathLineI(GpPath *path, INT x1, INT y1, INT x2, INT y2)
316 {
317     return GdipAddPathLine(path, (REAL)x1, (REAL)y1, (REAL)x2, (REAL)y2);
318 }
319 
320 GpStatus WINGDIPAPI GdipAddPathPath(GpPath *path, GDIPCONST GpPath* addingPath,
321     BOOL connect)
322 {
323     INT old_count, count;
324 
325     if(!path || !addingPath)
326         return InvalidParameter;
327 
328     old_count = path->pathdata.Count;
329     count = addingPath->pathdata.Count;
330 
331     if(!lengthen_path(path, count))
332         return OutOfMemory;
333 
334     memcpy(&path->pathdata.Points[old_count], addingPath->pathdata.Points,
335            count * sizeof(GpPointF));
336     memcpy(&path->pathdata.Types[old_count], addingPath->pathdata.Types, count);
337 
338     if(path->newfigure || !connect)
339         path->pathdata.Types[old_count] = PathPointTypeStart;
340     else
341         path->pathdata.Types[old_count] = PathPointTypeLine;
342 
343     path->newfigure = FALSE;
344     path->pathdata.Count += count;
345 
346     return Ok;
347 }
348 
349 GpStatus WINGDIPAPI GdipAddPathPolygon(GpPath *path, GDIPCONST GpPointF *points, INT count)
350 {
351     INT old_count;
352 
353     if(!path || !points || count < 3)
354         return InvalidParameter;
355 
356     if(!lengthen_path(path, count))
357         return OutOfMemory;
358 
359     old_count = path->pathdata.Count;
360 
361     memcpy(&path->pathdata.Points[old_count], points, count*sizeof(GpPointF));
362     memset(&path->pathdata.Types[old_count + 1], PathPointTypeLine, count - 1);
363 
364     /* A polygon is an intrinsic figure */
365     path->pathdata.Types[old_count] = PathPointTypeStart;
366     path->pathdata.Types[old_count + count - 1] |= PathPointTypeCloseSubpath;
367     path->newfigure = TRUE;
368     path->pathdata.Count += count;
369 
370     return Ok;
371 }
372 
373 GpStatus WINGDIPAPI GdipAddPathPolygonI(GpPath *path, GDIPCONST GpPoint *points, INT count)
374 {
375     GpPointF *ptf;
376     GpStatus status;
377     INT i;
378 
379     if(!points || count < 3)
380         return InvalidParameter;
381 
382     ptf = GdipAlloc(sizeof(GpPointF) * count);
383     if(!ptf)
384         return OutOfMemory;
385 
386     for(i = 0; i < count; i++){
387         ptf[i].X = (REAL)points[i].X;
388         ptf[i].Y = (REAL)points[i].Y;
389     }
390 
391     status = GdipAddPathPolygon(path, ptf, count);
392 
393     GdipFree(ptf);
394 
395     return status;
396 }
397 
398 GpStatus WINGDIPAPI GdipClonePath(GpPath* path, GpPath **clone)
399 {
400     if(!path || !clone)
401         return InvalidParameter;
402 
403     *clone = GdipAlloc(sizeof(GpPath));
404     if(!*clone) return OutOfMemory;
405 
406     **clone = *path;
407 
408     (*clone)->pathdata.Points = GdipAlloc(path->datalen * sizeof(PointF));
409     (*clone)->pathdata.Types = GdipAlloc(path->datalen);
410     if(!(*clone)->pathdata.Points || !(*clone)->pathdata.Types){
411         GdipFree(*clone);
412         GdipFree((*clone)->pathdata.Points);
413         GdipFree((*clone)->pathdata.Types);
414         return OutOfMemory;
415     }
416 
417     memcpy((*clone)->pathdata.Points, path->pathdata.Points,
418            path->datalen * sizeof(PointF));
419     memcpy((*clone)->pathdata.Types, path->pathdata.Types, path->datalen);
420 
421     return Ok;
422 }
423 
424 GpStatus WINGDIPAPI GdipClosePathFigure(GpPath* path)
425 {
426     if(!path)
427         return InvalidParameter;
428 
429     if(path->pathdata.Count > 0){
430         path->pathdata.Types[path->pathdata.Count - 1] |= PathPointTypeCloseSubpath;
431         path->newfigure = TRUE;
432     }
433 
434     return Ok;
435 }
436 
437 GpStatus WINGDIPAPI GdipClosePathFigures(GpPath* path)
438 {
439     INT i;
440 
441     if(!path)
442         return InvalidParameter;
443 
444     for(i = 1; i < path->pathdata.Count; i++){
445         if(path->pathdata.Types[i] == PathPointTypeStart)
446             path->pathdata.Types[i-1] |= PathPointTypeCloseSubpath;
447     }
448 
449     path->newfigure = TRUE;
450 
451     return Ok;
452 }
453 
454 GpStatus WINGDIPAPI GdipCreatePath(GpFillMode fill, GpPath **path)
455 {
456     if(!path)
457         return InvalidParameter;
458 
459     *path = GdipAlloc(sizeof(GpPath));
460     if(!*path)  return OutOfMemory;
461 
462     (*path)->fill = fill;
463     (*path)->newfigure = TRUE;
464 
465     return Ok;
466 }
467 
468 GpStatus WINGDIPAPI GdipCreatePath2(GDIPCONST GpPointF* points,
469     GDIPCONST BYTE* types, INT count, GpFillMode fill, GpPath **path)
470 {
471     if(!path)
472         return InvalidParameter;
473 
474     *path = GdipAlloc(sizeof(GpPath));
475     if(!*path)  return OutOfMemory;
476 
477     (*path)->pathdata.Points = GdipAlloc(count * sizeof(PointF));
478     (*path)->pathdata.Types = GdipAlloc(count);
479 
480     if(!(*path)->pathdata.Points || !(*path)->pathdata.Types){
481         GdipFree((*path)->pathdata.Points);
482         GdipFree((*path)->pathdata.Types);
483         GdipFree(*path);
484         return OutOfMemory;
485     }
486 
487     memcpy((*path)->pathdata.Points, points, count * sizeof(PointF));
488     memcpy((*path)->pathdata.Types, types, count);
489     (*path)->pathdata.Count = count;
490     (*path)->datalen = count;
491 
492     (*path)->fill = fill;
493     (*path)->newfigure = TRUE;
494 
495     return Ok;
496 }
497 
498 GpStatus WINGDIPAPI GdipCreatePath2I(GDIPCONST GpPoint* points,
499     GDIPCONST BYTE* types, INT count, GpFillMode fill, GpPath **path)
500 {
501     GpPointF *ptF;
502     GpStatus ret;
503     INT i;
504 
505     ptF = GdipAlloc(sizeof(GpPointF)*count);
506 
507     for(i = 0;i < count; i++){
508         ptF[i].X = (REAL)points[i].X;
509         ptF[i].Y = (REAL)points[i].Y;
510     }
511 
512     ret = GdipCreatePath2(ptF, types, count, fill, path);
513 
514     GdipFree(ptF);
515 
516     return ret;
517 }
518 
519 GpStatus WINGDIPAPI GdipDeletePath(GpPath *path)
520 {
521     if(!path)
522         return InvalidParameter;
523 
524     GdipFree(path->pathdata.Points);
525     GdipFree(path->pathdata.Types);
526     GdipFree(path);
527 
528     return Ok;
529 }
530 
531 GpStatus WINGDIPAPI GdipGetPathData(GpPath *path, GpPathData* pathData)
532 {
533     if(!path || !pathData)
534         return InvalidParameter;
535 
536     /* Only copy data. pathData allocation/freeing controlled by wrapper class.
537        Assumed that pathData is enough wide to get all data - controlled by wrapper too. */
538     memcpy(pathData->Points, path->pathdata.Points, sizeof(PointF) * pathData->Count);
539     memcpy(pathData->Types , path->pathdata.Types , pathData->Count);
540 
541     return Ok;
542 }
543 
544 GpStatus WINGDIPAPI GdipGetPathFillMode(GpPath *path, GpFillMode *fillmode)
545 {
546     if(!path || !fillmode)
547         return InvalidParameter;
548 
549     *fillmode = path->fill;
550 
551     return Ok;
552 }
553 
554 GpStatus WINGDIPAPI GdipGetPathPoints(GpPath *path, GpPointF* points, INT count)
555 {
556     if(!path)
557         return InvalidParameter;
558 
559     if(count < path->pathdata.Count)
560         return InsufficientBuffer;
561 
562     memcpy(points, path->pathdata.Points, path->pathdata.Count * sizeof(GpPointF));
563 
564     return Ok;
565 }
566 
567 GpStatus WINGDIPAPI GdipGetPathPointsI(GpPath *path, GpPoint* points, INT count)
568 {
569     GpStatus ret;
570     GpPointF *ptf;
571     INT i;
572 
573     if(count <= 0)
574         return InvalidParameter;
575 
576     ptf = GdipAlloc(sizeof(GpPointF)*count);
577     if(!ptf)    return OutOfMemory;
578 
579     ret = GdipGetPathPoints(path,ptf,count);
580     if(ret == Ok)
581         for(i = 0;i < count;i++){
582             points[i].X = roundr(ptf[i].X);
583             points[i].Y = roundr(ptf[i].Y);
584         };
585     GdipFree(ptf);
586 
587     return ret;
588 }
589 
590 GpStatus WINGDIPAPI GdipGetPathTypes(GpPath *path, BYTE* types, INT count)
591 {
592     if(!path)
593         return InvalidParameter;
594 
595     if(count < path->pathdata.Count)
596         return InsufficientBuffer;
597 
598     memcpy(types, path->pathdata.Types, path->pathdata.Count);
599 
600     return Ok;
601 }
602 
603 /* Windows expands the bounding box to the maximum possible bounding box
604  * for a given pen.  For example, if a line join can extend past the point
605  * it's joining by x units, the bounding box is extended by x units in every
606  * direction (even though this is too conservative for most cases). */
607 GpStatus WINGDIPAPI GdipGetPathWorldBounds(GpPath* path, GpRectF* bounds,
608     GDIPCONST GpMatrix *matrix, GDIPCONST GpPen *pen)
609 {
610     GpPointF * points, temp_pts[4];
611     INT count, i;
612     REAL path_width = 1.0, width, height, temp, low_x, low_y, high_x, high_y;
613 
614     /* Matrix and pen can be null. */
615     if(!path || !bounds)
616         return InvalidParameter;
617 
618     /* If path is empty just return. */
619     count = path->pathdata.Count;
620     if(count == 0){
621         bounds->X = bounds->Y = bounds->Width = bounds->Height = 0.0;
622         return Ok;
623     }
624 
625     points = path->pathdata.Points;
626 
627     low_x = high_x = points[0].X;
628     low_y = high_y = points[0].Y;
629 
630     for(i = 1; i < count; i++){
631         low_x = min(low_x, points[i].X);
632         low_y = min(low_y, points[i].Y);
633         high_x = max(high_x, points[i].X);
634         high_y = max(high_y, points[i].Y);
635     }
636 
637     width = high_x - low_x;
638     height = high_y - low_y;
639 
640     /* This looks unusual but it's the only way I can imitate windows. */
641     if(matrix){
642         temp_pts[0].X = low_x;
643         temp_pts[0].Y = low_y;
644         temp_pts[1].X = low_x;
645         temp_pts[1].Y = high_y;
646         temp_pts[2].X = high_x;
647         temp_pts[2].Y = high_y;
648         temp_pts[3].X = high_x;
649         temp_pts[3].Y = low_y;
650 
651         GdipTransformMatrixPoints((GpMatrix*)matrix, temp_pts, 4);
652         low_x = temp_pts[0].X;
653         low_y = temp_pts[0].Y;
654 
655         for(i = 1; i < 4; i++){
656             low_x = min(low_x, temp_pts[i].X);
657             low_y = min(low_y, temp_pts[i].Y);
658         }
659 
660         temp = width;
661         width = height * fabs(matrix->matrix[2]) + width * fabs(matrix->matrix[0]);
662         height = height * fabs(matrix->matrix[3]) + temp * fabs(matrix->matrix[1]);
663     }
664 
665     if(pen){
666         path_width = pen->width / 2.0;
667 
668         if(count > 2)
669             path_width = max(path_width,  pen->width * pen->miterlimit / 2.0);
670         /* FIXME: this should probably also check for the startcap */
671         if(pen->endcap & LineCapNoAnchor)
672             path_width = max(path_width,  pen->width * 2.2);
673 
674         low_x -= path_width;
675         low_y -= path_width;
676         width += 2.0 * path_width;
677         height += 2.0 * path_width;
678     }
679 
680     bounds->X = low_x;
681     bounds->Y = low_y;
682     bounds->Width = width;
683     bounds->Height = height;
684 
685     return Ok;
686 }
687 
688 GpStatus WINGDIPAPI GdipGetPathWorldBoundsI(GpPath* path, GpRect* bounds,
689     GDIPCONST GpMatrix *matrix, GDIPCONST GpPen *pen)
690 {
691     GpStatus ret;
692     GpRectF boundsF;
693 
694     ret = GdipGetPathWorldBounds(path,&boundsF,matrix,pen);
695 
696     if(ret == Ok){
697         bounds->X      = roundr(boundsF.X);
698         bounds->Y      = roundr(boundsF.Y);
699         bounds->Width  = roundr(boundsF.Width);
700         bounds->Height = roundr(boundsF.Height);
701     }
702 
703     return ret;
704 }
705 
706 GpStatus WINGDIPAPI GdipGetPointCount(GpPath *path, INT *count)
707 {
708     if(!path)
709         return InvalidParameter;
710 
711     *count = path->pathdata.Count;
712 
713     return Ok;
714 }
715 
716 GpStatus WINGDIPAPI GdipIsOutlineVisiblePathPointI(GpPath* path, INT x, INT y,
717     GpPen *pen, GpGraphics *graphics, BOOL *result)
718 {
719     static int calls;
720 
721     if(!path || !pen)
722         return InvalidParameter;
723 
724     if(!(calls++))
725         FIXME("not implemented\n");
726 
727     return NotImplemented;
728 }
729 
730 GpStatus WINGDIPAPI GdipStartPathFigure(GpPath *path)
731 {
732     if(!path)
733         return InvalidParameter;
734 
735     path->newfigure = TRUE;
736 
737     return Ok;
738 }
739 
740 GpStatus WINGDIPAPI GdipResetPath(GpPath *path)
741 {
742     if(!path)
743         return InvalidParameter;
744 
745     path->pathdata.Count = 0;
746     path->newfigure = TRUE;
747     path->fill = FillModeAlternate;
748 
749     return Ok;
750 }
751 
752 GpStatus WINGDIPAPI GdipSetPathFillMode(GpPath *path, GpFillMode fill)
753 {
754     if(!path)
755         return InvalidParameter;
756 
757     path->fill = fill;
758 
759     return Ok;
760 }
761 
762 GpStatus WINGDIPAPI GdipTransformPath(GpPath *path, GpMatrix *matrix)
763 {
764     if(!path)
765         return InvalidParameter;
766 
767     if(path->pathdata.Count == 0)
768         return Ok;
769 
770     return GdipTransformMatrixPoints(matrix, path->pathdata.Points,
771                                      path->pathdata.Count);
772 }
773 
774 GpStatus WINGDIPAPI GdipAddPathRectangle(GpPath *path, REAL x, REAL y,
775     REAL width, REAL height)
776 {
777     GpPath *backup;
778     GpPointF ptf[2];
779     GpStatus retstat;
780     BOOL old_new;
781 
782     if(!path || width < 0.0 || height < 0.0)
783         return InvalidParameter;
784 
785     /* make a backup copy of path data */
786     if((retstat = GdipClonePath(path, &backup)) != Ok)
787         return retstat;
788 
789     /* rectangle should start as new path */
790     old_new = path->newfigure;
791     path->newfigure = TRUE;
792     if((retstat = GdipAddPathLine(path,x,y,x+width,y)) != Ok){
793         path->newfigure = old_new;
794         goto fail;
795     }
796 
797     ptf[0].X = x+width;
798     ptf[0].Y = y+height;
799     ptf[1].X = x;
800     ptf[1].Y = y+height;
801 
802     if((retstat = GdipAddPathLine2(path,(GDIPCONST GpPointF*)&ptf,2)) != Ok)  goto fail;
803     path->pathdata.Types[path->pathdata.Count-1] |= PathPointTypeCloseSubpath;
804 
805     /* free backup */
806     GdipDeletePath(backup);
807     return Ok;
808 
809 fail:
810     /* reverting */
811     GdipDeletePath(path);
812     GdipClonePath(backup, &path);
813     GdipDeletePath(backup);
814 
815     return retstat;
816 }
817 
818 GpStatus WINGDIPAPI GdipAddPathRectangleI(GpPath *path, INT x, INT y,
819     INT width, INT height)
820 {
821     return GdipAddPathRectangle(path,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
822 }
823 
824 GpStatus WINGDIPAPI GdipAddPathRectangles(GpPath *path, GDIPCONST GpRectF *rects, INT count)
825 {
826     GpPath *backup;
827     GpStatus retstat;
828     INT i;
829 
830     /* count == 0 - verified condition  */
831     if(!path || !rects || count == 0)
832         return InvalidParameter;
833 
834     if(count < 0)
835         return OutOfMemory;
836 
837     /* make a backup copy */
838     if((retstat = GdipClonePath(path, &backup)) != Ok)
839         return retstat;
840 
841     for(i = 0; i < count; i++){
842         if((retstat = GdipAddPathRectangle(path,rects[i].X,rects[i].Y,rects[i].Width,rects[i].Height)) != Ok)
843             goto fail;
844     }
845 
846     /* free backup */
847     GdipDeletePath(backup);
848     return Ok;
849 
850 fail:
851     /* reverting */
852     GdipDeletePath(path);
853     GdipClonePath(backup, &path);
854     GdipDeletePath(backup);
855 
856     return retstat;
857 }
858 
859 GpStatus WINGDIPAPI GdipAddPathRectanglesI(GpPath *path, GDIPCONST GpRect *rects, INT count)
860 {
861     GpRectF *rectsF;
862     GpStatus retstat;
863     INT i;
864 
865     if(!rects || count == 0)
866         return InvalidParameter;
867 
868     if(count < 0)
869         return OutOfMemory;
870 
871     rectsF = GdipAlloc(sizeof(GpRectF)*count);
872 
873     for(i = 0;i < count;i++){
874         rectsF[i].X      = (REAL)rects[i].X;
875         rectsF[i].Y      = (REAL)rects[i].Y;
876         rectsF[i].Width  = (REAL)rects[i].Width;
877         rectsF[i].Height = (REAL)rects[i].Height;
878     }
879 
880     retstat = GdipAddPathRectangles(path, rectsF, count);
881     GdipFree(rectsF);
882 
883     return retstat;
884 }
885 
886 GpStatus WINGDIPAPI GdipSetPathMarker(GpPath* path)
887 {
888     INT count;
889 
890     if(!path)
891         return InvalidParameter;