Vincent Povirk : gdiplus: Implement GdipPlayMetafileRecord for EMF records.

Alexandre Julliard julliard at winehq.org
Fri Jul 8 11:23:41 CDT 2011


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

Author: Vincent Povirk <vincent at codeweavers.com>
Date:   Thu Jul  7 16:25:25 2011 -0500

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..38923a0 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 == MetafileTypeEmf)
+        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);




More information about the wine-cvs mailing list