gdiplus: Add support for containers in metafiles.

Signed-off-by: Vincent Povirk <vincent@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Vincent Povirk 2016-08-15 16:25:41 -05:00 committed by Alexandre Julliard
parent c90e46b66d
commit f28803c0a4
4 changed files with 225 additions and 0 deletions

View file

@ -96,6 +96,10 @@ extern GpStatus METAFILE_MultiplyWorldTransform(GpMetafile* metafile, GDIPCONST
extern GpStatus METAFILE_RotateWorldTransform(GpMetafile* metafile, REAL angle, MatrixOrder order) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_TranslateWorldTransform(GpMetafile* metafile, REAL dx, REAL dy, MatrixOrder order) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_ResetWorldTransform(GpMetafile* metafile) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_BeginContainerNoParams(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_EndContainer(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_SaveGraphics(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_RestoreGraphics(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN;
extern void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
@ -368,6 +372,7 @@ struct GpMetafile{
GpUnit page_unit;
REAL page_scale;
GpRegion *base_clip; /* clip region in device space for all metafile output */
struct list containers;
};
struct GpBitmap{

View file

@ -5194,6 +5194,13 @@ static GpStatus begin_container(GpGraphics *graphics,
list_add_head(&graphics->containers, &container->entry);
*state = graphics->contid = container->contid;
if (graphics->image && graphics->image->type == ImageTypeMetafile) {
if (type == BEGIN_CONTAINER)
METAFILE_BeginContainerNoParams((GpMetafile*)graphics->image, container->contid);
else
METAFILE_SaveGraphics((GpMetafile*)graphics->image, container->contid);
}
return Ok;
}
@ -5261,6 +5268,13 @@ static GpStatus end_container(GpGraphics *graphics, GraphicsContainerType type,
list_remove(&container->entry);
delete_container(container);
if (graphics->image && graphics->image->type == ImageTypeMetafile) {
if (type == BEGIN_CONTAINER)
METAFILE_EndContainer((GpMetafile*)graphics->image, state);
else
METAFILE_RestoreGraphics((GpMetafile*)graphics->image, state);
}
return Ok;
}

View file

@ -4062,6 +4062,7 @@ static GpStatus decode_image_olepicture_metafile(IStream* stream, GpImage **imag
(*image)->frame_count = 1;
(*image)->current_frame = 0;
(*image)->palette = NULL;
list_init(&(*(GpMetafile**)image)->containers);
TRACE("<-- %p\n", *image);

View file

@ -116,6 +116,29 @@ typedef struct EmfPlusTranslateWorldTransform
REAL dy;
} EmfPlusTranslateWorldTransform;
typedef struct EmfPlusContainerRecord
{
EmfPlusRecordHeader Header;
DWORD StackIndex;
} EmfPlusContainerRecord;
enum container_type
{
BEGIN_CONTAINER,
SAVE_GRAPHICS
};
typedef struct container
{
struct list entry;
DWORD id;
enum container_type type;
GraphicsContainer state;
GpMatrix world_transform;
GpUnit page_unit;
REAL page_scale;
} container;
static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
{
DWORD size_needed;
@ -308,6 +331,7 @@ GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF
(*metafile)->comment_data_size = 0;
(*metafile)->comment_data_length = 0;
(*metafile)->hemf = NULL;
list_init(&(*metafile)->containers);
if (!frameRect)
{
@ -726,6 +750,98 @@ GpStatus METAFILE_ResetWorldTransform(GpMetafile* metafile)
return Ok;
}
GpStatus METAFILE_BeginContainerNoParams(GpMetafile* metafile, DWORD StackIndex)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusContainerRecord *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusContainerRecord),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeBeginContainerNoParams;
record->Header.Flags = 0;
record->StackIndex = StackIndex;
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_EndContainer(GpMetafile* metafile, DWORD StackIndex)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusContainerRecord *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusContainerRecord),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeEndContainer;
record->Header.Flags = 0;
record->StackIndex = StackIndex;
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_SaveGraphics(GpMetafile* metafile, DWORD StackIndex)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusContainerRecord *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusContainerRecord),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeSave;
record->Header.Flags = 0;
record->StackIndex = StackIndex;
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_RestoreGraphics(GpMetafile* metafile, DWORD StackIndex)
{
if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
{
EmfPlusContainerRecord *record;
GpStatus stat;
stat = METAFILE_AllocateRecord(metafile,
sizeof(EmfPlusContainerRecord),
(void**)&record);
if (stat != Ok)
return stat;
record->Header.Type = EmfPlusRecordTypeRestore;
record->Header.Flags = 0;
record->StackIndex = StackIndex;
METAFILE_WriteRecords(metafile);
}
return Ok;
}
GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc)
{
if (hdc != metafile->record_dc)
@ -1131,6 +1247,87 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
}
case EmfPlusRecordTypeBeginContainerNoParams:
case EmfPlusRecordTypeSave:
{
EmfPlusContainerRecord *record = (EmfPlusContainerRecord*)header;
container* cont;
cont = heap_alloc_zero(sizeof(*cont));
if (!cont)
return OutOfMemory;
if (recordType == EmfPlusRecordTypeBeginContainerNoParams)
stat = GdipBeginContainer2(metafile->playback_graphics, &cont->state);
else
stat = GdipSaveGraphics(metafile->playback_graphics, &cont->state);
if (stat != Ok)
{
heap_free(cont);
return stat;
}
cont->id = record->StackIndex;
if (recordType == EmfPlusRecordTypeBeginContainerNoParams)
cont->type = BEGIN_CONTAINER;
else
cont->type = SAVE_GRAPHICS;
cont->world_transform = *metafile->world_transform;
cont->page_unit = metafile->page_unit;
cont->page_scale = metafile->page_scale;
list_add_head(&real_metafile->containers, &cont->entry);
break;
}
case EmfPlusRecordTypeEndContainer:
case EmfPlusRecordTypeRestore:
{
EmfPlusContainerRecord *record = (EmfPlusContainerRecord*)header;
container* cont;
enum container_type type;
BOOL found=FALSE;
if (recordType == EmfPlusRecordTypeEndContainer)
type = BEGIN_CONTAINER;
else
type = SAVE_GRAPHICS;
LIST_FOR_EACH_ENTRY(cont, &real_metafile->containers, container, entry)
{
if (cont->id == record->StackIndex && cont->type == type)
{
found = TRUE;
break;
}
}
if (found)
{
container* cont2;
/* pop any newer items on the stack */
while ((cont2 = LIST_ENTRY(list_head(&real_metafile->containers), container, entry)) != cont)
{
list_remove(&cont2->entry);
heap_free(cont2);
}
if (type == BEGIN_CONTAINER)
GdipEndContainer(real_metafile->playback_graphics, cont->state);
else
GdipRestoreGraphics(real_metafile->playback_graphics, cont->state);
*real_metafile->world_transform = cont->world_transform;
real_metafile->page_unit = cont->page_unit;
real_metafile->page_scale = cont->page_scale;
list_remove(&cont->entry);
heap_free(cont);
}
break;
}
default:
FIXME("Not implemented for record type %x\n", recordType);
return NotImplemented;
@ -1309,6 +1506,13 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
GdipDeleteRegion(real_metafile->base_clip);
real_metafile->base_clip = NULL;
while (list_head(&real_metafile->containers))
{
container* cont = LIST_ENTRY(list_head(&real_metafile->containers), container, entry);
list_remove(&cont->entry);
heap_free(cont);
}
GdipEndContainer(graphics, state);
}
@ -1553,6 +1757,7 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
(*metafile)->metafile_type = header.Type;
(*metafile)->hemf = hemf;
(*metafile)->preserve_hemf = !delete;
list_init(&(*metafile)->containers);
TRACE("<-- %p\n", *metafile);