From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/gdiplus/metafile.c | 165 +++++++++++++++++++++++++++++++++- dlls/gdiplus/tests/metafile.c | 1 - 2 files changed, 164 insertions(+), 2 deletions(-)
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index 92c818afbac..13450954c5c 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -2340,6 +2340,163 @@ static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_si return status; }
+static GpStatus metafile_deserialize_custom_line_cap(const BYTE *record_data, UINT data_size, GpCustomLineCap **cap) +{ + EmfPlusCustomStartCapData *custom_cap_data = (EmfPlusCustomStartCapData *)record_data; + EmfPlusCustomLineCap *line_cap; + GpStatus status; + UINT offset; + + *cap = NULL; + + if (data_size < FIELD_OFFSET(EmfPlusCustomStartCapData, data)) + return InvalidParameter; + if (data_size < FIELD_OFFSET(EmfPlusCustomStartCapData, data) + custom_cap_data->CustomStartCapSize) + return InvalidParameter; + offset = FIELD_OFFSET(EmfPlusCustomStartCapData, data); + line_cap = (EmfPlusCustomLineCap *)(record_data + offset); + + if (data_size < offset + FIELD_OFFSET(EmfPlusCustomLineCap, CustomLineCapData)) + return InvalidParameter; + offset += FIELD_OFFSET(EmfPlusCustomLineCap, CustomLineCapData); + + if (line_cap->Type == CustomLineCapTypeAdjustableArrow) + { + EmfPlusCustomLineCapArrowData *arrow_data; + GpAdjustableArrowCap *arrow_cap; + + arrow_data = (EmfPlusCustomLineCapArrowData *)(record_data + offset); + + if (data_size < offset + sizeof(EmfPlusCustomLineCapArrowData)) + return InvalidParameter; + + if ((status = GdipCreateAdjustableArrowCap(arrow_data->Height, arrow_data->Width, + arrow_data->FillState, &arrow_cap))) + return status; + + if ((status = GdipSetAdjustableArrowCapMiddleInset(arrow_cap, arrow_data->MiddleInset))) + goto arrow_cap_failed; + if ((status = GdipSetCustomLineCapStrokeCaps((GpCustomLineCap *)arrow_cap, arrow_data->LineStartCap, arrow_data->LineEndCap))) + goto arrow_cap_failed; + if ((status = GdipSetCustomLineCapStrokeJoin((GpCustomLineCap *)arrow_cap, arrow_data->LineJoin))) + goto arrow_cap_failed; + if ((status = GdipSetCustomLineCapWidthScale((GpCustomLineCap *)arrow_cap, arrow_data->WidthScale))) + goto arrow_cap_failed; + + *cap = (GpCustomLineCap *)arrow_cap; + return Ok; + + arrow_cap_failed: + GdipDeleteCustomLineCap((GpCustomLineCap *)arrow_cap); + return status; + } + else + { + EmfPlusCustomLineCapData *line_cap_data; + GpCustomLineCap *line_cap; + unsigned int point_size; + EmfPlusPath *path; + BYTE *types; + + line_cap_data = (EmfPlusCustomLineCapData *)(record_data + offset); + + if (data_size < offset + FIELD_OFFSET(EmfPlusCustomLineCapData, OptionalData)) + return InvalidParameter; + offset += FIELD_OFFSET(EmfPlusCustomLineCapData, OptionalData); + + if (line_cap_data->CustomLineCapDataFlags == CustomLineCapDataFillPath) + { + EmfPlusCustomLineCapDataFillPath *fill_path = (EmfPlusCustomLineCapDataFillPath *)(record_data + offset); + + if (data_size < offset + FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath, FillPath)) + return InvalidParameter; + if (data_size < offset + fill_path->FillPathLength) + return InvalidParameter; + offset += FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath, FillPath); + path = (EmfPlusPath *)(record_data + offset); + } + else + { + EmfPlusCustomLineCapDataLinePath *line_path = (EmfPlusCustomLineCapDataLinePath *)(record_data + offset); + + if (data_size < offset + FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath, LinePath)) + return InvalidParameter; + if (data_size < offset + line_path->LinePathLength) + return InvalidParameter; + + offset += FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath, LinePath); + path = (EmfPlusPath *)(record_data + offset); + } + + if (path->PathPointFlags & 0x800) /* R */ + { + FIXME("RLE encoded path data is not supported.\n"); + return NotImplemented; + } + + if (path->PathPointFlags & 0x4000) /* C */ + point_size = sizeof(EmfPlusPoint); + else + point_size = sizeof(EmfPlusPointF); + + if (data_size < offset + FIELD_OFFSET(EmfPlusPath, data)) + return InvalidParameter; + if (data_size < offset + FIELD_OFFSET(EmfPlusPath, data) + path->PathPointCount * (point_size + sizeof(BYTE))) + return InvalidParameter; + + line_cap = heap_alloc_zero(sizeof(GpCustomLineCap)); + if (!line_cap) + return OutOfMemory; + + line_cap->pathdata.Points = heap_alloc_zero(path->PathPointCount * sizeof(PointF)); + if (!line_cap->pathdata.Points) + { + heap_free(line_cap); + return OutOfMemory; + } + line_cap->pathdata.Types = heap_alloc_zero(path->PathPointCount * sizeof(BYTE)); + if (!line_cap->pathdata.Types) + { + heap_free(line_cap->pathdata.Points); + heap_free(line_cap); + return OutOfMemory; + } + + if (path->PathPointFlags & 0x4000) /* C */ + { + EmfPlusPoint *points = (EmfPlusPoint *)((BYTE *)path + FIELD_OFFSET(EmfPlusPath, data)); + int i; + + for (i = 0; i < path->PathPointCount; i++) + { + line_cap->pathdata.Points[i].X = points[i].X; + line_cap->pathdata.Points[i].Y = points[i].Y; + } + types = (BYTE *)(points + path->PathPointCount); + } + else + { + EmfPlusPointF *points = (EmfPlusPointF *)((BYTE *)path + FIELD_OFFSET(EmfPlusPath, data)); + + memcpy(line_cap->pathdata.Points, points, path->PathPointCount * point_size); + types = (BYTE *)(points + path->PathPointCount); + } + + memcpy(line_cap->pathdata.Types, types, path->PathPointCount * sizeof(BYTE)); + line_cap->pathdata.Count = path->PathPointCount; + line_cap->type = CustomLineCapTypeDefault; + line_cap->fill = line_cap_data->CustomLineCapDataFlags == CustomLineCapDataFillPath; + line_cap->basecap = line_cap_data->BaseCap; + line_cap->inset = line_cap_data->BaseInset; + line_cap->strokeStartCap = line_cap_data->StrokeStartCap; + line_cap->strokeEndCap = line_cap_data->StrokeEndCap; + line_cap->join = line_cap_data->StrokeJoin; + line_cap->scale = line_cap_data->WidthScale; + *cap = line_cap; + return Ok; + } +} + static GpStatus metafile_get_pen_brush_data_offset(EmfPlusPen *data, UINT data_size, DWORD *ret) { EmfPlusPenData *pendata = (EmfPlusPenData *)data->data; @@ -2446,6 +2603,7 @@ static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT d { EmfPlusPen *data = (EmfPlusPen *)record_data; EmfPlusPenData *pendata = (EmfPlusPenData *)data->data; + GpCustomLineCap *custom_line_cap; GpBrush *brush; DWORD offset; GpPen *pen; @@ -2542,7 +2700,12 @@ static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT d if (pendata->PenDataFlags & PenDataCustomStartCap) { EmfPlusCustomStartCapData *startcap = (EmfPlusCustomStartCapData *)((BYTE *)pendata + offset); - FIXME("PenDataCustomStartCap is not supported.\n"); + if ((status = metafile_deserialize_custom_line_cap((BYTE *)startcap, data_size, &custom_line_cap)) != Ok) + goto penfailed; + status = GdipSetPenCustomStartCap(pen, custom_line_cap); + GdipDeleteCustomLineCap(custom_line_cap); + if (status != Ok) + goto penfailed; offset += FIELD_OFFSET(EmfPlusCustomStartCapData, data) + startcap->CustomStartCapSize; }
diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index ceca8e4a9bb..4e4277d4d1f 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -3983,7 +3983,6 @@ static void test_pen(void)
stat = GdipBitmapGetPixel(bitmap, 10, 10, &color); expect(Ok, stat); - todo_wine expect(0xffff0000, color);
stat = GdipBitmapGetPixel(bitmap, 40, 90, &color);