diff --git a/dlls/gdiplus/region.c b/dlls/gdiplus/region.c index 4cd9636e5a6..4f16f624160 100644 --- a/dlls/gdiplus/region.c +++ b/dlls/gdiplus/region.c @@ -87,6 +87,22 @@ typedef struct packed_point short Y; } packed_point; +/* Test to see if the path could be stored as an array of shorts */ +static BOOL is_integer_path(const GpPath *path) +{ + int i; + + if (!path->pathdata.Count) return FALSE; + + for (i = 0; i < path->pathdata.Count; i++) + { + if (path->pathdata.Points[i].X != gdip_round(path->pathdata.Points[i].X) || + path->pathdata.Points[i].Y != gdip_round(path->pathdata.Points[i].Y)) + return FALSE; + } + return TRUE; +} + /* Everything is measured in DWORDS; round up if there's a remainder */ static inline INT get_pathtypes_size(const GpPath* path) { @@ -106,9 +122,20 @@ static inline INT get_element_size(const region_element* element) case RegionDataRect: return needed + sizeof(GpRect); case RegionDataPath: - needed += element->elementdata.pathdata.pathheader.size; - needed += sizeof(DWORD); /* Extra DWORD for pathheader.size */ - return needed; + { + const GpPath *path = element->elementdata.pathdata.path; + DWORD flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS; + /* 3 for headers, once again size doesn't count itself */ + needed += sizeof(DWORD) * 3; + if (flags & FLAGS_INTPATH) + needed += 2 * sizeof(SHORT) * path->pathdata.Count; + else + needed += 2 * sizeof(FLOAT) * path->pathdata.Count; + + needed += get_pathtypes_size(path); + needed += sizeof(DWORD); /* Extra DWORD for pathheader.size */ + return needed; + } case RegionDataEmptyRect: case RegionDataInfiniteRect: return needed; @@ -128,7 +155,7 @@ static inline GpStatus init_region(GpRegion* region, const RegionType type) region->header.checksum = 0xdeadbeef; region->header.magic = VERSION_MAGIC; region->header.num_children = 0; - region->header.size = sizeheader_size + get_element_size(®ion->node); + region->header.size = 0; return Ok; } @@ -426,8 +453,6 @@ GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region) { region_element* element; GpStatus stat; - DWORD flags; - INT count, i; TRACE("%p, %p\n", path, region); @@ -444,20 +469,6 @@ GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region) return stat; } element = &(*region)->node; - count = path->pathdata.Count; - - flags = count ? FLAGS_INTPATH : FLAGS_NOFLAGS; - - /* Test to see if the path is an Integer path */ - for (i = 0; i < count; i++) - { - if (path->pathdata.Points[i].X != gdip_round(path->pathdata.Points[i].X) || - path->pathdata.Points[i].Y != gdip_round(path->pathdata.Points[i].Y)) - { - flags = FLAGS_NOFLAGS; - break; - } - } stat = GdipClonePath(path, &element->elementdata.pathdata.path); if (stat != Ok) @@ -466,29 +477,6 @@ GpStatus WINGDIPAPI GdipCreateRegionPath(GpPath *path, GpRegion **region) return stat; } - /* 3 for headers, once again size doesn't count itself */ - element->elementdata.pathdata.pathheader.size = ((sizeof(DWORD) * 3)); - switch(flags) - { - /* Floats, sent out as floats */ - case FLAGS_NOFLAGS: - element->elementdata.pathdata.pathheader.size += - (sizeof(DWORD) * count * 2); - break; - /* INTs, sent out as packed shorts */ - case FLAGS_INTPATH: - element->elementdata.pathdata.pathheader.size += - (sizeof(DWORD) * count); - break; - default: - FIXME("Unhandled flags (%08x). Expect wrong results.\n", flags); - } - element->elementdata.pathdata.pathheader.size += get_pathtypes_size(path); - element->elementdata.pathdata.pathheader.magic = VERSION_MAGIC; - element->elementdata.pathdata.pathheader.count = count; - element->elementdata.pathdata.pathheader.flags = flags; - (*region)->header.size = sizeheader_size + get_element_size(element); - return Ok; } @@ -754,11 +742,30 @@ static void write_element(const region_element* element, DWORD *buffer, { INT i; const GpPath* path = element->elementdata.pathdata.path; + struct _pathheader + { + DWORD size; + DWORD magic; + DWORD count; + DWORD flags; + } *pathheader; - memcpy(buffer + *filled, &element->elementdata.pathdata.pathheader, - sizeof(element->elementdata.pathdata.pathheader)); - *filled += sizeof(element->elementdata.pathdata.pathheader) / sizeof(DWORD); - switch (element->elementdata.pathdata.pathheader.flags) + pathheader = (struct _pathheader *)(buffer + *filled); + + pathheader->flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS; + /* 3 for headers, once again size doesn't count itself */ + pathheader->size = sizeof(DWORD) * 3; + if (pathheader->flags & FLAGS_INTPATH) + pathheader->size += 2 * sizeof(SHORT) * path->pathdata.Count; + else + pathheader->size += 2 * sizeof(FLOAT) * path->pathdata.Count; + pathheader->size += get_pathtypes_size(path); + pathheader->magic = VERSION_MAGIC; + pathheader->count = path->pathdata.Count; + + *filled += 4; + + switch (pathheader->flags & FLAGS_INTPATH) { case FLAGS_NOFLAGS: for (i = 0; i < path->pathdata.Count; i++) @@ -773,6 +780,7 @@ static void write_element(const region_element* element, DWORD *buffer, write_packed_point(buffer, filled, &path->pathdata.Points[i]); } + break; } write_path_types(buffer, filled, path); break; @@ -819,6 +827,13 @@ static void write_element(const region_element* element, DWORD *buffer, GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size, UINT *needed) { + struct _region_header + { + DWORD size; + DWORD checksum; + DWORD magic; + DWORD num_children; + } *region_header; INT filled = 0; TRACE("%p, %p, %d, %p\n", region, buffer, size, needed); @@ -826,8 +841,12 @@ GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size, if (!(region && buffer && size)) return InvalidParameter; - memcpy(buffer, ®ion->header, sizeof(region->header)); - filled += sizeof(region->header) / sizeof(DWORD); + region_header = (struct _region_header *)buffer; + region_header->size = sizeheader_size + get_element_size(®ion->node); + region_header->checksum = 0; + region_header->magic = VERSION_MAGIC; + region_header->num_children = region->header.num_children; + filled += 4; /* With few exceptions, everything written is DWORD aligned, * so use that as our base */ write_element(®ion->node, (DWORD*)buffer, &filled); @@ -849,7 +868,7 @@ GpStatus WINGDIPAPI GdipGetRegionDataSize(GpRegion *region, UINT *needed) return InvalidParameter; /* header.size doesn't count header.size and header.checksum */ - *needed = region->header.size + sizeof(DWORD) * 2; + *needed = sizeof(DWORD) * 2 + sizeheader_size + get_element_size(®ion->node); return Ok; } diff --git a/dlls/gdiplus/tests/region.c b/dlls/gdiplus/tests/region.c index f5092049734..23c7a07095c 100644 --- a/dlls/gdiplus/tests/region.c +++ b/dlls/gdiplus/tests/region.c @@ -427,37 +427,24 @@ static void test_getregiondata(void) needed = 0; status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed); expect(Ok, status); -todo_wine expect(72, needed); -todo_wine expect_dword(buf, 64); expect_magic(buf + 2); expect_dword(buf + 3 , 0); expect_dword(buf + 4 , RGNDATA_PATH); -todo_wine expect_dword(buf + 5, 48); expect_magic(buf + 6); expect_dword(buf + 7, 4); /* flags 0 means that a path is an array of FLOATs */ -todo_wine expect_dword(buf + 8, 0); -todo_wine expect_float(buf + 9, 5.6); -todo_wine expect_float(buf + 10, 6.8); -todo_wine expect_float(buf + 11, 7.6); -todo_wine expect_float(buf + 12, 8.8); -todo_wine expect_float(buf + 13, 8.6); -todo_wine expect_float(buf + 14, 1.8); -todo_wine expect_float(buf + 15, 5.6); -todo_wine expect_float(buf + 16, 6.8); -todo_wine expect_dword(buf + 17, 0x81010100); /* 0x01010100 if we don't close the path */ status = GdipDeletePath(path);