Nikolay Sivov : gdiplus/metafile: Implement EmfPlusRecordTypeObject for image attributes object.
Alexandre Julliard
julliard at winehq.org
Thu Oct 12 13:47:51 CDT 2017
Module: wine
Branch: master
Commit: 825f393299393321f3ed6631b9f8e6b6c37f4d78
URL: http://source.winehq.org/git/wine.git/?a=commit;h=825f393299393321f3ed6631b9f8e6b6c37f4d78
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Thu Oct 12 13:44:29 2017 +0300
gdiplus/metafile: Implement EmfPlusRecordTypeObject for image attributes object.
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 | 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 566092e..d6ccb95 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 80ad65f..c0b54d0 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 ecfbab2..78ea854 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;
More information about the wine-cvs
mailing list