Vincent Povirk : gdiplus: Account for GDI+ drawing operations in the metafile frame.
Alexandre Julliard
julliard at winehq.org
Sun Jul 3 12:18:28 CDT 2016
Module: wine
Branch: master
Commit: da31ddb797485be02a938d88dc846ebefccda099
URL: http://source.winehq.org/git/wine.git/?a=commit;h=da31ddb797485be02a938d88dc846ebefccda099
Author: Vincent Povirk <vincent at 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 at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at 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);
More information about the wine-cvs
mailing list