[PATCH] gdiplus: Handle some degenerate cases with GdipCreatePath2.

Jeff Smith whydoubt at gmail.com
Thu Apr 9 14:52:36 CDT 2020


Signed-off-by: Jeff Smith <whydoubt at gmail.com>
---
 dlls/gdiplus/graphicspath.c       | 22 ++++++++
 dlls/gdiplus/tests/graphicspath.c | 87 +++++++++++++++++++++++++++++++
 2 files changed, 109 insertions(+)

diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c
index 55545a449a..db011607e8 100644
--- a/dlls/gdiplus/graphicspath.c
+++ b/dlls/gdiplus/graphicspath.c
@@ -1213,14 +1213,34 @@ GpStatus WINGDIPAPI GdipCreatePath(GpFillMode fill, GpPath **path)
 GpStatus WINGDIPAPI GdipCreatePath2(GDIPCONST GpPointF* points,
     GDIPCONST BYTE* types, INT count, GpFillMode fill, GpPath **path)
 {
+    int i;
+
     TRACE("(%p, %p, %d, %d, %p)\n", points, types, count, fill, path);
 
     if(!path)
         return InvalidParameter;
 
+    if(count <= 0) {
+        *path = NULL;
+        return OutOfMemory;
+    }
+
     *path = heap_alloc_zero(sizeof(GpPath));
     if(!*path)  return OutOfMemory;
 
+    for(i = 1; i < count; i++) {
+        if((types[i] & PathPointTypePathTypeMask) == PathPointTypeBezier) {
+            if(i+2 < count &&
+                    (types[i+1] & PathPointTypePathTypeMask) == PathPointTypeBezier &&
+                    (types[i+2] & PathPointTypePathTypeMask) == PathPointTypeBezier)
+                i += 2;
+            else {
+                count = 0;
+                break;
+            }
+        }
+    }
+
     (*path)->pathdata.Points = heap_alloc_zero(count * sizeof(PointF));
     (*path)->pathdata.Types = heap_alloc_zero(count);
 
@@ -1233,6 +1253,8 @@ GpStatus WINGDIPAPI GdipCreatePath2(GDIPCONST GpPointF* points,
 
     memcpy((*path)->pathdata.Points, points, count * sizeof(PointF));
     memcpy((*path)->pathdata.Types, types, count);
+    if(count > 0)
+        (*path)->pathdata.Types[0] = PathPointTypeStart;
     (*path)->pathdata.Count = count;
     (*path)->datalen = count;
 
diff --git a/dlls/gdiplus/tests/graphicspath.c b/dlls/gdiplus/tests/graphicspath.c
index 17e6a7cafb..2f6ed41339 100644
--- a/dlls/gdiplus/tests/graphicspath.c
+++ b/dlls/gdiplus/tests/graphicspath.c
@@ -25,6 +25,7 @@
 
 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
 #define expectf(expected, got) ok(fabs(expected - got) < 2.0, "Expected %.2f, got %.2f\n", expected, got)
+#define expectp(expected, got) ok(got == expected, "Expected %p, got %p\n", expected, got)
 #define POINT_TYPE_MAX_LEN (75)
 
 static void stringify_point_type(PathPointType type, char * name)
@@ -174,6 +175,91 @@ static void test_getpathdata(void)
     GdipDeletePath(path);
 }
 
+static void test_createpath2(void)
+{
+    GpStatus status;
+    GpPath* path = NULL;
+    GpPathData data;
+    INT i, count, expect_count;
+
+    PointF test_line_points[] = {{1.0,1.0}, {2.0,1.0}};
+    BYTE test_line_types[] = {PathPointTypeStart, PathPointTypeLine};
+
+    PointF test_bez_points[] = {{1.0,1.0}, {2.0,1.0}, {3.0,1.0}, {4.0,1.0},
+            {5.0,1.0}, {6.0,1.0}, {7.0,1.0}};
+    BYTE test_bez_types[] = {PathPointTypeStart, PathPointTypeBezier,
+            PathPointTypeBezier, PathPointTypeBezier, PathPointTypeBezier,
+            PathPointTypeBezier, PathPointTypeBezier};
+
+    status = GdipCreatePath2(test_line_points, test_line_types, 2, FillModeAlternate, &path);
+    expect(Ok, status);
+    status = GdipGetPointCount(path, &count);
+    expect(Ok, status);
+    expect(2, count);
+    GdipDeletePath(path);
+
+    status = GdipCreatePath2(test_line_points, test_line_types, 1, FillModeAlternate, &path);
+    expect(Ok, status);
+    status = GdipGetPointCount(path, &count);
+    expect(Ok, status);
+    expect(1, count);
+    GdipDeletePath(path);
+
+    path = (void *)0xdeadbeef;
+    status = GdipCreatePath2(test_line_points, test_line_types, 0, FillModeAlternate, &path);
+    expect(OutOfMemory, status);
+    expectp(NULL, path);
+    if(path && path != (void *)0xdeadbeef)
+        GdipDeletePath(path);
+
+    path = (void *)0xdeadbeef;
+    status = GdipCreatePath2(test_line_points, test_line_types, -1, FillModeAlternate, &path);
+    expect(OutOfMemory, status);
+    expectp(NULL, path);
+    if(path && path != (void *)0xdeadbeef)
+        GdipDeletePath(path);
+
+    /* Zero-length line points do not get altered */
+    path = NULL;
+    test_line_points[1].X = test_line_points[0].X;
+    test_line_points[1].Y = test_line_points[0].Y;
+    status = GdipCreatePath2(test_line_points, test_line_types, 2, FillModeAlternate, &path);
+    expect(Ok, status);
+    status = GdipGetPointCount(path, &count);
+    expect(Ok, status);
+    expect(2, count);
+    GdipDeletePath(path);
+
+    /* The type of the first point is always converted to PathPointTypeStart */
+    test_line_types[0] = PathPointTypeLine;
+    status = GdipCreatePath2(test_line_points, test_line_types, 1, FillModeAlternate, &path);
+    expect(Ok, status);
+    status = GdipGetPointCount(path, &count);
+    expect(Ok, status);
+    expect(1, count);
+    data.Count  = count;
+    data.Types  = GdipAlloc(sizeof(BYTE) * count);
+    data.Points = GdipAlloc(sizeof(PointF) * count);
+    status = GdipGetPathData(path, &data);
+    expect(Ok, status);
+    expect((data.Points[0].X == 1.0) && (data.Points[0].Y == 1.0), TRUE);
+    expect(data.Types[0], PathPointTypeStart);
+    GdipFree(data.Points);
+    GdipFree(data.Types);
+    GdipDeletePath(path);
+
+    /* Bezier points must come in groups of three */
+    for(i = 2; i <= 7; i++) {
+        expect_count = (i % 3 == 1) ? i : 0;
+        status = GdipCreatePath2(test_bez_points, test_bez_types, i, FillModeAlternate, &path);
+        expect(Ok, status);
+        status = GdipGetPointCount(path, &count);
+        expect(Ok, status);
+        expect(expect_count, count);
+        GdipDeletePath(path);
+    }
+}
+
 static path_test_t line2_path[] = {
     {0.0, 50.0, PathPointTypeStart, 0, 0}, /*0*/
     {5.0, 45.0, PathPointTypeLine, 0, 0}, /*1*/
@@ -1663,6 +1749,7 @@ START_TEST(graphicspath)
 
     test_constructor_destructor();
     test_getpathdata();
+    test_createpath2();
     test_line2();
     test_arc();
     test_worldbounds();
-- 
2.23.0




More information about the wine-devel mailing list