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(&region->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(&region);
+    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, &region2);
+    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, &region2);
+    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