[4/4] gdiplus: Reimplement GdipCreateMetafileFromEmf without using IPicture.

Vincent Povirk madewokherd at gmail.com
Wed Oct 31 16:09:04 CDT 2012


-------------- next part --------------
From 538e5ed4c940dbb0c293c5f724bcfebfedb16e27 Mon Sep 17 00:00:00 2001
From: Vincent Povirk <vincent at codeweavers.com>
Date: Wed, 31 Oct 2012 15:37:16 -0500
Subject: [PATCH 4/4] gdiplus: Reimplement GdipCreateMetafileFromEmf without
 using IPicture.

---
 dlls/gdiplus/gdiplus_private.h |    2 ++
 dlls/gdiplus/graphics.c        |   70 ++++++++++++++++------------------------
 dlls/gdiplus/image.c           |    3 +-
 dlls/gdiplus/metafile.c        |   38 ++++++++++++++++++++++
 4 files changed, 70 insertions(+), 43 deletions(-)

diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 53f978c..13a63e6 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -58,6 +58,7 @@ extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **r
 extern GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) DECLSPEC_HIDDEN;
 extern GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc) DECLSPEC_HIDDEN;
 extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN;
+extern MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf) DECLSPEC_HIDDEN;
 
 extern void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1,
     REAL *y1, REAL *x2, REAL *y2) DECLSPEC_HIDDEN;
@@ -280,6 +281,7 @@ struct GpMetafile{
     GpUnit unit;
     MetafileType metafile_type;
     HENHMETAFILE hemf;
+    int preserve_hemf; /* if true, hemf belongs to the app and should not be deleted */
 
     /* recording */
     HDC record_dc;
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 7380c5d..b3eaa86d 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -2350,62 +2350,43 @@ GpStatus WINGDIPAPI GdipCreateFromHWNDICM(HWND hwnd, GpGraphics **graphics)
 GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
     GpMetafile **metafile)
 {
-    IStream *stream = NULL;
-    UINT read;
-    ENHMETAHEADER *copy;
-    GpStatus retval = Ok;
+    ENHMETAHEADER header;
+    MetafileType metafile_type;
 
     TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
 
     if(!hemf || !metafile)
         return InvalidParameter;
 
-    read = GetEnhMetaFileBits(hemf, 0, NULL);
-    copy = GdipAlloc(read);
-    GetEnhMetaFileBits(hemf, read, (BYTE *)copy);
-
-    if(CreateStreamOnHGlobal(copy, TRUE, &stream) != S_OK){
-        ERR("could not make stream\n");
-        GdipFree(copy);
-        retval = GenericError;
-        goto err;
-    }
+    if (GetEnhMetaFileHeader(hemf, sizeof(header), &header) == 0)
+        return GenericError;
 
-    *metafile = GdipAlloc(sizeof(GpMetafile));
-    if(!*metafile){
-        retval = OutOfMemory;
-        goto err;
-    }
+    metafile_type = METAFILE_GetEmfType(hemf);
 
-    if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
-        (LPVOID*) &((*metafile)->image.picture)) != S_OK)
-    {
-        retval = GenericError;
-        goto err;
-    }
+    if (metafile_type == MetafileTypeInvalid)
+        return GenericError;
 
+    *metafile = GdipAlloc(sizeof(GpMetafile));
+    if (!*metafile)
+        return OutOfMemory;
 
     (*metafile)->image.type = ImageTypeMetafile;
