[try 5][Gdiplus 6/6] Implement GdipGetRegionData

Adam Petaccia adam at tpetaccia.com
Thu Jul 24 18:01:49 CDT 2008


Changelog:
(try4):
    region->node is no longer a pointer
    Apply const qualifier to helper function
(try2):
    We might not write a whole DWORD for pathflags, so make sure its not
    garbage; revealed by the added test at the end of this series.
---
 dlls/gdiplus/region.c       |  119 +++++++++++++++++++++++++++++++++++++++++-
 dlls/gdiplus/tests/region.c |   39 ++++++++------
 2 files changed, 138 insertions(+), 20 deletions(-)

diff --git a/dlls/gdiplus/region.c b/dlls/gdiplus/region.c
index 6c52623..e8886fa 100644
--- a/dlls/gdiplus/region.c
+++ b/dlls/gdiplus/region.c
@@ -81,11 +81,31 @@ typedef enum RegionType
     RegionDataInfiniteRect  = 0x10000003,
 } RegionType;
 
+#define FLAGS_NOFLAGS   0x0
+#define FLAGS_INTPATH   0x4000
+
 /* Header size as far as header->size is concerned. This doesn't include
  * header->size or header->checksum
  */
 static const INT sizeheader_size = sizeof(DWORD) * 2;
 
+typedef struct packed_point
+{
+    short X;
+    short Y;
+} packed_point;
+
+/* Everything is measured in DWORDS; round up if there's a remainder */
+static inline INT get_pathtypes_size(const GpPath* path)
+{
+    INT needed = path->pathdata.Count / sizeof(DWORD);
+
+    if (path->pathdata.Count % sizeof(DWORD) > 0)
+        needed++;
+
+    return needed * sizeof(DWORD);
+}
+
 static inline INT get_element_size(const region_element* element)
 {
     INT needed = sizeof(DWORD); /* DWORD for the type */
@@ -258,11 +278,104 @@ GpStatus WINGDIPAPI GdipGetRegionBoundsI(GpRegion *region, GpGraphics *graphics,
     return NotImplemented;
 }
 
-GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size, UINT *needed)
+static inline void write_dword(BYTE* location, INT* offset, DWORD write)
 {
-    FIXME("(%p, %p, %d, %p): stub\n", region, buffer, size, needed);
+    ((DWORD*)location)[*offset] = write;
+    (*offset)++;
+}
 
