mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-15 08:20:20 +00:00
gdiplus/metafile: Implement EmfPlusRegion deserialization.
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:
parent
363d24d458
commit
aef2f0799f
|
@ -396,6 +396,7 @@ struct emfplus_object {
|
||||||
GpBrush *brush;
|
GpBrush *brush;
|
||||||
GpPen *pen;
|
GpPen *pen;
|
||||||
GpPath *path;
|
GpPath *path;
|
||||||
|
GpRegion *region;
|
||||||
GpImage *image;
|
GpImage *image;
|
||||||
GpFont *font;
|
GpFont *font;
|
||||||
GpImageAttributes *image_attributes;
|
GpImageAttributes *image_attributes;
|
||||||
|
@ -561,6 +562,30 @@ struct GpRegion{
|
||||||
region_element node;
|
region_element node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct memory_buffer
|
||||||
|
{
|
||||||
|
const BYTE *buffer;
|
||||||
|
INT size, pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void init_memory_buffer(struct memory_buffer *mbuf, const BYTE *buffer, INT size)
|
||||||
|
{
|
||||||
|
mbuf->buffer = buffer;
|
||||||
|
mbuf->size = size;
|
||||||
|
mbuf->pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const void *buffer_read(struct memory_buffer *mbuf, INT size)
|
||||||
|
{
|
||||||
|
if (mbuf->size - mbuf->pos >= size)
|
||||||
|
{
|
||||||
|
const void *data = mbuf->buffer + mbuf->pos;
|
||||||
|
mbuf->pos += size;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
typedef GpStatus (*gdip_format_string_callback)(HDC hdc,
|
typedef GpStatus (*gdip_format_string_callback)(HDC hdc,
|
||||||
GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
|
GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
|
||||||
GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
|
GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
|
||||||
|
|
|
@ -265,6 +265,12 @@ typedef struct EmfPlusPath
|
||||||
BYTE data[1];
|
BYTE data[1];
|
||||||
} EmfPlusPath;
|
} EmfPlusPath;
|
||||||
|
|
||||||
|
typedef struct EmfPlusRegionNodePath
|
||||||
|
{
|
||||||
|
DWORD RegionNodePathLength;
|
||||||
|
EmfPlusPath RegionNodePath;
|
||||||
|
} EmfPlusRegionNodePath;
|
||||||
|
|
||||||
typedef struct EmfPlusRegion
|
typedef struct EmfPlusRegion
|
||||||
{
|
{
|
||||||
DWORD Version;
|
DWORD Version;
|
||||||
|
@ -429,6 +435,9 @@ static void metafile_free_object_table_entry(GpMetafile *metafile, BYTE id)
|
||||||
case ObjectTypePath:
|
case ObjectTypePath:
|
||||||
GdipDeletePath(object->u.path);
|
GdipDeletePath(object->u.path);
|
||||||
break;
|
break;
|
||||||
|
case ObjectTypeRegion:
|
||||||
|
GdipDeleteRegion(object->u.region);
|
||||||
|
break;
|
||||||
case ObjectTypeImage:
|
case ObjectTypeImage:
|
||||||
GdipDisposeImage(object->u.image);
|
GdipDisposeImage(object->u.image);
|
||||||
break;
|
break;
|
||||||
|
@ -1685,6 +1694,132 @@ static GpStatus metafile_deserialize_path(const BYTE *record_data, UINT data_siz
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GpStatus metafile_read_region_node(struct memory_buffer *mbuf, GpRegion *region, region_element *node, UINT *count)
|
||||||
|
{
|
||||||
|
const DWORD *type;
|
||||||
|
GpStatus status;
|
||||||
|
|
||||||
|
type = buffer_read(mbuf, sizeof(*type));
|
||||||
|
if (!type) return Ok;
|
||||||
|
|
||||||
|
node->type = *type;
|
||||||
|
|
||||||
|
switch (node->type)
|
||||||
|
{
|
||||||
|
case CombineModeReplace:
|
||||||
|
case CombineModeIntersect:
|
||||||
|
case CombineModeUnion:
|
||||||
|
case CombineModeXor:
|
||||||
|
case CombineModeExclude:
|
||||||
|
case CombineModeComplement:
|
||||||
|
{
|
||||||
|
region_element *left, *right;
|
||||||
|
|
||||||
|
left = heap_alloc_zero(sizeof(*left));
|
||||||
|
if (!left)
|
||||||
|
return OutOfMemory;
|
||||||
|
|
||||||
|
right = heap_alloc_zero(sizeof(*right));
|
||||||
|
if (!right)
|
||||||
|
{
|
||||||
|
heap_free(left);
|
||||||
|
return OutOfMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = metafile_read_region_node(mbuf, region, left, count);
|
||||||
|
if (status == Ok)
|
||||||
|
{
|
||||||
|
status = metafile_read_region_node(mbuf, region, right, count);
|
||||||
|
if (status == Ok)
|
||||||
|
{
|
||||||
|
node->elementdata.combine.left = left;
|
||||||
|
node->elementdata.combine.right = right;
|
||||||
|
region->num_children += 2;
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_free(left);
|
||||||
|
heap_free(right);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
case RegionDataRect:
|
||||||
|
{
|
||||||
|
const EmfPlusRectF *rect;
|
||||||
|
|
||||||
|
rect = buffer_read(mbuf, sizeof(*rect));
|
||||||
|
if (!rect)
|
||||||
|
return InvalidParameter;
|
||||||
|
|
||||||
|
memcpy(&node->elementdata.rect, rect, sizeof(*rect));
|
||||||
|
*count += 1;
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
case RegionDataPath:
|
||||||
|
{
|
||||||
|
const BYTE *path_data;
|
||||||
|
const UINT *data_size;
|
||||||
|
GpPath *path;
|
||||||
|
|
||||||
|
data_size = buffer_read(mbuf, FIELD_OFFSET(EmfPlusRegionNodePath, RegionNodePath));
|
||||||
|
if (!data_size)
|
||||||
|
return InvalidParameter;
|
||||||
|
|
||||||
|
path_data = buffer_read(mbuf, *data_size);
|
||||||
|
if (!path_data)
|
||||||
|
return InvalidParameter;
|
||||||
|
|
||||||
|
status = metafile_deserialize_path(path_data, *data_size, &path);
|
||||||
|
if (status == Ok)
|
||||||
|
{
|
||||||
|
node->elementdata.path = path;
|
||||||
|
*count += 1;
|
||||||
|
}
|
||||||
|
return Ok;
|
||||||
|
}
|
||||||
|
case RegionDataEmptyRect:
|
||||||
|
case RegionDataInfiniteRect:
|
||||||
|
*count += 1;
|
||||||
|
return Ok;
|
||||||
|
default:
|
||||||
|
FIXME("element type %#x is not supported\n", *type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GpStatus metafile_deserialize_region(const BYTE *record_data, UINT data_size, GpRegion **region)
|
||||||
|
{
|
||||||
|
struct memory_buffer mbuf;
|
||||||
|
GpStatus status;
|
||||||
|
UINT count;
|
||||||
|
|
||||||
|
*region = NULL;
|
||||||
|
|
||||||
|
init_memory_buffer(&mbuf, record_data, data_size);
|
||||||
|
|
||||||
|
if (!buffer_read(&mbuf, FIELD_OFFSET(EmfPlusRegion, RegionNode)))
|
||||||
|
return InvalidParameter;
|
||||||
|
|
||||||
|
status = GdipCreateRegion(region);
|
||||||
|
if (status != Ok)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
status = metafile_read_region_node(&mbuf, *region, &(*region)->node, &count);
|
||||||
|
if (status == Ok && !count)
|
||||||
|
status = InvalidParameter;
|
||||||
|
|
||||||
|
if (status != Ok)
|
||||||
|
{
|
||||||
|
GdipDeleteRegion(*region);
|
||||||
|
*region = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_size, GpBrush **brush)
|
static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_size, GpBrush **brush)
|
||||||
{
|
{
|
||||||
static const UINT header_size = FIELD_OFFSET(EmfPlusBrush, BrushData);
|
static const UINT header_size = FIELD_OFFSET(EmfPlusBrush, BrushData);
|
||||||
|
@ -1935,6 +2070,9 @@ static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT d
|
||||||
case ObjectTypePath:
|
case ObjectTypePath:
|
||||||
status = metafile_deserialize_path(record_data, data_size, (GpPath **)&object);
|
status = metafile_deserialize_path(record_data, data_size, (GpPath **)&object);
|
||||||
break;
|
break;
|
||||||
|
case ObjectTypeRegion:
|
||||||
|
status = metafile_deserialize_region(record_data, data_size, (GpRegion **)&object);
|
||||||
|
break;
|
||||||
case ObjectTypeImage:
|
case ObjectTypeImage:
|
||||||
status = metafile_deserialize_image(record_data, data_size, (GpImage **)&object);
|
status = metafile_deserialize_image(record_data, data_size, (GpImage **)&object);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -76,12 +76,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
|
||||||
|
|
||||||
#define FLAGS_INTPATH 0x4000
|
#define FLAGS_INTPATH 0x4000
|
||||||
|
|
||||||
struct memory_buffer
|
|
||||||
{
|
|
||||||
const BYTE *buffer;
|
|
||||||
INT size, pos;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct region_header
|
struct region_header
|
||||||
{
|
{
|
||||||
DWORD magic;
|
DWORD magic;
|
||||||
|
@ -778,24 +772,6 @@ GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
|
||||||
return Ok;
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void init_memory_buffer(struct memory_buffer *mbuf, const BYTE *buffer, INT size)
|
|
||||||
{
|
|
||||||
mbuf->buffer = buffer;
|
|
||||||
mbuf->size = size;
|
|
||||||
mbuf->pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline const void *buffer_read(struct memory_buffer *mbuf, INT size)
|
|
||||||
{
|
|
||||||
if (mbuf->size - mbuf->pos >= size)
|
|
||||||
{
|
|
||||||
const void *data = mbuf->buffer + mbuf->pos;
|
|
||||||
mbuf->pos += size;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GpStatus read_element(struct memory_buffer *mbuf, GpRegion *region, region_element *node, INT *count)
|
static GpStatus read_element(struct memory_buffer *mbuf, GpRegion *region, region_element *node, INT *count)
|
||||||
{
|
{
|
||||||
GpStatus status;
|
GpStatus status;
|
||||||
|
|
|
@ -2170,7 +2170,7 @@ static const emfplus_record clipping_records[] = {
|
||||||
{ EmfPlusRecordTypeRestore },
|
{ EmfPlusRecordTypeRestore },
|
||||||
{ EmfPlusRecordTypeSetClipRect, 0x300 },
|
{ EmfPlusRecordTypeSetClipRect, 0x300 },
|
||||||
{ EmfPlusRecordTypeFillRects, 0xc000 },
|
{ EmfPlusRecordTypeFillRects, 0xc000 },
|
||||||
{ EmfPlusRecordTypeObject, ObjectTypeRegion << 8, 0, 1 },
|
{ EmfPlusRecordTypeObject, ObjectTypeRegion << 8 },
|
||||||
{ EmfPlusRecordTypeSetClipRegion, 0x100, 0, 1 },
|
{ EmfPlusRecordTypeSetClipRegion, 0x100, 0, 1 },
|
||||||
{ EmfPlusRecordTypeEndOfFile },
|
{ EmfPlusRecordTypeEndOfFile },
|
||||||
{ EMR_EOF },
|
{ EMR_EOF },
|
||||||
|
|
Loading…
Reference in a new issue