[4/4] gdiplus: Reimplement GdipCreateMetafileFromEmf without using IPicture.
Vincent Povirk
madewokherd at gmail.com
Wed Oct 31 16:09:04 CDT 2012
-------------- next part --------------
From 538e5ed4c940dbb0c293c5f724bcfebfedb16e27 Mon Sep 17 00:00:00 2001
From: Vincent Povirk <vincent at codeweavers.com>
Date: Wed, 31 Oct 2012 15:37:16 -0500
Subject: [PATCH 4/4] gdiplus: Reimplement GdipCreateMetafileFromEmf without
using IPicture.
---
dlls/gdiplus/gdiplus_private.h | 2 ++
dlls/gdiplus/graphics.c | 70 ++++++++++++++++------------------------
dlls/gdiplus/image.c | 3 +-
dlls/gdiplus/metafile.c | 38 ++++++++++++++++++++++
4 files changed, 70 insertions(+), 43 deletions(-)
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 53f978c..13a63e6 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -58,6 +58,7 @@ extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **r
extern GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN;
+extern MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf) DECLSPEC_HIDDEN;
extern void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1,
REAL *y1, REAL *x2, REAL *y2) DECLSPEC_HIDDEN;
@@ -280,6 +281,7 @@ struct GpMetafile{
GpUnit unit;
MetafileType metafile_type;
HENHMETAFILE hemf;
+ int preserve_hemf; /* if true, hemf belongs to the app and should not be deleted */
/* recording */
HDC record_dc;
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 7380c5d..b3eaa86d 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -2350,62 +2350,43 @@ GpStatus WINGDIPAPI GdipCreateFromHWNDICM(HWND hwnd, GpGraphics **graphics)
GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
GpMetafile **metafile)
{
- IStream *stream = NULL;
- UINT read;
- ENHMETAHEADER *copy;
- GpStatus retval = Ok;
+ ENHMETAHEADER header;
+ MetafileType metafile_type;
TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
if(!hemf || !metafile)
return InvalidParameter;
- read = GetEnhMetaFileBits(hemf, 0, NULL);
- copy = GdipAlloc(read);
- GetEnhMetaFileBits(hemf, read, (BYTE *)copy);
-
- if(CreateStreamOnHGlobal(copy, TRUE, &stream) != S_OK){
- ERR("could not make stream\n");
- GdipFree(copy);
- retval = GenericError;
- goto err;
- }
+ if (GetEnhMetaFileHeader(hemf, sizeof(header), &header) == 0)
+ return GenericError;
- *metafile = GdipAlloc(sizeof(GpMetafile));
- if(!*metafile){
- retval = OutOfMemory;
- goto err;
- }
+ metafile_type = METAFILE_GetEmfType(hemf);
- if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
- (LPVOID*) &((*metafile)->image.picture)) != S_OK)
- {
- retval = GenericError;
- goto err;
- }
+ if (metafile_type == MetafileTypeInvalid)
+ return GenericError;
+ *metafile = GdipAlloc(sizeof(GpMetafile));
+ if (!*metafile)
+ return OutOfMemory;
(*metafile)->image.type = ImageTypeMetafile;
- memcpy(&(*metafile)->image.format, &ImageFormatWMF, sizeof(GUID));
- (*metafile)->image.palette = NULL;
- (*metafile)->image.xres = (REAL)copy->szlDevice.cx;
- (*metafile)->image.yres = (REAL)copy->szlDevice.cy;
- (*metafile)->bounds.X = (REAL)copy->rclBounds.left;
- (*metafile)->bounds.Y = (REAL)copy->rclBounds.top;
- (*metafile)->bounds.Width = (REAL)(copy->rclBounds.right - copy->rclBounds.left);
- (*metafile)->bounds.Height = (REAL)(copy->rclBounds.bottom - copy->rclBounds.top);
+ (*metafile)->image.format = ImageFormatEMF;
+ (*metafile)->image.frame_count = 1;
+ (*metafile)->image.xres = (REAL)header.szlDevice.cx;
+ (*metafile)->image.yres = (REAL)header.szlDevice.cy;
+ (*metafile)->bounds.X = (REAL)header.rclBounds.left;
+ (*metafile)->bounds.Y = (REAL)header.rclBounds.top;
+ (*metafile)->bounds.Width = (REAL)(header.rclBounds.right - header.rclBounds.left);
+ (*metafile)->bounds.Height = (REAL)(header.rclBounds.bottom - header.rclBounds.top);
(*metafile)->unit = UnitPixel;
-
- if(delete)
- DeleteEnhMetaFile(hemf);
+ (*metafile)->metafile_type = metafile_type;
+ (*metafile)->hemf = hemf;
+ (*metafile)->preserve_hemf = !delete;
TRACE("<-- %p\n", *metafile);
-err:
- if (retval != Ok)
- GdipFree(*metafile);
- IStream_Release(stream);
- return retval;
+ return Ok;
}
GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
@@ -2431,7 +2412,8 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
GdipFree(copy);
- retval = GdipCreateMetafileFromEmf(hemf, FALSE, metafile);
+ /* FIXME: We should store and use hwmf instead of converting to hemf */
+ retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
if (retval == Ok)
{
@@ -2443,9 +2425,13 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
placeable->BoundingBox.Left);
(*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
placeable->BoundingBox.Top);
+ (*metafile)->metafile_type = MetafileTypeWmfPlaceable;
+ (*metafile)->image.format = ImageFormatWMF;
if (delete) DeleteMetaFile(hwmf);
}
+ else
+ DeleteEnhMetaFile(hemf);
return retval;
}
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c
index 3918301..73f08b9 100644
--- a/dlls/gdiplus/image.c
+++ b/dlls/gdiplus/image.c
@@ -2189,7 +2189,8 @@ static GpStatus free_image_data(GpImage *image)
GpMetafile *metafile = (GpMetafile*)image;
GdipFree(metafile->comment_data);
DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc));
- DeleteEnhMetaFile(metafile->hemf);
+ if (!metafile->preserve_hemf)
+ DeleteEnhMetaFile(metafile->hemf);
if (metafile->record_graphics)
{
WARN("metafile closed while recording\n");
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
index 030b2a2..4345ece 100644
--- a/dlls/gdiplus/metafile.c
+++ b/dlls/gdiplus/metafile.c
@@ -548,3 +548,41 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
return stat;
}
+
+static int CALLBACK get_metafile_type_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
+ int nObj, LPARAM lpData)
+{
+ MetafileType *result = (MetafileType*)lpData;
+
+ if (lpEMFR->iType == EMR_GDICOMMENT)
+ {
+ const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
+
+ if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
+ {
+ const EmfPlusRecordHeader *header = (const EmfPlusRecordHeader*)&comment->Data[4];
+
+ if (4 + sizeof(EmfPlusRecordHeader) <= comment->cbData &&
+ header->Type == EmfPlusRecordTypeHeader)
+ {
+ if ((header->Flags & 1) == 1)
+ *result = MetafileTypeEmfPlusDual;
+ else
+ *result = MetafileTypeEmfPlusOnly;
+ }
+ }
+ else
+ *result = MetafileTypeEmf;
+ }
+ else
+ *result = MetafileTypeEmf;
+
+ return FALSE;
+}
+
+MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf)
+{
+ MetafileType result = MetafileTypeInvalid;
+ EnumEnhMetaFile(NULL, hemf, get_metafile_type_proc, &result, NULL);
+ return result;
+}
--
1.7.9.5
More information about the wine-patches
mailing list