Module: wine Branch: master Commit: da31ddb797485be02a938d88dc846ebefccda099 URL: http://source.winehq.org/git/wine.git/?a=commit;h=da31ddb797485be02a938d88dc...
Author: Vincent Povirk vincent@codeweavers.com Date: Fri Jun 24 12:51:43 2016 -0500
gdiplus: Account for GDI+ drawing operations in the metafile frame.
Signed-off-by: Vincent Povirk vincent@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
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 e21085f..25ae5ee 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 b1c38db..022af38 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; i<num_points; i++) + { + if (points[i].X < metafile->auto_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; i<count; i++) + { + corners[0].X = rects[i].X; + corners[0].Y = rects[i].Y; + corners[1].X = rects[i].X + rects[i].Width; + corners[1].Y = rects[i].Y; + corners[2].X = rects[i].X; + corners[2].Y = rects[i].Y + rects[i].Height; + corners[3].X = rects[i].X + rects[i].Width; + corners[3].Y = rects[i].Y + rects[i].Height; + + GdipTransformPoints(metafile->record_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 68dc407..e8281ba 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);