Nikolay Sivov : gdiplus: Implement trivial case of GdipCreateRegionRgnData for empty and infinite regions.
Alexandre Julliard
julliard at wine.codeweavers.com
Wed Jun 10 10:09:18 CDT 2015
Module: wine
Branch: master
Commit: 0a15e163dbfcd568963465c9c56c96023089a5d3
URL: http://source.winehq.org/git/wine.git/?a=commit;h=0a15e163dbfcd568963465c9c56c96023089a5d3
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Tue Jun 9 09:35:38 2015 +0300
gdiplus: Implement trivial case of GdipCreateRegionRgnData for empty and infinite regions.
---
dlls/gdiplus/gdiplus_private.h | 3 +-
dlls/gdiplus/region.c | 99 ++++++++++++++++++++++++++++++++++--------
dlls/gdiplus/tests/region.c | 63 +++++++++++++++++++++++++++
3 files changed, 145 insertions(+), 20 deletions(-)
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 57b3de3..1f0f47d 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -39,7 +39,8 @@
#define MAX_DASHLEN (16) /* this is a limitation of gdi */
#define INCH_HIMETRIC (2540)
-#define VERSION_MAGIC 0xdbc01001
+#define VERSION_MAGIC 0xdbc01001
+#define VERSION_MAGIC2 0xdbc01002
#define TENSION_CONST (0.3)
#define GIF_DISPOSE_UNSPECIFIED 0
diff --git a/dlls/gdiplus/region.c b/dlls/gdiplus/region.c
index 4ba86eb..572df62 100644
--- a/dlls/gdiplus/region.c
+++ b/dlls/gdiplus/region.c
@@ -522,15 +522,6 @@ GpStatus WINGDIPAPI GdipCreateRegionRectI(GDIPCONST GpRect *rect,
return GdipCreateRegionRect(&rectf, region);
}
-GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region)
-{
- FIXME("(%p, %d, %p): stub\n", data, size, region);
-
- *region = NULL;
- return NotImplemented;
-}
-
-
/******************************************************************************
* GdipCreateRegionHrgn [GDIPLUS.@]
*/
@@ -787,6 +778,14 @@ static void write_element(const region_element* element, DWORD *buffer,
}
}
+struct region_header
+{
+ DWORD size;
+ DWORD checksum;
+ DWORD magic;
+ DWORD num_children;
+};
+
/*****************************************************************************
* GdipGetRegionData [GDIPLUS.@]
*
@@ -823,13 +822,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 +840,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;
@@ -863,6 +856,74 @@ GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
return Ok;
}
+static inline GpStatus read_dword(DWORD **buffer, INT *size, DWORD *ret)
+{
+ if (*size < sizeof(DWORD))
+ return GenericError;
+
+ *ret = **buffer;
+ (*buffer)++;
+ (*size) -= sizeof(DWORD);
+ return Ok;
+}
+
+static GpStatus read_element(GpRegion *region, region_element *element, DWORD **buffer, INT *size)
+{
+ GpStatus status;
+
+ status = read_dword(buffer, size, &element->type);
+ if (status != Ok)
+ return status;
+
+ switch (element->type)
+ {
+ case RegionDataInfiniteRect:
+ case RegionDataEmptyRect:
+ break;
+ default:
+ FIXME("region element type 0x%08x not supported\n", element->type);
+ return NotImplemented;
+ }
+
+ return Ok;
+}
+
+/*****************************************************************************
+ * GdipCreateRegionRgnData [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipCreateRegionRgnData(GDIPCONST BYTE *data, INT size, GpRegion **region)
+{
+ struct region_header *region_header;
+ DWORD *buffer = (DWORD*)data;
+ GpStatus status;
+
+ TRACE("(%p, %d, %p)\n", data, size, region);
+
+ if (!data || size < sizeof(*region_header) || !region)
+ return InvalidParameter;
+
+ region_header = (struct region_header *)buffer;
+ if (region_header->magic != VERSION_MAGIC && region_header->magic != VERSION_MAGIC2)
+ return InvalidParameter;
+
+ status = GdipCreateRegion(region);
+ if (status != Ok)
+ return status;
+
+ /* skip header */
+ buffer += 4;
+ size -= sizeof(*region_header);
+
+ status = read_element(*region, &(*region)->node, &buffer, &size);
+ if (status != Ok)
+ {
+ GdipDeleteRegion(*region);
+ *region = NULL;
+ }
+
+ return status;
+}
+
/*****************************************************************************
* GdipGetRegionDataSize [GDIPLUS.@]
*/
@@ -988,7 +1049,7 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
case CombineModeIntersect:
return get_region_hrgn(element->elementdata.combine.right, graphics, hrgn);
case CombineModeXor: case CombineModeExclude:
- left = CreateRectRgn(-4194304, -4194304, 4194304, 4194304);
+ left = CreateRectRgn(-(1 << 22), -(1 << 22), 1 << 22, 1 << 22);
break;
case CombineModeUnion: case CombineModeComplement:
*hrgn = NULL;
@@ -1013,7 +1074,7 @@ static GpStatus get_region_hrgn(struct region_element *element, GpGraphics *grap
*hrgn = left;
return Ok;
case CombineModeXor: case CombineModeComplement:
- right = CreateRectRgn(-4194304, -4194304, 4194304, 4194304);
+ right = CreateRectRgn(-(1 << 22), -(1 << 22), 1 << 22, 1 << 22);
break;
case CombineModeUnion: case CombineModeExclude:
DeleteObject(left);
diff --git a/dlls/gdiplus/tests/region.c b/dlls/gdiplus/tests/region.c
index 5632e4d..92569c7 100644
--- a/dlls/gdiplus/tests/region.c
+++ b/dlls/gdiplus/tests/region.c
@@ -2132,6 +2132,68 @@ static void test_excludeinfinite(void)
GdipDeleteMatrix(identity);
}
+static void test_GdipCreateRegionRgnData(void)
+{
+ GpGraphics *graphics = NULL;
+ GpRegion *region, *region2;
+ HDC hdc = GetDC(0);
+ GpStatus status;
+ BYTE buf[512];
+ UINT needed;
+ BOOL ret;
+
+ status = GdipCreateRegionRgnData(NULL, 0, NULL);
+ ok(status == InvalidParameter, "status %d\n", status);
+
+ status = GdipCreateFromHDC(hdc, &graphics);
+ ok(status == Ok, "status %d\n", status);
+
+ status = GdipCreateRegion(®ion);
+ ok(status == Ok, "status %d\n", status);
+
+ /* infinite region */
+ memset(buf, 0xee, sizeof(buf));
+ needed = 0;
+ status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed);
+ ok(status == Ok, "status %d\n", status);
+ expect(20, needed);
+
+ status = GdipCreateRegionRgnData(buf, needed, NULL);
+ ok(status == InvalidParameter, "status %d\n", status);
+
+ status = GdipCreateRegionRgnData(buf, needed, ®ion2);
+ ok(status == Ok, "status %d\n", status);
+
+ ret = FALSE;
+ status = GdipIsInfiniteRegion(region2, graphics, &ret);
+ ok(status == Ok, "status %d\n", status);
+ ok(ret, "got %d\n", ret);
+ GdipDeleteRegion(region2);
+
+ /* empty region */
+ status = GdipSetEmpty(region);
+ ok(status == Ok, "status %d\n", status);
+
+ memset(buf, 0xee, sizeof(buf));
+ needed = 0;
+ status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed);
+ ok(status == Ok, "status %d\n", status);
+ expect(20, needed);
+
+ status = GdipCreateRegionRgnData(buf, needed, ®ion2);
+ ok(status == Ok, "status %d\n", status);
+
+ ret = FALSE;
+ status = GdipIsEmptyRegion(region2, graphics, &ret);
+ ok(status == Ok, "status %d\n", status);
+ ok(ret, "got %d\n", ret);
+ GdipDeleteRegion(region2);
+
+ GdipDeleteGraphics(graphics);
+ GdipDeleteRegion(region);
+ ReleaseDC(0, hdc);
+}
+
START_TEST(region)
{
struct GdiplusStartupInput gdiplusStartupInput;
@@ -2158,6 +2220,7 @@ START_TEST(region)
test_isvisiblepoint();
test_isvisiblerect();
test_excludeinfinite();
+ test_GdipCreateRegionRgnData();
GdiplusShutdown(gdiplusToken);
}
More information about the wine-cvs
mailing list