Nikolay Sivov : gdiplus/metafile: Implement EmfPlusRegion deserialization.
Alexandre Julliard
julliard at winehq.org
Fri Oct 20 15:09:37 CDT 2017
Module: wine
Branch: master
Commit: aef2f0799f09595f3458d3495e85bba0c9059865
URL: http://source.winehq.org/git/wine.git/?a=commit;h=aef2f0799f09595f3458d3495e85bba0c9059865
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Fri Oct 20 00:45:40 2017 +0300
gdiplus/metafile: Implement EmfPlusRegion deserialization.
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Vincent Povirk <vincent at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/gdiplus/gdiplus_private.h | 25 ++++++++
dlls/gdiplus/metafile.c | 138 +++++++++++++++++++++++++++++++++++++++++
dlls/gdiplus/region.c | 24 -------
dlls/gdiplus/tests/metafile.c | 2 +-
4 files changed, 164 insertions(+), 25 deletions(-)
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index f39838e..ca2c022 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -396,6 +396,7 @@ struct emfplus_object {
GpBrush *brush;
GpPen *pen;
GpPath *path;
+ GpRegion *region;
GpImage *image;
GpFont *font;
GpImageAttributes *image_attributes;
@@ -561,6 +562,30 @@ struct GpRegion{
region_element node;
};
+struct memory_buffer
+{
+ const BYTE *buffer;
+ INT size, pos;
+};
+
+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;
+}
+
typedef GpStatus (*gdip_format_string_callback)(HDC hdc,
GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
index f18411b..7289ea5 100644
--- a/dlls/gdiplus/metafile.c
+++ b/dlls/gdiplus/metafile.c
@@ -265,6 +265,12 @@ typedef struct EmfPlusPath
BYTE data[1];
} EmfPlusPath;
+typedef struct EmfPlusRegionNodePath
+{
+ DWORD RegionNodePathLength;
+ EmfPlusPath RegionNodePath;
+} EmfPlusRegionNodePath;
+
typedef struct EmfPlusRegion
{
DWORD Version;
@@ -429,6 +435,9 @@ static void metafile_free_object_table_entry(GpMetafile *metafile, BYTE id)
case ObjectTypePath:
GdipDeletePath(object->u.path);
break;
+ case ObjectTypeRegion:
+ GdipDeleteRegion(object->u.region);
+ break;
case ObjectTypeImage:
GdipDisposeImage(object->u.image);
break;
@@ -1685,6 +1694,132 @@ static GpStatus metafile_deserialize_path(const BYTE *record_data, UINT data_siz
return Ok;
}
+static GpStatus metafile_read_region_node(struct memory_buffer *mbuf, GpRegion *region, region_element *node, UINT *count)
+{
+ const DWORD *type;
+ GpStatus status;
+
+ type = buffer_read(mbuf, sizeof(*type));
+ if (!type) return Ok;
+
+ node->type = *type;
+
+ switch (node->type)
+ {
+ case CombineModeReplace:
+ case CombineModeIntersect:
+ case CombineModeUnion:
+ case CombineModeXor:
+ case CombineModeExclude:
+ case CombineModeComplement:
+ {
+ region_element *left, *right;
+
+ left = heap_alloc_zero(sizeof(*left));
+ if (!left)
+ return OutOfMemory;
+
+ right = heap_alloc_zero(sizeof(*right));
+ if (!right)
+ {
+ heap_free(left);
+ return OutOfMemory;
+ }
+
+ status = metafile_read_region_node(mbuf, region, left, count);
+ if (status == Ok)
+ {
+ status = metafile_read_region_node(mbuf, region, right, count);
+ if (status == Ok)
+ {
+ node->elementdata.combine.left = left;
+ node->elementdata.combine.right = right;
+ region->num_children += 2;
+ return Ok;
+ }
+ }
+
+ heap_free(left);
+ heap_free(right);
+ return status;
+ }
+ case RegionDataRect:
+ {
+ const EmfPlusRectF *rect;
+
+ rect = buffer_read(mbuf, sizeof(*rect));
+ if (!rect)
+ return InvalidParameter;
+
+ memcpy(&node->elementdata.rect, rect, sizeof(*rect));
+ *count += 1;
+ return Ok;
+ }
+ case RegionDataPath:
+ {
+ const BYTE *path_data;
+ const UINT *data_size;
+ GpPath *path;
+
+ data_size = buffer_read(mbuf, FIELD_OFFSET(EmfPlusRegionNodePath, RegionNodePath));
+ if (!data_size)
+ return InvalidParameter;
+
+ path_data = buffer_read(mbuf, *data_size);
+ if (!path_data)
+ return InvalidParameter;
+
+ status = metafile_deserialize_path(path_data, *data_size, &path);
+ if (status == Ok)
+ {
+ node->elementdata.path = path;
+ *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;
+}
+
+static GpStatus metafile_deserialize_region(const BYTE *record_data, UINT data_size, GpRegion **region)
+{
+ struct memory_buffer mbuf;
+ GpStatus status;
+ UINT count;
+
+ *region = NULL;
+
+ init_memory_buffer(&mbuf, record_data, data_size);
+
+ if (!buffer_read(&mbuf, FIELD_OFFSET(EmfPlusRegion, RegionNode)))
+ return InvalidParameter;
+
+ status = GdipCreateRegion(region);
+ if (status != Ok)
+ return status;
+
+ count = 0;
+ status = metafile_read_region_node(&mbuf, *region, &(*region)->node, &count);
+ if (status == Ok && !count)
+ status = InvalidParameter;
+
+ if (status != Ok)
+ {
+ GdipDeleteRegion(*region);
+ *region = NULL;
+ }
+
+ return status;
+}
+
static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_size, GpBrush **brush)
{
static const UINT header_size = FIELD_OFFSET(EmfPlusBrush, BrushData);
@@ -1935,6 +2070,9 @@ static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT d
case ObjectTypePath:
status = metafile_deserialize_path(record_data, data_size, (GpPath **)&object);
break;
+ case ObjectTypeRegion:
+ status = metafile_deserialize_region(record_data, data_size, (GpRegion **)&object);
+ break;
case ObjectTypeImage:
status = metafile_deserialize_image(record_data, data_size, (GpImage **)&object);
break;
diff --git a/dlls/gdiplus/region.c b/dlls/gdiplus/region.c
index 8a2ca6b..8eb3ff3 100644
--- a/dlls/gdiplus/region.c
+++ b/dlls/gdiplus/region.c
@@ -76,12 +76,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
#define FLAGS_INTPATH 0x4000
-struct memory_buffer
-{
- const BYTE *buffer;
- INT size, pos;
-};
-
struct region_header
{
DWORD magic;
@@ -778,24 +772,6 @@ GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
return Ok;
}
-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;
diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c
index 0e47607..f232210 100644
--- a/dlls/gdiplus/tests/metafile.c
+++ b/dlls/gdiplus/tests/metafile.c
@@ -2170,7 +2170,7 @@ static const emfplus_record clipping_records[] = {
{ EmfPlusRecordTypeRestore },
{ EmfPlusRecordTypeSetClipRect, 0x300 },
{ EmfPlusRecordTypeFillRects, 0xc000 },
- { EmfPlusRecordTypeObject, ObjectTypeRegion << 8, 0, 1 },
+ { EmfPlusRecordTypeObject, ObjectTypeRegion << 8 },
{ EmfPlusRecordTypeSetClipRegion, 0x100, 0, 1 },
{ EmfPlusRecordTypeEndOfFile },
{ EMR_EOF },
More information about the wine-cvs
mailing list