Huw Davies : gdi32: If the WMF was created by GetWinMetaFileBits() then return the original EMF.

Alexandre Julliard julliard at winehq.org
Wed Jun 8 11:07:36 CDT 2016


Module: wine
Branch: master
Commit: 19d1416ceff5ebd47a7a41196cf5629d9925fee4
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=19d1416ceff5ebd47a7a41196cf5629d9925fee4

Author: Huw Davies <huw at codeweavers.com>
Date:   Wed Jun  8 11:00:46 2016 +0100

gdi32: If the WMF was created by GetWinMetaFileBits() then return the original EMF.

Signed-off-by: Huw Davies <huw at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/gdi32/enhmetafile.c    | 56 +++++++++++++++++++++++++++++++++++++++++++++
 dlls/gdi32/gdi_private.h    | 21 +++++++++++++++++
 dlls/gdi32/metafile.c       | 22 +-----------------
 dlls/gdi32/tests/metafile.c | 22 +++++++++++++++---
 4 files changed, 97 insertions(+), 24 deletions(-)

diff --git a/dlls/gdi32/enhmetafile.c b/dlls/gdi32/enhmetafile.c
index 17ccd1f..c251b4e 100644
--- a/dlls/gdi32/enhmetafile.c
+++ b/dlls/gdi32/enhmetafile.c
@@ -2686,6 +2686,59 @@ UINT WINAPI GetEnhMetaFilePaletteEntries( HENHMETAFILE hEmf,
   return infoForCallBack.cEntries;
 }
 
+/******************************************************************
+ *             extract_emf_from_comment
+ *
+ * If the WMF was created by GetWinMetaFileBits, then extract the
+ * original EMF that is stored in MFCOMMENT chunks.
+ */
+static HENHMETAFILE extract_emf_from_comment( const BYTE *buf, UINT mf_size )
+{
+    METAHEADER *mh = (METAHEADER *)buf;
+    METARECORD *mr;
+    emf_in_wmf_comment *chunk;
+    WORD checksum = 0;
+    DWORD size = 0, remaining, chunks;
+    BYTE *emf_bits = NULL, *ptr;
+    UINT offset;
+    HENHMETAFILE emf = NULL;
+
+    if (mf_size < sizeof(*mh)) return NULL;
+
+    for (offset = mh->mtHeaderSize * 2; offset < mf_size; offset += (mr->rdSize * 2))
+    {
+	mr = (METARECORD *)((char *)mh + offset);
+        chunk = (emf_in_wmf_comment *)(mr->rdParm + 2);
+
+        if (mr->rdFunction != META_ESCAPE || mr->rdParm[0] != MFCOMMENT) goto done;
+        if (chunk->magic != WMFC_MAGIC) goto done;
+
+        if (!emf_bits)
+        {
+            size = remaining = chunk->emf_size;
+            chunks = chunk->num_chunks;
+            emf_bits = ptr = HeapAlloc( GetProcessHeap(), 0, size );
+            if (!emf_bits) goto done;
+        }
+        if (chunk->chunk_size > remaining) goto done;
+        remaining -= chunk->chunk_size;
+        if (chunk->remaining_size != remaining) goto done;
+        memcpy( ptr, chunk->emf_data, chunk->chunk_size );
+        ptr += chunk->chunk_size;
+        if (--chunks == 0) break;
+    }
+
+    for (offset = 0; offset < mf_size / 2; offset++)
+        checksum += *((WORD *)buf + offset);
+    if (checksum) goto done;
+
+    emf = SetEnhMetaFileBits( size, emf_bits );
+
+done:
+    HeapFree( GetProcessHeap(), 0, emf_bits );
+    return emf;
+}
+
 typedef struct gdi_mf_comment
 {
     DWORD ident;
@@ -2722,6 +2775,9 @@ HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer, const BYTE *lpbBuffer, HDC
         return NULL;
     }
 
+    ret = extract_emf_from_comment( lpbBuffer, cbBuffer );
+    if (ret) return ret;
+
     if(!hdcRef)
         hdcRef = hdcdisp = CreateDCW(szDisplayW, NULL, NULL, NULL);
 
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index cde9867..08a5d3b 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -311,6 +311,27 @@ extern void GDI_hdc_not_using_object(HGDIOBJ obj, HDC hdc) DECLSPEC_HIDDEN;
 extern HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh) DECLSPEC_HIDDEN;
 extern METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mr, LPCVOID filename, BOOL unicode ) DECLSPEC_HIDDEN;
 
