Fix Cafe Stella (SteamID: 1829980) Flowchart crashes once there are 2 things on it.
-- v6: gdiplus: Support playing back pen custom end line cap. gdiplus: Support playing back pen custom start line cap.
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/gdiplus/tests/metafile.c | 126 ++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+)
diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index aa844a62ff9..ceca8e4a9bb 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -3874,6 +3874,131 @@ static void test_setclippath(void) expect(Ok, stat); }
+static const emfplus_record pen_dc_records[] = +{ + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeObject, ObjectTypePen << 8 }, + { EmfPlusRecordTypeObject, (ObjectTypePath << 8) | 1 }, + { EmfPlusRecordTypeDrawPath, 1 }, + { EMR_SAVEDC, 0, 1 }, + { EMR_SETICMMODE, 0, 1 }, + { EMR_BITBLT, 0, 1 }, + { EMR_RESTOREDC, 0, 1 }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 } +}; + +static const emfplus_record pen_bitmap_records[] = +{ + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeObject, ObjectTypePen << 8 }, + { EmfPlusRecordTypeObject, (ObjectTypePath << 8) | 1 }, + { EmfPlusRecordTypeDrawPath, 1 }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 } +}; + +static void test_pen(void) +{ + static const GpPointF dst_points[3] = {{0.0, 0.0}, {100.0, 0.0}, {0.0, 100.0}}; + static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; + GpMetafile *metafile, *clone_metafile; + GpPath *draw_path, *line_cap_path; + GpCustomLineCap *custom_line_cap; + GpGraphics *graphics; + HENHMETAFILE hemf; + GpBitmap *bitmap; + GpStatus stat; + ARGB color; + GpPen *pen; + BOOL ret; + HDC hdc; + + /* Record */ + hdc = CreateCompatibleDC(0); + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(Ok, stat); + DeleteDC(hdc); + + stat = GdipGetImageGraphicsContext((GpImage *)metafile, &graphics); + expect(Ok, stat); + + stat = GdipCreatePath(FillModeAlternate, &draw_path); + expect(Ok, stat); + stat = GdipAddPathLine(draw_path, 25, 25, 25, 75); + expect(Ok, stat); + + stat = GdipCreatePen1((ARGB)0xffff0000, 1.0f, UnitPixel, &pen); + expect(Ok, stat); + stat = GdipCreatePath(FillModeAlternate, &line_cap_path); + expect(Ok, stat); + stat = GdipAddPathRectangle(line_cap_path, 5.0, 5.0, 10.0, 10.0); + expect(Ok, stat); + stat = GdipCreateCustomLineCap(NULL, line_cap_path, LineCapCustom, 0.0, &custom_line_cap); + expect(Ok, stat); + stat = GdipSetPenCustomStartCap(pen, custom_line_cap); + expect(Ok, stat); + stat = GdipSetPenCustomEndCap(pen, custom_line_cap); + expect(Ok, stat); + stat = GdipDeleteCustomLineCap(custom_line_cap); + expect(Ok, stat); + stat = GdipDeletePath(line_cap_path); + expect(Ok, stat); + + stat = GdipDrawPath(graphics, pen, draw_path); + expect(Ok, stat); + + stat = GdipDeletePen(pen); + expect(Ok, stat); + stat = GdipDeletePath(draw_path); + expect(Ok, stat); + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + + sync_metafile(&metafile, "pen.emf"); + GdipCloneImage((GpImage *)metafile, (GpImage **)&clone_metafile); + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(Ok, stat); + + check_emfplus(hemf, pen_dc_records, "pen record"); + + ret = DeleteEnhMetaFile(hemf); + ok(ret != 0, "Failed to delete enhmetafile.\n"); + stat = GdipDisposeImage((GpImage *)metafile); + expect(Ok, stat); + + /* Play back */ + stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat24bppRGB, NULL, &bitmap); + expect(Ok, stat); + + stat = GdipGetImageGraphicsContext((GpImage *)bitmap, &graphics); + expect(Ok, stat); + + play_metafile(clone_metafile, graphics, pen_bitmap_records, "pen playback", dst_points, &frame, UnitPixel); + + stat = GdipBitmapGetPixel(bitmap, 10, 10, &color); + expect(Ok, stat); + todo_wine + expect(0xffff0000, color); + + stat = GdipBitmapGetPixel(bitmap, 40, 90, &color); + expect(Ok, stat); + todo_wine + expect(0xffff0000, color); + + stat = GdipDisposeImage((GpImage *)clone_metafile); + expect(Ok, stat); + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + stat = GdipDisposeImage((GpImage *)bitmap); + expect(Ok, stat); +} + START_TEST(metafile) { struct GdiplusStartupInput gdiplusStartupInput; @@ -3934,6 +4059,7 @@ START_TEST(metafile) test_offsetclip(); test_resetclip(); test_setclippath(); + test_pen();
GdiplusShutdown(gdiplusToken); }
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/gdiplus/metafile.c | 223 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 208 insertions(+), 15 deletions(-)
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index 90ef39e34d6..26f17ad6182 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -46,6 +46,12 @@ HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**);
typedef ARGB EmfPlusARGB;
+typedef struct EmfPlusPointF +{ + float X; + float Y; +} EmfPlusPointF; + typedef struct EmfPlusRecordHeader { WORD Type; @@ -177,6 +183,12 @@ enum PenDataFlags PenDataCustomEndCap = 0x1000 };
+enum CustomLineCapData +{ + CustomLineCapDataFillPath = 0x1, + CustomLineCapDataLinePath = 0x2, +}; + typedef struct EmfPlusTransformMatrix { REAL TransformMatrix[6]; @@ -287,14 +299,20 @@ typedef struct EmfPlusBrush } BrushData; } EmfPlusBrush;
-typedef struct EmfPlusPen -{ - DWORD Version; - DWORD Type; - /* EmfPlusPenData */ - /* EmfPlusBrush */ - BYTE data[1]; -} EmfPlusPen; +typedef struct EmfPlusCustomLineCapArrowData +{ + REAL Width; + REAL Height; + REAL MiddleInset; + BOOL FillState; + DWORD LineStartCap; + DWORD LineEndCap; + DWORD LineJoin; + REAL LineMiterLimit; + REAL WidthScale; + EmfPlusPointF FillHotSpot; + EmfPlusPointF LineHotSpot; +} EmfPlusCustomLineCapArrowData;
typedef struct EmfPlusPath { @@ -307,6 +325,55 @@ typedef struct EmfPlusPath BYTE data[1]; } EmfPlusPath;
+typedef struct EmfPlusCustomLineCapDataFillPath +{ + INT FillPathLength; + /* EmfPlusPath */ + BYTE FillPath[1]; +} EmfPlusCustomLineCapDataFillPath; + +typedef struct EmfPlusCustomLineCapDataLinePath +{ + INT LinePathLength; + /* EmfPlusPath */ + BYTE LinePath[1]; +} EmfPlusCustomLineCapDataLinePath; + +typedef struct EmfPlusCustomLineCapData +{ + DWORD CustomLineCapDataFlags; + DWORD BaseCap; + REAL BaseInset; + DWORD StrokeStartCap; + DWORD StrokeEndCap; + DWORD StrokeJoin; + REAL StrokeMiterLimit; + REAL WidthScale; + EmfPlusPointF FillHotSpot; + EmfPlusPointF LineHotSpot; + /* EmfPlusCustomLineCapDataFillPath */ + /* EmfPlusCustomLineCapDataLinePath */ + BYTE OptionalData[1]; +} EmfPlusCustomLineCapData; + +typedef struct EmfPlusCustomLineCap +{ + DWORD Version; + DWORD Type; + /* EmfPlusCustomLineCapArrowData */ + /* EmfPlusCustomLineCapData */ + BYTE CustomLineCapData[1]; +} EmfPlusCustomLineCap; + +typedef struct EmfPlusPen +{ + DWORD Version; + DWORD Type; + /* EmfPlusPenData */ + /* EmfPlusBrush */ + BYTE data[1]; +} EmfPlusPen; + typedef struct EmfPlusRegionNodePath { DWORD RegionNodePathLength; @@ -416,12 +483,6 @@ typedef struct EmfPlusPoint short Y; } EmfPlusPoint;
-typedef struct EmfPlusPointF -{ - float X; - float Y; -} EmfPlusPointF; - typedef struct EmfPlusDrawImage { EmfPlusRecordHeader Header; @@ -1055,6 +1116,127 @@ static void METAFILE_FillBrushData(GDIPCONST GpBrush *brush, EmfPlusBrush *data) } }
+static void METAFILE_PrepareCustomLineCapData(GDIPCONST GpCustomLineCap *cap, DWORD *ret_cap_size, + DWORD *ret_cap_data_size, DWORD *ret_path_size) +{ + DWORD cap_size, path_size = 0; + + /* EmfPlusCustomStartCapData */ + cap_size = FIELD_OFFSET(EmfPlusCustomStartCapData, data); + /* -> EmfPlusCustomLineCap */ + cap_size += FIELD_OFFSET(EmfPlusCustomLineCap, CustomLineCapData); + /* -> EmfPlusCustomLineCapArrowData */ + if (cap->type == CustomLineCapTypeAdjustableArrow) + cap_size += sizeof(EmfPlusCustomLineCapArrowData); + /* -> EmfPlusCustomLineCapData */ + else + { + /* -> EmfPlusCustomLineCapOptionalData */ + cap_size += FIELD_OFFSET(EmfPlusCustomLineCapData, OptionalData); + if (cap->fill) + /* -> EmfPlusCustomLineCapDataFillPath */ + cap_size += FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath, FillPath); + else + /* -> EmfPlusCustomLineCapDataLinePath */ + cap_size += FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath, LinePath); + + /* -> EmfPlusPath in EmfPlusCustomLineCapDataFillPath and EmfPlusCustomLineCapDataLinePath */ + path_size = FIELD_OFFSET(EmfPlusPath, data); + path_size += sizeof(PointF) * cap->pathdata.Count; + path_size += sizeof(BYTE) * cap->pathdata.Count; + path_size = (path_size + 3) & ~3; + + cap_size += path_size; + } + + *ret_cap_size = cap_size; + *ret_cap_data_size = cap_size - FIELD_OFFSET(EmfPlusCustomStartCapData, data); + *ret_path_size = path_size; +} + +static void METAFILE_FillCustomLineCapData(GDIPCONST GpCustomLineCap *cap, BYTE *ptr, + REAL line_miter_limit, DWORD data_size, DWORD path_size) +{ + EmfPlusCustomStartCapData *cap_data; + EmfPlusCustomLineCap *line_cap; + DWORD i; + + cap_data = (EmfPlusCustomStartCapData *)ptr; + cap_data->CustomStartCapSize = data_size; + i = FIELD_OFFSET(EmfPlusCustomStartCapData, data); + + line_cap = (EmfPlusCustomLineCap *)(ptr + i); + line_cap->Version = VERSION_MAGIC2; + line_cap->Type = cap->type; + i += FIELD_OFFSET(EmfPlusCustomLineCap, CustomLineCapData); + + if (cap->type == CustomLineCapTypeAdjustableArrow) + { + EmfPlusCustomLineCapArrowData *arrow_data; + GpAdjustableArrowCap *arrow_cap; + + arrow_data = (EmfPlusCustomLineCapArrowData *)(ptr + i); + arrow_cap = (GpAdjustableArrowCap *)cap; + arrow_data->Width = arrow_cap->width; + arrow_data->Height = arrow_cap->height; + arrow_data->MiddleInset = arrow_cap->middle_inset; + arrow_data->FillState = arrow_cap->cap.fill; + arrow_data->LineStartCap = arrow_cap->cap.strokeStartCap; + arrow_data->LineEndCap = arrow_cap->cap.strokeEndCap; + arrow_data->LineJoin = arrow_cap->cap.join; + arrow_data->LineMiterLimit = line_miter_limit; + arrow_data->WidthScale = arrow_cap->cap.scale; + arrow_data->FillHotSpot.X = 0; + arrow_data->FillHotSpot.Y = 0; + arrow_data->LineHotSpot.X = 0; + arrow_data->LineHotSpot.Y = 0; + } + else + { + EmfPlusCustomLineCapData *line_cap_data = (EmfPlusCustomLineCapData *)(ptr + i); + EmfPlusPath *path; + + if (cap->fill) + line_cap_data->CustomLineCapDataFlags = CustomLineCapDataFillPath; + else + line_cap_data->CustomLineCapDataFlags = CustomLineCapDataLinePath; + line_cap_data->BaseCap = cap->basecap; + line_cap_data->BaseInset = cap->inset; + line_cap_data->StrokeStartCap = cap->strokeStartCap; + line_cap_data->StrokeEndCap = cap->strokeEndCap; + line_cap_data->StrokeJoin = cap->join; + line_cap_data->StrokeMiterLimit = line_miter_limit; + line_cap_data->WidthScale = cap->scale; + line_cap_data->FillHotSpot.X = 0; + line_cap_data->FillHotSpot.Y = 0; + line_cap_data->LineHotSpot.X = 0; + line_cap_data->LineHotSpot.Y = 0; + i += FIELD_OFFSET(EmfPlusCustomLineCapData, OptionalData); + + if (cap->fill) + { + EmfPlusCustomLineCapDataFillPath *fill_path = (EmfPlusCustomLineCapDataFillPath *)(ptr + i); + fill_path->FillPathLength = path_size; + i += FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath, FillPath); + } + else + { + EmfPlusCustomLineCapDataLinePath *line_path = (EmfPlusCustomLineCapDataLinePath *)(ptr + i); + line_path->LinePathLength = path_size; + i += FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath, LinePath); + } + + path = (EmfPlusPath *)(ptr + i); + path->Version = VERSION_MAGIC2; + path->PathPointCount = cap->pathdata.Count; + path->PathPointFlags = 0; + i += FIELD_OFFSET(EmfPlusPath, data); + memcpy(ptr + i, cap->pathdata.Points, cap->pathdata.Count * sizeof(PointF)); + i += cap->pathdata.Count * sizeof(PointF); + memcpy(ptr + i, cap->pathdata.Types, cap->pathdata.Count * sizeof(BYTE)); + } +} + static GpStatus METAFILE_AddBrushObject(GpMetafile *metafile, GDIPCONST GpBrush *brush, DWORD *id) { EmfPlusObject *object_record; @@ -4562,6 +4744,7 @@ static GpStatus METAFILE_AddPathObject(GpMetafile *metafile, GpPath *path, DWORD
static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *id) { + DWORD custom_start_cap_size = 0, custom_start_cap_data_size = 0, custom_start_cap_path_size = 0; DWORD i, data_flags, pen_data_size, brush_size; EmfPlusObject *object_record; EmfPlusPenData *pen_data; @@ -4626,7 +4809,10 @@ static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *i /* TODO: Add support for PenDataCompoundLine */ if (pen->customstart) { - FIXME("ignoring custom start cup\n"); + data_flags |= PenDataCustomStartCap; + METAFILE_PrepareCustomLineCapData(pen->customstart, &custom_start_cap_size, + &custom_start_cap_data_size, &custom_start_cap_path_size); + pen_data_size += custom_start_cap_size; } if (pen->customend) { @@ -4719,6 +4905,13 @@ static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *i *(REAL*)(pen_data->OptionalData + i) = pen->align; i += sizeof(DWORD); } + if (data_flags & PenDataCustomStartCap) + { + METAFILE_FillCustomLineCapData(pen->customstart, pen_data->OptionalData + i, + pen->miterlimit, custom_start_cap_data_size, + custom_start_cap_path_size); + i += custom_start_cap_size; + }
METAFILE_FillBrushData(pen->brush, (EmfPlusBrush*)(object_record->ObjectData.pen.data + pen_data_size));
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/gdiplus/metafile.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index 26f17ad6182..92c818afbac 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -4745,6 +4745,7 @@ static GpStatus METAFILE_AddPathObject(GpMetafile *metafile, GpPath *path, DWORD static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *id) { DWORD custom_start_cap_size = 0, custom_start_cap_data_size = 0, custom_start_cap_path_size = 0; + DWORD custom_end_cap_size = 0, custom_end_cap_data_size = 0, custom_end_cap_path_size = 0; DWORD i, data_flags, pen_data_size, brush_size; EmfPlusObject *object_record; EmfPlusPenData *pen_data; @@ -4816,7 +4817,10 @@ static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *i } if (pen->customend) { - FIXME("ignoring custom end cup\n"); + data_flags |= PenDataCustomEndCap; + METAFILE_PrepareCustomLineCapData(pen->customend, &custom_end_cap_size, + &custom_end_cap_data_size, &custom_end_cap_path_size); + pen_data_size += custom_end_cap_size; }
stat = METAFILE_PrepareBrushData(pen->brush, &brush_size); @@ -4912,6 +4916,13 @@ static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *i custom_start_cap_path_size); i += custom_start_cap_size; } + if (data_flags & PenDataCustomEndCap) + { + METAFILE_FillCustomLineCapData(pen->customend, pen_data->OptionalData + i, + pen->miterlimit, custom_end_cap_data_size, + custom_end_cap_path_size); + i += custom_end_cap_size; + }
METAFILE_FillBrushData(pen->brush, (EmfPlusBrush*)(object_record->ObjectData.pen.data + pen_data_size));
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/gdiplus/metafile.c | 124 +++++++++++++++++++++++++++++++++- dlls/gdiplus/tests/metafile.c | 1 - 2 files changed, 123 insertions(+), 2 deletions(-)
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index 92c818afbac..87ab0d3089b 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -2340,6 +2340,122 @@ 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 + { + GpPath *path, *fill_path = NULL, *stroke_path = NULL; + EmfPlusCustomLineCapData *line_cap_data; + GpCustomLineCap *line_cap; + GpStatus status; + + 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); + } + 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); + } + + if ((status = metafile_deserialize_path(record_data + offset, data_size - offset, &path))) + return status; + + if (line_cap_data->CustomLineCapDataFlags == CustomLineCapDataFillPath) + fill_path = path; + else + stroke_path = path; + + if ((status = GdipCreateCustomLineCap(fill_path, stroke_path, line_cap_data->BaseCap, + line_cap_data->BaseInset, &line_cap))) + goto default_cap_failed; + if ((status = GdipSetCustomLineCapStrokeCaps(line_cap, line_cap_data->StrokeStartCap, line_cap_data->StrokeEndCap))) + goto default_cap_failed; + if ((status = GdipSetCustomLineCapStrokeJoin(line_cap, line_cap_data->StrokeJoin))) + goto default_cap_failed; + if ((status = GdipSetCustomLineCapWidthScale(line_cap, line_cap_data->WidthScale))) + goto default_cap_failed; + + GdipDeletePath(path); + *cap = line_cap; + return Ok; + + default_cap_failed: + if (line_cap) + GdipDeleteCustomLineCap(line_cap); + GdipDeletePath(path); + return status; + } +} + static GpStatus metafile_get_pen_brush_data_offset(EmfPlusPen *data, UINT data_size, DWORD *ret) { EmfPlusPenData *pendata = (EmfPlusPenData *)data->data; @@ -2446,6 +2562,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 +2659,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);
From: Zhiyi Zhang zzhang@codeweavers.com
Fix Cafe Stella (SteamID: 1829980) Flowchart crashes once there are 2 things on it. --- dlls/gdiplus/metafile.c | 7 ++++++- dlls/gdiplus/tests/metafile.c | 1 - 2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index 87ab0d3089b..dff9e5ed189 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -2671,7 +2671,12 @@ static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT d if (pendata->PenDataFlags & PenDataCustomEndCap) { EmfPlusCustomEndCapData *endcap = (EmfPlusCustomEndCapData *)((BYTE *)pendata + offset); - FIXME("PenDataCustomEndCap is not supported.\n"); + if ((status = metafile_deserialize_custom_line_cap((BYTE *)endcap, data_size, &custom_line_cap)) != Ok) + goto penfailed; + status = GdipSetPenCustomEndCap(pen, custom_line_cap); + GdipDeleteCustomLineCap(custom_line_cap); + if (status != Ok) + goto penfailed; offset += FIELD_OFFSET(EmfPlusCustomEndCapData, data) + endcap->CustomEndCapSize; }
diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index 4e4277d4d1f..f6a9f5e54a8 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -3987,7 +3987,6 @@ static void test_pen(void)
stat = GdipBitmapGetPixel(bitmap, 40, 90, &color); expect(Ok, stat); - todo_wine expect(0xffff0000, color);
stat = GdipDisposeImage((GpImage *)clone_metafile);
Esme Povirk (@madewokherd) commented about dlls/gdiplus/metafile.c:
if ((status = GdipCreateCustomLineCap(fill_path, stroke_path, line_cap_data->BaseCap,
line_cap_data->BaseInset, &line_cap)))
goto default_cap_failed;
if ((status = GdipSetCustomLineCapStrokeCaps(line_cap, line_cap_data->StrokeStartCap, line_cap_data->StrokeEndCap)))
goto default_cap_failed;
if ((status = GdipSetCustomLineCapStrokeJoin(line_cap, line_cap_data->StrokeJoin)))
goto default_cap_failed;
if ((status = GdipSetCustomLineCapWidthScale(line_cap, line_cap_data->WidthScale)))
goto default_cap_failed;
GdipDeletePath(path);
*cap = line_cap;
return Ok;
- default_cap_failed:
if (line_cap)
line_cap should be null-initialized. I don't think it's possible for GdipCreateCustomLineCap to return an error to this function without setting the result to NULL, but it shouldn't rely on that.