gdiplus: Implement GdipPlayMetafileRecord for EMF records.

This commit is contained in:
Vincent Povirk 2011-07-07 16:25:25 -05:00 committed by Alexandre Julliard
parent 3a6ba94011
commit fda2fc7684
3 changed files with 141 additions and 27 deletions

View File

@ -274,12 +274,21 @@ struct GpMetafile{
GpRectF bounds; GpRectF bounds;
GpUnit unit; GpUnit unit;
MetafileType metafile_type; MetafileType metafile_type;
HENHMETAFILE hemf;
/* recording */
HDC record_dc; HDC record_dc;
GpGraphics *record_graphics; GpGraphics *record_graphics;
BYTE *comment_data; BYTE *comment_data;
DWORD comment_data_size; DWORD comment_data_size;
DWORD comment_data_length; DWORD comment_data_length;
HENHMETAFILE hemf;
/* playback */
GpGraphics *playback_graphics;
HDC playback_dc;
GpPointF playback_points[3];
HANDLETABLE *handle_table;
int handle_count;
}; };
struct GpBitmap{ struct GpBitmap{

View File

@ -357,18 +357,100 @@ GpStatus WINGDIPAPI GdipGetHemfFromMetafile(GpMetafile *metafile, HENHMETAFILE *
return Ok; return Ok;
} }
static GpStatus METAFILE_PlaybackGetDC(GpMetafile *metafile)
{
GpStatus stat = Ok;
stat = GdipGetDC(metafile->playback_graphics, &metafile->playback_dc);
if (stat == Ok)
{
/* The result of GdipGetDC always expects device co-ordinates, but the
* device co-ordinates of the source metafile do not correspond to
* device co-ordinates of the destination. Therefore, we set up the DC
* so that the metafile's bounds map to the destination points where we
* are drawing this metafile. */
SetMapMode(metafile->playback_dc, MM_ANISOTROPIC);
SetWindowOrgEx(metafile->playback_dc, metafile->bounds.X, metafile->bounds.Y, NULL);
SetWindowExtEx(metafile->playback_dc, metafile->bounds.Width, metafile->bounds.Height, NULL);
SetViewportOrgEx(metafile->playback_dc, metafile->playback_points[0].X, metafile->playback_points[0].Y, NULL);
SetViewportExtEx(metafile->playback_dc,
metafile->playback_points[1].X - metafile->playback_points[0].X,
metafile->playback_points[2].Y - metafile->playback_points[0].Y, NULL);
}
return stat;
}
static void METAFILE_PlaybackReleaseDC(GpMetafile *metafile)
{
if (metafile->playback_dc)
{
GdipReleaseDC(metafile->playback_graphics, metafile->playback_dc);
metafile->playback_dc = NULL;
}
}
GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile, GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data) EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data)
{ {
FIXME("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data); TRACE("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data);
return NotImplemented; if (!metafile || (dataSize && !data) || !metafile->playback_graphics)
return InvalidParameter;
if (recordType >= 1 && recordType <= 0x7a)
{
/* regular EMF record */
if (metafile->playback_dc)
{
ENHMETARECORD *record;
record = GdipAlloc(dataSize + 8);
if (record)
{
record->iType = recordType;
record->nSize = dataSize;
memcpy(record->dParm, data, dataSize);
PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table,
record, metafile->handle_count);
GdipFree(record);
}
else
return OutOfMemory;
}
}
else
{
METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
switch(recordType)
{
case EmfPlusRecordTypeHeader:
case EmfPlusRecordTypeEndOfFile:
break;
case EmfPlusRecordTypeGetDC:
METAFILE_PlaybackGetDC((GpMetafile*)metafile);
break;
default:
FIXME("Not implemented for record type %x\n", recordType);
return NotImplemented;
}
}
return Ok;
} }
struct enum_metafile_data struct enum_metafile_data
{ {
EnumerateMetafileProc callback; EnumerateMetafileProc callback;
void *callback_data; void *callback_data;
GpMetafile *metafile;
}; };
static int CALLBACK enum_metafile_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, static int CALLBACK enum_metafile_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
@ -378,6 +460,9 @@ static int CALLBACK enum_metafile_proc(HDC hDC, HANDLETABLE *lpHTable, const ENH
struct enum_metafile_data *data = (struct enum_metafile_data*)lpData; struct enum_metafile_data *data = (struct enum_metafile_data*)lpData;
const BYTE* pStr; const BYTE* pStr;
data->metafile->handle_table = lpHTable;
data->metafile->handle_count = nObj;
/* First check for an EMF+ record. */ /* First check for an EMF+ record. */
if (lpEMFR->iType == EMR_GDICOMMENT) if (lpEMFR->iType == EMR_GDICOMMENT)
{ {
@ -424,6 +509,8 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes) VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
{ {
struct enum_metafile_data data; struct enum_metafile_data data;
GpStatus stat;
GpMetafile *real_metafile = (GpMetafile*)metafile; /* whoever made this const was joking */
TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile, TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile,
destPoints, count, srcRect, srcUnit, callback, callbackData, destPoints, count, srcRect, srcUnit, callback, callbackData,
@ -435,14 +522,32 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
if (!metafile->hemf) if (!metafile->hemf)
return InvalidParameter; return InvalidParameter;
if (metafile->playback_graphics)
return ObjectBusy;
TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect), srcUnit, TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect), srcUnit,
debugstr_pointf(&destPoints[0]), debugstr_pointf(&destPoints[1]), debugstr_pointf(&destPoints[0]), debugstr_pointf(&destPoints[1]),
debugstr_pointf(&destPoints[2])); debugstr_pointf(&destPoints[2]));
data.callback = callback; data.callback = callback;
data.callback_data = callbackData; data.callback_data = callbackData;
data.metafile = real_metafile;
EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL); real_metafile->playback_graphics = graphics;
real_metafile->playback_dc = NULL;
return Ok; memcpy(real_metafile->playback_points, destPoints, sizeof(PointF) * 3);
stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, real_metafile->playback_points, 3);
if (stat == Ok && metafile->metafile_type == MetafileTypeEmf)
stat = METAFILE_PlaybackGetDC((GpMetafile*)metafile);
if (stat == Ok)
EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL);
METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
real_metafile->playback_graphics = NULL;
return stat;
} }

