/* * Copyright (C) 2007 Google (Evan Stade) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * */ #include #include #include "windef.h" #include "winbase.h" #include "winuser.h" #include "wingdi.h" #include "gdiplus.h" #include "gdiplus_private.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(gdiplus); /* make sure path has enough space for len more points */ static BOOL lengthen_path(GpPath *path, INT len) { /* initial allocation */ if(path->datalen == 0){ path->datalen = len * 2; path->pathdata.Points = GdipAlloc(path->datalen * sizeof(PointF)); if(!path->pathdata.Points) return FALSE; path->pathdata.Types = GdipAlloc(path->datalen); if(!path->pathdata.Types){ GdipFree(path->pathdata.Points); return FALSE; } } /* reallocation, double size of arrays */ else if(path->datalen - path->pathdata.Count < len){ while(path->datalen - path->pathdata.Count < len) path->datalen *= 2; path->pathdata.Points = HeapReAlloc(GetProcessHeap(), 0, path->pathdata.Points, path->datalen * sizeof(PointF)); if(!path->pathdata.Points) return FALSE; path->pathdata.Types = HeapReAlloc(GetProcessHeap(), 0, path->pathdata.Types, path->datalen); if(!path->pathdata.Types) return FALSE; } return TRUE; } GpStatus WINGDIPAPI GdipAddPathArc(GpPath *path, REAL x1, REAL y1, REAL x2, REAL y2, REAL startAngle, REAL sweepAngle) { INT count, old_count, i; if(!path) return InvalidParameter; count = arc2polybezier(NULL, x1, y1, x2, y2, startAngle, sweepAngle); if(count == 0) return Ok; if(!lengthen_path(path, count)) return OutOfMemory; old_count = path->pathdata.Count; arc2polybezier(&path->pathdata.Points[old_count], x1, y1, x2, y2, startAngle, sweepAngle); for(i = 0; i < count; i++){ path->pathdata.Types[old_count + i] = PathPointTypeBezier; } path->pathdata.Types[old_count] = (path->newfigure ? PathPointTypeStart : PathPointTypeLine); path->newfigure = FALSE; path->pathdata.Count += count; return Ok; } GpStatus WINGDIPAPI GdipAddPathLine2(GpPath *path, GDIPCONST GpPointF *points, INT count) { INT i, old_count; if(!path || !points) return InvalidParameter; if(!lengthen_path(path, count)) return OutOfMemory; old_count = path->pathdata.Count; for(i = 0; i < count; i++){ path->pathdata.Points[old_count + i].X = points[i].X; path->pathdata.Points[old_count + i].Y = points[i].Y; path->pathdata.Types[old_count + i] = PathPointTypeLine; } if(path->newfigure){ path->pathdata.Types[old_count] = PathPointTypeStart; path->newfigure = FALSE; } path->pathdata.Count += count; return Ok; } GpStatus WINGDIPAPI GdipClosePathFigure(GpPath* path) { if(!path) return InvalidParameter; if(path->pathdata.Count > 0){ path->pathdata.Types[path->pathdata.Count - 1] |= PathPointTypeCloseSubpath; path->newfigure = TRUE; } return Ok; } GpStatus WINGDIPAPI GdipClosePathFigures(GpPath* path) { INT i; if(!path) return InvalidParameter; for(i = 1; i < path->pathdata.Count; i++){ if(path->pathdata.Types[i] == PathPointTypeStart) path->pathdata.Types[i-1] |= PathPointTypeCloseSubpath; } path->newfigure = TRUE; return Ok; } GpStatus WINGDIPAPI GdipCreatePath(GpFillMode fill, GpPath **path) { if(!path) return InvalidParameter; *path = GdipAlloc(sizeof(GpPath)); if(!*path) return OutOfMemory; (*path)->fill = fill; (*path)->newfigure = TRUE; return Ok; } GpStatus WINGDIPAPI GdipDeletePath(GpPath *path) { if(!path) return InvalidParameter; GdipFree(path->pathdata.Points); GdipFree(path->pathdata.Types); GdipFree(path); return Ok; } GpStatus WINGDIPAPI GdipGetPathPoints(GpPath *path, GpPointF* points, INT count) { if(!path) return InvalidParameter; if(count < path->pathdata.Count) return InsufficientBuffer; memcpy(points, path->pathdata.Points, path->pathdata.Count * sizeof(GpPointF)); return Ok; } GpStatus WINGDIPAPI GdipGetPathTypes(GpPath *path, BYTE* types, INT count) { if(!path) return InvalidParameter; if(count < path->pathdata.Count) return InsufficientBuffer; memcpy(types, path->pathdata.Types, path->pathdata.Count); return Ok; } /* Windows expands the bounding box to the maximum possible bounding box * for a given pen. For example, if a line join can extend past the point * it's joining by x units, the bounding box is extended by x units in every * direction (even though this is too conservative for most cases). */ GpStatus WINGDIPAPI GdipGetPathWorldBounds(GpPath* path, GpRectF* bounds, GDIPCONST GpMatrix *matrix, GDIPCONST GpPen *pen) { /* extrema[0] is upper left corner of bounding box, * extrema[1] is lower right corner */ GpPointF extrema[2]; GpPointF * points; INT count, i; /* Matrix and pen can be null. */ if(!path || !bounds) return InvalidParameter; /* If path is empty just return. */ count = path->pathdata.Count; if(count == 0){ bounds->X = bounds->Y = bounds->Width = bounds->Height = 0.0; return Ok; } /* FIXME: implement case where pen is non-NULL. */ if(pen) return NotImplemented; points = path->pathdata.Points; extrema[0].X = extrema[1].X = points[0].X; extrema[0].Y = extrema[1].Y = points[0].Y; for(i = 1; i < count; i++){ extrema[0].X = min(points[i].X, extrema[0].X); extrema[0].Y = min(points[i].Y, extrema[0].Y); extrema[1].X = max(points[i].X, extrema[1].X); extrema[1].Y = max(points[i].Y, extrema[1].Y); } /* If matrix is non-null transform the points. */ if(matrix){ GdipTransformMatrixPoints((GpMatrix*)matrix, extrema, 2); } bounds->X = extrema[0].X; bounds->Y = extrema[0].Y; bounds->Width = extrema[1].X - extrema[0].X; bounds->Height = extrema[1].Y - extrema[0].Y; return Ok; } GpStatus WINGDIPAPI GdipGetPointCount(GpPath *path, INT *count) { if(!path) return InvalidParameter; *count = path->pathdata.Count; return Ok; } GpStatus WINGDIPAPI GdipStartPathFigure(GpPath *path) { if(!path) return InvalidParameter; path->newfigure = TRUE; return Ok; } GpStatus WINGDIPAPI GdipTransformPath(GpPath *path, GpMatrix *matrix) { if(!path) return InvalidParameter; if(path->pathdata.Count == 0) return Ok; return GdipTransformMatrixPoints(matrix, (GpPointF*) path->pathdata.Points, path->pathdata.Count); }