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
28 #include "gdiplus_private.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
33 /* make sure path has enough space for len more points */
34 static BOOL lengthen_path(GpPath *path, INT len)
36 /* initial allocation */
37 if(path->datalen == 0){
38 path->datalen = len * 2;
40 path->pathdata.Points = GdipAlloc(path->datalen * sizeof(PointF));
41 if(!path->pathdata.Points) return FALSE;
43 path->pathdata.Types = GdipAlloc(path->datalen);
44 if(!path->pathdata.Types){
45 GdipFree(path->pathdata.Points);
49 /* reallocation, double size of arrays */
50 else if(path->datalen - path->pathdata.Count < len){
51 while(path->datalen - path->pathdata.Count < len)
54 path->pathdata.Points = HeapReAlloc(GetProcessHeap(), 0,
55 path->pathdata.Points, path->datalen * sizeof(PointF));
56 if(!path->pathdata.Points) return FALSE;
58 path->pathdata.Types = HeapReAlloc(GetProcessHeap(), 0,
59 path->pathdata.Types, path->datalen);
60 if(!path->pathdata.Types) return FALSE;
66 GpStatus WINGDIPAPI GdipAddPathArc(GpPath *path, REAL x1, REAL y1, REAL x2,
67 REAL y2, REAL startAngle, REAL sweepAngle)
69 INT count, old_count, i;
72 return InvalidParameter;
74 count = arc2polybezier(NULL, x1, y1, x2, y2, startAngle, sweepAngle);
78 if(!lengthen_path(path, count))
81 old_count = path->pathdata.Count;
82 arc2polybezier(&path->pathdata.Points[old_count], x1, y1, x2, y2,
83 startAngle, sweepAngle);
85 for(i = 0; i < count; i++){
86 path->pathdata.Types[old_count + i] = PathPointTypeBezier;
89 path->pathdata.Types[old_count] =
90 (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
91 path->newfigure = FALSE;
92 path->pathdata.Count += count;
97 GpStatus WINGDIPAPI GdipAddPathLine2(GpPath *path, GDIPCONST GpPointF *points,
103 return InvalidParameter;
105 if(!lengthen_path(path, count))
108 old_count = path->pathdata.Count;
110 for(i = 0; i < count; i++){
111 path->pathdata.Points[old_count + i].X = points[i].X;
112 path->pathdata.Points[old_count + i].Y = points[i].Y;
113 path->pathdata.Types[old_count + i] = PathPointTypeLine;
117 path->pathdata.Types[old_count] = PathPointTypeStart;
118 path->newfigure = FALSE;
121 path->pathdata.Count += count;
126 GpStatus WINGDIPAPI GdipClosePathFigure(GpPath* path)
129 return InvalidParameter;
131 if(path->pathdata.Count > 0){
132 path->pathdata.Types[path->pathdata.Count - 1] |= PathPointTypeCloseSubpath;
133 path->newfigure = TRUE;
139 GpStatus WINGDIPAPI GdipClosePathFigures(GpPath* path)
144 return InvalidParameter;
146 for(i = 1; i < path->pathdata.Count; i++){
147 if(path->pathdata.Types[i] == PathPointTypeStart)
148 path->pathdata.Types[i-1] |= PathPointTypeCloseSubpath;
151 path->newfigure = TRUE;
156 GpStatus WINGDIPAPI GdipCreatePath(GpFillMode fill, GpPath **path)
159 return InvalidParameter;
161 *path = GdipAlloc(sizeof(GpPath));
162 if(!*path) return OutOfMemory;
164 (*path)->fill = fill;
165 (*path)->newfigure = TRUE;
170 GpStatus WINGDIPAPI GdipDeletePath(GpPath *path)
173 return InvalidParameter;
175 GdipFree(path->pathdata.Points);
176 GdipFree(path->pathdata.Types);
182 GpStatus WINGDIPAPI GdipGetPathPoints(GpPath *path, GpPointF* points, INT count)
185 return InvalidParameter;
187 if(count < path->pathdata.Count)
188 return InsufficientBuffer;
190 memcpy(points, path->pathdata.Points, path->pathdata.Count * sizeof(GpPointF));
195 GpStatus WINGDIPAPI GdipGetPathTypes(GpPath *path, BYTE* types, INT count)
198 return InvalidParameter;
200 if(count < path->pathdata.Count)
201 return InsufficientBuffer;
203 memcpy(types, path->pathdata.Types, path->pathdata.Count);
208 /* Windows expands the bounding box to the maximum possible bounding box
209 * for a given pen. For example, if a line join can extend past the point
210 * it's joining by x units, the bounding box is extended by x units in every
211 * direction (even though this is too conservative for most cases). */
212 GpStatus WINGDIPAPI GdipGetPathWorldBounds(GpPath* path, GpRectF* bounds,
213 GDIPCONST GpMatrix *matrix, GDIPCONST GpPen *pen)
215 /* extrema[0] is upper left corner of bounding box,
216 * extrema[1] is lower right corner */
222 /* Matrix and pen can be null. */
224 return InvalidParameter;
226 /* If path is empty just return. */
227 count = path->pathdata.Count;
229 bounds->X = bounds->Y = bounds->Width = bounds->Height = 0.0;
233 points = path->pathdata.Points;
234 extrema[0].X = extrema[1].X = points[0].X;
235 extrema[0].Y = extrema[1].Y = points[0].Y;
237 for(i = 1; i < count; i++){
238 extrema[0].X = min(points[i].X, extrema[0].X);
239 extrema[0].Y = min(points[i].Y, extrema[0].Y);
240 extrema[1].X = max(points[i].X, extrema[1].X);
241 extrema[1].Y = max(points[i].Y, extrema[1].Y);
244 /* If matrix is non-null transform the points. */
246 GdipTransformMatrixPoints((GpMatrix*)matrix, extrema, 2);
250 path_width = pen->width * pen->miterlimit / 2.0;
251 extrema[0].X -= path_width;
252 extrema[0].Y -= path_width;
253 extrema[1].X += path_width;
254 extrema[1].Y += path_width;
257 bounds->X = extrema[0].X;
258 bounds->Y = extrema[0].Y;
259 bounds->Width = extrema[1].X - extrema[0].X;
260 bounds->Height = extrema[1].Y - extrema[0].Y;
265 GpStatus WINGDIPAPI GdipGetPointCount(GpPath *path, INT *count)
268 return InvalidParameter;
270 *count = path->pathdata.Count;
275 GpStatus WINGDIPAPI GdipStartPathFigure(GpPath *path)
278 return InvalidParameter;
280 path->newfigure = TRUE;
285 GpStatus WINGDIPAPI GdipTransformPath(GpPath *path, GpMatrix *matrix)
288 return InvalidParameter;
290 if(path->pathdata.Count == 0)
293 return GdipTransformMatrixPoints(matrix, (GpPointF*) path->pathdata.Points,
294 path->pathdata.Count);