mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-01 10:44:47 +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
4 changed files with 164 additions and 25 deletions
|
@ -396,6 +396,7 @@ struct emfplus_object {
|
|||
GpBrush *brush;
|
||||
GpPen *pen;
|
||||
GpPath *path;
|
||||
GpRegion *region;
|
||||
GpImage *image;
|
||||
GpFont *font;
|
||||
GpImageAttributes *image_attributes;
|
||||
|
@ -561,6 +562,30 @@ struct GpRegion{
|
|||
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,
|
||||
GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
|
||||
GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
|
||||
|
|
|
@ -265,6 +265,12 @@ typedef struct EmfPlusPath
|
|||
BYTE data[1];
|
||||
} EmfPlusPath;
|
||||
|
||||
typedef struct EmfPlusRegionNodePath
|
||||
{
|
||||
DWORD RegionNodePathLength;
|
||||
EmfPlusPath RegionNodePath;
|
||||
} EmfPlusRegionNodePath;
|
||||
|
||||
typedef struct EmfPlusRegion
|
||||
{
|
||||
DWORD Version;
|
||||
|
@ -429,6 +435,9 @@ static void metafile_free_object_table_entry(GpMetafile *metafile, BYTE id)
|
|||
case ObjectTypePath:
|
||||
GdipDeletePath(object->u.path);
|
||||
break;
|
||||
case ObjectTypeRegion:
|
||||
GdipDeleteRegion(object->u.region);
|
||||
break;
|
||||
case ObjectTypeImage:
|
||||
GdipDisposeImage(object->u.image);
|
||||
break;
|
||||
|
@ -1685,6 +1694,132 @@ static GpStatus metafile_deserialize_path(const BYTE *record_data, UINT data_siz
|
|||
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 const UINT header_size = FIELD_OFFSET(EmfPlusBrush, BrushData);
|
||||
|
@ -1935,6 +2070,9 @@ static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT d
|
|||
case ObjectTypePath:
|
||||
status = metafile_deserialize_path(record_data, data_size, (GpPath **)&object);
|
||||
break;
|
||||
case ObjectTypeRegion:
|
||||
status = metafile_deserialize_region(record_data, data_size, (GpRegion **)&object);
|
||||
break;
|
||||
case ObjectTypeImage:
|
||||
status = metafile_deserialize_image(record_data, data_size, (GpImage **)&object);
|
||||
break;
|
||||
|
|
|
@ -76,12 +76,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
|
|||
|
||||
#define FLAGS_INTPATH 0x4000
|
||||
|
||||
struct memory_buffer
|
||||
{
|
||||
const BYTE *buffer;
|
||||
INT size, pos;
|
||||
};
|
||||
|
||||
struct region_header
|
||||
{
|
||||
DWORD magic;
|
||||
|
@ -778,24 +772,6 @@ GpStatus WINGDIPAPI GdipGetRegionData(GpRegion *region, BYTE *buffer, UINT size,
|
|||
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)
|
||||
{
|
||||
GpStatus status;
|
||||
|
|
|
@ -2170,7 +2170,7 @@ static const emfplus_record clipping_records[] = {
|
|||
{ EmfPlusRecordTypeRestore },
|
||||
{ EmfPlusRecordTypeSetClipRect, 0x300 },
|
||||
{ EmfPlusRecordTypeFillRects, 0xc000 },
|
||||
{ EmfPlusRecordTypeObject, ObjectTypeRegion << 8, 0, 1 },
|
||||
{ EmfPlusRecordTypeObject, ObjectTypeRegion << 8 },
|
||||
{ EmfPlusRecordTypeSetClipRegion, 0x100, 0, 1 },
|
||||
{ EmfPlusRecordTypeEndOfFile },
|
||||
{ EMR_EOF },
|
||||
|
|
Loading…
Reference in a new issue