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
30 changes: 19 additions & 11 deletions lib/web_ui/lib/src/engine/html/dom_canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import 'package:ui/ui.dart' as ui;

import '../browser_detection.dart';
import '../engine_canvas.dart';
import '../html_image_codec.dart';
import '../text/canvas_paragraph.dart';
import '../util.dart';
import '../vector_math.dart';
import 'painting.dart';
import 'path/path.dart';
import 'path/path_to_svg.dart';
import 'shaders/image_shader.dart';
import 'shaders/shader.dart';

/// A canvas that renders to DOM elements and CSS properties.
class DomCanvas extends EngineCanvas with SaveElementStackTracking {
Expand Down Expand Up @@ -162,7 +162,6 @@ ui.Color blurColor(ui.Color color, double sigma) {

html.HtmlElement buildDrawRectElement(
ui.Rect rect, SurfacePaintData paint, String tagName, Matrix4 transform) {
assert(paint.shader == null);
final html.HtmlElement rectangle =
html.document.createElement(tagName) as html.HtmlElement;
assert(() {
Expand Down Expand Up @@ -226,19 +225,28 @@ html.HtmlElement buildDrawRectElement(
style
..width = '${right - left}px'
..height = '${bottom - top}px'
..backgroundColor = cssColor;

if (paint.shader != null && paint.shader is EngineImageShader) {
_applyImageShaderToElement(rectangle, paint.shader! as EngineImageShader);
}
..backgroundColor = cssColor
..backgroundImage = _getBackgroundImageCssValue(paint.shader, rect);
}
return rectangle;
}

void _applyImageShaderToElement(html.HtmlElement targetElement,
EngineImageShader imageShader) {
final HtmlImage image = imageShader.image;
targetElement.style.backgroundImage = image.imgElement.src;
String _getBackgroundImageCssValue(ui.Shader? shader, ui.Rect bounds) {
final String url = _getBackgroundImageUrl(shader, bounds);
return (url != '') ? "url('$url'": '';
}

String _getBackgroundImageUrl(ui.Shader? shader, ui.Rect bounds) {
if(shader != null) {
if(shader is EngineImageShader) {
return shader.image.imgElement.src ?? '';
}

if(shader is EngineGradient) {
return shader.createImageBitmap(bounds, 1, true) as String;
}
}
return '';
}

void applyRRectBorderRadius(html.CssStyleDeclaration style, ui.RRect rrect) {
Expand Down
7 changes: 6 additions & 1 deletion lib/web_ui/lib/src/engine/html/shader_mask.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,13 @@ class PersistedShaderMask extends PersistedContainerSurface
void _applyGradientShader() {
if (shader is EngineGradient) {
final EngineGradient gradientShader = shader as EngineGradient;

// The gradient shader's bounds are in the context of the element itself,
// rather than the global position, so translate it back to the origin.
final ui.Rect translatedRect =
maskRect.translate(-maskRect.left, -maskRect.top);
final String imageUrl =
gradientShader.createImageBitmap(maskRect, 1, true) as String;
gradientShader.createImageBitmap(translatedRect, 1, true) as String;
ui.BlendMode blendModeTemp = blendMode;
switch (blendModeTemp) {
case ui.BlendMode.clear:
Expand Down
8 changes: 0 additions & 8 deletions lib/web_ui/lib/src/engine/html/shaders/shader.dart
Original file line number Diff line number Diff line change
Expand Up @@ -234,14 +234,6 @@ class GradientLinear extends EngineGradient {
_createLinearFragmentShader(normalizedGradient, tileMode));
gl.useProgram(glProgram);

/// When creating an image to apply to a dom element, render
/// contents at 0,0 and adjust gradient vector for shaderBounds.
final bool translateToOrigin = createDataUrl;

if (translateToOrigin) {
shaderBounds = shaderBounds.translate(-shaderBounds.left, -shaderBounds.top);
}

// Setup from/to uniforms.
//
// From/to is relative to shaderBounds.
Expand Down
34 changes: 34 additions & 0 deletions lib/web_ui/test/html/shaders/gradient_golden_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,40 @@ Future<void> testMain() async {
canvas.restore();
await _checkScreenshot(canvas, 'linear_gradient_rect_clamp_rotated');
});

test('Paints linear gradient properly when within svg context', () async {
final RecordingCanvas canvas =
RecordingCanvas(const Rect.fromLTRB(0, 0, 500, 240));
canvas.save();

canvas.renderStrategy.isInsideSvgFilterTree = true;

final SurfacePaint borderPaint = SurfacePaint()
..style = PaintingStyle.stroke
..strokeWidth = 1
..color = const Color(0xFF000000);

const List<Color> colors = <Color>[
Color(0xFFFF0000),
Color(0xFF0000FF),
];

final GradientLinear linearGradient = GradientLinear(const Offset(125, 75),
const Offset(175, 125),
colors, null, TileMode.clamp,
Matrix4.identity().storage);

const double kBoxWidth = 150;
const double kBoxHeight = 100;
// Gradient with default center.
const Rect rectBounds = Rect.fromLTWH(100, 50, kBoxWidth, kBoxHeight);
canvas.drawRect(rectBounds,
SurfacePaint()..shader = engineLinearGradientToShader(linearGradient, rectBounds));
canvas.drawRect(rectBounds, borderPaint);

canvas.restore();
await _checkScreenshot(canvas, 'linear_gradient_in_svg_context');
});
}

Shader engineGradientToShader(GradientSweep gradient, Rect rect) {
Expand Down