From: Jeff Smith Subject: [PATCH] gdiplus: Handle some degenerate cases with GdipCreatePath2. Message-Id: <20200409195236.1112915-1-whydoubt@gmail.com> Date: Thu, 9 Apr 2020 14:52:36 -0500 Signed-off-by: Jeff Smith --- 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