View File

@ -212,9 +212,9 @@ static BOOL CALLBACK play_metafile_proc(EmfPlusRecordType record_type, unsigned
if (state->expected[state->count].record_type) if (state->expected[state->count].record_type)
{ {
if (state->expected[state->count].playback_todo) if (state->expected[state->count].playback_todo)
todo_wine ok(stat == Ok, "%s: GdipPlayMetafileRecord failed with stat %i\n", state->desc, stat); todo_wine ok(stat == Ok, "%s.%i: GdipPlayMetafileRecord failed with stat %i\n", state->desc, state->count, stat);
else else
ok(stat == Ok, "%s: GdipPlayMetafileRecord failed with stat %i\n", state->desc, stat); ok(stat == Ok, "%s.%i: GdipPlayMetafileRecord failed with stat %i\n", state->desc, state->count, stat);
state->count++; state->count++;
} }
else else
@ -324,16 +324,16 @@ static void test_empty(void)
} }
static const emfplus_record getdc_records[] = { static const emfplus_record getdc_records[] = {
{0, EMR_HEADER, 1}, {0, EMR_HEADER},
{0, EmfPlusRecordTypeHeader, 1}, {0, EmfPlusRecordTypeHeader},
{0, EmfPlusRecordTypeGetDC, 1}, {0, EmfPlusRecordTypeGetDC},
{0, EMR_CREATEBRUSHINDIRECT, 1}, {0, EMR_CREATEBRUSHINDIRECT},
{0, EMR_SELECTOBJECT, 1}, {0, EMR_SELECTOBJECT},
{0, EMR_RECTANGLE, 1}, {0, EMR_RECTANGLE},
{0, EMR_SELECTOBJECT, 1}, {0, EMR_SELECTOBJECT},
{0, EMR_DELETEOBJECT, 1}, {0, EMR_DELETEOBJECT},
{0, EmfPlusRecordTypeEndOfFile, 1}, {0, EmfPlusRecordTypeEndOfFile},
{0, EMR_EOF, 1}, {0, EMR_EOF},
{0} {0}
}; };
@ -411,7 +411,7 @@ static void test_getdc(void)
stat = GdipBitmapGetPixel(bitmap, 50, 50, &color); stat = GdipBitmapGetPixel(bitmap, 50, 50, &color);
expect(Ok, stat); expect(Ok, stat);
todo_wine expect(0xff0000ff, color); expect(0xff0000ff, color);
stat = GdipBitmapSetPixel(bitmap, 50, 50, 0); stat = GdipBitmapSetPixel(bitmap, 50, 50, 0);
expect(Ok, stat); expect(Ok, stat);
@ -420,7 +420,7 @@ static void test_getdc(void)
stat = GdipBitmapGetPixel(bitmap, 15, 15, &color); stat = GdipBitmapGetPixel(bitmap, 15, 15, &color);
expect(Ok, stat); expect(Ok, stat);
todo_wine expect(0xff0000ff, color); expect(0xff0000ff, color);
stat = GdipBitmapGetPixel(bitmap, 50, 50, &color); stat = GdipBitmapGetPixel(bitmap, 50, 50, &color);
expect(Ok, stat); expect(Ok, stat);
@ -445,13 +445,13 @@ static void test_getdc(void)
} }
static const emfplus_record emfonly_records[] = { static const emfplus_record emfonly_records[] = {
{0, EMR_HEADER, 1}, {0, EMR_HEADER},
{0, EMR_CREATEBRUSHINDIRECT, 1}, {0, EMR_CREATEBRUSHINDIRECT},
{0, EMR_SELECTOBJECT, 1}, {0, EMR_SELECTOBJECT},
{0, EMR_RECTANGLE, 1}, {0, EMR_RECTANGLE},
{0, EMR_SELECTOBJECT, 1}, {0, EMR_SELECTOBJECT},
{0, EMR_DELETEOBJECT, 1}, {0, EMR_DELETEOBJECT},
{0, EMR_EOF, 1}, {0, EMR_EOF},
{0} {0}
}; };
@ -528,7 +528,7 @@ static void test_emfonly(void)
stat = GdipBitmapGetPixel(bitmap, 50, 50, &color); stat = GdipBitmapGetPixel(bitmap, 50, 50, &color);
expect(Ok, stat); expect(Ok, stat);
todo_wine expect(0xff0000ff, color); expect(0xff0000ff, color);
stat = GdipDeleteGraphics(graphics); stat = GdipDeleteGraphics(graphics);
expect(Ok, stat); expect(Ok, stat);