-    return NotImplemented;
+static inline void write_float(BYTE* location, INT* offset, FLOAT write)
+{
+    ((FLOAT*)location)[*offset] = write;
+    (*offset)++;
+}
+
+static inline void  write_packed_point(BYTE* location, INT* offset,
+        GpPointF* write)
+{
+    packed_point point;
+
+    point.X = (short)write->X;
+    point.Y = (short)write->Y;
+    memcpy(location + (*offset * sizeof(DWORD)), &point, sizeof(DWORD));
+    (*offset)++;
+}
+
+static void write_element(const region_element* element, BYTE *buffer,
+        INT* filled)
+{
+    write_dword(buffer, filled, element->type);
+    switch (element->type)
+    {
+        case CombineModeReplace:
+        case CombineModeIntersect:
+        case CombineModeUnion:
+        case CombineModeXor:
+        case CombineModeExclude:
+        case CombineModeComplement:
+            write_element(element->elementdata.combine.left, buffer, filled);
+            write_element(element->elementdata.combine.right, buffer, filled);
+            break;
+        case RegionDataRect:
+            write_float(buffer, filled, element->elementdata.rect.X);
+            write_float(buffer, filled, element->elementdata.rect.Y);
+            write_float(buffer, filled, element->elementdata.rect.Width);
+            write_float(buffer, filled, element->elementdata.rect.Height);
+            break;
+        case RegionDataPath:
+        {
+            INT i;
+            GpPath* path = element->elementdata.pathdata.path;
+            memcpy((DWORD*)buffer +*filled,
+                    &element->elementdata.pathdata.pathheader,
+                    sizeof(DWORD) * 4);
+            *filled += 4; /* Four DWORDS for the header */
+            switch (element->elementdata.pathdata.pathheader.flags)
+            {
+                case FLAGS_NOFLAGS:
+                    for (i = 0; i < path->pathdata.Count; i++)
+                    {
+                        write_float(buffer, filled, path->pathdata.Points[i].X);
+                        write_float(buffer, filled, path->pathdata.Points[i].Y);
+                    }
+                    break;
+                case FLAGS_INTPATH:
+                    for (i = 0; i < path->pathdata.Count; i++)
+                    {
+                        write_packed_point(buffer, filled,
+                                &path->pathdata.Points[i]);
+                    }
+            }
+            /* We might not write a whole DWORD so make sure its not garbage */
+            ZeroMemory(buffer + (*filled * 4), get_pathtypes_size(path));
+            GdipGetPathTypes(path, buffer+ (*filled * 4), path->pathdata.Count);
+            *filled += (get_pathtypes_size(path) / sizeof(DWORD));
+            break;
+        }
+        case RegionDataEmptyRect:
+        case RegionDataInfiniteRect:
+            break;
+    }
+}
+
+/* needed may be NULL */
+GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
+        UINT *needed)
+{
+    INT filled = 0;
+
+    if (!(region && buffer && size))
+        return InvalidParameter;
+
+    TRACE("%p, %p, %d, %p\n", region, buffer, size, needed);
+    memcpy(buffer, &region->header, sizeof(region->header));
+    filled += sizeof(region->header) / sizeof(DWORD);
+    write_element(&region->node, buffer, &filled);
+
+    if (needed)
+        *needed = filled * sizeof(DWORD);
+
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipGetRegionDataSize(GpRegion *region, UINT *needed)
diff --git a/dlls/gdiplus/tests/region.c b/dlls/gdiplus/tests/region.c
index 8c3bada..01991a2 100644
--- a/dlls/gdiplus/tests/region.c
+++ b/dlls/gdiplus/tests/region.c
@@ -71,13 +71,9 @@ static void test_getregiondata(void)
     ok(status == Ok, "status %08x\n", status);
     expect(20, needed);
 todo_wine
-{
     status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed);
     ok(status == Ok, "status %08x\n", status);
-}
     expect(20, needed);
-todo_wine
-{
     expect_dword(buf, 12);
     trace("buf[1] = %08x\n", buf[1]);
     expect_magic((DWORD*)(buf + 2));
@@ -85,26 +81,18 @@ todo_wine
     expect_dword(buf + 4, RGNDATA_INFINITE_RECT);
 
     status = GdipSetEmpty(region);
-}
     ok(status == Ok, "status %08x\n", status);
-todo_wine
-{
     status = GdipGetRegionDataSize(region, &needed);
-}
     ok(status == Ok, "status %08x\n", status);
     expect(20, needed);
     status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed);
-todo_wine
     ok(status == Ok, "status %08x\n", status);
     expect(20, needed);
-todo_wine
-{
     expect_dword(buf, 12);
     trace("buf[1] = %08x\n", buf[1]);
     expect_magic((DWORD*)(buf + 2));
     expect_dword(buf + 3, 0);
     expect_dword(buf + 4, RGNDATA_EMPTY_RECT);
-}
 
     status = GdipSetInfinite(region);
     ok(status == Ok, "status %08x\n", status);
@@ -112,17 +100,13 @@ todo_wine
     ok(status == Ok, "status %08x\n", status);
     expect(20, needed);
     status = GdipGetRegionData(region, (BYTE*)buf, sizeof(buf), &needed);
-todo_wine
     ok(status == Ok, "status %08x\n", status);
     expect(20, needed);
