[1/2] gdiplus: Add support for containers in metafiles.
Vincent Povirk
madewokherd at gmail.com
Mon Aug 15 16:25:41 CDT 2016
From: Vincent Povirk <vincent at codeweavers.com>
Signed-off-by: Vincent Povirk <vincent at codeweavers.com>
---
dlls/gdiplus/gdiplus_private.h | 5 +
dlls/gdiplus/graphics.c | 14 +++
dlls/gdiplus/image.c | 1 +
dlls/gdiplus/metafile.c | 205 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 225 insertions(+)
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 1a028a5..4ad49ca 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -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{
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index f0cf98c..370fa88 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -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;
}
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c
index 4d0496a..c3f6a5e 100644
--- a/dlls/gdiplus/image.c
+++ b/dlls/gdiplus/image.c
@@ -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);
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
index 63d9e22..faa8f72 100644
--- a/dlls/gdiplus/metafile.c
+++ b/dlls/gdiplus/metafile.c
@@ -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);
--
2.7.4
More information about the wine-patches
mailing list