From 825f393299393321f3ed6631b9f8e6b6c37f4d78 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Thu, 12 Oct 2017 13:44:29 +0300 Subject: [PATCH] gdiplus/metafile: Implement EmfPlusRecordTypeObject for image attributes object. Signed-off-by: Nikolay Sivov Signed-off-by: Vincent Povirk Signed-off-by: Alexandre Julliard --- dlls/gdiplus/gdiplus_private.h | 28 +++++++++ dlls/gdiplus/image.c | 19 +----- dlls/gdiplus/metafile.c | 112 ++++++++++++++++++++++++++++----- 3 files changed, 126 insertions(+), 33 deletions(-) diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 566092eba70..d6ccb95b07f 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -121,6 +121,7 @@ extern GpStatus METAFILE_DrawImagePointsRect(GpMetafile* metafile, GpImage *imag extern GpStatus METAFILE_AddSimpleProperty(GpMetafile *metafile, SHORT prop, SHORT val) DECLSPEC_HIDDEN; extern GpStatus METAFILE_DrawPath(GpMetafile *metafile, GpPen *pen, GpPath *path) DECLSPEC_HIDDEN; extern GpStatus METAFILE_FillPath(GpMetafile *metafile, GpBrush *brush, GpPath *path) DECLSPEC_HIDDEN; +extern void METAFILE_Free(GpMetafile *metafile) DECLSPEC_HIDDEN; extern void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1, REAL *y1, REAL *x2, REAL *y2) DECLSPEC_HIDDEN; @@ -371,6 +372,32 @@ struct GpImage{ LONG busy; }; +#define EmfPlusObjectTableSize 64 + +typedef enum EmfPlusObjectType +{ + ObjectTypeInvalid, + ObjectTypeBrush, + ObjectTypePen, + ObjectTypePath, + ObjectTypeRegion, + ObjectTypeImage, + ObjectTypeFont, + ObjectTypeStringFormat, + ObjectTypeImageAttributes, + ObjectTypeCustomLineCap, + ObjectTypeMax = ObjectTypeCustomLineCap, +} EmfPlusObjectType; + +/* Deserialized EmfPlusObject record. */ +struct emfplus_object { + EmfPlusObjectType type; + union { + GpImageAttributes *image_attributes; + void *object; + } u; +}; + struct GpMetafile{ GpImage image; GpRectF bounds; @@ -404,6 +431,7 @@ struct GpMetafile{ GpRegion *base_clip; /* clip region in device space for all metafile output */ GpRegion *clip; /* clip region within the metafile */ struct list containers; + struct emfplus_object objtable[EmfPlusObjectTableSize]; }; struct GpBitmap{ diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index 80ad65f050d..c0b54d04d83 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -2085,24 +2085,7 @@ static GpStatus free_image_data(GpImage *image) heap_free(((GpBitmap*)image)->prop_item); } else if (image->type == ImageTypeMetafile) - { - GpMetafile *metafile = (GpMetafile*)image; - heap_free(metafile->comment_data); - DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc)); - if (!metafile->preserve_hemf) - DeleteEnhMetaFile(metafile->hemf); - if (metafile->record_graphics) - { - WARN("metafile closed while recording\n"); - /* not sure what to do here; for now just prevent the graphics from functioning or using this object */ - metafile->record_graphics->image = NULL; - metafile->record_graphics->busy = TRUE; - } - if (metafile->record_stream) - { - IStream_Release(metafile->record_stream); - } - } + METAFILE_Free((GpMetafile *)image); else { WARN("invalid image: %p\n", image); diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index ecfbab20bb8..78ea854c4c1 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -297,20 +297,6 @@ typedef struct EmfPlusImageAttributes DWORD Reserved2; } EmfPlusImageAttributes; -typedef enum ObjectType -{ - ObjectTypeInvalid, - ObjectTypeBrush, - ObjectTypePen, - ObjectTypePath, - ObjectTypeRegion, - ObjectTypeImage, - ObjectTypeFont, - ObjectTypeStringFormat, - ObjectTypeImageAttributes, - ObjectTypeCustomLineCap, -} ObjectType; - typedef struct EmfPlusObject { EmfPlusRecordHeader Header; @@ -370,9 +356,52 @@ typedef struct EmfPlusFillPath } data; } EmfPlusFillPath; +static void metafile_free_object_table_entry(GpMetafile *metafile, BYTE id) +{ + struct emfplus_object *object = &metafile->objtable[id]; + + switch (object->type) + { + case ObjectTypeInvalid: + break; + case ObjectTypeImageAttributes: + GdipDisposeImageAttributes(object->u.image_attributes); + break; + default: + FIXME("not implemented for object type %u.\n", object->type); + return; + } + + object->type = ObjectTypeInvalid; + object->u.object = NULL; +} + +void METAFILE_Free(GpMetafile *metafile) +{ + unsigned int i; + + heap_free(metafile->comment_data); + DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc)); + if (!metafile->preserve_hemf) + DeleteEnhMetaFile(metafile->hemf); + if (metafile->record_graphics) + { + WARN("metafile closed while recording\n"); + /* not sure what to do here; for now just prevent the graphics from functioning or using this object */ + metafile->record_graphics->image = NULL; + metafile->record_graphics->busy = TRUE; + } + + if (metafile->record_stream) + IStream_Release(metafile->record_stream); + + for (i = 0; i < sizeof(metafile->objtable)/sizeof(metafile->objtable[0]); i++) + metafile_free_object_table_entry(metafile, i); +} + static DWORD METAFILE_AddObjectId(GpMetafile *metafile) { - return (metafile->next_object_id++) % 64; + return (metafile->next_object_id++) % EmfPlusObjectTableSize; } static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result) @@ -1407,6 +1436,55 @@ static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile) return stat; } +static void metafile_set_object_table_entry(GpMetafile *metafile, BYTE id, BYTE type, void *object) +{ + metafile_free_object_table_entry(metafile, id); + metafile->objtable[id].type = type; + metafile->objtable[id].u.object = object; +} + +static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT data_size, const BYTE *record_data) +{ + BYTE type = (flags >> 8) & 0xff; + BYTE id = flags & 0xff; + void *object = NULL; + GpStatus status; + + if (type > ObjectTypeMax || id >= EmfPlusObjectTableSize) + return InvalidParameter; + + switch (type) + { + case ObjectTypeImageAttributes: + { + EmfPlusImageAttributes *data = (EmfPlusImageAttributes *)record_data; + GpImageAttributes *attributes = NULL; + + if (data_size != sizeof(*data)) + return InvalidParameter; + + if ((status = GdipCreateImageAttributes(&attributes)) != Ok) + return status; + + status = GdipSetImageAttributesWrapMode(attributes, data->WrapMode, *(DWORD *)&data->ClampColor, + !!data->ObjectClamp); + if (status == Ok) + object = attributes; + else + GdipDisposeImageAttributes(attributes); + break; + } + default: + FIXME("not implemented for object type %d.\n", type); + return NotImplemented; + } + + if (status == Ok) + metafile_set_object_table_entry(metafile, id, type, object); + + return status; +} + GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile, EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data) { @@ -1852,6 +1930,10 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile, { return GdipSetSmoothingMode(real_metafile->playback_graphics, (flags >> 1) & 0xff); } + case EmfPlusRecordTypeObject: + { + return METAFILE_PlaybackObject(real_metafile, flags, dataSize, data); + } default: FIXME("Not implemented for record type %x\n", recordType); return NotImplemented;