-todo_wine
-{
     expect_dword(buf, 12);
     trace("buf[1] = %08x\n", buf[1]);
     expect_magic((DWORD*)(buf + 2));
     expect_dword(buf + 3, 0);
     expect_dword(buf + 4, RGNDATA_INFINITE_RECT);
-}
 
     status = GdipDeleteRegion(region);
     ok(status == Ok, "status %08x\n", status);
@@ -143,8 +127,11 @@ todo_wine
     expect(36, needed);
     expect_dword(buf, 28);
     trace("buf[1] = %08x\n", buf[1]);
+}
     expect_magic((DWORD*)(buf + 2));
     expect_dword(buf + 3, 0);
+todo_wine
+{
     expect_dword(buf + 4, RGNDATA_RECT);
     expect_float(buf + 5, 10.0);
     expect_float(buf + 6, 20.0);
@@ -195,7 +182,10 @@ todo_wine
     expect(156, needed);
     expect_dword(buf, 148);
     trace("buf[1] = %08x\n", buf[1]);
+}
     expect_magic((DWORD*)(buf + 2));
+todo_wine
+{
     expect_dword(buf + 3, 10);
     expect_dword(buf + 4, CombineModeExclude);
     expect_dword(buf + 5, CombineModeComplement);
@@ -257,8 +247,11 @@ todo_wine
     expect(72, needed);
     expect_dword(buf, 64);
     trace("buf[1] = %08x\n", buf[1]);
+}
     expect_magic((DWORD*)(buf + 2));
     expect_dword(buf + 3, 0);
+todo_wine
+{
     expect_dword(buf + 4, RGNDATA_PATH);
     expect_dword(buf + 5, 0x00000030);
     expect_magic((DWORD*)(buf + 6));
@@ -289,7 +282,10 @@ todo_wine
     expect(96, needed);
     expect_dword(buf, 88);
     trace("buf[1] = %08x\n", buf[1]);
+}
     expect_magic((DWORD*)(buf + 2));
+todo_wine
+{
     expect_dword(buf + 3, 2);
     expect_dword(buf + 4, CombineModeIntersect);
     expect_dword(buf + 5, RGNDATA_PATH);
@@ -333,8 +329,11 @@ todo_wine
     expect(36, needed);
     expect_dword(buf, 28);
     trace("buf[1] = %08x\n", buf[1]);
+}
     expect_magic((DWORD*)(buf + 2));
     expect_dword(buf + 3, 0);
+todo_wine
+{
     expect_dword(buf + 4, RGNDATA_PATH);
 
     /* Second signature for pathdata */
@@ -365,9 +364,12 @@ todo_wine
     expect(Ok, status);
     expect(56, needed);
     expect_dword(buf, 48);
+}
     trace("buf[1] = %08x\n", buf[1]);
     expect_magic((DWORD*)(buf + 2));
     expect_dword(buf + 3 , 0);
+todo_wine
+{
     expect_dword(buf + 4 , RGNDATA_PATH);
 
     expect_dword(buf + 5, 32);
@@ -399,9 +401,9 @@ todo_wine
     expect(Ok, status);
     status = GdipAddPathLine(path, 8.1, 1.6, 5.6, 6.2);
     expect(Ok, status);
+    status = GdipCreateRegionPath(path, &region);
 todo_wine
 {
-    status = GdipCreateRegionPath(path, &region);
     expect(Ok, status);
     status = GdipGetRegionDataSize(region, &needed);
     expect(Ok, status);
@@ -411,8 +413,11 @@ todo_wine
     expect(72, needed);
     expect_dword(buf, 64);
     trace("buf[1] = %08x\n", buf[1]);
+}
     expect_magic((DWORD*)(buf + 2));
     expect_dword(buf + 3, 0);
+todo_wine
+{
     expect_dword(buf + 4, RGNDATA_PATH);
 
     expect_dword(buf + 5, 48);
-- 
1.5.4.3




More information about the wine-patches mailing list