gdiplus/metafile: Implement EmfPlusRecordTypeObject for image attributes object.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Vincent Povirk <vincent@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2017-10-12 13:44:29 +03:00 committed by Alexandre Julliard
parent 2e877152de
commit 825f393299
3 changed files with 126 additions and 33 deletions

View file

@ -121,6 +121,7 @@ extern GpStatus METAFILE_DrawImagePointsRect(GpMetafile* metafile, GpImage *imag
extern GpStatus METAFILE_AddSimpleProperty(GpMetafile *metafile, SHORT prop, SHORT val) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_DrawPath(GpMetafile *metafile, GpPen *pen, GpPath *path) DECLSPEC_HIDDEN;
extern GpStatus METAFILE_FillPath(GpMetafile *metafile, GpBrush *brush, GpPath *path) DECLSPEC_HIDDEN;
extern void METAFILE_Free(GpMetafile *metafile) DECLSPEC_HIDDEN;
extern void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
REAL *y1, REAL *x2, REAL *y2) DECLSPEC_HIDDEN;
@ -371,6 +372,32 @@ struct GpImage{
LONG busy;
};
#define EmfPlusObjectTableSize 64
typedef enum EmfPlusObjectType
{
ObjectTypeInvalid,
ObjectTypeBrush,
ObjectTypePen,
ObjectTypePath,
ObjectTypeRegion,
ObjectTypeImage,
ObjectTypeFont,
ObjectTypeStringFormat,
ObjectTypeImageAttributes,
ObjectTypeCustomLineCap,
ObjectTypeMax = ObjectTypeCustomLineCap,
} EmfPlusObjectType;
/* Deserialized EmfPlusObject record. */
struct emfplus_object {
EmfPlusObjectType type;
union {
GpImageAttributes *image_attributes;
void *object;
} u;
};
struct GpMetafile{
GpImage image;
GpRectF bounds;
@ -404,6 +431,7 @@ struct GpMetafile{
GpRegion *base_clip; /* clip region in device space for all metafile output */
GpRegion *clip; /* clip region within the metafile */
struct list containers;
struct emfplus_object objtable[EmfPlusObjectTableSize];
};
struct GpBitmap{

View file

@ -2085,24 +2085,7 @@ static GpStatus free_image_data(GpImage *image)
heap_free(((GpBitmap*)image)->prop_item);
}
else if (image->type == ImageTypeMetafile)
{
GpMetafile *metafile = (GpMetafile*)image;
heap_free(metafile->comment_data);
DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc));
if (!metafile->preserve_hemf)
DeleteEnhMetaFile(metafile->hemf);
if (metafile->record_graphics)
{
WARN("metafile closed while recording\n");
/* not sure what to do here; for now just prevent the graphics from functioning or using this object */
metafile->record_graphics->image = NULL;
metafile->record_graphics->busy = TRUE;
}
if (metafile->record_stream)
{
IStream_Release(metafile->record_stream);
}
}
METAFILE_Free((GpMetafile *)image);
else
{
WARN("invalid image: %p\n", image);

View file

@ -297,20 +297,6 @@ typedef struct EmfPlusImageAttributes
DWORD Reserved2;
} EmfPlusImageAttributes;
typedef enum ObjectType
{
ObjectTypeInvalid,
ObjectTypeBrush,
ObjectTypePen,
ObjectTypePath,
ObjectTypeRegion,
ObjectTypeImage,
ObjectTypeFont,
ObjectTypeStringFormat,
ObjectTypeImageAttributes,
ObjectTypeCustomLineCap,
} ObjectType;
typedef struct EmfPlusObject
{
EmfPlusRecordHeader Header;
@ -370,9 +356,52 @@ typedef struct EmfPlusFillPath
} data;
} EmfPlusFillPath;
static void metafile_free_object_table_entry(GpMetafile *metafile, BYTE id)
{
struct emfplus_object *object = &metafile->objtable[id];
switch (object->type)
{
case ObjectTypeInvalid:
break;
case ObjectTypeImageAttributes:
GdipDisposeImageAttributes(object->u.image_attributes);
break;
default:
FIXME("not implemented for object type %u.\n", object->type);
return;
}
object->type = ObjectTypeInvalid;
object->u.object = NULL;
}
void METAFILE_Free(GpMetafile *metafile)
{
unsigned int i;
heap_free(metafile->comment_data);
DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc));
if (!metafile->preserve_hemf)
DeleteEnhMetaFile(metafile->hemf);
if (metafile->record_graphics)
{
WARN("metafile closed while recording\n");
/* not sure what to do here; for now just prevent the graphics from functioning or using this object */
metafile->record_graphics->image = NULL;
metafile->record_graphics->busy = TRUE;
}
if (metafile->record_stream)
IStream_Release(metafile->record_stream);
for (i = 0; i < sizeof(metafile->objtable)/sizeof(metafile->objtable[0]); i++)
metafile_free_object_table_entry(metafile, i);
}
static DWORD METAFILE_AddObjectId(GpMetafile *metafile)
{
return (metafile->next_object_id++) % 64;
return (metafile->next_object_id++) % EmfPlusObjectTableSize;
}
static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
@ -1407,6 +1436,55 @@ static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile)
return stat;
}
static void metafile_set_object_table_entry(GpMetafile *metafile, BYTE id, BYTE type, void *object)
{
metafile_free_object_table_entry(metafile, id);
metafile->objtable[id].type = type;
metafile->objtable[id].u.object = object;
}
static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT data_size, const BYTE *record_data)
{
BYTE type = (flags >> 8) & 0xff;
BYTE id = flags & 0xff;
void *object = NULL;
GpStatus status;
if (type > ObjectTypeMax || id >= EmfPlusObjectTableSize)
return InvalidParameter;
switch (type)
{
case ObjectTypeImageAttributes:
{
EmfPlusImageAttributes *data = (EmfPlusImageAttributes *)record_data;
GpImageAttributes *attributes = NULL;
if (data_size != sizeof(*data))
return InvalidParameter;
if ((status = GdipCreateImageAttributes(&attributes)) != Ok)
return status;
status = GdipSetImageAttributesWrapMode(attributes, data->WrapMode, *(DWORD *)&data->ClampColor,
!!data->ObjectClamp);
if (status == Ok)
object = attributes;
else
GdipDisposeImageAttributes(attributes);
break;
}
default:
FIXME("not implemented for object type %d.\n", type);
return NotImplemented;
}
if (status == Ok)
metafile_set_object_table_entry(metafile, id, type, object);
return status;
}
GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data)
{
@ -1852,6 +1930,10 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
{
return GdipSetSmoothingMode(real_metafile->playback_graphics, (flags >> 1) & 0xff);
}
case EmfPlusRecordTypeObject:
{
return METAFILE_PlaybackObject(real_metafile, flags, dataSize, data);
}
default:
FIXME("Not implemented for record type %x\n", recordType);
return NotImplemented;