From aac33dab2a7a3ff7e7ffd1bcbe432b8d4507d73b Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Wed, 16 Aug 2017 13:28:59 -0500 Subject: [PATCH] gdiplus: Implement transform matrix for line gradient brushes. Signed-off-by: Andrew Eikum Signed-off-by: Vincent Povirk Signed-off-by: Alexandre Julliard --- dlls/gdiplus/brush.c | 127 ++++++++---- dlls/gdiplus/gdiplus_private.h | 1 + dlls/gdiplus/graphics.c | 22 +- dlls/gdiplus/tests/brush.c | 443 +++++++++++++++++++++++++++++++++-------- include/gdiplusflat.h | 1 + 5 files changed, 450 insertions(+), 144 deletions(-) diff --git a/dlls/gdiplus/brush.c b/dlls/gdiplus/brush.c index a1842768044..201fadf11a4 100644 --- a/dlls/gdiplus/brush.c +++ b/dlls/gdiplus/brush.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 Google (Evan Stade) + * Copyright (C) 2003-2004,2007 Novell, Inc. http://www.novell.com (Ravindra (rkumar@novell.com)) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -149,6 +150,8 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone) return OutOfMemory; } + dest->transform = src->transform; + memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL)); memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL)); @@ -259,6 +262,41 @@ GpStatus WINGDIPAPI GdipCreateHatchBrush(HatchStyle hatchstyle, ARGB forecol, AR return Ok; } +static void linegradient_init_transform(GpLineGradient *line) +{ + float trans_x = line->rect.X + (line->rect.Width / 2.f); + float trans_y = line->rect.Y + (line->rect.Height / 2.f); + float dx = line->endpoint.X - line->startpoint.X; + float dy = line->endpoint.Y - line->startpoint.Y; + float t_cos, t_sin, w_ratio, h_ratio; + float h; + GpMatrix rot; + + h = sqrtf(dx * dx + dy * dy); + + t_cos = dx / h; + t_sin = dy / h; + + w_ratio = (fabs(t_cos) * line->rect.Width + fabs(t_sin) * line->rect.Height) / line->rect.Width; + h_ratio = (fabs(t_sin) * line->rect.Width + fabs(t_cos) * line->rect.Height) / line->rect.Height; + + GdipSetMatrixElements(&line->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); + + GdipSetMatrixElements(&rot, t_cos, t_sin, -1.f * t_sin, t_cos, 0, 0); + + /* center about the origin */ + GdipTranslateMatrix(&line->transform, -trans_x, -trans_y, MatrixOrderAppend); + + /* scale to normalize gradient along gradient line (?) */ + GdipScaleMatrix(&line->transform, w_ratio, h_ratio, MatrixOrderAppend); + + /* rotate so the gradient is horizontal */ + GdipMultiplyMatrix(&line->transform, &rot, MatrixOrderAppend); + + /* restore original offset in new coords */ + GdipTranslateMatrix(&line->transform, trans_x, trans_y, MatrixOrderAppend); +} + /****************************************************************************** * GdipCreateLineBrush [GDIPLUS.@] */ @@ -325,6 +363,8 @@ GpStatus WINGDIPAPI GdipCreateLineBrush(GDIPCONST GpPointF* startpoint, (*line)->pblendpos = NULL; (*line)->pblendcount = 0; + linegradient_init_transform(*line); + TRACE("<-- %p\n", *line); return Ok; @@ -357,6 +397,7 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRect(GDIPCONST GpRectF* rect, { GpPointF start, end; GpStatus stat; + float far_x, far_y; TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode, wrap, line); @@ -364,31 +405,34 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRect(GDIPCONST GpRectF* rect, if(!line || !rect) return InvalidParameter; + far_x = rect->X + rect->Width; + far_y = rect->Y + rect->Height; + switch (mode) { case LinearGradientModeHorizontal: - start.X = rect->X; + start.X = min(rect->X, far_x); start.Y = rect->Y; - end.X = rect->X + rect->Width; + end.X = max(rect->X, far_x); end.Y = rect->Y; break; case LinearGradientModeVertical: start.X = rect->X; - start.Y = rect->Y; + start.Y = min(rect->Y, far_y); end.X = rect->X; - end.Y = rect->Y + rect->Height; + end.Y = max(rect->Y, far_y); break; case LinearGradientModeForwardDiagonal: - start.X = rect->X; - start.Y = rect->Y; - end.X = rect->X + rect->Width; - end.Y = rect->Y + rect->Height; + start.X = min(rect->X, far_x); + start.Y = min(rect->Y, far_y); + end.X = max(rect->X, far_x); + end.Y = max(rect->Y, far_y); break; case LinearGradientModeBackwardDiagonal: - start.X = rect->X + rect->Width; - start.Y = rect->Y; - end.X = rect->X; - end.Y = rect->Y + rect->Height; + start.X = max(rect->X, far_x); + start.Y = min(rect->Y, far_y); + end.X = min(rect->X, far_x); + end.Y = max(rect->Y, far_y); break; default: return InvalidParameter; @@ -497,6 +541,8 @@ GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF* rect (*line)->startpoint.X = rect->X + exofs; (*line)->startpoint.Y = rect->Y + eyofs; } + + linegradient_init_transform(*line); } return stat; @@ -2005,78 +2051,73 @@ GpStatus WINGDIPAPI GdipGetLinePresetBlendCount(GpLineGradient *brush, GpStatus WINGDIPAPI GdipResetLineTransform(GpLineGradient *brush) { - static int calls; - TRACE("(%p)\n", brush); - if(!(calls++)) - FIXME("not implemented\n"); + if(!brush) + return InvalidParameter; - return NotImplemented; + return GdipSetMatrixElements(&brush->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); } GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush, GDIPCONST GpMatrix *matrix) { - static int calls; - TRACE("(%p,%p)\n", brush, matrix); - if(!(calls++)) - FIXME("not implemented\n"); + if(!brush || !matrix) + return InvalidParameter; - return NotImplemented; + brush->transform = *matrix; + + return Ok; } GpStatus WINGDIPAPI GdipGetLineTransform(GpLineGradient *brush, GpMatrix *matrix) { - static int calls; - TRACE("(%p,%p)\n", brush, matrix); - if(!(calls++)) - FIXME("not implemented\n"); + if(!brush || !matrix) + return InvalidParameter; - return NotImplemented; + *matrix = brush->transform; + + return Ok; } GpStatus WINGDIPAPI GdipScaleLineTransform(GpLineGradient *brush, REAL sx, REAL sy, GpMatrixOrder order) { - static int calls; - TRACE("(%p,%0.2f,%0.2f,%u)\n", brush, sx, sy, order); - if(!(calls++)) - FIXME("not implemented\n"); + if(!brush) + return InvalidParameter; - return NotImplemented; + return GdipScaleMatrix(&brush->transform, sx, sy, order); } GpStatus WINGDIPAPI GdipMultiplyLineTransform(GpLineGradient *brush, GDIPCONST GpMatrix *matrix, GpMatrixOrder order) { - static int calls; - TRACE("(%p,%p,%u)\n", brush, matrix, order); - if(!(calls++)) - FIXME("not implemented\n"); + if(!brush) + return InvalidParameter; - return NotImplemented; + if(!matrix) + return Ok; + + return GdipMultiplyMatrix(&brush->transform, matrix, order); } -GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient* brush, +GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient *brush, REAL dx, REAL dy, GpMatrixOrder order) { - static int calls; - TRACE("(%p,%f,%f,%d)\n", brush, dx, dy, order); - if(!(calls++)) - FIXME("not implemented\n"); + if(!brush) + return InvalidParameter; - return Ok; + return GdipTranslateMatrix(&brush->transform, dx, dy, order); } /****************************************************************************** diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 33966767cc6..e1169c6cdfb 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -312,6 +312,7 @@ struct GpLineGradient{ ARGB* pblendcolor; /* preset blend colors */ REAL* pblendpos; /* preset blend positions */ INT pblendcount; + GpMatrix transform; }; struct GpTexture{ diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index e45618eefec..80206c93938 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -547,6 +547,7 @@ static ARGB blend_line_gradient(GpLineGradient* brush, REAL position) REAL blendfac; /* clamp to between 0.0 and 1.0, using the wrap mode */ + position = (position - brush->rect.X) / brush->rect.Width; if (brush->wrap == WrapModeTile) { position = fmodf(position, 1.0f); @@ -1138,10 +1139,8 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush, case BrushTypeLinearGradient: { GpLineGradient *fill = (GpLineGradient*)brush; - GpPointF draw_points[3], line_points[3]; + GpPointF draw_points[3]; GpStatus stat; - static const GpRectF box_1 = { 0.0, 0.0, 1.0, 1.0 }; - GpMatrix *world_to_gradient; /* FIXME: Store this in the brush? */ int x, y; draw_points[0].X = fill_area->X; @@ -1159,22 +1158,11 @@ static GpStatus brush_fill_pixels(GpGraphics *graphics, GpBrush *brush, if (stat == Ok) { - line_points[0] = fill->startpoint; - line_points[1] = fill->endpoint; - line_points[2].X = fill->startpoint.X + (fill->startpoint.Y - fill->endpoint.Y); - line_points[2].Y = fill->startpoint.Y + (fill->endpoint.X - fill->startpoint.X); - - stat = GdipCreateMatrix3(&box_1, line_points, &world_to_gradient); - } - - if (stat == Ok) - { - stat = GdipInvertMatrix(world_to_gradient); + GpMatrix world_to_gradient = fill->transform; + stat = GdipInvertMatrix(&world_to_gradient); if (stat == Ok) - stat = GdipTransformMatrixPoints(world_to_gradient, draw_points, 3); - - GdipDeleteMatrix(world_to_gradient); + stat = GdipTransformMatrixPoints(&world_to_gradient, draw_points, 3); } if (stat == Ok) diff --git a/dlls/gdiplus/tests/brush.c b/dlls/gdiplus/tests/brush.c index 9fd80d23056..045d5e5b8ac 100644 --- a/dlls/gdiplus/tests/brush.c +++ b/dlls/gdiplus/tests/brush.c @@ -27,6 +27,8 @@ #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) #define expectf(expected, got) ok(fabs(expected - got) < 0.0001, "Expected %.2f, got %.2f\n", expected, got) +static HWND hwnd; + static void test_constructor_destructor(void) { GpStatus status; @@ -174,12 +176,17 @@ static void test_transform(void) { GpStatus status; GpTexture *texture; + GpLineGradient *line; GpGraphics *graphics = NULL; GpBitmap *bitmap; HDC hdc = GetDC(0); GpMatrix *m, *m1; BOOL res; + GpPointF start, end; + GpRectF rectf; + REAL elements[6]; + /* GpTexture */ status = GdipCreateMatrix2(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, &m); expect(Ok, status); @@ -233,6 +240,245 @@ static void test_transform(void) expect(Ok, status); status = GdipDeleteGraphics(graphics); expect(Ok, status); + + + + status = GdipCreateFromHWND(hwnd, &graphics); + expect(Ok, status); + + /* GpLineGradient */ + /* create with vertical gradient line */ + start.X = start.Y = end.X = 0.0; + end.Y = 100.0; + + status = GdipCreateLineBrush(&start, &end, (ARGB)0xffff0000, 0xff00ff00, WrapModeTile, &line); + expect(Ok, status); + + status = GdipCreateMatrix2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, &m); + expect(Ok, status); + + /* NULL arguments */ + status = GdipResetLineTransform(NULL); + expect(InvalidParameter, status); + status = GdipSetLineTransform(NULL, m); + expect(InvalidParameter, status); + status = GdipSetLineTransform(line, NULL); + expect(InvalidParameter, status); + status = GdipGetLineTransform(NULL, m); + expect(InvalidParameter, status); + status = GdipGetLineTransform(line, NULL); + expect(InvalidParameter, status); + status = GdipScaleLineTransform(NULL, 1, 1, MatrixOrderPrepend); + expect(InvalidParameter, status); + status = GdipMultiplyLineTransform(NULL, m, MatrixOrderPrepend); + expect(InvalidParameter, status); + status = GdipTranslateLineTransform(NULL, 0, 0, MatrixOrderPrepend); + expect(InvalidParameter, status); + + /* initial transform */ + status = GdipGetLineTransform(line, m); + expect(Ok, status); + + status = GdipGetMatrixElements(m, elements); + expect(Ok, status); + expectf(0.0, elements[0]); + expectf(1.0, elements[1]); + expectf(-1.0, elements[2]); + expectf(0.0, elements[3]); + expectf(50.0, elements[4]); + expectf(50.0, elements[5]); + + status = GdipGetLineRect(line, &rectf); + expect(Ok, status); + expectf(-50.0, rectf.X); + expectf(0.0, rectf.Y); + expectf(100.0, rectf.Width); + expectf(100.0, rectf.Height); + + status = GdipFillRectangle(graphics, (GpBrush*)line, 0, 0, 200, 200); + expect(Ok, status); + + /* manually set transform */ + GdipSetMatrixElements(m, 2.0, 0.0, 0.0, 4.0, 0.0, 0.0); + + status = GdipSetLineTransform(line, m); + expect(Ok, status); + + status = GdipGetLineTransform(line, m); + expect(Ok, status); + + status = GdipGetMatrixElements(m, elements); + expect(Ok, status); + expectf(2.0, elements[0]); + expectf(0.0, elements[1]); + expectf(0.0, elements[2]); + expectf(4.0, elements[3]); + expectf(0.0, elements[4]); + expectf(0.0, elements[5]); + + status = GdipGetLineRect(line, &rectf); + expect(Ok, status); + expectf(-50.0, rectf.X); + expectf(0.0, rectf.Y); + expectf(100.0, rectf.Width); + expectf(100.0, rectf.Height); + + status = GdipFillRectangle(graphics, (GpBrush*)line, 200, 0, 200, 200); + expect(Ok, status); + + /* scale transform */ + status = GdipScaleLineTransform(line, 4.0, 0.5, MatrixOrderAppend); + expect(Ok, status); + + status = GdipGetLineTransform(line, m); + expect(Ok, status); + + status = GdipGetMatrixElements(m, elements); + expect(Ok, status); + expectf(8.0, elements[0]); + expectf(0.0, elements[1]); + expectf(0.0, elements[2]); + expectf(2.0, elements[3]); + expectf(0.0, elements[4]); + expectf(0.0, elements[5]); + + status = GdipGetLineRect(line, &rectf); + expect(Ok, status); + expectf(-50.0, rectf.X); + expectf(0.0, rectf.Y); + expectf(100.0, rectf.Width); + expectf(100.0, rectf.Height); + + status = GdipFillRectangle(graphics, (GpBrush*)line, 400, 0, 200, 200); + expect(Ok, status); + + /* translate transform */ + status = GdipTranslateLineTransform(line, 10.0, -20.0, MatrixOrderAppend); + expect(Ok, status); + + status = GdipGetLineTransform(line, m); + expect(Ok, status); + + status = GdipGetMatrixElements(m, elements); + expect(Ok, status); + expectf(8.0, elements[0]); + expectf(0.0, elements[1]); + expectf(0.0, elements[2]); + expectf(2.0, elements[3]); + expectf(10.0, elements[4]); + expectf(-20.0, elements[5]); + + status = GdipGetLineRect(line, &rectf); + expect(Ok, status); + expectf(-50.0, rectf.X); + expectf(0.0, rectf.Y); + expectf(100.0, rectf.Width); + expectf(100.0, rectf.Height); + + status = GdipFillRectangle(graphics, (GpBrush*)line, 0, 200, 200, 200); + expect(Ok, status); + + /* multiply transform */ + GdipSetMatrixElements(m, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); + GdipRotateMatrix(m, 45.0, MatrixOrderAppend); + GdipScaleMatrix(m, 0.25, 0.5, MatrixOrderAppend); + + status = GdipMultiplyLineTransform(line, m, MatrixOrderAppend); + expect(Ok, status); + + /* NULL transform does nothing */ + status = GdipMultiplyLineTransform(line, NULL, MatrixOrderAppend); + expect(Ok, status); + + status = GdipGetLineTransform(line, m); + expect(Ok, status); + + status = GdipGetMatrixElements(m, elements); + expect(Ok, status); + expectf(1.414214, elements[0]); + expectf(2.828427, elements[1]); + expectf(-0.353553, elements[2]); + expectf(0.707107, elements[3]); + expectf(5.303300, elements[4]); + expectf(-3.535534, elements[5]); + + status = GdipGetLineRect(line, &rectf); + expect(Ok, status); + expectf(-50.0, rectf.X); + expectf(0.0, rectf.Y); + expectf(100.0, rectf.Width); + expectf(100.0, rectf.Height); + + status = GdipFillRectangle(graphics, (GpBrush*)line, 200, 200, 200, 200); + expect(Ok, status); + + /* reset transform sets to identity */ + status = GdipResetLineTransform(line); + expect(Ok, status); + + status = GdipGetLineTransform(line, m); + expect(Ok, status); + + status = GdipGetMatrixElements(m, elements); + expect(Ok, status); + expectf(1.0, elements[0]); + expectf(0.0, elements[1]); + expectf(0.0, elements[2]); + expectf(1.0, elements[3]); + expectf(0.0, elements[4]); + expectf(0.0, elements[5]); + + status = GdipGetLineRect(line, &rectf); + expect(Ok, status); + expectf(-50.0, rectf.X); + expectf(0.0, rectf.Y); + expectf(100.0, rectf.Width); + expectf(100.0, rectf.Height); + + status = GdipFillRectangle(graphics, (GpBrush*)line, 400, 200, 200, 200); + expect(Ok, status); + + GdipDeleteBrush((GpBrush*)line); + + /* passing negative Width/Height to LinearGradientModeHorizontal */ + rectf.X = rectf.Y = 10.0; + rectf.Width = rectf.Height = -100.0; + status = GdipCreateLineBrushFromRect(&rectf, (ARGB)0xffff0000, 0xff00ff00, + LinearGradientModeHorizontal, WrapModeTile, &line); + expect(Ok, status); + memset(&rectf, 0, sizeof(GpRectF)); + status = GdipGetLineRect(line, &rectf); + expect(Ok, status); + expectf(10.0, rectf.X); + expectf(10.0, rectf.Y); + expectf(-100.0, rectf.Width); + expectf(-100.0, rectf.Height); + status = GdipGetLineTransform(line, m); + expect(Ok, status); + status = GdipGetMatrixElements(m, elements); + expect(Ok,status); + expectf(1.0, elements[0]); + expectf(0.0, elements[1]); + expectf(0.0, elements[2]); + expectf(1.0, elements[3]); + expectf(0.0, elements[4]); + expectf(0.0, elements[5]); + status = GdipFillRectangle(graphics, (GpBrush*)line, 0, 400, 200, 200); + expect(Ok, status); + status = GdipDeleteBrush((GpBrush*)line); + expect(Ok,status); + + if(0){ + /* enable to visually compare with Windows */ + MSG msg; + while(GetMessageW(&msg, hwnd, 0, 0) > 0){ + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + + GdipDeleteMatrix(m); + GdipDeleteGraphics(graphics); ReleaseDC(0, hdc); } @@ -308,20 +554,18 @@ static void test_gradientgetrect(void) expectf(99.0, rectf.Width); expectf(99.0, rectf.Height); status = GdipGetLineTransform(brush, transform); - todo_wine expect(Ok, status); - if (status == Ok) - { - status = GdipGetMatrixElements(transform, elements); - expect(Ok, status); - expectf(1.0, elements[0]); - expectf(1.0, elements[1]); - expectf(-1.0, elements[2]); - expectf(1.0, elements[3]); - expectf(50.50, elements[4]); - expectf(-50.50, elements[5]); - } + expect(Ok, status); + status = GdipGetMatrixElements(transform, elements); + expect(Ok, status); + expectf(1.0, elements[0]); + expectf(1.0, elements[1]); + expectf(-1.0, elements[2]); + expectf(1.0, elements[3]); + expectf(50.50, elements[4]); + expectf(-50.50, elements[5]); status = GdipDeleteBrush((GpBrush*)brush); expect(Ok, status); + /* vertical gradient */ pt1.X = pt1.Y = pt2.X = 0.0; pt2.Y = 10.0; @@ -335,20 +579,18 @@ static void test_gradientgetrect(void) expectf(10.0, rectf.Width); expectf(10.0, rectf.Height); status = GdipGetLineTransform(brush, transform); - todo_wine expect(Ok, status); - if (status == Ok) - { - status = GdipGetMatrixElements(transform, elements); - expect(Ok, status); - expectf(0.0, elements[0]); - expectf(1.0, elements[1]); - expectf(-1.0, elements[2]); - expectf(0.0, elements[3]); - expectf(5.0, elements[4]); - expectf(5.0, elements[5]); - } + expect(Ok, status); + status = GdipGetMatrixElements(transform, elements); + expect(Ok, status); + expectf(0.0, elements[0]); + expectf(1.0, elements[1]); + expectf(-1.0, elements[2]); + expectf(0.0, elements[3]); + expectf(5.0, elements[4]); + expectf(5.0, elements[5]); status = GdipDeleteBrush((GpBrush*)brush); expect(Ok, status); + /* horizontal gradient */ pt1.X = pt1.Y = pt2.Y = 0.0; pt2.X = 10.0; @@ -362,20 +604,18 @@ static void test_gradientgetrect(void) expectf(10.0, rectf.Width); expectf(10.0, rectf.Height); status = GdipGetLineTransform(brush, transform); - todo_wine expect(Ok, status); - if (status == Ok) - { - status = GdipGetMatrixElements(transform, elements); - expect(Ok, status); - expectf(1.0, elements[0]); - expectf(0.0, elements[1]); - expectf(0.0, elements[2]); - expectf(1.0, elements[3]); - expectf(0.0, elements[4]); - expectf(0.0, elements[5]); - } + expect(Ok, status); + status = GdipGetMatrixElements(transform, elements); + expect(Ok, status); + expectf(1.0, elements[0]); + expectf(0.0, elements[1]); + expectf(0.0, elements[2]); + expectf(1.0, elements[3]); + expectf(0.0, elements[4]); + expectf(0.0, elements[5]); status = GdipDeleteBrush((GpBrush*)brush); expect(Ok, status); + /* slope = -1 */ pt1.X = pt1.Y = 0.0; pt2.X = 20.0; @@ -390,20 +630,18 @@ static void test_gradientgetrect(void) expectf(20.0, rectf.Width); expectf(20.0, rectf.Height); status = GdipGetLineTransform(brush, transform); - todo_wine expect(Ok, status); - if (status == Ok) - { - status = GdipGetMatrixElements(transform, elements); - expect(Ok, status); - expectf(1.0, elements[0]); - expectf(-1.0, elements[1]); - expectf(1.0, elements[2]); - expectf(1.0, elements[3]); - expectf(10.0, elements[4]); - expectf(10.0, elements[5]); - } + expect(Ok, status); + status = GdipGetMatrixElements(transform, elements); + expect(Ok, status); + expectf(1.0, elements[0]); + expectf(-1.0, elements[1]); + expectf(1.0, elements[2]); + expectf(1.0, elements[3]); + expectf(10.0, elements[4]); + expectf(10.0, elements[5]); status = GdipDeleteBrush((GpBrush*)brush); expect(Ok, status); + /* slope = 1/100 */ pt1.X = pt1.Y = 0.0; pt2.X = 100.0; @@ -418,20 +656,18 @@ static void test_gradientgetrect(void) expectf(100.0, rectf.Width); expectf(1.0, rectf.Height); status = GdipGetLineTransform(brush, transform); - todo_wine expect(Ok, status); - if (status == Ok) - { - status = GdipGetMatrixElements(transform, elements); - expect(Ok,status); - expectf(1.0, elements[0]); - expectf(0.01, elements[1]); - expectf(-0.02, elements[2]); - /* expectf(2.0, elements[3]); */ - expectf(0.01, elements[4]); - /* expectf(-1.0, elements[5]); */ - } + expect(Ok, status); + status = GdipGetMatrixElements(transform, elements); + expect(Ok,status); + expectf(1.0, elements[0]); + expectf(0.01, elements[1]); + expectf(-0.02, elements[2]); + /* expectf(2.0, elements[3]); */ + expectf(0.01, elements[4]); + /* expectf(-1.0, elements[5]); */ status = GdipDeleteBrush((GpBrush*)brush); expect(Ok,status); + /* zero height rect */ rectf.X = rectf.Y = 10.0; rectf.Width = 100.0; @@ -439,6 +675,7 @@ static void test_gradientgetrect(void) status = GdipCreateLineBrushFromRect(&rectf, 0, 0, LinearGradientModeVertical, WrapModeTile, &brush); expect(OutOfMemory, status); + /* zero width rect */ rectf.X = rectf.Y = 10.0; rectf.Width = 0.0; @@ -446,6 +683,7 @@ static void test_gradientgetrect(void) status = GdipCreateLineBrushFromRect(&rectf, 0, 0, LinearGradientModeHorizontal, WrapModeTile, &brush); expect(OutOfMemory, status); + /* from rect with LinearGradientModeHorizontal */ rectf.X = rectf.Y = 10.0; rectf.Width = rectf.Height = 100.0; @@ -460,20 +698,18 @@ static void test_gradientgetrect(void) expectf(100.0, rectf.Width); expectf(100.0, rectf.Height); status = GdipGetLineTransform(brush, transform); - todo_wine expect(Ok, status); - if (status == Ok) - { - status = GdipGetMatrixElements(transform, elements); - expect(Ok,status); - expectf(1.0, elements[0]); - expectf(0.0, elements[1]); - expectf(0.0, elements[2]); - expectf(1.0, elements[3]); - expectf(0.0, elements[4]); - expectf(0.0, elements[5]); - } + expect(Ok, status); + status = GdipGetMatrixElements(transform, elements); + expect(Ok,status); + expectf(1.0, elements[0]); + expectf(0.0, elements[1]); + expectf(0.0, elements[2]); + expectf(1.0, elements[3]); + expectf(0.0, elements[4]); + expectf(0.0, elements[5]); status = GdipDeleteBrush((GpBrush*)brush); expect(Ok,status); + /* passing negative Width/Height to LinearGradientModeHorizontal */ rectf.X = rectf.Y = 10.0; rectf.Width = rectf.Height = -100.0; @@ -488,21 +724,45 @@ static void test_gradientgetrect(void) expectf(-100.0, rectf.Width); expectf(-100.0, rectf.Height); status = GdipGetLineTransform(brush, transform); - todo_wine expect(Ok, status); - if (status == Ok) - { - status = GdipGetMatrixElements(transform, elements); - expect(Ok,status); - expectf(1.0, elements[0]); - expectf(0.0, elements[1]); - expectf(0.0, elements[2]); - expectf(1.0, elements[3]); - expectf(0.0, elements[4]); - expectf(0.0, elements[5]); - } + expect(Ok, status); + status = GdipGetMatrixElements(transform, elements); + expect(Ok,status); + expectf(1.0, elements[0]); + expectf(0.0, elements[1]); + expectf(0.0, elements[2]); + expectf(1.0, elements[3]); + expectf(0.0, elements[4]); + expectf(0.0, elements[5]); status = GdipDeleteBrush((GpBrush*)brush); expect(Ok,status); + /* reverse gradient line as immediately previous */ + pt1.X = 10.0; + pt1.Y = 10.0; + pt2.X = -90.0; + pt2.Y = 10.0; + status = GdipCreateLineBrush(&pt1, &pt2, 0, 0, WrapModeTile, &brush); + expect(Ok, status); + memset(&rectf, 0, sizeof(GpRectF)); + status = GdipGetLineRect(brush, &rectf); + expect(Ok, status); + expectf(-90.0, rectf.X); + expectf(-40.0, rectf.Y); + expectf(100.0, rectf.Width); + expectf(100.0, rectf.Height); + status = GdipGetLineTransform(brush, transform); + expect(Ok, status); + status = GdipGetMatrixElements(transform, elements); + expect(Ok, status); + expectf(-1.0, elements[0]); + expectf(0.0, elements[1]); + expectf(0.0, elements[2]); + expectf(-1.0, elements[3]); + expectf(-80.0, elements[4]); + expectf(20.0, elements[5]); + status = GdipDeleteBrush((GpBrush*)brush); + expect(Ok, status); + GdipDeleteMatrix(transform); } @@ -1275,12 +1535,26 @@ START_TEST(brush) ULONG_PTR gdiplusToken; HMODULE hmsvcrt; int (CDECL * _controlfp_s)(unsigned int *cur, unsigned int newval, unsigned int mask); + WNDCLASSA class; /* Enable all FP exceptions except _EM_INEXACT, which gdi32 can trigger */ hmsvcrt = LoadLibraryA("msvcrt"); _controlfp_s = (void*)GetProcAddress(hmsvcrt, "_controlfp_s"); if (_controlfp_s) _controlfp_s(0, 0, 0x0008001e); + memset( &class, 0, sizeof(class) ); + class.lpszClassName = "gdiplus_test"; + class.style = CS_HREDRAW | CS_VREDRAW; + class.lpfnWndProc = DefWindowProcA; + class.hInstance = GetModuleHandleA(0); + class.hIcon = LoadIconA(0, (LPCSTR)IDI_APPLICATION); + class.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); + class.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + RegisterClassA( &class ); + hwnd = CreateWindowA( "gdiplus_test", "graphics test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, 0, 0, GetModuleHandleA(0), 0 ); + ok(hwnd != NULL, "Expected window to be created\n"); + gdiplusStartupInput.GdiplusVersion = 1; gdiplusStartupInput.DebugEventCallback = NULL; gdiplusStartupInput.SuppressBackgroundThread = 0; @@ -1306,4 +1580,5 @@ START_TEST(brush) test_pathgradientblend(); GdiplusShutdown(gdiplusToken); + DestroyWindow(hwnd); } diff --git a/include/gdiplusflat.h b/include/gdiplusflat.h index 10d537a0170..f2ac91e83dd 100644 --- a/include/gdiplusflat.h +++ b/include/gdiplusflat.h @@ -495,6 +495,7 @@ GpStatus WINGDIPAPI GdipSetLinePresetBlend(GpLineGradient*,GDIPCONST ARGB*, GpStatus WINGDIPAPI GdipGetLinePresetBlend(GpLineGradient*,ARGB*,REAL*,INT); GpStatus WINGDIPAPI GdipGetLinePresetBlendCount(GpLineGradient*,INT*); GpStatus WINGDIPAPI GdipGetLineTransform(GpLineGradient*,GpMatrix*); +GpStatus WINGDIPAPI GdipMultiplyLineTransform(GpLineGradient*,GDIPCONST GpMatrix*,GpMatrixOrder); GpStatus WINGDIPAPI GdipResetLineTransform(GpLineGradient*); GpStatus WINGDIPAPI GdipRotateLineTransform(GpLineGradient*,REAL,GpMatrixOrder); GpStatus WINGDIPAPI GdipScaleLineTransform(GpLineGradient*,REAL,REAL, -- 2.11.4.GIT