From 0f30681ee760c8197b95273e6c38cd6c2a4164a6 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Mon, 21 Mar 2016 14:34:04 +0800
Subject: gdiplus: Reimplement metafile loading using gdi32 instead of
 IPicture. (v2)

---
 dlls/gdiplus/Makefile.in       |   2 +-
 dlls/gdiplus/gdiplus_private.h |   1 -
 dlls/gdiplus/graphics.c        |  18 +---
 dlls/gdiplus/image.c           | 204 +++++++++++++++++++++--------------------
 dlls/gdiplus/metafile.c        |   1 -
 dlls/gdiplus/tests/image.c     |  10 +-
 6 files changed, 113 insertions(+), 123 deletions(-)

diff --git a/dlls/gdiplus/Makefile.in b/dlls/gdiplus/Makefile.in
index 6495eb7..ac12bd1 100644
--- a/dlls/gdiplus/Makefile.in
+++ b/dlls/gdiplus/Makefile.in
@@ -1,6 +1,6 @@
 MODULE    = gdiplus.dll
 IMPORTLIB = gdiplus
-IMPORTS   = uuid shlwapi oleaut32 ole32 user32 gdi32
+IMPORTS   = uuid shlwapi ole32 user32 gdi32
 DELAYIMPORTS = windowscodecs
 
 C_SRCS = \
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 0013d75..5c8e7a4 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -319,7 +319,6 @@ struct GpAdustableArrowCap{
 };
 
 struct GpImage{
-    IPicture *picture;
     IWICBitmapDecoder *decoder;
     ImageType type;
     GUID format;
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 15c0bed..a51b689 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -2897,23 +2897,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
     srcheight = units_to_pixels(srcheight, srcUnit, image->yres);
     TRACE("src pixels: %f,%f %fx%f\n", srcx, srcy, srcwidth, srcheight);
 
-    if (image->picture)
-    {
-        if (!graphics->hdc)
-        {
-            FIXME("graphics object has no HDC\n");
-        }
-
-        if(IPicture_Render(image->picture, graphics->hdc,
-            pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y,
-            srcx, srcy, srcwidth, srcheight, NULL) != S_OK)
-        {
-            if(callback)
-                callback(callbackData);
-            return GenericError;
-        }
-    }
-    else if (image->type == ImageTypeBitmap)
+    if (image->type == ImageTypeBitmap)
     {
         GpBitmap* bitmap = (GpBitmap*)image;
         BOOL do_resampling = FALSE;
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c
index f803efa..2402c9d 100644
--- a/dlls/gdiplus/image.c
+++ b/dlls/gdiplus/image.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google (Evan Stade)
- * Copyright (C) 2012 Dmitry Timoshkov
+ * Copyright (C) 2012,2016 Dmitry Timoshkov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -124,34 +124,6 @@ static ColorPalette *get_palette(IWICBitmapFrameDecode *frame, WICBitmapPaletteT
     return palette;
 }
 
-static INT ipicture_pixel_height(IPicture *pic)
-{
-    HDC hdcref;
-    OLE_YSIZE_HIMETRIC y;
-
-    IPicture_get_Height(pic, &y);
-
-    hdcref = CreateCompatibleDC(0);
-    y = MulDiv(y, GetDeviceCaps(hdcref, LOGPIXELSY), INCH_HIMETRIC);
-    DeleteDC(hdcref);
-
-    return y;
-}
-
-static INT ipicture_pixel_width(IPicture *pic)
-{
-    HDC hdcref;
-    OLE_XSIZE_HIMETRIC x;
-
-    IPicture_get_Width(pic, &x);
-
-    hdcref = CreateCompatibleDC(0);
-    x = MulDiv(x, GetDeviceCaps(hdcref, LOGPIXELSX), INCH_HIMETRIC);
-    DeleteDC(hdcref);
-
-    return x;
-}
-
 GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap* bitmap, CGpEffect* effect,
     RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
 {
@@ -1309,45 +1281,12 @@ GpStatus WINGDIPAPI GdipCloneBitmapAreaI(INT x, INT y, INT width, INT height,
 
 GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
 {
-    GpStatus stat = GenericError;
-
     TRACE("%p, %p\n", image, cloneImage);
 
     if (!image || !cloneImage)
         return InvalidParameter;
 
-    if (image->picture)
-    {
-        IStream* stream;
-        HRESULT hr;
-        INT size;
-        LARGE_INTEGER move;
-
-        hr = CreateStreamOnHGlobal(0, TRUE, &stream);
-        if (FAILED(hr))
-            return GenericError;
-
-        hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
-        if(FAILED(hr))
-        {
-            WARN("Failed to save image on stream\n");
-            goto out;
-        }
-
-        /* Set seek pointer back to the beginning of the picture */
-        move.QuadPart = 0;
-        hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
-        if (FAILED(hr))
-            goto out;
-
-        stat = GdipLoadImageFromStream(stream, cloneImage);
-        if (stat != Ok) WARN("Failed to load image from stream\n");
-
-    out:
-        IStream_Release(stream);
-        return stat;
-    }
-    else if (image->type == ImageTypeBitmap)
+    if (image->type == ImageTypeBitmap)
     {
         GpBitmap *bitmap = (GpBitmap *)image;
 
@@ -1884,7 +1823,6 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     (*bitmap)->width = width;
     (*bitmap)->height = height;
     (*bitmap)->format = format;
-    (*bitmap)->image.picture = NULL;
     (*bitmap)->image.decoder = NULL;
     (*bitmap)->hbitmap = hbitmap;
     (*bitmap)->hdc = NULL;
@@ -2148,8 +2086,6 @@ static GpStatus free_image_data(GpImage *image)
         WARN("invalid image: %p\n", image);
         return ObjectBusy;
     }
-    if (image->picture)
-        IPicture_Release(image->picture);
     if (image->decoder)
         IWICBitmapDecoder_Release(image->decoder);
     heap_free(image->palette);
@@ -2215,12 +2151,6 @@ GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
         srcRect->Height = (REAL) ((GpBitmap*)image)->height;
         *srcUnit = UnitPixel;
     }
-    else{
-        srcRect->X = srcRect->Y = 0.0;
-        srcRect->Width = ipicture_pixel_width(image->picture);
-        srcRect->Height = ipicture_pixel_height(image->picture);
-        *srcUnit = UnitPixel;
-    }
 
     TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
           srcRect->Width, srcRect->Height, *srcUnit);
@@ -2244,10 +2174,6 @@ GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
         *height = ((GpBitmap*)image)->height;
         *width = ((GpBitmap*)image)->width;
     }
-    else{
-        *height = ipicture_pixel_height(image->picture);
-        *width = ipicture_pixel_width(image->picture);
-    }
 
     TRACE("returning (%f, %f)\n", *height, *width);
     return Ok;
@@ -2302,8 +2228,6 @@ GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
         *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
     else if(image->type == ImageTypeBitmap)
         *height = ((GpBitmap*)image)->height;
-    else
-        *height = ipicture_pixel_height(image->picture);
 
     TRACE("returning %d\n", *height);
 
@@ -2402,8 +2326,6 @@ GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
         *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
     else if(image->type == ImageTypeBitmap)
         *width = ((GpBitmap*)image)->width;
-    else
-        *width = ipicture_pixel_width(image->picture);
 
     TRACE("returning %d\n", *width);
 
@@ -3982,32 +3904,118 @@ static GpStatus decode_image_tiff(IStream* stream, GpImage **image)
     return decode_image_wic(stream, &GUID_ContainerFormatTiff, NULL, image);
 }
 
-static GpStatus decode_image_olepicture_metafile(IStream* stream, GpImage **image)
+static GpStatus load_wmf(IStream *stream, GpMetafile **metafile)
+{
+    GpStatus status = GenericError;
+    HRESULT hr;
+    UINT size;
+    LARGE_INTEGER pos;
+    WmfPlaceableFileHeader pfh;
+    BOOL is_placeable = FALSE;
+    METAHEADER mh;
+    HMETAFILE hmf;
+    void *buf;
+
+    pos.QuadPart = 0;
+    IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
+
+    hr = IStream_Read(stream, &mh, sizeof(mh), &size);
+    if (hr != S_OK || size != sizeof(mh))
+        return GenericError;
+
+    if (mh.mtType == 0xcdd7 && mh.mtHeaderSize == 0x9ac6)
+    {
+        is_placeable = TRUE;
+
+        pos.QuadPart = 0;
+        IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
+
+        hr = IStream_Read(stream, &pfh, sizeof(pfh), &size);
+        if (hr != S_OK || size != sizeof(pfh))
+            return GenericError;
+
+        hr = IStream_Read(stream, &mh, sizeof(mh), &size);
+        if (hr != S_OK || size != sizeof(mh))
+            return GenericError;
+    }
+
+    pos.QuadPart = is_placeable ? sizeof(pfh) : 0;
+    IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
+
+    buf = heap_alloc(mh.mtSize * 2);
+    if (!buf) return OutOfMemory;
+
+    hr = IStream_Read(stream, buf, mh.mtSize * 2, &size);
+    if (hr == S_OK && size == mh.mtSize * 2)
+    {
+        hmf = SetMetaFileBitsEx(mh.mtSize * 2, buf);
+        if (hmf)
+        {
+            status = GdipCreateMetafileFromWmf(hmf, TRUE, is_placeable ? &pfh : NULL, metafile);
+            if (status != Ok)
+                DeleteMetaFile(hmf);
+        }
+    }
+
+    heap_free(buf);
+    return status;
+}
+
+static GpStatus load_emf(IStream *stream, GpMetafile **metafile)
 {
-    IPicture *pic;
+    GpStatus status = GenericError;
+    HRESULT hr;
+    UINT size;
+    LARGE_INTEGER pos;
+    ENHMETAHEADER emh;
+    HENHMETAFILE hemf;
+    void *buf;
+
+    pos.QuadPart = 0;
+    IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
+
+    hr = IStream_Read(stream, &emh, sizeof(emh), &size);
+    if (hr != S_OK || size != sizeof(emh) || emh.dSignature != ENHMETA_SIGNATURE)
+        return GenericError;
+
+    pos.QuadPart = 0;
+    IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
+
+    buf = heap_alloc(emh.nBytes);
+    if (!buf) return OutOfMemory;
+
+    hr = IStream_Read(stream, buf, emh.nBytes, &size);
+    if (hr == S_OK && size == emh.nBytes)
+    {
+        hemf = SetEnhMetaFileBits(emh.nBytes, buf);
+        if (hemf)
+        {
+            status = GdipCreateMetafileFromEmf(hemf, FALSE, metafile);
+            if (status != Ok)
+                DeleteEnhMetaFile(hemf);
+        }
+    }
+
+    heap_free(buf);
+    return status;
+}
+
+static GpStatus decode_image_metafile(IStream *stream, GpImage **image)
+{
+    GpMetafile *metafile;
 
     TRACE("%p %p\n", stream, image);
 
     if(!stream || !image)
         return InvalidParameter;
 
-    if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
-        (LPVOID*) &pic) != S_OK){
-        TRACE("Could not load picture\n");
+    if (load_emf(stream, &metafile) != Ok && load_wmf(stream, &metafile) != Ok)
+    {
+        TRACE("Could not load metafile\n");
         return GenericError;
     }
 
-    /* FIXME: missing initialization code */
-    *image = heap_alloc_zero(sizeof(GpMetafile));
-    if(!*image) return OutOfMemory;
-    (*image)->type = ImageTypeMetafile;
-    (*image)->decoder = NULL;
-    (*image)->picture = pic;
-    (*image)->flags   = ImageFlagsNone;
-    (*image)->frame_count = 1;
-    (*image)->current_frame = 0;
-    (*image)->palette = NULL;
-
+    *image = (GpImage *)metafile;
     TRACE("<-- %p\n", *image);
 
     return Ok;
@@ -4665,7 +4673,7 @@ static const struct image_codec codecs[NUM_CODECS] = {
             /* SigMask */            emf_sig_mask,
         },
         NULL,
-        decode_image_olepicture_metafile,
+        decode_image_metafile,
         NULL
     },
     {
@@ -4685,7 +4693,7 @@ static const struct image_codec codecs[NUM_CODECS] = {
             /* SigMask */            wmf_sig_mask,
         },
         NULL,
-        decode_image_olepicture_metafile,
+        decode_image_metafile,
         NULL
     },
     {
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
index 922c101..e8bab06 100644
--- a/dlls/gdiplus/metafile.c
+++ b/dlls/gdiplus/metafile.c
@@ -255,7 +255,6 @@ GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF
     }
 
     (*metafile)->image.type = ImageTypeMetafile;
