Signed-off-by: Shawn M. Chapla schapla@codeweavers.com --- dlls/gdiplus/tests/metafile.c | 146 ++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+)
diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index ddb58504c99..bba44d15dae 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -3270,6 +3270,151 @@ static void test_fillregion(void) GdipDisposeImage((GpImage*)metafile); }
+static const emfplus_record lineargradient_records[] = { + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeObject, ObjectTypeBrush << 8, 1 }, + { EmfPlusRecordTypeFillRects, 0x4000, 1 }, + { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 1, 1 }, + { EmfPlusRecordTypeFillRects, 0x4000, 1 }, + { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 2, 1 }, + { EmfPlusRecordTypeFillRects, 0x4000, 1 }, + { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 3, 1 }, + { EmfPlusRecordTypeFillRects, 0x4000, 1 }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 } +}; + +static void test_lineargradient(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}; + static const GpRectF horizrect = {10.0, 10.0, 20.0, 20.0}; + static const GpRectF vertrect = {50.0, 10.0, 20.0, 20.0}; + static const GpRectF blendrect = {10.0, 50.0, 20.0, 20.0}; + static const GpRectF presetrect = {50.0, 50.0, 20.0, 20.0}; + static const REAL blendfac[3] = {0.0, 0.9, 1.0}; + static const REAL blendpos[3] = {0.0, 0.5, 1.0}; + static const ARGB pblendcolor[3] = {0xffff0000, 0xff00ff00, 0xff0000ff}; + static const REAL pblendpos[3] = {0.0, 0.5, 1.0}; + + ARGB color; + GpBitmap *bitmap; + GpBrush *horizbrush, *vertbrush, *blendbrush, *presetbrush; + GpGraphics *graphics; + GpMetafile *metafile; + GpStatus stat; + HDC hdc; + + hdc = CreateCompatibleDC(0); + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, + L"winetest", &metafile); + expect(Ok, stat); + DeleteDC(hdc); + hdc = NULL; + + stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics); + expect(Ok, stat); + + /* Test various brush types to cover all valid combinations + of optional serialized data. */ + stat = GdipCreateLineBrushFromRect(&horizrect, 0xffff0000, 0xff0000ff, + LinearGradientModeHorizontal, WrapModeTile, (GpLineGradient**)&horizbrush); + expect(Ok, stat); + + stat = GdipCreateLineBrushFromRect(&vertrect, 0xffff0000, 0xff0000ff, + LinearGradientModeVertical, WrapModeTile, (GpLineGradient**)&vertbrush); + expect(Ok, stat); + + stat = GdipCreateLineBrushFromRect(&blendrect, 0xffff0000, 0xff0000ff, + LinearGradientModeHorizontal, WrapModeTile, (GpLineGradient**)&blendbrush); + expect(Ok, stat); + + stat = GdipSetLineBlend((GpLineGradient*)blendbrush, blendfac, blendpos, 3); + expect(Ok, stat); + + stat = GdipCreateLineBrushFromRect(&presetrect, 0xffff0000, 0xff0000ff, + LinearGradientModeVertical, WrapModeTile, (GpLineGradient**)&presetbrush); + expect(Ok, stat); + + stat = GdipSetLinePresetBlend((GpLineGradient*)presetbrush, pblendcolor, pblendpos, 3); + expect(Ok, stat); + + stat = GdipFillRectangles(graphics, vertbrush, &vertrect, 1); + todo_wine expect(Ok, stat); + + stat = GdipFillRectangles(graphics, horizbrush, &horizrect, 1); + todo_wine expect(Ok, stat); + + stat = GdipFillRectangles(graphics, blendbrush, &blendrect, 1); + todo_wine expect(Ok, stat); + + stat = GdipFillRectangles(graphics, presetbrush, &presetrect, 1); + todo_wine expect(Ok, stat); + + stat = GdipDeleteGraphics(graphics); + graphics = NULL; + expect(Ok, stat); + + check_metafile(metafile, lineargradient_records, "lineargradient metafile", dst_points, + &frame, UnitPixel); + sync_metafile(&metafile, "lineargradient.emf"); + + stat = GdipCreateBitmapFromScan0(100, 100, 0, PixelFormat32bppARGB, NULL, &bitmap); + expect(Ok, stat); + + stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); + expect(Ok, stat); + + play_metafile(metafile, graphics, lineargradient_records, "lineargradient playback", + dst_points, &frame, UnitPixel); + + /* Verify horizontal gradient fill. */ + stat = GdipBitmapGetPixel(bitmap, 10, 10, &color); + expect(Ok, stat); + todo_wine expect(0xffff0000, color); + + stat = GdipBitmapGetPixel(bitmap, 18, 10, &color); + expect(Ok, stat); + todo_wine expect(0xff990066, color); + + /* Verify vertical gradient fill. */ + stat = GdipBitmapGetPixel(bitmap, 50, 10, &color); + expect(Ok, stat); + todo_wine expect(0xffff0000, color); + + stat = GdipBitmapGetPixel(bitmap, 50, 18, &color); + expect(Ok, stat); + todo_wine expect(0xff990066, color); + + /* Verify custom blend gradient fill. */ + stat = GdipBitmapGetPixel(bitmap, 10, 50, &color); + expect(Ok, stat); + todo_wine expect(0xffff0000, color); + + stat = GdipBitmapGetPixel(bitmap, 18, 50, &color); + expect(Ok, stat); + todo_wine expect(0xff4700b8, color); + + /* Verify preset color gradient fill. */ + stat = GdipBitmapGetPixel(bitmap, 50, 50, &color); + expect(Ok, stat); + todo_wine expect(0xffff0000, color); + + stat = GdipBitmapGetPixel(bitmap, 50, 60, &color); + expect(Ok, stat); + todo_wine expect(0xff00ff00, color); + + GdipDeleteBrush(vertbrush); + GdipDeleteBrush(horizbrush); + GdipDeleteBrush(blendbrush); + GdipDeleteBrush(presetbrush); + GdipDeleteGraphics(graphics); + GdipDisposeImage((GpImage*)bitmap); + GdipDisposeImage((GpImage*)metafile); +} + START_TEST(metafile) { struct GdiplusStartupInput gdiplusStartupInput; @@ -3322,6 +3467,7 @@ START_TEST(metafile) test_drawdriverstring(); test_unknownfontdecode(); test_fillregion(); + test_lineargradient();
GdiplusShutdown(gdiplusToken); }
Signed-off-by: Shawn M. Chapla schapla@codeweavers.com --- dlls/gdiplus/metafile.c | 81 +++++++++++++++++++++++++++++++++++ dlls/gdiplus/tests/metafile.c | 30 ++++++------- 2 files changed, 96 insertions(+), 15 deletions(-)
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index 1d7c0fe3062..ff21b8ed242 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -1036,6 +1036,26 @@ static GpStatus METAFILE_PrepareBrushData(GDIPCONST GpBrush *brush, DWORD *size) case BrushTypeHatchFill: *size = FIELD_OFFSET(EmfPlusBrush, BrushData) + sizeof(EmfPlusHatchBrushData); break; + case BrushTypeLinearGradient: + { + BOOL ignore_xform; + GpLineGradient *gradient = (GpLineGradient*)brush; + + *size = FIELD_OFFSET(EmfPlusBrush, BrushData.lineargradient.OptionalData); + + GdipIsMatrixIdentity(&gradient->transform, &ignore_xform); + if (!ignore_xform) + *size += sizeof(gradient->transform); + + if (gradient->pblendcount > 1 && gradient->pblendcolor && gradient->pblendpos) + *size += sizeof(DWORD) + gradient->pblendcount * + (sizeof(*gradient->pblendcolor) + sizeof(*gradient->pblendpos)); + else if (gradient->blendcount > 1 && gradient->blendfac && gradient->blendpos) + *size += sizeof(DWORD) + gradient->blendcount * + (sizeof(*gradient->blendfac) + sizeof(*gradient->blendpos)); + + break; + } default: FIXME("unsupported brush type: %d\n", brush->bt); return NotImplemented; @@ -1065,6 +1085,67 @@ static void METAFILE_FillBrushData(GDIPCONST GpBrush *brush, EmfPlusBrush *data) data->BrushData.hatch.BackColor = hatch->backcol; break; } + case BrushTypeLinearGradient: + { + BYTE *cursor; + BOOL ignore_xform; + GpLineGradient *gradient = (GpLineGradient*)brush; + + data->BrushData.lineargradient.BrushDataFlags = 0; + data->BrushData.lineargradient.WrapMode = gradient->wrap; + data->BrushData.lineargradient.RectF.X = gradient->rect.X; + data->BrushData.lineargradient.RectF.Y = gradient->rect.Y; + data->BrushData.lineargradient.RectF.Width = gradient->rect.Width; + data->BrushData.lineargradient.RectF.Height = gradient->rect.Height; + data->BrushData.lineargradient.StartColor = gradient->startcolor; + data->BrushData.lineargradient.EndColor = gradient->endcolor; + data->BrushData.lineargradient.Reserved1 = gradient->startcolor; + data->BrushData.lineargradient.Reserved2 = gradient->endcolor; + + if (gradient->gamma) + data->BrushData.lineargradient.BrushDataFlags |= BrushDataIsGammaCorrected; + + cursor = &data->BrushData.lineargradient.OptionalData[0]; + + GdipIsMatrixIdentity(&gradient->transform, &ignore_xform); + if (!ignore_xform) + { + data->BrushData.lineargradient.BrushDataFlags |= BrushDataTransform; + memcpy(cursor, &gradient->transform, sizeof(gradient->transform)); + cursor += sizeof(gradient->transform); + } + + if (gradient->pblendcount > 1 && gradient->pblendcolor && gradient->pblendpos) + { + const DWORD count = gradient->pblendcount; + + data->BrushData.lineargradient.BrushDataFlags |= BrushDataPresetColors; + + memcpy(cursor, &count, sizeof(count)); + cursor += sizeof(count); + + memcpy(cursor, gradient->pblendpos, count * sizeof(*gradient->pblendpos)); + cursor += count * sizeof(*gradient->pblendpos); + + memcpy(cursor, gradient->pblendcolor, count * sizeof(*gradient->pblendcolor)); + } + else if (gradient->blendcount > 1 && gradient->blendfac && gradient->blendpos) + { + const DWORD count = gradient->blendcount; + + data->BrushData.lineargradient.BrushDataFlags |= BrushDataBlendFactorsH; + + memcpy(cursor, &count, sizeof(count)); + cursor += sizeof(count); + + memcpy(cursor, gradient->blendpos, count * sizeof(*gradient->blendpos)); + cursor += count * sizeof(*gradient->blendpos); + + memcpy(cursor, gradient->blendfac, count * sizeof(*gradient->blendfac)); + } + + break; + } default: FIXME("unsupported brush type: %d\n", brush->bt); } diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index bba44d15dae..29113fc3a05 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -3273,14 +3273,14 @@ static void test_fillregion(void) static const emfplus_record lineargradient_records[] = { { EMR_HEADER }, { EmfPlusRecordTypeHeader }, - { EmfPlusRecordTypeObject, ObjectTypeBrush << 8, 1 }, - { EmfPlusRecordTypeFillRects, 0x4000, 1 }, - { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 1, 1 }, - { EmfPlusRecordTypeFillRects, 0x4000, 1 }, - { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 2, 1 }, - { EmfPlusRecordTypeFillRects, 0x4000, 1 }, - { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 3, 1 }, - { EmfPlusRecordTypeFillRects, 0x4000, 1 }, + { EmfPlusRecordTypeObject, ObjectTypeBrush << 8, 0, 1 }, + { EmfPlusRecordTypeFillRects, 0x4000, 0, 1 }, + { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 1, 0, 1 }, + { EmfPlusRecordTypeFillRects, 0x4000, 0, 1 }, + { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 2 }, + { EmfPlusRecordTypeFillRects, 0x4000 }, + { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 3 }, + { EmfPlusRecordTypeFillRects, 0x4000 }, { EmfPlusRecordTypeEndOfFile }, { EMR_EOF }, { 0 } @@ -3342,16 +3342,16 @@ static void test_lineargradient(void) expect(Ok, stat);
stat = GdipFillRectangles(graphics, vertbrush, &vertrect, 1); - todo_wine expect(Ok, stat); + expect(Ok, stat);
stat = GdipFillRectangles(graphics, horizbrush, &horizrect, 1); - todo_wine expect(Ok, stat); + expect(Ok, stat);
stat = GdipFillRectangles(graphics, blendbrush, &blendrect, 1); - todo_wine expect(Ok, stat); + expect(Ok, stat);
stat = GdipFillRectangles(graphics, presetbrush, &presetrect, 1); - todo_wine expect(Ok, stat); + expect(Ok, stat);
stat = GdipDeleteGraphics(graphics); graphics = NULL; @@ -3391,7 +3391,7 @@ static void test_lineargradient(void) /* Verify custom blend gradient fill. */ stat = GdipBitmapGetPixel(bitmap, 10, 50, &color); expect(Ok, stat); - todo_wine expect(0xffff0000, color); + expect(0xffff0000, color);
stat = GdipBitmapGetPixel(bitmap, 18, 50, &color); expect(Ok, stat); @@ -3400,11 +3400,11 @@ static void test_lineargradient(void) /* Verify preset color gradient fill. */ stat = GdipBitmapGetPixel(bitmap, 50, 50, &color); expect(Ok, stat); - todo_wine expect(0xffff0000, color); + expect(0xffff0000, color);
stat = GdipBitmapGetPixel(bitmap, 50, 60, &color); expect(Ok, stat); - todo_wine expect(0xff00ff00, color); + expect(0xff00ff00, color);
GdipDeleteBrush(vertbrush); GdipDeleteBrush(horizbrush);
Signed-off-by: Esme Povirk esme@codeweavers.com
Signed-off-by: Shawn M. Chapla schapla@codeweavers.com --- dlls/gdiplus/metafile.c | 4 ++-- dlls/gdiplus/tests/metafile.c | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index ff21b8ed242..7f019749eaf 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -2206,7 +2206,7 @@ static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_si UINT position_count = 0;
offset = header_size + FIELD_OFFSET(EmfPlusLinearGradientBrushData, OptionalData); - if (data_size <= offset) + if (data_size < offset) return InvalidParameter;
brushflags = data->BrushData.lineargradient.BrushDataFlags; @@ -2215,7 +2215,7 @@ static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_si
if (brushflags & BrushDataTransform) { - if (data_size <= offset + sizeof(EmfPlusTransformMatrix)) + if (data_size < offset + sizeof(EmfPlusTransformMatrix)) return InvalidParameter; transform = (EmfPlusTransformMatrix *)(record_data + offset); offset += sizeof(EmfPlusTransformMatrix); diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index 29113fc3a05..cdc53b39a1f 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -3273,10 +3273,10 @@ static void test_fillregion(void) static const emfplus_record lineargradient_records[] = { { EMR_HEADER }, { EmfPlusRecordTypeHeader }, - { EmfPlusRecordTypeObject, ObjectTypeBrush << 8, 0, 1 }, - { EmfPlusRecordTypeFillRects, 0x4000, 0, 1 }, - { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 1, 0, 1 }, - { EmfPlusRecordTypeFillRects, 0x4000, 0, 1 }, + { EmfPlusRecordTypeObject, ObjectTypeBrush << 8 }, + { EmfPlusRecordTypeFillRects, 0x4000 }, + { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 1 }, + { EmfPlusRecordTypeFillRects, 0x4000 }, { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 2 }, { EmfPlusRecordTypeFillRects, 0x4000 }, { EmfPlusRecordTypeObject, (ObjectTypeBrush << 8) | 3 }, @@ -3373,7 +3373,7 @@ static void test_lineargradient(void) /* Verify horizontal gradient fill. */ stat = GdipBitmapGetPixel(bitmap, 10, 10, &color); expect(Ok, stat); - todo_wine expect(0xffff0000, color); + expect(0xffff0000, color);
stat = GdipBitmapGetPixel(bitmap, 18, 10, &color); expect(Ok, stat); @@ -3382,11 +3382,11 @@ static void test_lineargradient(void) /* Verify vertical gradient fill. */ stat = GdipBitmapGetPixel(bitmap, 50, 10, &color); expect(Ok, stat); - todo_wine expect(0xffff0000, color); + expect(0xffff0000, color);
stat = GdipBitmapGetPixel(bitmap, 50, 18, &color); expect(Ok, stat); - todo_wine expect(0xff990066, color); + expect(0xff990066, color);
/* Verify custom blend gradient fill. */ stat = GdipBitmapGetPixel(bitmap, 10, 50, &color);
Signed-off-by: Esme Povirk esme@codeweavers.com
Signed-off-by: Shawn M. Chapla schapla@codeweavers.com --- dlls/gdiplus/metafile.c | 15 ++++++++------- dlls/gdiplus/tests/metafile.c | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index 7f019749eaf..e0ff6cae7a4 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -2202,7 +2202,7 @@ static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_si case BrushTypeLinearGradient: { GpLineGradient *gradient = NULL; - GpPointF startpoint, endpoint; + GpRectF rect; UINT position_count = 0;
offset = header_size + FIELD_OFFSET(EmfPlusLinearGradientBrushData, OptionalData); @@ -2240,13 +2240,14 @@ static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_si return InvalidParameter; }
- startpoint.X = data->BrushData.lineargradient.RectF.X; - startpoint.Y = data->BrushData.lineargradient.RectF.Y; - endpoint.X = startpoint.X + data->BrushData.lineargradient.RectF.Width; - endpoint.Y = startpoint.Y + data->BrushData.lineargradient.RectF.Height; + rect.X = data->BrushData.lineargradient.RectF.X; + rect.Y = data->BrushData.lineargradient.RectF.Y; + rect.Width = data->BrushData.lineargradient.RectF.Width; + rect.Height = data->BrushData.lineargradient.RectF.Height;
- status = GdipCreateLineBrush(&startpoint, &endpoint, data->BrushData.lineargradient.StartColor, - data->BrushData.lineargradient.EndColor, data->BrushData.lineargradient.WrapMode, &gradient); + status = GdipCreateLineBrushFromRect(&rect, data->BrushData.lineargradient.StartColor, + data->BrushData.lineargradient.EndColor, LinearGradientModeHorizontal, + data->BrushData.lineargradient.WrapMode, &gradient); if (status == Ok) { if (transform) diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index cdc53b39a1f..e2d5171f8a7 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -3377,7 +3377,7 @@ static void test_lineargradient(void)
stat = GdipBitmapGetPixel(bitmap, 18, 10, &color); expect(Ok, stat); - todo_wine expect(0xff990066, color); + expect(0xff990066, color);
/* Verify vertical gradient fill. */ stat = GdipBitmapGetPixel(bitmap, 50, 10, &color); @@ -3395,7 +3395,7 @@ static void test_lineargradient(void)
stat = GdipBitmapGetPixel(bitmap, 18, 50, &color); expect(Ok, stat); - todo_wine expect(0xff4700b8, color); + expect(0xff4700b8, color);
/* Verify preset color gradient fill. */ stat = GdipBitmapGetPixel(bitmap, 50, 50, &color);
Signed-off-by: Esme Povirk esme@codeweavers.com