+/* Format of comment record added by GetWinMetaFileBits */
+#include <pshpack2.h>
+typedef struct
+{
+    DWORD magic;   /* WMFC */
+    WORD unk04;    /* 1 */
+    WORD unk06;    /* 0 */
+    WORD unk08;    /* 0 */
+    WORD unk0a;    /* 1 */
+    WORD checksum;
+    DWORD unk0e;   /* 0 */
+    DWORD num_chunks;
+    DWORD chunk_size;
+    DWORD remaining_size;
+    DWORD emf_size;
+    BYTE emf_data[1];
+} emf_in_wmf_comment;
+#include <poppack.h>
+
+#define WMFC_MAGIC 0x43464d57
+
 /* path.c */
 
 extern void free_gdi_path( struct gdi_path *path ) DECLSPEC_HIDDEN;
diff --git a/dlls/gdi32/metafile.c b/dlls/gdi32/metafile.c
index 925d648..c7e25a7 100644
--- a/dlls/gdi32/metafile.c
+++ b/dlls/gdi32/metafile.c
@@ -1114,26 +1114,6 @@ UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
     return mfSize;
 }
 
-#include <pshpack2.h>
-typedef struct
-{
-    DWORD magic;   /* WMFC */
-    WORD unk04;    /* 1 */
-    WORD unk06;    /* 0 */
-    WORD unk08;    /* 0 */
-    WORD unk0a;    /* 1 */
-    WORD checksum;
-    DWORD unk0e;   /* 0 */
-    DWORD num_chunks;
-    DWORD chunk_size;
-    DWORD remaining_size;
-    DWORD emf_size;
-    BYTE emf_data[1];
-} emf_in_wmf_comment;
-#include <poppack.h>
-
-static const DWORD wmfc_magic = 0x43464d57;
-
 /******************************************************************
  *         add_mf_comment
  *
@@ -1158,7 +1138,7 @@ static BOOL add_mf_comment(HDC hdc, HENHMETAFILE emf)
     chunk = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(emf_in_wmf_comment, emf_data[max_chunk_size]));
     if(!chunk) goto end;
 
-    chunk->magic = wmfc_magic;
+    chunk->magic = WMFC_MAGIC;
     chunk->unk04 = 1;
     chunk->unk06 = 0;
     chunk->unk08 = 0;
diff --git a/dlls/gdi32/tests/metafile.c b/dlls/gdi32/tests/metafile.c
index 9a5c1a5..79f072b 100644
--- a/dlls/gdi32/tests/metafile.c
+++ b/dlls/gdi32/tests/metafile.c
@@ -3249,16 +3249,17 @@ static BOOL near_match(int x, int y)
 
 static void getwinmetafilebits(UINT mode, int scale, RECT *rc)
 {
-    HENHMETAFILE emf;
+    HENHMETAFILE emf, emf2;
     HDC display_dc, emf_dc;
-    ENHMETAHEADER *enh_header;
-    UINT size, emf_size, i;
+    ENHMETAHEADER *enh_header, *enh2_header;
+    UINT size, emf_size, i, emf2_size;
     WORD check = 0;
     DWORD rec_num = 0;
     METAHEADER *mh = NULL;
     METARECORD *rec;
     INT horz_res, vert_res, horz_size, vert_size;
     INT curve_caps, line_caps, poly_caps;
+    METAFILEPICT mfp;
 
     display_dc = GetDC(NULL);
     ok(display_dc != NULL, "display_dc is NULL\n");
@@ -3401,6 +3402,21 @@ static void getwinmetafilebits(UINT mode, int scale, RECT *rc)
         rec = (METARECORD*)((WORD*)rec + rec->rdSize);
     }
 
+    /* Show that we get the original back when we do the reverse conversion.
+       mfp is ignored in this case. */
+    mfp.mm = MM_ISOTROPIC;
+    mfp.xExt = 0xcafe;
+    mfp.yExt = 0xbeef;
+    emf2 = SetWinMetaFileBits( size, (BYTE*)mh, NULL, &mfp );
+    ok( !!emf2, "got NULL\n" );
+    emf2_size = GetEnhMetaFileBits( emf2, 0, NULL );
+    enh2_header = HeapAlloc( GetProcessHeap(), 0, emf2_size );
+    emf2_size = GetEnhMetaFileBits( emf2, emf2_size, (BYTE*)enh2_header );
+    ok( emf_size == emf2_size, "%d %d\n", emf_size, emf2_size );
+    ok( !memcmp( enh_header, enh2_header, emf_size ), "mismatch\n" );
+    HeapFree( GetProcessHeap(), 0, enh2_header );
+    DeleteEnhMetaFile( emf2 );
+
 end:
     HeapFree(GetProcessHeap(), 0, mh);
     HeapFree(GetProcessHeap(), 0, enh_header);




More information about the wine-cvs mailing list