diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/html/shaders/shader.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/html/shaders/shader.dart index 27a27ae2758..0a71c0db66c 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/html/shaders/shader.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/html/shaders/shader.dart @@ -178,8 +178,11 @@ class GradientLinear extends EngineGradient { final double offsetX = shaderBounds!.left; final double offsetY = shaderBounds.top; if (matrix4 != null) { - final centerX = (from.dx + to.dx) / 2.0; - final centerY = (from.dy + to.dy) / 2.0; + // The matrix is relative to shaderBounds so we shift center by + // shaderBounds top-left origin. + final centerX = (from.dx + to.dx) / 2.0 - shaderBounds.left; + final centerY = (from.dy + to.dy) / 2.0 - shaderBounds.top; + matrix4.transform(from.dx - centerX, from.dy - centerY); final double fromX = matrix4.transformedX + centerX; final double fromY = matrix4.transformedY + centerY; @@ -188,8 +191,9 @@ class GradientLinear extends EngineGradient { fromX - offsetX, fromY - offsetY, matrix4.transformedX + centerX - offsetX, - matrix4.transformedY - offsetY + centerY); + matrix4.transformedY + centerY - offsetY); } else { + print('matrix is null'); gradient = ctx!.createLinearGradient(from.dx - offsetX, from.dy - offsetY, to.dx - offsetX, to.dy - offsetY); } diff --git a/engine/src/flutter/lib/web_ui/test/golden_tests/engine/gradient_golden_test.dart b/engine/src/flutter/lib/web_ui/test/golden_tests/engine/gradient_golden_test.dart index a0615fd36b6..ba513ff1fa0 100644 --- a/engine/src/flutter/lib/web_ui/test/golden_tests/engine/gradient_golden_test.dart +++ b/engine/src/flutter/lib/web_ui/test/golden_tests/engine/gradient_golden_test.dart @@ -344,6 +344,53 @@ void testMain() async { canvas.restore(); await _checkScreenshot(canvas, 'linear_gradient_rect_shifted'); }); + + test('Paints clamped, rotated and shifted linear gradient', () async { + final RecordingCanvas canvas = + RecordingCanvas(const Rect.fromLTRB(0, 0, 400, 300)); + canvas.save(); + + final Paint borderPaint = Paint() + ..style = PaintingStyle.stroke + ..strokeWidth = 1 + ..color = Color(0xFF000000); + + List colors = [ + Color(0xFF000000), + Color(0xFFFF3C38), + Color(0xFFFF8C42), + Color(0xFFFFF275), + Color(0xFF6699CC), + Color(0xFF656D78),]; + List stops = [0.0, 0.05, 0.4, 0.6, 0.9, 1.0]; + + EngineGradient linearGradient = GradientLinear(Offset(50, 50), + Offset(200,130), + colors, stops, TileMode.clamp, + Matrix4.identity().storage); + + const double kBoxWidth = 150; + const double kBoxHeight = 80; + // Gradient with default center. + Rect rectBounds = Rect.fromLTWH(10, 20, kBoxWidth, kBoxHeight); + canvas.drawRect(rectBounds, + Paint()..shader = engineLinearGradientToShader(linearGradient, rectBounds)); + canvas.drawRect(rectBounds, borderPaint); + + // Tile mode repeat + rectBounds = Rect.fromLTWH(10, 110, kBoxWidth, kBoxHeight); + linearGradient = GradientLinear(Offset(50, 50), + Offset(200,130), + colors, stops, TileMode.clamp, + Matrix4.identity().storage); + + canvas.drawRect(rectBounds, + new Paint()..shader = engineLinearGradientToShader(linearGradient, rectBounds)); + canvas.drawRect(rectBounds, borderPaint); + + canvas.restore(); + await _checkScreenshot(canvas, 'linear_gradient_rect_clamp_rotated'); + }); } Shader engineGradientToShader(GradientSweep gradient, Rect rect) { diff --git a/engine/src/flutter/lib/web_ui/test/golden_tests/engine/linear_gradient_golden_test.dart b/engine/src/flutter/lib/web_ui/test/golden_tests/engine/linear_gradient_golden_test.dart index 3cf4c59c3f3..be3881e77bb 100644 --- a/engine/src/flutter/lib/web_ui/test/golden_tests/engine/linear_gradient_golden_test.dart +++ b/engine/src/flutter/lib/web_ui/test/golden_tests/engine/linear_gradient_golden_test.dart @@ -49,6 +49,13 @@ void testMain() async { double yOffset = 0; for (double angle in angles) { final Rect shaderRect = Rect.fromLTWH(50, 50 + yOffset, 100, 100); + Matrix4 matrix = Matrix4.identity(); + matrix.translate(shaderRect.left, shaderRect.top); + matrix.multiply(Matrix4 + .rotationZ((angle / 180) * math.pi)); + Matrix4 post = Matrix4.identity(); + post.translate(-shaderRect.left, -shaderRect.top); + matrix.multiply(post); final Paint paint = Paint() ..shader = Gradient.linear( Offset(shaderRect.left, shaderRect.top), @@ -56,9 +63,7 @@ void testMain() async { [Color(0xFFFF0000), Color(0xFF042a85)], null, TileMode.clamp, - Matrix4 - .rotationZ((angle / 180) * math.pi) - .toFloat64()); + matrix.toFloat64()); rc.drawRect(shaderRect, Paint() ..color = Color(0xFF000000)); rc.drawOval(shaderRect, paint);