gdiplus: Implemented GdipAddPathCurve2I using GdipAddPathCurve2.
[wine/multimedia.git] / dlls / gdiplus / graphicspath.c
blob8e8930d439db2217f893ec03a5229806a21e0d24
1 /*
2 * Copyright (C) 2007 Google (Evan Stade)
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.
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.
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
20 #include <stdarg.h>
21 #include <math.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "wingdi.h"
28 #include "objbase.h"
30 #include "gdiplus.h"
31 #include "gdiplus_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
36 /* make sure path has enough space for len more points */
37 static BOOL lengthen_path(GpPath *path, INT len)
39 /* initial allocation */
40 if(path->datalen == 0){
41 path->datalen = len * 2;
43 path->pathdata.Points = GdipAlloc(path->datalen * sizeof(PointF));
44 if(!path->pathdata.Points) return FALSE;
46 path->pathdata.Types = GdipAlloc(path->datalen);
47 if(!path->pathdata.Types){
48 GdipFree(path->pathdata.Points);
49 return FALSE;
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;
57 path->pathdata.Points = HeapReAlloc(GetProcessHeap(), 0,
58 path->pathdata.Points, path->datalen * sizeof(PointF));
59 if(!path->pathdata.Points) return FALSE;
61 path->pathdata.Types = HeapReAlloc(GetProcessHeap(), 0,
62 path->pathdata.Types, path->datalen);
63 if(!path->pathdata.Types) return FALSE;
66 return TRUE;
69 GpStatus WINGDIPAPI GdipAddPathArc(GpPath *path, REAL x1, REAL y1, REAL x2,
70 REAL y2, REAL startAngle, REAL sweepAngle)
72 INT count, old_count, i;
74 if(!path)
75 return InvalidParameter;
77 count = arc2polybezier(NULL, x1, y1, x2, y2, startAngle, sweepAngle);
79 if(count == 0)
80 return Ok;
81 if(!lengthen_path(path, count))
82 return OutOfMemory;
84 old_count = path->pathdata.Count;
85 arc2polybezier(&path->pathdata.Points[old_count], x1, y1, x2, y2,
86 startAngle, sweepAngle);
88 for(i = 0; i < count; i++){
89 path->pathdata.Types[old_count + i] = PathPointTypeBezier;
92 path->pathdata.Types[old_count] =
93 (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
94 path->newfigure = FALSE;
95 path->pathdata.Count += count;
97 return Ok;
100 GpStatus WINGDIPAPI GdipAddPathArcI(GpPath *path, INT x1, INT y1, INT x2,
101 INT y2, REAL startAngle, REAL sweepAngle)
103 return GdipAddPathArc(path,(REAL)x1,(REAL)y1,(REAL)x2,(REAL)y2,startAngle,sweepAngle);
106 GpStatus WINGDIPAPI GdipAddPathBezier(GpPath *path, REAL x1, REAL y1, REAL x2,
107 REAL y2, REAL x3, REAL y3, REAL x4, REAL y4)
109 INT old_count;
111 if(!path)
112 return InvalidParameter;
114 if(!lengthen_path(path, 4))
115 return OutOfMemory;
117 old_count = path->pathdata.Count;
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;
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;
134 path->newfigure = FALSE;
135 path->pathdata.Count += 4;
137 return Ok;
140 GpStatus WINGDIPAPI GdipAddPathBezierI(GpPath *path, INT x1, INT y1, INT x2,
141 INT y2, INT x3, INT y3, INT x4, INT y4)
143 return GdipAddPathBezier(path,(REAL)x1,(REAL)y1,(REAL)x2,(REAL)y2,(REAL)x3,(REAL)y3,
144 (REAL)x4,(REAL)y4);
147 GpStatus WINGDIPAPI GdipAddPathBeziers(GpPath *path, GDIPCONST GpPointF *points,
148 INT count)
150 INT i, old_count;
152 if(!path || !points || ((count - 1) % 3))
153 return InvalidParameter;
155 if(!lengthen_path(path, count))
156 return OutOfMemory;
158 old_count = path->pathdata.Count;
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;
166 path->pathdata.Types[old_count] =
167 (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
168 path->newfigure = FALSE;
169 path->pathdata.Count += count;
171 return Ok;
174 GpStatus WINGDIPAPI GdipAddPathBeziersI(GpPath *path, GDIPCONST GpPoint *points,
175 INT count)
177 GpPointF *ptsF;
178 GpStatus ret;
179 INT i;
181 if(!points || ((count - 1) % 3))
182 return InvalidParameter;
184 ptsF = GdipAlloc(sizeof(GpPointF) * count);
185 if(!ptsF)
186 return OutOfMemory;
188 for(i = 0; i < count; i++){
189 ptsF[i].X = (REAL)points[i].X;
190 ptsF[i].Y = (REAL)points[i].Y;
193 ret = GdipAddPathBeziers(path, ptsF, count);
194 GdipFree(ptsF);
196 return ret;
199 GpStatus WINGDIPAPI GdipAddPathCurve2(GpPath *path, GDIPCONST GpPointF *points, INT count,
200 REAL tension)
202 INT i, len_pt = count*3-2;
203 GpPointF *pt;
204 REAL x1, x2, y1, y2;
205 GpStatus stat;
207 if(!path || !points || count <= 1)
208 return InvalidParameter;
210 pt = GdipAlloc(len_pt * sizeof(GpPointF));
211 if(!pt)
212 return OutOfMemory;
214 tension = tension * TENSION_CONST;
216 calc_curve_bezier_endp(points[0].X, points[0].Y, points[1].X, points[1].Y,
217 tension, &x1, &y1);
219 pt[0].X = points[0].X;
220 pt[0].Y = points[0].Y;
221 pt[1].X = x1;
222 pt[1].Y = y1;
224 for(i = 0; i < count-2; i++){
225 calc_curve_bezier(&(points[i]), tension, &x1, &y1, &x2, &y2);
227 pt[3*i+2].X = x1;
228 pt[3*i+2].Y = y1;
229 pt[3*i+3].X = points[i+1].X;
230 pt[3*i+3].Y = points[i+1].Y;
231 pt[3*i+4].X = x2;
232 pt[3*i+4].Y = y2;
235 calc_curve_bezier_endp(points[count-1].X, points[count-1].Y,
236 points[count-2].X, points[count-2].Y, tension, &x1, &y1);
238 pt[len_pt-2].X = x1;
239 pt[len_pt-2].Y = y1;
240 pt[len_pt-1].X = points[count-1].X;
241 pt[len_pt-1].Y = points[count-1].Y;
243 stat = GdipAddPathBeziers(path, pt, len_pt);
245 GdipFree(pt);
247 return stat;
250 GpStatus WINGDIPAPI GdipAddPathCurve2I(GpPath *path, GDIPCONST GpPoint *points,
251 INT count, REAL tension)
253 GpPointF *ptf;
254 INT i;
255 GpStatus stat;
257 if(!path || !points || count <= 1)
258 return InvalidParameter;
260 ptf = GdipAlloc(sizeof(GpPointF)*count);
261 if(!ptf)
262 return OutOfMemory;
264 for(i = 0; i < count; i++){
265 ptf[i].X = (REAL)points[i].X;
266 ptf[i].Y = (REAL)points[i].Y;
269 stat = GdipAddPathCurve2(path, ptf, count, tension);
271 GdipFree(ptf);
273 return stat;
276 GpStatus WINGDIPAPI GdipAddPathEllipse(GpPath *path, REAL x, REAL y, REAL width,
277 REAL height)
279 INT old_count, numpts;
281 if(!path)
282 return InvalidParameter;
284 if(!lengthen_path(path, MAX_ARC_PTS))
285 return OutOfMemory;
287 old_count = path->pathdata.Count;
288 if((numpts = arc2polybezier(&path->pathdata.Points[old_count], x, y, width,
289 height, 0.0, 360.0)) != MAX_ARC_PTS){
290 ERR("expected %d points but got %d\n", MAX_ARC_PTS, numpts);
291 return GenericError;
294 memset(&path->pathdata.Types[old_count + 1], PathPointTypeBezier,
295 MAX_ARC_PTS - 1);
297 /* An ellipse is an intrinsic figure (always is its own subpath). */
298 path->pathdata.Types[old_count] = PathPointTypeStart;
299 path->pathdata.Types[old_count + MAX_ARC_PTS - 1] |= PathPointTypeCloseSubpath;
300 path->newfigure = TRUE;
301 path->pathdata.Count += MAX_ARC_PTS;
303 return Ok;
306 GpStatus WINGDIPAPI GdipAddPathEllipseI(GpPath *path, INT x, INT y, INT width,
307 INT height)
309 return GdipAddPathEllipse(path,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
312 GpStatus WINGDIPAPI GdipAddPathLine2(GpPath *path, GDIPCONST GpPointF *points,
313 INT count)
315 INT i, old_count;
317 if(!path || !points)
318 return InvalidParameter;
320 if(!lengthen_path(path, count))
321 return OutOfMemory;
323 old_count = path->pathdata.Count;
325 for(i = 0; i < count; i++){
326 path->pathdata.Points[old_count + i].X = points[i].X;
327 path->pathdata.Points[old_count + i].Y = points[i].Y;
328 path->pathdata.Types[old_count + i] = PathPointTypeLine;
331 if(path->newfigure){
332 path->pathdata.Types[old_count] = PathPointTypeStart;
333 path->newfigure = FALSE;
336 path->pathdata.Count += count;
338 return Ok;
341 GpStatus WINGDIPAPI GdipAddPathLine2I(GpPath *path, GDIPCONST GpPoint *points, INT count)
343 GpPointF *pointsF;
344 INT i;
345 GpStatus stat;
347 if(count <= 0)
348 return InvalidParameter;
350 pointsF = GdipAlloc(sizeof(GpPointF) * count);
351 if(!pointsF) return OutOfMemory;
353 for(i = 0;i < count; i++){
354 pointsF[i].X = (REAL)points[i].X;
355 pointsF[i].Y = (REAL)points[i].Y;
358 stat = GdipAddPathLine2(path, pointsF, count);
360 GdipFree(pointsF);
362 return stat;
365 GpStatus WINGDIPAPI GdipAddPathLine(GpPath *path, REAL x1, REAL y1, REAL x2, REAL y2)
367 INT old_count;
369 if(!path)
370 return InvalidParameter;
372 if(!lengthen_path(path, 2))
373 return OutOfMemory;
375 old_count = path->pathdata.Count;
377 path->pathdata.Points[old_count].X = x1;
378 path->pathdata.Points[old_count].Y = y1;
379 path->pathdata.Points[old_count + 1].X = x2;
380 path->pathdata.Points[old_count + 1].Y = y2;
382 path->pathdata.Types[old_count] =
383 (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
384 path->pathdata.Types[old_count + 1] = PathPointTypeLine;
386 path->newfigure = FALSE;
387 path->pathdata.Count += 2;
389 return Ok;
392 GpStatus WINGDIPAPI GdipAddPathLineI(GpPath *path, INT x1, INT y1, INT x2, INT y2)
394 return GdipAddPathLine(path, (REAL)x1, (REAL)y1, (REAL)x2, (REAL)y2);
397 GpStatus WINGDIPAPI GdipAddPathPath(GpPath *path, GDIPCONST GpPath* addingPath,
398 BOOL connect)
400 INT old_count, count;
402 if(!path || !addingPath)
403 return InvalidParameter;
405 old_count = path->pathdata.Count;
406 count = addingPath->pathdata.Count;
408 if(!lengthen_path(path, count))
409 return OutOfMemory;
411 memcpy(&path->pathdata.Points[old_count], addingPath->pathdata.Points,
412 count * sizeof(GpPointF));
413 memcpy(&path->pathdata.Types[old_count], addingPath->pathdata.Types, count);
415 if(path->newfigure || !connect)
416 path->pathdata.Types[old_count] = PathPointTypeStart;
417 else
418 path->pathdata.Types[old_count] = PathPointTypeLine;
420 path->newfigure = FALSE;
421 path->pathdata.Count += count;
423 return Ok;
426 GpStatus WINGDIPAPI GdipAddPathPolygon(GpPath *path, GDIPCONST GpPointF *points, INT count)
428 INT old_count;
430 if(!path || !points || count < 3)
431 return InvalidParameter;
433 if(!lengthen_path(path, count))
434 return OutOfMemory;
436 old_count = path->pathdata.Count;
438 memcpy(&path->pathdata.Points[old_count], points, count*sizeof(GpPointF));
439 memset(&path->pathdata.Types[old_count + 1], PathPointTypeLine, count - 1);
441 /* A polygon is an intrinsic figure */
442 path->pathdata.Types[old_count] = PathPointTypeStart;
443 path->pathdata.Types[old_count + count - 1] |= PathPointTypeCloseSubpath;
444 path->newfigure = TRUE;
445 path->pathdata.Count += count;
447 return Ok;
450 GpStatus WINGDIPAPI GdipAddPathPolygonI(GpPath *path, GDIPCONST GpPoint *points, INT count)
452 GpPointF *ptf;
453 GpStatus status;
454 INT i;
456 if(!points || count < 3)
457 return InvalidParameter;
459 ptf = GdipAlloc(sizeof(GpPointF) * count);
460 if(!ptf)
461 return OutOfMemory;
463 for(i = 0; i < count; i++){
464 ptf[i].X = (REAL)points[i].X;
465 ptf[i].Y = (REAL)points[i].Y;
468 status = GdipAddPathPolygon(path, ptf, count);
470 GdipFree(ptf);
472 return status;
475 GpStatus WINGDIPAPI GdipClonePath(GpPath* path, GpPath **clone)
477 if(!path || !clone)
478 return InvalidParameter;
480 *clone = GdipAlloc(sizeof(GpPath));
481 if(!*clone) return OutOfMemory;
483 **clone = *path;
485 (*clone)->pathdata.Points = GdipAlloc(path->datalen * sizeof(PointF));
486 (*clone)->pathdata.Types = GdipAlloc(path->datalen);
487 if(!(*clone)->pathdata.Points || !(*clone)->pathdata.Types){
488 GdipFree(*clone);
489 GdipFree((*clone)->pathdata.Points);
490 GdipFree((*clone)->pathdata.Types);
491 return OutOfMemory;
494 memcpy((*clone)->pathdata.Points, path->pathdata.Points,
495 path->datalen * sizeof(PointF));
496 memcpy((*clone)->pathdata.Types, path->pathdata.Types, path->datalen);
498 return Ok;
501 GpStatus WINGDIPAPI GdipClosePathFigure(GpPath* path)
503 if(!path)
504 return InvalidParameter;
506 if(path->pathdata.Count > 0){
507 path->pathdata.Types[path->pathdata.Count - 1] |= PathPointTypeCloseSubpath;
508 path->newfigure = TRUE;
511 return Ok;
514 GpStatus WINGDIPAPI GdipClosePathFigures(GpPath* path)
516 INT i;
518 if(!path)
519 return InvalidParameter;
521 for(i = 1; i < path->pathdata.Count; i++){
522 if(path->pathdata.Types[i] == PathPointTypeStart)
523 path->pathdata.Types[i-1] |= PathPointTypeCloseSubpath;
526 path->newfigure = TRUE;
528 return Ok;
531 GpStatus WINGDIPAPI GdipCreatePath(GpFillMode fill, GpPath **path)
533 if(!path)
534 return InvalidParameter;
536 *path = GdipAlloc(sizeof(GpPath));
537 if(!*path) return OutOfMemory;
539 (*path)->fill = fill;
540 (*path)->newfigure = TRUE;
542 return Ok;
545 GpStatus WINGDIPAPI GdipCreatePath2(GDIPCONST GpPointF* points,
546 GDIPCONST BYTE* types, INT count, GpFillMode fill, GpPath **path)
548 if(!path)
549 return InvalidParameter;
551 *path = GdipAlloc(sizeof(GpPath));
552 if(!*path) return OutOfMemory;
554 (*path)->pathdata.Points = GdipAlloc(count * sizeof(PointF));
555 (*path)->pathdata.Types = GdipAlloc(count);
557 if(!(*path)->pathdata.Points || !(*path)->pathdata.Types){
558 GdipFree((*path)->pathdata.Points);
559 GdipFree((*path)->pathdata.Types);
560 GdipFree(*path);
561 return OutOfMemory;
564 memcpy((*path)->pathdata.Points, points, count * sizeof(PointF));
565 memcpy((*path)->pathdata.Types, types, count);
566 (*path)->pathdata.Count = count;
567 (*path)->datalen = count;
569 (*path)->fill = fill;
570 (*path)->newfigure = TRUE;
572 return Ok;
575 GpStatus WINGDIPAPI GdipCreatePath2I(GDIPCONST GpPoint* points,
576 GDIPCONST BYTE* types, INT count, GpFillMode fill, GpPath **path)
578 GpPointF *ptF;
579 GpStatus ret;
580 INT i;
582 ptF = GdipAlloc(sizeof(GpPointF)*count);
584 for(i = 0;i < count; i++){
585 ptF[i].X = (REAL)points[i].X;
586 ptF[i].Y = (REAL)points[i].Y;
589 ret = GdipCreatePath2(ptF, types, count, fill, path);
591 GdipFree(ptF);
593 return ret;
596 GpStatus WINGDIPAPI GdipDeletePath(GpPath *path)
598 if(!path)
599 return InvalidParameter;
601 GdipFree(path->pathdata.Points);
602 GdipFree(path->pathdata.Types);
603 GdipFree(path);
605 return Ok;
608 GpStatus WINGDIPAPI GdipGetPathData(GpPath *path, GpPathData* pathData)
610 if(!path || !pathData)
611 return InvalidParameter;
613 /* Only copy data. pathData allocation/freeing controlled by wrapper class.
614 Assumed that pathData is enough wide to get all data - controlled by wrapper too. */
615 memcpy(pathData->Points, path->pathdata.Points, sizeof(PointF) * pathData->Count);
616 memcpy(pathData->Types , path->pathdata.Types , pathData->Count);
618 return Ok;
621 GpStatus WINGDIPAPI GdipGetPathFillMode(GpPath *path, GpFillMode *fillmode)
623 if(!path || !fillmode)
624 return InvalidParameter;
626 *fillmode = path->fill;
628 return Ok;
631 GpStatus WINGDIPAPI GdipGetPathLastPoint(GpPath* path, GpPointF* lastPoint)
633 INT count;
635 if(!path || !lastPoint)
636 return InvalidParameter;
638 count = path->pathdata.Count;
639 if(count > 0)
640 *lastPoint = path->pathdata.Points[count-1];
642 return Ok;
645 GpStatus WINGDIPAPI GdipGetPathPoints(GpPath *path, GpPointF* points, INT count)
647 if(!path)
648 return InvalidParameter;
650 if(count < path->pathdata.Count)
651 return InsufficientBuffer;
653 memcpy(points, path->pathdata.Points, path->pathdata.Count * sizeof(GpPointF));
655 return Ok;
658 GpStatus WINGDIPAPI GdipGetPathPointsI(GpPath *path, GpPoint* points, INT count)
660 GpStatus ret;
661 GpPointF *ptf;
662 INT i;
664 if(count <= 0)
665 return InvalidParameter;
667 ptf = GdipAlloc(sizeof(GpPointF)*count);
668 if(!ptf) return OutOfMemory;
670 ret = GdipGetPathPoints(path,ptf,count);
671 if(ret == Ok)
672 for(i = 0;i < count;i++){
673 points[i].X = roundr(ptf[i].X);
674 points[i].Y = roundr(ptf[i].Y);
676 GdipFree(ptf);
678 return ret;
681 GpStatus WINGDIPAPI GdipGetPathTypes(GpPath *path, BYTE* types, INT count)
683 if(!path)
684 return InvalidParameter;
686 if(count < path->pathdata.Count)
687 return InsufficientBuffer;
689 memcpy(types, path->pathdata.Types, path->pathdata.Count);
691 return Ok;
694 /* Windows expands the bounding box to the maximum possible bounding box
695 * for a given pen. For example, if a line join can extend past the point
696 * it's joining by x units, the bounding box is extended by x units in every
697 * direction (even though this is too conservative for most cases). */
698 GpStatus WINGDIPAPI GdipGetPathWorldBounds(GpPath* path, GpRectF* bounds,
699 GDIPCONST GpMatrix *matrix, GDIPCONST GpPen *pen)
701 GpPointF * points, temp_pts[4];
702 INT count, i;
703 REAL path_width = 1.0, width, height, temp, low_x, low_y, high_x, high_y;
705 /* Matrix and pen can be null. */
706 if(!path || !bounds)
707 return InvalidParameter;
709 /* If path is empty just return. */
710 count = path->pathdata.Count;
711 if(count == 0){
712 bounds->X = bounds->Y = bounds->Width = bounds->Height = 0.0;
713 return Ok;
716 points = path->pathdata.Points;
718 low_x = high_x = points[0].X;
719 low_y = high_y = points[0].Y;
721 for(i = 1; i < count; i++){
722 low_x = min(low_x, points[i].X);
723 low_y = min(low_y, points[i].Y);
724 high_x = max(high_x, points[i].X);
725 high_y = max(high_y, points[i].Y);
728 width = high_x - low_x;
729 height = high_y - low_y;
731 /* This looks unusual but it's the only way I can imitate windows. */
732 if(matrix){
733 temp_pts[0].X = low_x;
734 temp_pts[0].Y = low_y;
735 temp_pts[1].X = low_x;
736 temp_pts[1].Y = high_y;
737 temp_pts[2].X = high_x;
738 temp_pts[2].Y = high_y;
739 temp_pts[3].X = high_x;
740 temp_pts[3].Y = low_y;
742 GdipTransformMatrixPoints((GpMatrix*)matrix, temp_pts, 4);
743 low_x = temp_pts[0].X;
744 low_y = temp_pts[0].Y;
746 for(i = 1; i < 4; i++){
747 low_x = min(low_x, temp_pts[i].X);
748 low_y = min(low_y, temp_pts[i].Y);
751 temp = width;
752 width = height * fabs(matrix->matrix[2]) + width * fabs(matrix->matrix[0]);
753 height = height * fabs(matrix->matrix[3]) + temp * fabs(matrix->matrix[1]);
756 if(pen){
757 path_width = pen->width / 2.0;
759 if(count > 2)
760 path_width = max(path_width, pen->width * pen->miterlimit / 2.0);
761 /* FIXME: this should probably also check for the startcap */
762 if(pen->endcap & LineCapNoAnchor)
763 path_width = max(path_width, pen->width * 2.2);
765 low_x -= path_width;
766 low_y -= path_width;
767 width += 2.0 * path_width;
768 height += 2.0 * path_width;
771 bounds->X = low_x;
772 bounds->Y = low_y;
773 bounds->Width = width;
774 bounds->Height = height;
776 return Ok;
779 GpStatus WINGDIPAPI GdipGetPathWorldBoundsI(GpPath* path, GpRect* bounds,
780 GDIPCONST GpMatrix *matrix, GDIPCONST GpPen *pen)
782 GpStatus ret;
783 GpRectF boundsF;
785 ret = GdipGetPathWorldBounds(path,&boundsF,matrix,pen);
787 if(ret == Ok){
788 bounds->X = roundr(boundsF.X);
789 bounds->Y = roundr(boundsF.Y);
790 bounds->Width = roundr(boundsF.Width);
791 bounds->Height = roundr(boundsF.Height);
794 return ret;
797 GpStatus WINGDIPAPI GdipGetPointCount(GpPath *path, INT *count)
799 if(!path)
800 return InvalidParameter;
802 *count = path->pathdata.Count;
804 return Ok;
807 GpStatus WINGDIPAPI GdipIsOutlineVisiblePathPointI(GpPath* path, INT x, INT y,
808 GpPen *pen, GpGraphics *graphics, BOOL *result)
810 return GdipIsOutlineVisiblePathPoint(path, x, y, pen, graphics, result);
813 GpStatus WINGDIPAPI GdipIsOutlineVisiblePathPoint(GpPath* path, REAL x, REAL y,
814 GpPen *pen, GpGraphics *graphics, BOOL *result)
816 static int calls;
818 if(!path || !pen)
819 return InvalidParameter;
821 if(!(calls++))
822 FIXME("not implemented\n");
824 return NotImplemented;
827 GpStatus WINGDIPAPI GdipIsVisiblePathPointI(GpPath* path, INT x, INT y, GpGraphics *graphics, BOOL *result)
829 return GdipIsVisiblePathPoint(path, x, y, graphics, result);
832 GpStatus WINGDIPAPI GdipIsVisiblePathPoint(GpPath* path, REAL x, REAL y, GpGraphics *graphics, BOOL *result)
834 static int calls;
836 if(!path) return InvalidParameter;
838 if(!(calls++))
839 FIXME("not implemented\n");
841 return NotImplemented;
844 GpStatus WINGDIPAPI GdipStartPathFigure(GpPath *path)
846 if(!path)
847 return InvalidParameter;
849 path->newfigure = TRUE;
851 return Ok;
854 GpStatus WINGDIPAPI GdipResetPath(GpPath *path)
856 if(!path)
857 return InvalidParameter;
859 path->pathdata.Count = 0;
860 path->newfigure = TRUE;
861 path->fill = FillModeAlternate;
863 return Ok;
866 GpStatus WINGDIPAPI GdipSetPathFillMode(GpPath *path, GpFillMode fill)
868 if(!path)
869 return InvalidParameter;
871 path->fill = fill;
873 return Ok;
876 GpStatus WINGDIPAPI GdipTransformPath(GpPath *path, GpMatrix *matrix)
878 if(!path)
879 return InvalidParameter;
881 if(path->pathdata.Count == 0)
882 return Ok;
884 return GdipTransformMatrixPoints(matrix, path->pathdata.Points,
885 path->pathdata.Count);
888 GpStatus WINGDIPAPI GdipAddPathRectangle(GpPath *path, REAL x, REAL y,
889 REAL width, REAL height)
891 GpPath *backup;
892 GpPointF ptf[2];
893 GpStatus retstat;
894 BOOL old_new;
896 if(!path || width < 0.0 || height < 0.0)
897 return InvalidParameter;
899 /* make a backup copy of path data */
900 if((retstat = GdipClonePath(path, &backup)) != Ok)
901 return retstat;
903 /* rectangle should start as new path */
904 old_new = path->newfigure;
905 path->newfigure = TRUE;
906 if((retstat = GdipAddPathLine(path,x,y,x+width,y)) != Ok){
907 path->newfigure = old_new;
908 goto fail;
911 ptf[0].X = x+width;
912 ptf[0].Y = y+height;
913 ptf[1].X = x;
914 ptf[1].Y = y+height;
916 if((retstat = GdipAddPathLine2(path, ptf, 2)) != Ok) goto fail;
917 path->pathdata.Types[path->pathdata.Count-1] |= PathPointTypeCloseSubpath;
919 /* free backup */
920 GdipDeletePath(backup);
921 return Ok;
923 fail:
924 /* reverting */
925 GdipDeletePath(path);
926 GdipClonePath(backup, &path);
927 GdipDeletePath(backup);
929 return retstat;
932 GpStatus WINGDIPAPI GdipAddPathRectangleI(GpPath *path, INT x, INT y,
933 INT width, INT height)
935 return GdipAddPathRectangle(path,(REAL)x,(REAL)y,(REAL)width,(REAL)height);
938 GpStatus WINGDIPAPI GdipAddPathRectangles(GpPath *path, GDIPCONST GpRectF *rects, INT count)
940 GpPath *backup;
941 GpStatus retstat;
942 INT i;
944 /* count == 0 - verified condition */
945 if(!path || !rects || count == 0)
946 return InvalidParameter;
948 if(count < 0)
949 return OutOfMemory;
951 /* make a backup copy */
952 if((retstat = GdipClonePath(path, &backup)) != Ok)
953 return retstat;
955 for(i = 0; i < count; i++){
956 if((retstat = GdipAddPathRectangle(path,rects[i].X,rects[i].Y,rects[i].Width,rects[i].Height)) != Ok)
957 goto fail;
960 /* free backup */
961 GdipDeletePath(backup);
962 return Ok;
964 fail:
965 /* reverting */
966 GdipDeletePath(path);
967 GdipClonePath(backup, &path);
968 GdipDeletePath(backup);
970 return retstat;
973 GpStatus WINGDIPAPI GdipAddPathRectanglesI(GpPath *path, GDIPCONST GpRect *rects, INT count)
975 GpRectF *rectsF;
976 GpStatus retstat;
977 INT i;
979 if(!rects || count == 0)
980 return InvalidParameter;
982 if(count < 0)
983 return OutOfMemory;
985 rectsF = GdipAlloc(sizeof(GpRectF)*count);
987 for(i = 0;i < count;i++){
988 rectsF[i].X = (REAL)rects[i].X;
989 rectsF[i].Y = (REAL)rects[i].Y;
990 rectsF[i].Width = (REAL)rects[i].Width;
991 rectsF[i].Height = (REAL)rects[i].Height;
994 retstat = GdipAddPathRectangles(path, rectsF, count);
995 GdipFree(rectsF);
997 return retstat;
1000 GpStatus WINGDIPAPI GdipSetPathMarker(GpPath* path)
1002 INT count;
1004 if(!path)
1005 return InvalidParameter;
1007 count = path->pathdata.Count;
1009 /* set marker flag */
1010 if(count > 0)
1011 path->pathdata.Types[count-1] |= PathPointTypePathMarker;
1013 return Ok;
1016 GpStatus WINGDIPAPI GdipClearPathMarkers(GpPath* path)
1018 INT count;
1019 INT i;
1021 if(!path)
1022 return InvalidParameter;
1024 count = path->pathdata.Count;
1026 for(i = 0; i < count - 1; i++){
1027 path->pathdata.Types[i] &= ~PathPointTypePathMarker;
1030 return Ok;