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>
This commit is contained in:
Vincent Povirk 2016-06-24 12:51:43 -05:00 committed by Alexandre Julliard
parent 0f3db73628
commit da31ddb797
3 changed files with 113 additions and 4 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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);