From da31ddb797485be02a938d88dc846ebefccda099 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Fri, 24 Jun 2016 12:51:43 -0500 Subject: [PATCH] gdiplus: Account for GDI+ drawing operations in the metafile frame. Signed-off-by: Vincent Povirk Signed-off-by: Alexandre Julliard --- dlls/gdiplus/gdiplus_private.h | 2 + dlls/gdiplus/metafile.c | 107 +++++++++++++++++++++++++++++++++ dlls/gdiplus/tests/metafile.c | 8 +-- 3 files changed, 113 insertions(+), 4 deletions(-) diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index e21085fea4d..25ae5ee24d6 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -348,6 +348,8 @@ struct GpMetafile{ DWORD comment_data_size; DWORD comment_data_length; IStream *record_stream; + BOOL auto_frame; /* If true, determine the frame automatically */ + GpPointF auto_frame_min, auto_frame_max; /* playback */ GpGraphics *playback_graphics; diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index b1c38db2b61..022af38c21c 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -277,6 +277,15 @@ GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF (*metafile)->comment_data_length = 0; (*metafile)->hemf = NULL; + if (!frameRect) + { + (*metafile)->auto_frame = TRUE; + (*metafile)->auto_frame_min.X = 0; + (*metafile)->auto_frame_min.Y = 0; + (*metafile)->auto_frame_max.X = -1; + (*metafile)->auto_frame_max.Y = -1; + } + stat = METAFILE_WriteHeader(*metafile, hdc); if (stat != Ok) @@ -335,6 +344,30 @@ GpStatus WINGDIPAPI GdipRecordMetafileStream(IStream *stream, HDC hdc, EmfType t return stat; } +static void METAFILE_AdjustFrame(GpMetafile* metafile, const GpPointF *points, + UINT num_points) +{ + int i; + + if (!metafile->auto_frame || !num_points) + return; + + if (metafile->auto_frame_max.X < metafile->auto_frame_min.X) + metafile->auto_frame_max = metafile->auto_frame_min = points[0]; + + for (i=0; iauto_frame_min.X) + metafile->auto_frame_min.X = points[i].X; + if (points[i].X > metafile->auto_frame_max.X) + metafile->auto_frame_max.X = points[i].X; + if (points[i].Y < metafile->auto_frame_min.Y) + metafile->auto_frame_min.Y = points[i].Y; + if (points[i].Y > metafile->auto_frame_max.Y) + metafile->auto_frame_max.Y = points[i].Y; + } +} + GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) { GpStatus stat; @@ -473,6 +506,29 @@ GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush, METAFILE_WriteRecords(metafile); } + if (metafile->auto_frame) + { + GpPointF corners[4]; + int i; + + for (i=0; irecord_graphics, CoordinateSpaceDevice, + CoordinateSpaceWorld, corners, 4); + + METAFILE_AdjustFrame(metafile, corners, 4); + } + } + return Ok; } @@ -526,6 +582,57 @@ GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) MetafileHeader header; stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header); + if (stat == Ok && metafile->auto_frame && + metafile->auto_frame_max.X >= metafile->auto_frame_min.X) + { + RECTL bounds_rc, gdi_bounds_rc; + REAL x_scale = 2540.0 / header.DpiX; + REAL y_scale = 2540.0 / header.DpiY; + BYTE* buffer; + UINT buffer_size; + + bounds_rc.left = floorf(metafile->auto_frame_min.X * x_scale); + bounds_rc.top = floorf(metafile->auto_frame_min.Y * y_scale); + bounds_rc.right = ceilf(metafile->auto_frame_max.X * x_scale); + bounds_rc.bottom = ceilf(metafile->auto_frame_max.Y * y_scale); + + gdi_bounds_rc = header.EmfHeader.rclBounds; + if (gdi_bounds_rc.right > gdi_bounds_rc.left && gdi_bounds_rc.bottom > gdi_bounds_rc.top) + { + bounds_rc.left = min(bounds_rc.left, gdi_bounds_rc.left); + bounds_rc.top = min(bounds_rc.top, gdi_bounds_rc.top); + bounds_rc.right = max(bounds_rc.right, gdi_bounds_rc.right); + bounds_rc.bottom = max(bounds_rc.bottom, gdi_bounds_rc.bottom); + } + + buffer_size = GetEnhMetaFileBits(metafile->hemf, 0, NULL); + buffer = heap_alloc(buffer_size); + if (buffer) + { + HENHMETAFILE new_hemf; + + GetEnhMetaFileBits(metafile->hemf, buffer_size, buffer); + + ((ENHMETAHEADER*)buffer)->rclFrame = bounds_rc; + + new_hemf = SetEnhMetaFileBits(buffer_size, buffer); + + if (new_hemf) + { + DeleteEnhMetaFile(metafile->hemf); + metafile->hemf = new_hemf; + } + else + stat = OutOfMemory; + + heap_free(buffer); + } + else + stat = OutOfMemory; + + if (stat == Ok) + stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header); + } if (stat == Ok) { metafile->bounds.X = header.X; diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index 68dc4075823..e8281ba1677 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -1010,10 +1010,10 @@ static void test_nullframerect(void) { stat = GdipGetImageBounds((GpImage*)metafile, &bounds, &unit); expect(Ok, stat); expect(UnitPixel, unit); - todo_wine expectf_(25.0, bounds.X, 0.05); - todo_wine expectf_(25.0, bounds.Y, 0.05); - todo_wine expectf_(75.0, bounds.Width, 0.05); - todo_wine expectf_(75.0, bounds.Height, 0.05); + expectf_(25.0, bounds.X, 0.05); + expectf_(25.0, bounds.Y, 0.05); + expectf_(75.0, bounds.Width, 0.05); + expectf_(75.0, bounds.Height, 0.05); stat = GdipDisposeImage((GpImage*)metafile); expect(Ok, stat);