Jeff Smith : gdiplus: Reuse point when calling GdipAddPathBezier on open figure.

Alexandre Julliard julliard at winehq.org
Thu Apr 16 16:45:12 CDT 2020


Module: wine
Branch: master
Commit: 1a3a8a00165b0debdcb458b3680de61163a71a84
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=1a3a8a00165b0debdcb458b3680de61163a71a84

Author: Jeff Smith <whydoubt at gmail.com>
Date:   Wed Apr 15 15:07:07 2020 -0500

gdiplus: Reuse point when calling GdipAddPathBezier on open figure.

Signed-off-by: Jeff Smith <whydoubt at gmail.com>
Signed-off-by: Vincent Povirk <vincent at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 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();




More information about the wine-cvs mailing list