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
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);
52 /* reallocation, double size of arrays */
53 else if(path->datalen - path->pathdata.Count < len){
54 while(path->datalen - path->pathdata.Count < len)
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;
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;
75 return InvalidParameter;
77 count = arc2polybezier(NULL, x1, y1, x2, y2, startAngle, sweepAngle);
81 if(!lengthen_path(path, count))
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;
100 GpStatus WINGDIPAPI GdipAddPathBeziers(GpPath *path, GDIPCONST GpPointF *points,
105 if(!path || !points || ((count - 1) % 3))
106 return InvalidParameter;
108 if(!lengthen_path(path, count))
111 old_count = path->pathdata.Count;
113 for(i = 0; i < count; i++){
114 path->pathdata.Points[old_count + i].X = points[i].X;
115 path->pathdata.Points[old_count + i].Y = points[i].Y;
116 path->pathdata.Types[old_count + i] = PathPointTypeBezier;
119 path->pathdata.Types[old_count] =
120 (path->newfigure ? PathPointTypeStart : PathPointTypeLine);
121 path->newfigure = FALSE;
122 path->pathdata.Count += count;
127 GpStatus WINGDIPAPI GdipAddPathEllipse(GpPath *path, REAL x, REAL y, REAL width,
130 INT old_count, numpts;
133 return InvalidParameter;
135 if(!lengthen_path(path, MAX_ARC_PTS))
138 old_count = path->pathdata.Count;
139 if((numpts = arc2polybezier(&path->pathdata.Points[old_count], x, y, width,
140 height, 0.0, 360.0)) != MAX_ARC_PTS){
141 ERR("expected %d points but got %d\n", MAX_ARC_PTS, numpts);
145 memset(&path->pathdata.Types[old_count + 1], PathPointTypeBezier,
148 /* An ellipse is an instrinsic figure (always its own subpath). */
149 path->pathdata.Types[old_count] = PathPointTypeStart;
150 path->pathdata.Types[old_count + MAX_ARC_PTS - 1] |= PathPointTypeCloseSubpath;
151 path->newfigure = TRUE;
152 path->pathdata.Count += MAX_ARC_PTS;
157 GpStatus WINGDIPAPI GdipAddPathLine2(GpPath *path, GDIPCONST GpPointF *points,
163 return InvalidParameter;
165 if(!lengthen_path(path, count))
168 old_count = path->pathdata.Count;
170 for(i = 0; i < count; i++){
171 path->pathdata.Points[old_count + i].X = points[i].X;
172 path->pathdata.Points[old_count + i].Y = points[i].Y;
173 path->pathdata.Types[old_count + i] = PathPointTypeLine;
177 path->pathdata.Types[old_count] = PathPointTypeStart;
178 path->newfigure = FALSE;
181 path->pathdata.Count += count;
186 GpStatus WINGDIPAPI GdipAddPathPath(GpPath *path, GDIPCONST GpPath* addingPath,
189 INT old_count, count;
191 if(!path || !addingPath)
192 return InvalidParameter;
194 old_count = path->pathdata.Count;
195 count = addingPath->pathdata.Count;
197 if(!lengthen_path(path, count))
200 memcpy(&path->pathdata.Points[old_count], addingPath->pathdata.Points,
201 count * sizeof(GpPointF));
202 memcpy(&path->pathdata.Types[old_count], addingPath->pathdata.Types, count);
204 if(path->newfigure || !connect)
205 path->pathdata.Types[old_count] = PathPointTypeStart;
207 path->pathdata.Types[old_count] = PathPointTypeLine;
209 path->newfigure = FALSE;
210 path->pathdata.Count += count;
215 GpStatus WINGDIPAPI GdipClonePath(GpPath* path, GpPath **clone)
218 return InvalidParameter;
220 *clone = GdipAlloc(sizeof(GpPath));
221 if(!*clone) return OutOfMemory;
223 memcpy(*clone, path, sizeof(GpPath));
225 (*clone)->pathdata.Points = GdipAlloc(path->datalen * sizeof(PointF));
226 (*clone)->pathdata.Types = GdipAlloc(path->datalen);
227 if(!(*clone)->pathdata.Points || !(*clone)->pathdata.Types){
229 GdipFree((*clone)->pathdata.Points);
230 GdipFree((*clone)->pathdata.Types);
234 memcpy((*clone)->pathdata.Points, path->pathdata.Points,
235 path->datalen * sizeof(PointF));
236 memcpy((*clone)->pathdata.Types, path->pathdata.Types, path->datalen);
241 GpStatus WINGDIPAPI GdipClosePathFigure(GpPath* path)
244 return InvalidParameter;
246 if(path->pathdata.Count > 0){
247 path->pathdata.Types[path->pathdata.Count - 1] |= PathPointTypeCloseSubpath;
248 path->newfigure = TRUE;
254 GpStatus WINGDIPAPI GdipClosePathFigures(GpPath* path)
259 return InvalidParameter;
261 for(i = 1; i < path->pathdata.Count; i++){
262 if(path->pathdata.Types[i] == PathPointTypeStart)
263 path->pathdata.Types[i-1] |= PathPointTypeCloseSubpath;
266 path->newfigure = TRUE;
271 GpStatus WINGDIPAPI GdipCreatePath(GpFillMode fill, GpPath **path)
274 return InvalidParameter;
276 *path = GdipAlloc(sizeof(GpPath));
277 if(!*path) return OutOfMemory;
279 (*path)->fill = fill;
280 (*path)->newfigure = TRUE;
285 GpStatus WINGDIPAPI GdipDeletePath(GpPath *path)
288 return InvalidParameter;
290 GdipFree(path->pathdata.Points);
291 GdipFree(path->pathdata.Types);
297 GpStatus WINGDIPAPI GdipGetPathFillMode(GpPath *path, GpFillMode *fillmode)
299 if(!path || !fillmode)
300 return InvalidParameter;
302 *fillmode = path->fill;
307 GpStatus WINGDIPAPI GdipGetPathPoints(GpPath *path, GpPointF* points, INT count)
310 return InvalidParameter;
312 if(count < path->pathdata.Count)
313 return InsufficientBuffer;
315 memcpy(points, path->pathdata.Points, path->pathdata.Count * sizeof(GpPointF));
320 GpStatus WINGDIPAPI GdipGetPathTypes(GpPath *path, BYTE* types, INT count)
323 return InvalidParameter;
325 if(count < path->pathdata.Count)
326 return InsufficientBuffer;
328 memcpy(types, path->pathdata.Types, path->pathdata.Count);
333 /* Windows expands the bounding box to the maximum possible bounding box
334 * for a given pen. For example, if a line join can extend past the point
335 * it's joining by x units, the bounding box is extended by x units in every
336 * direction (even though this is too conservative for most cases). */
337 GpStatus WINGDIPAPI GdipGetPathWorldBounds(GpPath* path, GpRectF* bounds,
338 GDIPCONST GpMatrix *matrix, GDIPCONST GpPen *pen)
340 GpPointF * points, temp_pts[4];
342 REAL path_width = 1.0, width, height, temp, low_x, low_y, high_x, high_y;
344 /* Matrix and pen can be null. */
346 return InvalidParameter;
348 /* If path is empty just return. */
349 count = path->pathdata.Count;
351 bounds->X = bounds->Y = bounds->Width = bounds->Height = 0.0;
355 points = path->pathdata.Points;
357 low_x = high_x = points[0].X;
358 low_y = high_y = points[0].Y;
360 for(i = 1; i < count; i++){
361 low_x = min(low_x, points[i].X);
362 low_y = min(low_y, points[i].Y);
363 high_x = max(high_x, points[i].X);
364 high_y = max(high_y, points[i].Y);
367 width = high_x - low_x;
368 height = high_y - low_y;
370 /* This looks unusual but it's the only way I can imitate windows. */
372 temp_pts[0].X = low_x;
373 temp_pts[0].Y = low_y;
374 temp_pts[1].X = low_x;
375 temp_pts[1].Y = high_y;
376 temp_pts[2].X = high_x;
377 temp_pts[2].Y = high_y;
378 temp_pts[3].X = high_x;
379 temp_pts[3].Y = low_y;
381 GdipTransformMatrixPoints((GpMatrix*)matrix, temp_pts, 4);
382 low_x = temp_pts[0].X;
383 low_y = temp_pts[0].Y;
385 for(i = 1; i < 4; i++){
386 low_x = min(low_x, temp_pts[i].X);
387 low_y = min(low_y, temp_pts[i].Y);
391 width = height * fabs(matrix->matrix[2]) + width * fabs(matrix->matrix[0]);
392 height = height * fabs(matrix->matrix[3]) + temp * fabs(matrix->matrix[1]);
396 path_width = pen->width / 2.0;
399 path_width = max(path_width, pen->width * pen->miterlimit / 2.0);
400 /* FIXME: this should probably also check for the startcap */
401 if(pen->endcap & LineCapNoAnchor)
402 path_width = max(path_width, pen->width * 2.2);
406 width += 2.0 * path_width;
407 height += 2.0 * path_width;
412 bounds->Width = width;
413 bounds->Height = height;
418 GpStatus WINGDIPAPI GdipGetPointCount(GpPath *path, INT *count)
421 return InvalidParameter;
423 *count = path->pathdata.Count;
428 GpStatus WINGDIPAPI GdipIsOutlineVisiblePathPointI(GpPath* path, INT x, INT y,
429 GpPen *pen, GpGraphics *graphics, BOOL *result)
434 return InvalidParameter;
437 FIXME("not implemented\n");
439 return NotImplemented;
442 GpStatus WINGDIPAPI GdipStartPathFigure(GpPath *path)
445 return InvalidParameter;
447 path->newfigure = TRUE;
452 GpStatus WINGDIPAPI GdipResetPath(GpPath *path)
455 return InvalidParameter;
457 path->pathdata.Count = 0;
458 path->newfigure = TRUE;
459 path->fill = FillModeAlternate;
464 GpStatus WINGDIPAPI GdipSetPathFillMode(GpPath *path, GpFillMode fill)
467 return InvalidParameter;
474 GpStatus WINGDIPAPI GdipTransformPath(GpPath *path, GpMatrix *matrix)
477 return InvalidParameter;
479 if(path->pathdata.Count == 0)
482 return GdipTransformMatrixPoints(matrix, (GpPointF*) path->pathdata.Points,
483 path->pathdata.Count);