From 35adc2a6f7c3be32803b91837cb19b50948a5674 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Fri, 31 Oct 2014 08:20:17 +0100 Subject: [PATCH] Added patch for implementation of GdipCreateRegionRgnData. --- README.md | 3 +- debian/changelog | 1 + patches/Makefile | 19 + ...ment-GdipCreateRegionRgnData.-Take-3.patch | 501 ++++++++++++++++++ .../definition | 4 + 5 files changed, 527 insertions(+), 1 deletion(-) create mode 100644 patches/gdiplus-GdipCreateRegionRgnData/0001-gdiplus-Implement-GdipCreateRegionRgnData.-Take-3.patch create mode 100644 patches/gdiplus-GdipCreateRegionRgnData/definition diff --git a/README.md b/README.md index b4b7da98..e0eb33a4 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,12 @@ Wine. All those differences are also documented on the Included bugfixes and improvements ================================== -**Bugfixes and features included in the next upcoming release [6]:** +**Bugfixes and features included in the next upcoming release [7]:** * Cinema 4D needs NotifyIpInterfaceChange ([Wine Bug #34573](http://bugs.winehq.org/show_bug.cgi?id=34573)) * D3DCompileShader should filter specific warning messages ([Wine Bug #33770](http://bugs.winehq.org/show_bug.cgi?id=33770)) * Emulate write to CR4 register ([Wine Bug #30220](http://bugs.winehq.org/show_bug.cgi?id=30220)) +* Support for GdipCreateRegionRgnData ([Wine Bug #34843](http://bugs.winehq.org/show_bug.cgi?id=34843)) * Support for RtlDecompressBuffer ([Wine Bug #37449](http://bugs.winehq.org/show_bug.cgi?id=37449)) * Support for pasting HTML from Unix applications ([Wine Bug #7372](http://bugs.winehq.org/show_bug.cgi?id=7372)) * Tumblebugs 2 requires DXTn software encoding support ([Wine Bug #29586](http://bugs.winehq.org/show_bug.cgi?id=29586)) diff --git a/debian/changelog b/debian/changelog index 900b95fa..b5c80cbf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -6,6 +6,7 @@ wine-compholio (1.7.30) UNRELEASED; urgency=low * Added patch to implement support for pasting HTML from native Unix applications. * Added patch to implement RtlDecompressBuffer. * Added patch to emulate write to CR4 register. + * Added patch for implementation of GdipCreateRegionRgnData. * Removed patch to avoid Clang compiler warning because of unused Vtable (accepted upstream). * Removed patch for additional ATL thunks (accepted upstream). * Removed patch to ímplement IRichEditOle and ITextDocument support for ITextServices (accepted upstream). diff --git a/patches/Makefile b/patches/Makefile index ba1bdfbf..a612ba9a 100644 --- a/patches/Makefile +++ b/patches/Makefile @@ -33,6 +33,7 @@ PATCHLIST := \ dsound-Fast_Mixer.ok \ fonts-Missing_Fonts.ok \ gdi32-MultiMonitor.ok \ + gdiplus-GdipCreateRegionRgnData.ok \ imagehlp-BindImageEx.ok \ imm32-Cross_Thread_Access.ok \ iphlpapi-Stubs.ok \ @@ -433,6 +434,24 @@ gdi32-MultiMonitor.ok: echo '+ { "gdi32-MultiMonitor", "Ken Thomases", "Add multi monitor support to gdi32." },'; \ ) > gdi32-MultiMonitor.ok +# Patchset gdiplus-GdipCreateRegionRgnData +# | +# | Included patches: +# | * Implement GdipCreateRegionRgnData. [rev 3, by Dmitry Timoshkov] +# | +# | This patchset fixes the following Wine bugs: +# | * [#34843] Support for GdipCreateRegionRgnData +# | +# | Modified files: +# | * dlls/gdiplus/region.c, dlls/gdiplus/tests/region.c +# | +.INTERMEDIATE: gdiplus-GdipCreateRegionRgnData.ok +gdiplus-GdipCreateRegionRgnData.ok: + $(call APPLY_FILE,gdiplus-GdipCreateRegionRgnData/0001-gdiplus-Implement-GdipCreateRegionRgnData.-Take-3.patch) + @( \ + echo '+ { "gdiplus-GdipCreateRegionRgnData", "Dmitry Timoshkov", "Implement GdipCreateRegionRgnData. [rev 3]" },'; \ + ) > gdiplus-GdipCreateRegionRgnData.ok + # Patchset imagehlp-BindImageEx # | # | Included patches: diff --git a/patches/gdiplus-GdipCreateRegionRgnData/0001-gdiplus-Implement-GdipCreateRegionRgnData.-Take-3.patch b/patches/gdiplus-GdipCreateRegionRgnData/0001-gdiplus-Implement-GdipCreateRegionRgnData.-Take-3.patch new file mode 100644 index 00000000..e89a9d44 --- /dev/null +++ b/patches/gdiplus-GdipCreateRegionRgnData/0001-gdiplus-Implement-GdipCreateRegionRgnData.-Take-3.patch @@ -0,0 +1,501 @@ +From 431cbd6d947169761c8768b23f0c804be67229f3 Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Mon, 2 Dec 2013 12:18:58 +0900 +Subject: gdiplus: Implement GdipCreateRegionRgnData. Take 3. + +--- + dlls/gdiplus/region.c | 258 ++++++++++++++++++++++++++++++++++++++++---- + dlls/gdiplus/tests/region.c | 65 +++++++++++ + 2 files changed, 304 insertions(+), 19 deletions(-) + +diff --git a/dlls/gdiplus/region.c b/dlls/gdiplus/region.c +index 4ba86eb..450105f 100644 +--- a/dlls/gdiplus/region.c ++++ b/dlls/gdiplus/region.c +@@ -1,5 +1,6 @@ + /* + * Copyright (C) 2008 Google (Lei Zhang) ++ * Copyright (C) 2013 Dmitry Timoshkov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -76,6 +77,28 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdiplus); + #define FLAGS_NOFLAGS 0x0 + #define FLAGS_INTPATH 0x4000 + ++struct memory_buffer ++{ ++ const BYTE *buffer; ++ INT size, pos; ++}; ++ ++struct region_header ++{ ++ DWORD size; ++ DWORD checksum; ++ DWORD magic; ++ DWORD num_children; ++}; ++ ++struct path_header ++{ ++ DWORD size; ++ DWORD magic; ++ DWORD count; ++ DWORD flags; ++}; ++ + /* Header size as far as header->size is concerned. This doesn't include + * header->size or header->checksum + */ +@@ -522,12 +545,221 @@ GpStatus WINGDIPAPI GdipCreateRegionRectI(GDIPCONST GpRect *rect, + return GdipCreateRegionRect(&rectf, region); + } + ++static inline void init_memory_buffer(struct memory_buffer *mbuf, const BYTE *buffer, INT size) ++{ ++ mbuf->buffer = buffer; ++ mbuf->size = size; ++ mbuf->pos = 0; ++} ++ ++static inline const void *buffer_read(struct memory_buffer *mbuf, INT size) ++{ ++ if (mbuf->size - mbuf->pos >= size) ++ { ++ const void *data = mbuf->buffer + mbuf->pos; ++ mbuf->pos += size; ++ return data; ++ } ++ return NULL; ++} ++ ++static GpStatus read_element(struct memory_buffer *mbuf, GpRegion *region, region_element *node, INT *count) ++{ ++ GpStatus status; ++ const DWORD *type; ++ ++ type = buffer_read(mbuf, sizeof(DWORD)); ++ if (!type) return Ok; ++ ++ TRACE("type %#x\n", *type); ++ ++ node->type = *type; ++ ++ switch (node->type) ++ { ++ case CombineModeReplace: ++ case CombineModeIntersect: ++ case CombineModeUnion: ++ case CombineModeXor: ++ case CombineModeExclude: ++ case CombineModeComplement: ++ { ++ region_element *left, *right; ++ ++ left = GdipAlloc(sizeof(region_element)); ++ if (!left) return OutOfMemory; ++ right = GdipAlloc(sizeof(region_element)); ++ if (!right) ++ { ++ GdipFree(left); ++ return OutOfMemory; ++ } ++ ++ status = read_element(mbuf, region, left, count); ++ if (status == Ok) ++ { ++ status = read_element(mbuf, region, right, count); ++ if (status == Ok) ++ { ++ node->elementdata.combine.left = left; ++ node->elementdata.combine.right = right; ++ region->num_children += 2; ++ return Ok; ++ } ++ } ++ ++ GdipFree(left); ++ GdipFree(right); ++ return status; ++ } ++ ++ case RegionDataRect: ++ { ++ const GpRectF *rc; ++ ++ rc = buffer_read(mbuf, sizeof(GpRectF)); ++ if (!rc) ++ { ++ ERR("failed to read rect data\n"); ++ return InvalidParameter; ++ } ++ ++ node->elementdata.rect = *rc; ++ *count += 1; ++ return Ok; ++ } ++ ++ case RegionDataPath: ++ { ++ GpPath *path; ++ const struct path_header *path_header; ++ const BYTE *types; ++ ++ path_header = buffer_read(mbuf, sizeof(struct path_header)); ++ if (!path_header) ++ { ++ ERR("failed to read path header\n"); ++ return InvalidParameter; ++ } ++ if (path_header->magic != VERSION_MAGIC) ++ { ++ ERR("invalid path header magic %#x\n", path_header->magic); ++ return InvalidParameter; ++ } ++ ++ /* Windows always fails to create an empty path in a region */ ++ if (!path_header->count) ++ { ++ TRACE("refusing to create an empty path in a region\n"); ++ return GenericError; ++ } ++ ++ status = GdipCreatePath(FillModeAlternate, &path); ++ if (status) return status; ++ ++ node->elementdata.path = path; ++ ++ if (!lengthen_path(path, path_header->count)) ++ return OutOfMemory; ++ ++ path->pathdata.Count = path_header->count; ++ ++ if (path_header->flags & ~FLAGS_INTPATH) ++ FIXME("unhandled path flags %#x\n", path_header->flags); ++ ++ if (path_header->flags & FLAGS_INTPATH) ++ { ++ const packed_point *pt; ++ DWORD i; ++ ++ pt = buffer_read(mbuf, sizeof(packed_point) * path_header->count); ++ if (!pt) ++ { ++ ERR("failed to read packed %u path points\n", path_header->count); ++ return InvalidParameter; ++ } ++ ++ for (i = 0; i < path_header->count; i++) ++ { ++ path->pathdata.Points[i].X = (REAL)pt[i].X; ++ path->pathdata.Points[i].Y = (REAL)pt[i].Y; ++ } ++ } ++ else ++ { ++ const GpPointF *ptf; ++ ++ ptf = buffer_read(mbuf, sizeof(GpPointF) * path_header->count); ++ if (!ptf) ++ { ++ ERR("failed to read %u path points\n", path_header->count); ++ return InvalidParameter; ++ } ++ memcpy(path->pathdata.Points, ptf, sizeof(GpPointF) * path_header->count); ++ } ++ ++ types = buffer_read(mbuf, path_header->count); ++ if (!types) ++ { ++ ERR("failed to read %u path types\n", path_header->count); ++ return InvalidParameter; ++ } ++ memcpy(path->pathdata.Types, types, path_header->count); ++ if (path_header->count & 3) ++ { ++ if (!buffer_read(mbuf, 4 - (path_header->count & 3))) ++ { ++ ERR("failed to read rounding %u bytes\n", 4 - (path_header->count & 3)); ++ return InvalidParameter; ++ } ++ } ++ ++ *count += 1; ++ return Ok; ++ } ++ ++ case RegionDataEmptyRect: ++ case RegionDataInfiniteRect: ++ *count += 1; ++ return Ok; ++ ++ default: ++ FIXME("element type %#x is not supported\n", *type); ++ break; ++ } ++ ++ return InvalidParameter; ++} ++ + GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region) + { +- FIXME("(%p, %d, %p): stub\n", data, size, region); ++ GpStatus status; ++ struct memory_buffer mbuf; ++ const struct region_header *region_header; ++ INT count; + +- *region = NULL; +- return NotImplemented; ++ if (!data || !size) return InvalidParameter; ++ ++ TRACE("%p, %d, %p\n", data, size, region); ++ ++ init_memory_buffer(&mbuf, data, size); ++ ++ region_header = buffer_read(&mbuf, sizeof(struct region_header)); ++ if (!region_header || region_header->magic != VERSION_MAGIC) ++ return InvalidParameter; ++ ++ status = GdipCreateRegion(region); ++ if (status != Ok) return status; ++ ++ count = 0; ++ status = read_element(&mbuf, *region, &(*region)->node, &count); ++ if (status == Ok && !count) ++ status = InvalidParameter; ++ ++ if (status != Ok) ++ GdipDeleteRegion(*region); ++ ++ return status; + } + + +@@ -738,15 +970,9 @@ static void write_element(const region_element* element, DWORD *buffer, + { + INT i; + const GpPath* path = element->elementdata.path; +- struct _pathheader +- { +- DWORD size; +- DWORD magic; +- DWORD count; +- DWORD flags; +- } *pathheader; ++ struct path_header *pathheader; + +- pathheader = (struct _pathheader *)(buffer + *filled); ++ pathheader = (struct path_header *)(buffer + *filled); + + pathheader->flags = is_integer_path(path) ? FLAGS_INTPATH : FLAGS_NOFLAGS; + /* 3 for headers, once again size doesn't count itself */ +@@ -823,13 +1049,7 @@ 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; ++ struct region_header *region_header; + INT filled = 0; + UINT required; + GpStatus status; +@@ -847,7 +1067,7 @@ GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size, + return InsufficientBuffer; + } + +- region_header = (struct _region_header *)buffer; ++ 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; +diff --git a/dlls/gdiplus/tests/region.c b/dlls/gdiplus/tests/region.c +index 5632e4d..a718a5c 100644 +--- a/dlls/gdiplus/tests/region.c ++++ b/dlls/gdiplus/tests/region.c +@@ -102,6 +102,56 @@ static void verify_region(HRGN hrgn, const RECT *rc) + rgn.data.rdh.rcBound.left, rgn.data.rdh.rcBound.top, rgn.data.rdh.rcBound.right, rgn.data.rdh.rcBound.bottom); + } + ++static void test_region_data(DWORD *data, UINT size, INT line) ++{ ++ GpStatus status; ++ GpRegion *region; ++ DWORD buf[256]; ++ UINT needed, i; ++ ++ status = GdipCreateRegionRgnData((BYTE *)data, size, ®ion); ++ /* Windows always fails to create an empty path in a region */ ++ if (data[4] == RGNDATA_PATH) ++ { ++ struct _path_header ++ { ++ DWORD size; ++ DWORD magic; ++ DWORD count; ++ DWORD flags; ++ } *path_header = (struct _path_header *)(data + 5); ++ if (!path_header->count) ++ { ++ ok_(__FILE__, line)(status == GenericError, "expected GenericError, got %d\n", status); ++ return; ++ } ++ } ++ ++ ok_(__FILE__, line)(status == Ok, "GdipCreateRegionRgnData error %d\n", status); ++ if (status != Ok) return; ++ ++ needed = 0; ++ status = GdipGetRegionDataSize(region, &needed); ++ ok_(__FILE__, line)(status == Ok, "status %d\n", status); ++ ok_(__FILE__, line)(needed == size, "data size mismatch: %u != %u\n", needed, size); ++ ++ memset(buf, 0xee, sizeof(buf)); ++ needed = 0; ++ status = GdipGetRegionData(region, (BYTE *)buf, sizeof(buf), &needed); ++ ok_(__FILE__, line)(status == Ok, "status %08x\n", status); ++ ok_(__FILE__, line)(needed == size, "data size mismatch: %u != %u\n", needed, size); ++ ++ size /= sizeof(DWORD); ++ for (i = 0; i < size - 1; i++) ++ { ++ if (i == 1) continue; /* data[1] never matches */ ++ ok_(__FILE__, line)(data[i] == buf[i], "off %u: %#x != %#x\n", i, data[i], buf[i]); ++ } ++ /* some Windows versions fail to properly clear the aligned DWORD */ ++ ok_(__FILE__, line)(data[size - 1] == buf[size - 1] || broken(data[size - 1] != buf[size - 1]), ++ "off %u: %#x != %#x\n", size - 1, data[size - 1], buf[size - 1]); ++} ++ + static void test_getregiondata(void) + { + GpStatus status; +@@ -143,6 +193,7 @@ static void test_getregiondata(void) + expect_dword(buf + 3, 0); + expect_dword(buf + 4, RGNDATA_INFINITE_RECT); + expect_dword(buf + 6, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + status = GdipSetEmpty(region); + ok(status == Ok, "status %08x\n", status); +@@ -160,6 +211,7 @@ static void test_getregiondata(void) + expect_dword(buf + 3, 0); + expect_dword(buf + 4, RGNDATA_EMPTY_RECT); + expect_dword(buf + 6, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + status = GdipSetInfinite(region); + ok(status == Ok, "status %08x\n", status); +@@ -177,6 +229,7 @@ static void test_getregiondata(void) + expect_dword(buf + 3, 0); + expect_dword(buf + 4, RGNDATA_INFINITE_RECT); + expect_dword(buf + 6, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + status = GdipDeleteRegion(region); + ok(status == Ok, "status %08x\n", status); +@@ -205,6 +258,7 @@ static void test_getregiondata(void) + expect_float(buf + 7, 100.0); + expect_float(buf + 8, 200.0); + expect_dword(buf + 10, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + rect.X = 50; + rect.Y = 30; +@@ -290,6 +344,7 @@ static void test_getregiondata(void) + expect_float(buf + 37, 22.0); + expect_float(buf + 38, 55.0); + expect_dword(buf + 39, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + status = GdipDeleteRegion(region2); + ok(status == Ok, "status %08x\n", status); +@@ -331,6 +386,7 @@ static void test_getregiondata(void) + expect_float(buf + 16, 28.0); + expect_dword(buf + 17, 0x81010100); + expect_dword(buf + 18, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + rect.X = 50; + rect.Y = 30; +@@ -371,6 +427,7 @@ static void test_getregiondata(void) + expect_float(buf + 22, 10.0); + expect_float(buf + 23, 20.0); + expect_dword(buf + 24, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + status = GdipDeleteRegion(region); + ok(status == Ok, "status %08x\n", status); +@@ -403,6 +460,7 @@ static void test_getregiondata(void) + ok(*(buf + 8) == 0x4000 /* before win7 */ || *(buf + 8) == 0, + "expected 0x4000 or 0, got %08x\n", *(buf + 8)); + expect_dword(buf + 10, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + /* Transform an empty region */ + status = GdipCreateMatrix(&matrix); +@@ -453,6 +511,7 @@ static void test_getregiondata(void) + expect(6, point[3].Y); + expect_dword(buf + 13, 0x81010100); /* 0x01010100 if we don't close the path */ + expect_dword(buf + 14, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + status = GdipTranslateRegion(region, 0.6, 0.8); + expect(Ok, status); +@@ -480,6 +539,7 @@ static void test_getregiondata(void) + expect_float(buf + 16, 6.8); + expect_dword(buf + 17, 0x81010100); /* 0x01010100 if we don't close the path */ + expect_dword(buf + 18, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + status = GdipDeletePath(path); + expect(Ok, status); +@@ -522,6 +582,7 @@ static void test_getregiondata(void) + expect_float(buf + 16, 6.2); + expect_dword(buf + 17, 0x01010100); + expect_dword(buf + 18, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + status = GdipDeletePath(path); + expect(Ok, status); +@@ -584,6 +645,7 @@ static void test_getregiondata(void) + ok(*(buf + 28) == 0x00000101 || *(buf + 28) == 0x43050101 /* Win 7 */, + "expected 00000101 or 43050101 got %08x\n", *(buf + 28)); + expect_dword(buf + 29, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + status = GdipDeletePath(path); + expect(Ok, status); +@@ -627,6 +689,7 @@ static void test_getregiondata(void) + expect(23, point[3].Y); + expect_dword(buf + 13, 0x81010100); /* 0x01010100 if we don't close the path */ + expect_dword(buf + 14, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + status = GdipDeletePath(path); + expect(Ok, status); +@@ -669,6 +732,7 @@ static void test_getregiondata(void) + expect_float(buf + 16, 2300.0); + expect_dword(buf + 17, 0x81010100); /* 0x01010100 if we don't close the path */ + expect_dword(buf + 18, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + status = GdipDeletePath(path); + expect(Ok, status); +@@ -732,6 +796,7 @@ static void test_getregiondata(void) + *(buf + 33) == 0x43030303 /* 32-bit win7 */ || *(buf + 33) == 0x4c030303 /* 64-bit win7 */, + "expected 0x00030303 or 0x43030303 or 0x4c030303 got %08x\n", *(buf + 33)); + expect_dword(buf + 34, 0xeeeeeeee); ++ test_region_data(buf, needed, __LINE__); + + status = GdipDeletePath(path); + expect(Ok, status); +-- +2.1.2 + diff --git a/patches/gdiplus-GdipCreateRegionRgnData/definition b/patches/gdiplus-GdipCreateRegionRgnData/definition new file mode 100644 index 00000000..fd8b0f30 --- /dev/null +++ b/patches/gdiplus-GdipCreateRegionRgnData/definition @@ -0,0 +1,4 @@ +Author: Dmitry Timoshkov +Subject: Implement GdipCreateRegionRgnData. +Revision: 3 +Fixes: [34843] Support for GdipCreateRegionRgnData