From ff148d0722b9924ecb98e8e9c158672842122daf Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Thu, 7 Jul 2011 16:25:25 -0500 Subject: [PATCH 6/6] gdiplus: Implement GdipPlayMetafileRecord for EMF records. --- dlls/gdiplus/gdiplus_private.h | 11 ++++- dlls/gdiplus/metafile.c | 113 ++++++++++++++++++++++++++++++++++++++-- dlls/gdiplus/tests/metafile.c | 44 ++++++++-------- 3 files changed, 141 insertions(+), 27 deletions(-) diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index d6888d9..9afe15b 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -274,12 +274,21 @@ struct GpMetafile{ GpRectF bounds; GpUnit unit; MetafileType metafile_type; + HENHMETAFILE hemf; + + /* recording */ HDC record_dc; GpGraphics *record_graphics; BYTE *comment_data; DWORD comment_data_size; DWORD comment_data_length; - HENHMETAFILE hemf; + + /* playback */ + GpGraphics *playback_graphics; + HDC playback_dc; + GpPointF playback_points[3]; + HANDLETABLE *handle_table; + int handle_count; }; struct GpBitmap{ diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index 3e79eb7..063fdbc 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -357,18 +357,100 @@ GpStatus WINGDIPAPI GdipGetHemfFromMetafile(GpMetafile *metafile, HENHMETAFILE * return Ok; } +static GpStatus METAFILE_PlaybackGetDC(GpMetafile *metafile) +{ + GpStatus stat = Ok; + + stat = GdipGetDC(metafile->playback_graphics, &metafile->playback_dc); + + if (stat == Ok) + { + /* The result of GdipGetDC always expects device co-ordinates, but the + * device co-ordinates of the source metafile do not correspond to + * device co-ordinates of the destination. Therefore, we set up the DC + * so that the metafile's bounds map to the destination points where we + * are drawing this metafile. */ + SetMapMode(metafile->playback_dc, MM_ANISOTROPIC); + + SetWindowOrgEx(metafile->playback_dc, metafile->bounds.X, metafile->bounds.Y, NULL); + SetWindowExtEx(metafile->playback_dc, metafile->bounds.Width, metafile->bounds.Height, NULL); + + SetViewportOrgEx(metafile->playback_dc, metafile->playback_points[0].X, metafile->playback_points[0].Y, NULL); + SetViewportExtEx(metafile->playback_dc, + metafile->playback_points[1].X - metafile->playback_points[0].X, + metafile->playback_points[2].Y - metafile->playback_points[0].Y, NULL); + } + + return stat; +} + +static void METAFILE_PlaybackReleaseDC(GpMetafile *metafile) +{ + if (metafile->playback_dc) + { + GdipReleaseDC(metafile->playback_graphics, metafile->playback_dc); + metafile->playback_dc = NULL; + } +} + GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile, EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data) { - FIXME("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data); + TRACE("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data); + + if (!metafile || (dataSize && !data) || !metafile->playback_graphics) + return InvalidParameter; + + if (recordType >= 1 && recordType <= 0x7a) + { + /* regular EMF record */ + if (metafile->playback_dc) + { + ENHMETARECORD *record; + + record = GdipAlloc(dataSize + 8); + + if (record) + { + record->iType = recordType; + record->nSize = dataSize; + memcpy(record->dParm, data, dataSize); - return NotImplemented; + PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table, + record, metafile->handle_count); + + GdipFree(record); + } + else + return OutOfMemory; + } + } + else + { + METAFILE_PlaybackReleaseDC((GpMetafile*)metafile); + + switch(recordType) + { + case EmfPlusRecordTypeHeader: + case EmfPlusRecordTypeEndOfFile: + break; + case EmfPlusRecordTypeGetDC: + METAFILE_PlaybackGetDC((GpMetafile*)metafile); + break; + default: + FIXME("Not implemented for record type %x\n", recordType); + return NotImplemented; + } + } + + return Ok; } struct enum_metafile_data { EnumerateMetafileProc callback; void *callback_data; + GpMetafile *metafile; }; static int CALLBACK enum_metafile_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, @@ -378,6 +460,9 @@ static int CALLBACK enum_metafile_proc(HDC hDC, HANDLETABLE *lpHTable, const ENH struct enum_metafile_data *data = (struct enum_metafile_data*)lpData; const BYTE* pStr; + data->metafile->handle_table = lpHTable; + data->metafile->handle_count = nObj; + /* First check for an EMF+ record. */ if (lpEMFR->iType == EMR_GDICOMMENT) { @@ -424,6 +509,8 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics, VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes) { struct enum_metafile_data data; + GpStatus stat; + GpMetafile *real_metafile = (GpMetafile*)metafile; /* whoever made this const was joking */ TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile, destPoints, count, srcRect, srcUnit, callback, callbackData, @@ -435,14 +522,32 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics, if (!metafile->hemf) return InvalidParameter; + if (metafile->playback_graphics) + return ObjectBusy; + TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect), srcUnit, debugstr_pointf(&destPoints[0]), debugstr_pointf(&destPoints[1]), debugstr_pointf(&destPoints[2])); data.callback = callback; data.callback_data = callbackData; + data.metafile = real_metafile; - EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL); + real_metafile->playback_graphics = graphics; + real_metafile->playback_dc = NULL; - return Ok; + memcpy(real_metafile->playback_points, destPoints, sizeof(PointF) * 3); + stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, real_metafile->playback_points, 3); + + if (stat == Ok && metafile->metafile_type == EmfTypeEmfOnly) + stat = METAFILE_PlaybackGetDC((GpMetafile*)metafile); + + if (stat == Ok) + EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL); + + METAFILE_PlaybackReleaseDC((GpMetafile*)metafile); + + real_metafile->playback_graphics = NULL; + + return stat; } diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index 5323751..9530b0c 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -212,9 +212,9 @@ static BOOL CALLBACK play_metafile_proc(EmfPlusRecordType record_type, unsigned if (state->expected[state->count].record_type) { if (state->expected[state->count].playback_todo) - todo_wine ok(stat == Ok, "%s: GdipPlayMetafileRecord failed with stat %i\n", state->desc, stat); + todo_wine ok(stat == Ok, "%s.%i: GdipPlayMetafileRecord failed with stat %i\n", state->desc, state->count, stat); else - ok(stat == Ok, "%s: GdipPlayMetafileRecord failed with stat %i\n", state->desc, stat); + ok(stat == Ok, "%s.%i: GdipPlayMetafileRecord failed with stat %i\n", state->desc, state->count, stat); state->count++; } else @@ -324,16 +324,16 @@ static void test_empty(void) } static const emfplus_record getdc_records[] = { - {0, EMR_HEADER, 1}, - {0, EmfPlusRecordTypeHeader, 1}, - {0, EmfPlusRecordTypeGetDC, 1}, - {0, EMR_CREATEBRUSHINDIRECT, 1}, - {0, EMR_SELECTOBJECT, 1}, - {0, EMR_RECTANGLE, 1}, - {0, EMR_SELECTOBJECT, 1}, - {0, EMR_DELETEOBJECT, 1}, - {0, EmfPlusRecordTypeEndOfFile, 1}, - {0, EMR_EOF, 1}, + {0, EMR_HEADER}, + {0, EmfPlusRecordTypeHeader}, + {0, EmfPlusRecordTypeGetDC}, + {0, EMR_CREATEBRUSHINDIRECT}, + {0, EMR_SELECTOBJECT}, + {0, EMR_RECTANGLE}, + {0, EMR_SELECTOBJECT}, + {0, EMR_DELETEOBJECT}, + {0, EmfPlusRecordTypeEndOfFile}, + {0, EMR_EOF}, {0} }; @@ -411,7 +411,7 @@ static void test_getdc(void) stat = GdipBitmapGetPixel(bitmap, 50, 50, &color); expect(Ok, stat); - todo_wine expect(0xff0000ff, color); + expect(0xff0000ff, color); stat = GdipBitmapSetPixel(bitmap, 50, 50, 0); expect(Ok, stat); @@ -420,7 +420,7 @@ static void test_getdc(void) stat = GdipBitmapGetPixel(bitmap, 15, 15, &color); expect(Ok, stat); - todo_wine expect(0xff0000ff, color); + expect(0xff0000ff, color); stat = GdipBitmapGetPixel(bitmap, 50, 50, &color); expect(Ok, stat); @@ -445,13 +445,13 @@ static void test_getdc(void) } static const emfplus_record emfonly_records[] = { - {0, EMR_HEADER, 1}, - {0, EMR_CREATEBRUSHINDIRECT, 1}, - {0, EMR_SELECTOBJECT, 1}, - {0, EMR_RECTANGLE, 1}, - {0, EMR_SELECTOBJECT, 1}, - {0, EMR_DELETEOBJECT, 1}, - {0, EMR_EOF, 1}, + {0, EMR_HEADER}, + {0, EMR_CREATEBRUSHINDIRECT}, + {0, EMR_SELECTOBJECT}, + {0, EMR_RECTANGLE}, + {0, EMR_SELECTOBJECT}, + {0, EMR_DELETEOBJECT}, + {0, EMR_EOF}, {0} }; @@ -528,7 +528,7 @@ static void test_emfonly(void) stat = GdipBitmapGetPixel(bitmap, 50, 50, &color); expect(Ok, stat); - todo_wine expect(0xff0000ff, color); + expect(0xff0000ff, color); stat = GdipDeleteGraphics(graphics); expect(Ok, stat); -- 1.7.1