-    memcpy(&(*metafile)->image.format, &ImageFormatWMF, sizeof(GUID));
-    (*metafile)->image.palette = NULL;
-    (*metafile)->image.xres = (REAL)copy->szlDevice.cx;
-    (*metafile)->image.yres = (REAL)copy->szlDevice.cy;
-    (*metafile)->bounds.X = (REAL)copy->rclBounds.left;
-    (*metafile)->bounds.Y = (REAL)copy->rclBounds.top;
-    (*metafile)->bounds.Width = (REAL)(copy->rclBounds.right - copy->rclBounds.left);
-    (*metafile)->bounds.Height = (REAL)(copy->rclBounds.bottom - copy->rclBounds.top);
+    (*metafile)->image.format = ImageFormatEMF;
+    (*metafile)->image.frame_count = 1;
+    (*metafile)->image.xres = (REAL)header.szlDevice.cx;
+    (*metafile)->image.yres = (REAL)header.szlDevice.cy;
+    (*metafile)->bounds.X = (REAL)header.rclBounds.left;
+    (*metafile)->bounds.Y = (REAL)header.rclBounds.top;
+    (*metafile)->bounds.Width = (REAL)(header.rclBounds.right - header.rclBounds.left);
+    (*metafile)->bounds.Height = (REAL)(header.rclBounds.bottom - header.rclBounds.top);
     (*metafile)->unit = UnitPixel;
-
-    if(delete)
-        DeleteEnhMetaFile(hemf);
+    (*metafile)->metafile_type = metafile_type;
+    (*metafile)->hemf = hemf;
+    (*metafile)->preserve_hemf = !delete;
 
     TRACE("<-- %p\n", *metafile);
 
-err:
-    if (retval != Ok)
-        GdipFree(*metafile);
-    IStream_Release(stream);
-    return retval;
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
@@ -2431,7 +2412,8 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
     hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
     GdipFree(copy);
 
-    retval = GdipCreateMetafileFromEmf(hemf, FALSE, metafile);
+    /* FIXME: We should store and use hwmf instead of converting to hemf */
+    retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
 
     if (retval == Ok)
     {
@@ -2443,9 +2425,13 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
                                            placeable->BoundingBox.Left);
         (*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
                                             placeable->BoundingBox.Top);
+        (*metafile)->metafile_type = MetafileTypeWmfPlaceable;
+        (*metafile)->image.format = ImageFormatWMF;
 
         if (delete) DeleteMetaFile(hwmf);
     }
+    else
+        DeleteEnhMetaFile(hemf);
     return retval;
 }
 
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c
index 3918301..73f08b9 100644
--- a/dlls/gdiplus/image.c
+++ b/dlls/gdiplus/image.c
@@ -2189,7 +2189,8 @@ static GpStatus free_image_data(GpImage *image)
         GpMetafile *metafile = (GpMetafile*)image;
         GdipFree(metafile->comment_data);
         DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc));
-        DeleteEnhMetaFile(metafile->hemf);
+        if (!metafile->preserve_hemf)
+            DeleteEnhMetaFile(metafile->hemf);
         if (metafile->record_graphics)
         {
             WARN("metafile closed while recording\n");
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
index 030b2a2..4345ece 100644
--- a/dlls/gdiplus/metafile.c
+++ b/dlls/gdiplus/metafile.c
@@ -548,3 +548,41 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
 
     return stat;
 }
+
+static int CALLBACK get_metafile_type_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
+    int nObj, LPARAM lpData)
+{
+    MetafileType *result = (MetafileType*)lpData;
+
+    if (lpEMFR->iType == EMR_GDICOMMENT)
+    {
+        const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
+
+        if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
+        {
+            const EmfPlusRecordHeader *header = (const EmfPlusRecordHeader*)&comment->Data[4];
+
+            if (4 + sizeof(EmfPlusRecordHeader) <= comment->cbData &&
+                header->Type == EmfPlusRecordTypeHeader)
+            {
+                if ((header->Flags & 1) == 1)
+                    *result = MetafileTypeEmfPlusDual;
+                else
+                    *result = MetafileTypeEmfPlusOnly;
+            }
+        }
+        else
+            *result = MetafileTypeEmf;
+    }
+    else
+        *result = MetafileTypeEmf;
+
+    return FALSE;
+}
+
+MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf)
+{
+    MetafileType result = MetafileTypeInvalid;
+    EnumEnhMetaFile(NULL, hemf, get_metafile_type_proc, &result, NULL);
+    return result;
+}
-- 
1.7.9.5


More information about the wine-patches mailing list