From 2a2f61dfe96297e99400aea0688e347d4d89c1a9 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 16 Oct 2017 10:12:23 +0300 Subject: [PATCH] gdiplus/metafile: Partially implement EmfPlusPath deserialization. Signed-off-by: Nikolay Sivov Signed-off-by: Vincent Povirk Signed-off-by: Alexandre Julliard --- dlls/gdiplus/gdiplus_private.h | 1 + dlls/gdiplus/metafile.c | 75 ++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index f659ccf1c1a..dc2f08923e7 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -394,6 +394,7 @@ struct emfplus_object { EmfPlusObjectType type; union { GpBrush *brush; + GpPath *path; GpImage *image; GpImageAttributes *image_attributes; void *object; diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index fa4bafde510..db74c9dcd42 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -388,6 +388,9 @@ static void metafile_free_object_table_entry(GpMetafile *metafile, BYTE id) case ObjectTypeBrush: GdipDeleteBrush(object->u.brush); break; + case ObjectTypePath: + GdipDeletePath(object->u.path); + break; case ObjectTypeImage: GdipDisposeImage(object->u.image); break; @@ -1572,6 +1575,75 @@ static GpStatus metafile_deserialize_image(const BYTE *record_data, UINT data_si return status; } +static GpStatus metafile_deserialize_path(const BYTE *record_data, UINT data_size, GpPath **path) +{ + EmfPlusPath *data = (EmfPlusPath *)record_data; + GpStatus status; + BYTE *types; + UINT size; + DWORD i; + + *path = NULL; + + if (data_size <= FIELD_OFFSET(EmfPlusPath, data)) + return InvalidParameter; + data_size -= FIELD_OFFSET(EmfPlusPath, data); + + if (data->PathPointFlags & 0x800) /* R */ + { + FIXME("RLE encoded path data is not supported.\n"); + return NotImplemented; + } + else + { + if (data->PathPointFlags & 0x4000) /* C */ + size = sizeof(EmfPlusPoint); + else + size = sizeof(EmfPlusPointF); + size += sizeof(BYTE); /* EmfPlusPathPointType */ + size *= data->PathPointCount; + } + + if (data_size < size) + return InvalidParameter; + + status = GdipCreatePath(FillModeAlternate, path); + if (status != Ok) + return status; + + (*path)->pathdata.Count = data->PathPointCount; + (*path)->pathdata.Points = GdipAlloc(data->PathPointCount * sizeof(*(*path)->pathdata.Points)); + (*path)->pathdata.Types = GdipAlloc(data->PathPointCount * sizeof(*(*path)->pathdata.Types)); + (*path)->datalen = (*path)->pathdata.Count; + + if (!(*path)->pathdata.Points || !(*path)->pathdata.Types) + { + GdipDeletePath(*path); + return OutOfMemory; + } + + if (data->PathPointFlags & 0x4000) /* C */ + { + EmfPlusPoint *points = (EmfPlusPoint *)data->data; + for (i = 0; i < data->PathPointCount; i++) + { + (*path)->pathdata.Points[i].X = points[i].X; + (*path)->pathdata.Points[i].Y = points[i].Y; + } + types = (BYTE *)(points + i); + } + else + { + EmfPlusPointF *points = (EmfPlusPointF *)data->data; + memcpy((*path)->pathdata.Points, points, sizeof(*points) * data->PathPointCount); + types = (BYTE *)(points + data->PathPointCount); + } + + memcpy((*path)->pathdata.Types, types, sizeof(*types) * data->PathPointCount); + + return Ok; +} + static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_size, GpBrush **brush) { static const UINT header_size = FIELD_OFFSET(EmfPlusBrush, BrushData); @@ -1614,6 +1686,9 @@ static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT d case ObjectTypeBrush: status = metafile_deserialize_brush(record_data, data_size, (GpBrush **)&object); break; + case ObjectTypePath: + status = metafile_deserialize_path(record_data, data_size, (GpPath **)&object); + break; case ObjectTypeImage: status = metafile_deserialize_image(record_data, data_size, (GpImage **)&object); break;