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