-    (*metafile)->image.picture = NULL;
     (*metafile)->image.flags   = ImageFlagsNone;
     (*metafile)->image.palette = NULL;
     (*metafile)->image.xres = dpix;
diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c
index 6a51714..e6de9db 100644
--- a/dlls/gdiplus/tests/image.c
+++ b/dlls/gdiplus/tests/image.c
@@ -1446,19 +1446,19 @@ static void test_loadwmf(void)
 
     stat = GdipGetImageBounds(img, &bounds, &unit);
     expect(Ok, stat);
-    todo_wine expect(UnitPixel, unit);
+    expect(UnitPixel, unit);
     expectf(0.0, bounds.X);
     expectf(0.0, bounds.Y);
-    todo_wine expectf(320.0, bounds.Width);
-    todo_wine expectf(320.0, bounds.Height);
+    expectf(320.0, bounds.Width);
+    expectf(320.0, bounds.Height);
 
     stat = GdipGetImageHorizontalResolution(img, &res);
     expect(Ok, stat);
-    todo_wine expectf(1440.0, res);
+    expectf(1440.0, res);
 
     stat = GdipGetImageVerticalResolution(img, &res);
     expect(Ok, stat);
-    todo_wine expectf(1440.0, res);
+    expectf(1440.0, res);
 
     memset(&header, 0, sizeof(header));
     stat = GdipGetMetafileHeaderFromMetafile((GpMetafile*)img, &header);
-- 
2.7.1

