Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/web_ui/dev/goldens_lock.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
repository: https://github.com/flutter/goldens.git
revision: 0c1a793bfd49e30fccdd7ad64329a114a9cb32f7
revision: b38daf293027908861f16362b378ca6865518ded
43 changes: 29 additions & 14 deletions lib/web_ui/lib/src/engine/shader.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,29 +80,47 @@ void _validateColorStops(List<ui.Color> colors, List<double> colorStops) {

class GradientLinear extends EngineGradient {
GradientLinear(
this.from,
this.to,
this.colors,
this.colorStops,
this.tileMode,
this.from,
this.to,
this.colors,
this.colorStops,
this.tileMode,
Float64List matrix,
) : assert(_offsetIsValid(from)),
assert(_offsetIsValid(to)),
assert(colors != null),
assert(tileMode != null),
this.matrix4 = matrix == null ? null : _FastMatrix64(matrix),
super._() {
_validateColorStops(colors, colorStops);
if (assertionsEnabled) {
_validateColorStops(colors, colorStops);
}
}

final ui.Offset from;
final ui.Offset to;
final List<ui.Color> colors;
final List<double> colorStops;
final ui.TileMode tileMode;
final _FastMatrix64 matrix4;

@override
html.CanvasGradient createPaintStyle(html.CanvasRenderingContext2D ctx) {
final html.CanvasGradient gradient =
ctx.createLinearGradient(from.dx, from.dy, to.dx, to.dy);
final bool hasMatrix = matrix4 != null;
html.CanvasGradient gradient;
if (hasMatrix) {
final centerX = (from.dx + to.dx) / 2.0;
final centerY = (from.dy + to.dy) / 2.0;
matrix4.transform(from.dx - centerX, from.dy - centerY);
final double fromX = matrix4.transformedX + centerX;
final double fromY = matrix4.transformedY + centerY;
matrix4.transform(to.dx - centerX, to.dy - centerY);
gradient = ctx.createLinearGradient(fromX, fromY,
matrix4.transformedX + centerX, matrix4.transformedY + centerY);
} else {
gradient = ctx.createLinearGradient(from.dx, from.dy, to.dx, to.dy);
}

if (colorStops == null) {
assert(colors.length == 2);
gradient.addColorStop(0, colorToCssString(colors[0]));
Expand Down Expand Up @@ -154,7 +172,9 @@ class GradientLinear extends EngineGradient {
}

// TODO(flutter_web): For transforms and tile modes implement as webgl
// shader instead. See https://github.com/flutter/flutter/issues/32819
// For now only GradientRotation is supported in flutter which is implemented
// for linear gradient.
// See https://github.com/flutter/flutter/issues/32819
class GradientRadial extends EngineGradient {
GradientRadial(this.center, this.radius, this.colors, this.colorStops,
this.tileMode, this.matrix4)
Expand All @@ -170,11 +190,6 @@ class GradientRadial extends EngineGradient {
@override
Object createPaintStyle(html.CanvasRenderingContext2D ctx) {
if (!experimentalUseSkia) {
// The DOM backend does not (yet) support all parameters.
if (matrix4 != null && !Matrix4.fromFloat32List(matrix4).isIdentity()) {
throw UnimplementedError(
'matrix4 not supported in GradientRadial shader');
}
if (tileMode != ui.TileMode.clamp) {
throw UnimplementedError(
'TileMode not supported in GradientRadial shader');
Expand Down
12 changes: 12 additions & 0 deletions lib/web_ui/lib/src/engine/util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -481,3 +481,15 @@ FutureOr<void> sendFontChangeMessage() async {
});
}
}

// Stores matrix in a form that allows zero allocation transforms.
class _FastMatrix64 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm implementing almost the same zero-alloc function in vector_math.dart for MaskFilter.blur. Can you please leave a TODO for me to consolidate the two? Would be good to share the same code everywhere.

final Float64List matrix;
double transformedX = 0, transformedY = 0;
_FastMatrix64(this.matrix);

void transform(double x, double y) {
transformedX = matrix[12] + (matrix[0] * x) + (matrix[4] * y);
transformedY = matrix[13] + (matrix[1] * x) + (matrix[5] * y);
}
}
3 changes: 1 addition & 2 deletions lib/web_ui/lib/src/ui/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1092,10 +1092,9 @@ abstract class Gradient extends Shader {
List<Color> colors, [
List<double> colorStops,
TileMode tileMode = TileMode.clamp,
// TODO(flutter_web): see https://github.com/flutter/flutter/issues/32819
Float64List matrix4,
]) =>
engine.GradientLinear(from, to, colors, colorStops, tileMode);
engine.GradientLinear(from, to, colors, colorStops, tileMode, matrix4);

/// Creates a radial gradient centered at `center` that ends at `radius`
/// distance from the center.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

// @dart = 2.6
import 'dart:html' as html;
import 'dart:math' as math;

import 'package:ui/ui.dart' hide TextStyle;
import 'package:ui/src/engine.dart';
Expand Down Expand Up @@ -46,7 +47,7 @@ void main() async {

test('Should draw linear gradient using rectangle.', () async {
final RecordingCanvas rc =
RecordingCanvas(const Rect.fromLTRB(0, 0, 500, 500));
RecordingCanvas(const Rect.fromLTRB(0, 0, 500, 500));
Rect shaderRect = const Rect.fromLTRB(50, 50, 300, 300);
final Paint paint = Paint()..shader = Gradient.linear(
Offset(shaderRect.left, shaderRect.top),
Expand All @@ -57,10 +58,36 @@ void main() async {
await _checkScreenshot(rc, 'linear_gradient_rect');
});

test('Should draw linear gradient with transform.', () async {
final RecordingCanvas rc =
RecordingCanvas(const Rect.fromLTRB(0, 0, 500, 500));
List<double> angles = [0.0, 90.0, 180.0];
double yOffset = 0;
for (double angle in angles) {
final Rect shaderRect = Rect.fromLTWH(50, 50 + yOffset, 100, 100);
final Paint paint = Paint()
..shader = Gradient.linear(
Offset(shaderRect.left, shaderRect.top),
Offset(shaderRect.right, shaderRect.bottom),
[Color(0xFFFF0000), Color(0xFF042a85)],
null,
TileMode.clamp,
Matrix4
.rotationZ((angle / 180) * math.pi)
.toFloat64());
rc.drawRect(shaderRect, Paint()
..color = Color(0xFF000000));
rc.drawOval(shaderRect, paint);
yOffset += 120;
}
expect(rc.hasArbitraryPaint, isTrue);
await _checkScreenshot(rc, 'linear_gradient_oval_matrix');
});

// Regression test for https://github.com/flutter/flutter/issues/50010
test('Should draw linear gradient using rounded rect.', () async {
final RecordingCanvas rc =
RecordingCanvas(const Rect.fromLTRB(0, 0, 500, 500));
RecordingCanvas(const Rect.fromLTRB(0, 0, 500, 500));
Rect shaderRect = const Rect.fromLTRB(50, 50, 300, 300);
final Paint paint = Paint()..shader = Gradient.linear(
Offset(shaderRect.left, shaderRect.top),
Expand Down