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

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Huw Davies 2016-06-08 11:00:46 +01:00 committed by Alexandre Julliard
parent 7be1c53d82
commit 19d1416cef
4 changed files with 97 additions and 24 deletions

View File

@ -2686,6 +2686,59 @@ UINT WINAPI GetEnhMetaFilePaletteEntries( HENHMETAFILE hEmf,
return infoForCallBack.cEntries; 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 typedef struct gdi_mf_comment
{ {
DWORD ident; DWORD ident;
@ -2722,6 +2775,9 @@ HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer, const BYTE *lpbBuffer, HDC
return NULL; return NULL;
} }
ret = extract_emf_from_comment( lpbBuffer, cbBuffer );
if (ret) return ret;
if(!hdcRef) if(!hdcRef)
hdcRef = hdcdisp = CreateDCW(szDisplayW, NULL, NULL, NULL); hdcRef = hdcdisp = CreateDCW(szDisplayW, NULL, NULL, NULL);

View File

@ -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 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh) DECLSPEC_HIDDEN;
extern METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mr, LPCVOID filename, BOOL unicode ) 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 */ /* path.c */
extern void free_gdi_path( struct gdi_path *path ) DECLSPEC_HIDDEN; extern void free_gdi_path( struct gdi_path *path ) DECLSPEC_HIDDEN;

View File

@ -1114,26 +1114,6 @@ UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
return mfSize; 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 * 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])); chunk = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(emf_in_wmf_comment, emf_data[max_chunk_size]));
if(!chunk) goto end; if(!chunk) goto end;
chunk->magic = wmfc_magic; chunk->magic = WMFC_MAGIC;
chunk->unk04 = 1; chunk->unk04 = 1;
chunk->unk06 = 0; chunk->unk06 = 0;
chunk->unk08 = 0; chunk->unk08 = 0;

View File

@ -3249,16 +3249,17 @@ static BOOL near_match(int x, int y)
static void getwinmetafilebits(UINT mode, int scale, RECT *rc) static void getwinmetafilebits(UINT mode, int scale, RECT *rc)
{ {
HENHMETAFILE emf; HENHMETAFILE emf, emf2;
HDC display_dc, emf_dc; HDC display_dc, emf_dc;
ENHMETAHEADER *enh_header; ENHMETAHEADER *enh_header, *enh2_header;
UINT size, emf_size, i; UINT size, emf_size, i, emf2_size;
WORD check = 0; WORD check = 0;
DWORD rec_num = 0; DWORD rec_num = 0;
METAHEADER *mh = NULL; METAHEADER *mh = NULL;
METARECORD *rec; METARECORD *rec;
INT horz_res, vert_res, horz_size, vert_size; INT horz_res, vert_res, horz_size, vert_size;
INT curve_caps, line_caps, poly_caps; INT curve_caps, line_caps, poly_caps;
METAFILEPICT mfp;
display_dc = GetDC(NULL); display_dc = GetDC(NULL);
ok(display_dc != NULL, "display_dc is NULL\n"); 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); 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: end:
HeapFree(GetProcessHeap(), 0, mh); HeapFree(GetProcessHeap(), 0, mh);
HeapFree(GetProcessHeap(), 0, enh_header); HeapFree(GetProcessHeap(), 0, enh_header);