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: 790616cbfb269fe17d44840ce52ec187fff5f9a7
revision: 0c1a793bfd49e30fccdd7ad64329a114a9cb32f7
24 changes: 21 additions & 3 deletions lib/web_ui/lib/src/engine/canvas_pool.dart
Original file line number Diff line number Diff line change
Expand Up @@ -501,8 +501,14 @@ class _CanvasPool extends _SaveStackTracking {
/// 'Runs' the given [path] by applying all of its commands to the canvas.
void _runPath(html.CanvasRenderingContext2D ctx, SurfacePath path) {
ctx.beginPath();
for (Subpath subpath in path.subpaths) {
for (PathCommand command in subpath.commands) {
final List<Subpath> subpaths = path.subpaths;
final int subpathCount = subpaths.length;
for (int subPathIndex = 0; subPathIndex < subpathCount; subPathIndex++) {
final Subpath subpath = subpaths[subPathIndex];
final List<PathCommand> commands = subpath.commands;
final int commandCount = commands.length;
for (int c = 0; c < commandCount; c++) {
final PathCommand command = commands[c];
switch (command.type) {
case PathCommandTypes.bezierCurveTo:
final BezierCurveTo curve = command;
Expand Down Expand Up @@ -587,7 +593,7 @@ class _CanvasPool extends _SaveStackTracking {

void drawPath(ui.Path path, ui.PaintingStyle style) {
_runPath(context, path);
contextHandle.paint(style);
contextHandle.paintPath(style, path.fillType);
}

void drawShadow(ui.Path path, ui.Color color, double elevation,
Expand Down Expand Up @@ -756,6 +762,18 @@ class ContextStateHandle {
}
}

void paintPath(ui.PaintingStyle style, ui.PathFillType pathFillType) {
if (style == ui.PaintingStyle.stroke) {
context.stroke();
} else {
if (pathFillType == ui.PathFillType.nonZero) {
context.fill();
} else {
context.fill('evenodd');
}
}
}

void reset() {
context.fillStyle = '';
// Read back fillStyle/strokeStyle values from context so that input such
Expand Down
16 changes: 8 additions & 8 deletions lib/web_ui/lib/src/engine/surface/path.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1005,22 +1005,22 @@ class SurfacePath implements ui.Path {
break;
case PathCommandTypes.rect:
final RectCommand cmd = op;
left = cmd.x;
minX = cmd.x;
double width = cmd.width;
if (cmd.width < 0) {
left -= width;
minX -= width;
width = -width;
}
double top = cmd.y;
minY = cmd.y;
double height = cmd.height;
if (cmd.height < 0) {
top -= height;
minY -= height;
height = -height;
}
curX = minX = left;
maxX = left + width;
curY = minY = top;
maxY = top + height;
curX = minX;
maxX = minX + width;
curY = minY;
maxY = minY + height;
break;
case PathCommandTypes.rRect:
final RRectCommand cmd = op;
Expand Down
27 changes: 15 additions & 12 deletions lib/web_ui/lib/src/engine/surface/recording_canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -440,19 +440,22 @@ class RecordingCanvas {
return;
}
}
_hasArbitraryPaint = true;
_didDraw = true;
ui.Rect pathBounds = path.getBounds();
final double paintSpread = _getPaintSpread(paint);
if (paintSpread != 0.0) {
pathBounds = pathBounds.inflate(paintSpread);
SurfacePath sPath = path;
if (sPath.subpaths.isNotEmpty) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice! I think I saw this in the cupertino slider as well. There were some commands thrown into the canvas without anything actually painted.

_hasArbitraryPaint = true;
_didDraw = true;
ui.Rect pathBounds = sPath.getBounds();
final double paintSpread = _getPaintSpread(paint);
if (paintSpread != 0.0) {
pathBounds = pathBounds.inflate(paintSpread);
}
// Clone path so it can be reused for subsequent draw calls.
final ui.Path clone = SurfacePath._shallowCopy(path);
final PaintDrawPath command = PaintDrawPath(clone, paint.paintData);
_paintBounds.grow(pathBounds, command);
clone.fillType = sPath.fillType;
_commands.add(command);
}
// Clone path so it can be reused for subsequent draw calls.
final ui.Path clone = SurfacePath._shallowCopy(path);
final PaintDrawPath command = PaintDrawPath(clone, paint.paintData);
_paintBounds.grow(pathBounds, command);
clone.fillType = path.fillType;
_commands.add(command);
}

void drawImage(ui.Image image, ui.Offset offset, SurfacePaint paint) {
Expand Down
72 changes: 72 additions & 0 deletions lib/web_ui/test/golden_tests/engine/canvas_winding_rule_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

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

import 'package:ui/src/engine.dart';
import 'package:ui/ui.dart';
import 'package:test/test.dart';

import 'package:web_engine_tester/golden_tester.dart';

void main() async {
final Rect region = Rect.fromLTWH(0, 0, 500, 500);

BitmapCanvas canvas;

setUp(() {
canvas = BitmapCanvas(region);
});

tearDown(() {
canvas.rootElement.remove();
});

test('draws paths using nonzero and evenodd winding rules', () async {
paintPaths(canvas);
html.document.body.append(canvas.rootElement);
await matchGoldenFile('canvas_path_winding.png', region: region);
});

}

void paintPaths(BitmapCanvas canvas) {
canvas.drawRect(Rect.fromLTRB(0, 0, 500, 500),
SurfacePaintData()
..color = Color(0xFFFFFFFF)
..style = PaintingStyle.fill); // white

SurfacePaint paintFill = SurfacePaint()
..style = PaintingStyle.fill
..color = Color(0xFF00B0FF);
SurfacePaint paintStroke = SurfacePaint()
..style = PaintingStyle.stroke
..strokeWidth = 2
..color = Color(0xFFE00000);
Path path1 = Path()
..fillType = PathFillType.evenOdd
..moveTo(50, 0)
..lineTo(21, 90)
..lineTo(98, 35)
..lineTo(2, 35)
..lineTo(79, 90)
..close()
..addRect(Rect.fromLTWH(20, 100, 200, 50))
..addRect(Rect.fromLTWH(40, 120, 160, 10));
Path path2 = Path()
..fillType = PathFillType.nonZero
..moveTo(50, 200)
..lineTo(21, 290)
..lineTo(98, 235)
..lineTo(2, 235)
..lineTo(79, 290)
..close()
..addRect(Rect.fromLTWH(20, 300, 200, 50))
..addRect(Rect.fromLTWH(40, 320, 160, 10));
canvas.drawPath(path1, paintFill.paintData);
canvas.drawPath(path2, paintFill.paintData);
canvas.drawPath(path1, paintStroke.paintData);
canvas.drawPath(path2, paintStroke.paintData);
}
10 changes: 10 additions & 0 deletions lib/web_ui/test/path_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ void main() {
expect(path.getBounds(), const Rect.fromLTRB(50, 60, 50, 60));
});

test('Should compute bounds for multiple addRect calls', () {
final Path emptyPath = Path();
expect(emptyPath.getBounds(), Rect.zero);

final SurfacePath path = SurfacePath();
path.addRect(Rect.fromLTWH(0, 0, 270, 45));
path.addRect(Rect.fromLTWH(134.5, 0, 1, 45));
expect(path.getBounds(), const Rect.fromLTRB(0, 0, 270, 45));
});

test('Should compute bounds for lines', () {
final SurfacePath path = SurfacePath();
path.moveTo(25, 30);
Expand Down