Signed-off-by: Jeff Smith whydoubt@gmail.com --- v2: Handle all new points in extend_current_figure.
dlls/gdiplus/graphicspath.c | 80 +++++++++++++++++++++---------- dlls/gdiplus/tests/graphicspath.c | 34 +++++++++++++ 2 files changed, 90 insertions(+), 24 deletions(-)
diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index 4d5a73588f..547f172d98 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -166,6 +166,52 @@ static BOOL flatten_bezier(path_list_node_t *start, REAL x2, REAL y2, REAL x3, R return TRUE; }
+/* GdipAddPath* helper + * + * Several GdipAddPath functions are expected to add onto an open figure. + * So if the first point being added is an exact match to the last point + * of the existing line, that point should not be added. + * + * Parameters: + * path : path to which points should be added + * points : array of points to add + * count : number of points to add (at least 1) + * type : type of the points being added + * + * Return value: + * OutOfMemory : out of memory, could not lengthen path + * Ok : success + */ +static GpStatus extend_current_figure(GpPath *path, GDIPCONST PointF *points, INT count, BYTE type) +{ + INT insert_index = path->pathdata.Count; + BYTE first_point_type = (path->newfigure ? PathPointTypeStart : PathPointTypeLine); + + if(!path->newfigure && + path->pathdata.Points[insert_index-1].X == points[0].X && + path->pathdata.Points[insert_index-1].Y == points[0].Y) + { + points++; + count--; + first_point_type = type; + } + + if(!count) + return Ok; + + if(!lengthen_path(path, count)) + return OutOfMemory; + + memcpy(path->pathdata.Points + insert_index, points, sizeof(GpPointF)*count); + path->pathdata.Types[insert_index] = first_point_type; + memset(path->pathdata.Types + insert_index + 1, type, count - 1); + + path->newfigure = FALSE; + path->pathdata.Count += count; + + return Ok; +} + /******************************************************************************* * GdipAddPathArc [GDIPLUS.1] * @@ -243,7 +289,7 @@ GpStatus WINGDIPAPI GdipAddPathArcI(GpPath *path, INT x1, INT y1, INT x2, GpStatus WINGDIPAPI GdipAddPathBezier(GpPath *path, REAL x1, REAL y1, REAL x2, REAL y2, REAL x3, REAL y3, REAL x4, REAL y4) { - INT old_count; + PointF points[4];
TRACE("(%p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n", path, x1, y1, x2, y2, x3, y3, x4, y4); @@ -251,30 +297,16 @@ GpStatus WINGDIPAPI GdipAddPathBezier(GpPath *path, REAL x1, REAL y1, REAL x2, if(!path) return InvalidParameter;
- if(!lengthen_path(path, 4)) - return OutOfMemory; - - old_count = path->pathdata.Count; + points[0].X = x1; + points[0].Y = y1; + points[1].X = x2; + points[1].Y = y2; + points[2].X = x3; + points[2].Y = y3; + points[3].X = x4; + points[3].Y = y4;
- path->pathdata.Points[old_count].X = x1; - path->pathdata.Points[old_count].Y = y1; - path->pathdata.Points[old_count + 1].X = x2; - path->pathdata.Points[old_count + 1].Y = y2; - path->pathdata.Points[old_count + 2].X = x3; - path->pathdata.Points[old_count + 2].Y = y3; - path->pathdata.Points[old_count + 3].X = x4; - path->pathdata.Points[old_count + 3].Y = y4; - - path->pathdata.Types[old_count] = - (path->newfigure ? PathPointTypeStart : PathPointTypeLine); - path->pathdata.Types[old_count + 1] = PathPointTypeBezier; - path->pathdata.Types[old_count + 2] = PathPointTypeBezier; - path->pathdata.Types[old_count + 3] = PathPointTypeBezier; - - path->newfigure = FALSE; - path->pathdata.Count += 4; - - return Ok; + return extend_current_figure(path, points, 4, PathPointTypeBezier); }
GpStatus WINGDIPAPI GdipAddPathBezierI(GpPath *path, INT x1, INT y1, INT x2, diff --git a/dlls/gdiplus/tests/graphicspath.c b/dlls/gdiplus/tests/graphicspath.c index 7670a6c41f..d85cf68dfc 100644 --- a/dlls/gdiplus/tests/graphicspath.c +++ b/dlls/gdiplus/tests/graphicspath.c @@ -332,6 +332,39 @@ static void test_line2(void) GdipDeletePath(path); }
+static path_test_t bezier_path[] = { + {10.0, 10.0, PathPointTypeStart, 0, 0}, /*0*/ + {20.0, 10.0, PathPointTypeBezier, 0, 0}, /*1*/ + {20.0, 20.0, PathPointTypeBezier, 0, 0}, /*2*/ + {30.0, 20.0, PathPointTypeBezier, 0, 0}, /*3*/ + {40.0, 20.0, PathPointTypeBezier, 0, 0}, /*4*/ + {40.0, 30.0, PathPointTypeBezier, 0, 0}, /*5*/ + {50.0, 30.0, PathPointTypeBezier, 0, 0}, /*6*/ + {50.0, 10.0, PathPointTypeLine, 0, 0}, /*7*/ + {60.0, 10.0, PathPointTypeBezier, 0, 0}, /*8*/ + {60.0, 20.0, PathPointTypeBezier, 0, 0}, /*9*/ + {70.0, 20.0, PathPointTypeBezier, 0, 0} /*10*/ + }; + +static void test_bezier(void) +{ + GpStatus status; + GpPath* path; + + GdipCreatePath(FillModeAlternate, &path); + + status = GdipAddPathBezier(path, 10.0, 10.0, 20.0, 10.0, 20.0, 20.0, 30.0, 20.0); + expect(Ok, status); + status = GdipAddPathBezier(path, 30.0, 20.0, 40.0, 20.0, 40.0, 30.0, 50.0, 30.0); + expect(Ok, status); + status = GdipAddPathBezier(path, 50.0, 10.0, 60.0, 10.0, 60.0, 20.0, 70.0, 20.0); + expect(Ok, status); + + ok_path(path, bezier_path, ARRAY_SIZE(bezier_path), FALSE); + + GdipDeletePath(path); +} + static path_test_t arc_path[] = { {600.0, 450.0, PathPointTypeStart, 0, 0}, /*0*/ {600.0, 643.3, PathPointTypeBezier, 0, 0}, /*1*/ @@ -1784,6 +1817,7 @@ START_TEST(graphicspath) test_getpathdata(); test_createpath2(); test_line2(); + test_bezier(); test_arc(); test_worldbounds(); test_pathpath();