mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
reland fix canvas drawLine bugs (flutter/engine#38949)
* fix canvas drawLine bugs * removed unecessary params from pathToSvgElement Co-authored-by: alanwutang11 <alpwu@google.com>
This commit is contained in:
parent
36da202b72
commit
08bfbfebc9
@ -538,20 +538,6 @@ class BitmapCanvas extends EngineCanvas {
|
||||
if (_useDomForRenderingFill(paint)) {
|
||||
final Matrix4 transform = _canvasPool.currentTransform;
|
||||
final SurfacePath surfacePath = path as SurfacePath;
|
||||
final ui.Rect? pathAsLine = surfacePath.toStraightLine();
|
||||
if (pathAsLine != null) {
|
||||
ui.Rect rect = (pathAsLine.top == pathAsLine.bottom)
|
||||
? ui.Rect.fromLTWH(
|
||||
pathAsLine.left, pathAsLine.top, pathAsLine.width, 1)
|
||||
: ui.Rect.fromLTWH(
|
||||
pathAsLine.left, pathAsLine.top, 1, pathAsLine.height);
|
||||
|
||||
rect = adjustRectForDom(rect, paint);
|
||||
final DomHTMLElement element = buildDrawRectElement(
|
||||
rect, paint, 'draw-rect', _canvasPool.currentTransform);
|
||||
_drawElement(element, rect.topLeft, paint);
|
||||
return;
|
||||
}
|
||||
|
||||
final ui.Rect? pathAsRect = surfacePath.toRect();
|
||||
if (pathAsRect != null) {
|
||||
@ -563,9 +549,7 @@ class BitmapCanvas extends EngineCanvas {
|
||||
drawRRect(pathAsRRect, paint);
|
||||
return;
|
||||
}
|
||||
final ui.Rect pathBounds = surfacePath.getBounds();
|
||||
final DomElement svgElm = pathToSvgElement(
|
||||
surfacePath, paint, '${pathBounds.right}', '${pathBounds.bottom}');
|
||||
final DomElement svgElm = pathToSvgElement(surfacePath, paint);
|
||||
if (!_canvasPool.isClipped) {
|
||||
final DomCSSStyleDeclaration style = svgElm.style;
|
||||
style.position = 'absolute';
|
||||
|
||||
@ -392,9 +392,7 @@ class PersistedPhysicalShape extends PersistedContainerSurface
|
||||
path,
|
||||
SurfacePaintData()
|
||||
..style = ui.PaintingStyle.fill
|
||||
..color = color.value,
|
||||
'${pathBounds2.right}',
|
||||
'${pathBounds2.bottom}');
|
||||
..color = color.value);
|
||||
|
||||
/// Render element behind the clipped content.
|
||||
rootElement!.insertBefore(_svgElement!, childContainer);
|
||||
|
||||
@ -14,6 +14,7 @@ import '../svg.dart';
|
||||
import '../text/canvas_paragraph.dart';
|
||||
import '../util.dart';
|
||||
import '../vector_math.dart';
|
||||
import 'bitmap_canvas.dart';
|
||||
import 'painting.dart';
|
||||
import 'path/path.dart';
|
||||
import 'path/path_to_svg.dart';
|
||||
@ -333,14 +334,11 @@ String _borderStrokeToCssUnit(double value) {
|
||||
return '${value.toStringAsFixed(3)}px';
|
||||
}
|
||||
|
||||
SVGSVGElement pathToSvgElement(
|
||||
SurfacePath path, SurfacePaintData paint, String width, String height) {
|
||||
SVGSVGElement pathToSvgElement(SurfacePath path, SurfacePaintData paint) {
|
||||
// In Firefox some SVG typed attributes are returned as null without a
|
||||
// setter. So we use strings here.
|
||||
final SVGSVGElement root = createSVGSVGElement()
|
||||
..setAttribute('width', '${width}px')
|
||||
..setAttribute('height', '${height}px')
|
||||
..setAttribute('viewBox', '0 0 $width $height');
|
||||
..setAttribute('overflow', 'visible');
|
||||
|
||||
final SVGPathElement svgPath = createSVGPathElement();
|
||||
root.append(svgPath);
|
||||
@ -350,6 +348,9 @@ SVGSVGElement pathToSvgElement(
|
||||
paint.strokeWidth != null)) {
|
||||
svgPath.setAttribute('stroke', colorValueToCssString(paint.color)!);
|
||||
svgPath.setAttribute('stroke-width', '${paint.strokeWidth ?? 1.0}');
|
||||
if (paint.strokeCap != null) {
|
||||
svgPath.setAttribute('stroke-linecap', '${stringForStrokeCap(paint.strokeCap)}');
|
||||
}
|
||||
svgPath.setAttribute('fill', 'none');
|
||||
} else if (paint.color != null) {
|
||||
svgPath.setAttribute('fill', colorValueToCssString(paint.color)!);
|
||||
|
||||
@ -17,13 +17,17 @@ Future<void> testMain() async {
|
||||
const Rect region = Rect.fromLTWH(0, 0, 300, 300);
|
||||
|
||||
late BitmapCanvas canvas;
|
||||
late BitmapCanvas domCanvas;
|
||||
|
||||
setUp(() {
|
||||
canvas = BitmapCanvas(region, RenderStrategy());
|
||||
// setting isInsideSvgFilterTree true forces use of DOM canvas
|
||||
domCanvas = BitmapCanvas(region, RenderStrategy()..isInsideSvgFilterTree = true);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
canvas.rootElement.remove();
|
||||
domCanvas.rootElement.remove();
|
||||
});
|
||||
|
||||
test('draws lines with varying strokeWidth', () async {
|
||||
@ -33,6 +37,75 @@ Future<void> testMain() async {
|
||||
domDocument.body!.append(canvas.rootElement);
|
||||
await matchGoldenFile('canvas_lines_thickness.png', region: region);
|
||||
});
|
||||
test('draws lines with varying strokeWidth with dom canvas', () async {
|
||||
|
||||
paintLines(domCanvas);
|
||||
|
||||
domDocument.body!.append(domCanvas.rootElement);
|
||||
await matchGoldenFile('canvas_lines_thickness_dom_canvas.png', region: region);
|
||||
});
|
||||
test('draws lines with negative Offset values with dom canvas', () async {
|
||||
// test rendering lines correctly with negative offset when using DOM
|
||||
final SurfacePaintData paintWithStyle = SurfacePaintData()
|
||||
..color = 0xFFE91E63 // Colors.pink
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 16
|
||||
..strokeCap = StrokeCap.round;
|
||||
|
||||
// canvas.drawLine ignores paint.style (defaults to fill) according to api docs.
|
||||
// expect lines are rendered the same regardless of the set paint.style
|
||||
final SurfacePaintData paintWithoutStyle = SurfacePaintData()
|
||||
..color = 0xFF4CAF50 // Colors.green
|
||||
..strokeWidth = 16
|
||||
..strokeCap = StrokeCap.round;
|
||||
|
||||
// test vertical, horizontal, and diagonal lines
|
||||
final List<Offset> points = <Offset>[
|
||||
const Offset(-25, 50), const Offset(45, 50),
|
||||
const Offset(100, -25), const Offset(100, 200),
|
||||
const Offset(-150, -145), const Offset(100, 200),
|
||||
];
|
||||
final List<Offset> shiftedPoints = points.map((Offset point) => point.translate(20, 20)).toList();
|
||||
|
||||
paintLinesFromPoints(domCanvas, paintWithStyle, points);
|
||||
paintLinesFromPoints(domCanvas, paintWithoutStyle, shiftedPoints);
|
||||
|
||||
domDocument.body!.append(domCanvas.rootElement);
|
||||
await matchGoldenFile('canvas_lines_with_negative_offset.png', region: region);
|
||||
});
|
||||
|
||||
test('drawLines method respects strokeCap with dom canvas', () async {
|
||||
final SurfacePaintData paintStrokeCapRound = SurfacePaintData()
|
||||
..color = 0xFFE91E63 // Colors.pink
|
||||
..strokeWidth = 16
|
||||
..strokeCap = StrokeCap.round;
|
||||
|
||||
final SurfacePaintData paintStrokeCapSquare = SurfacePaintData()
|
||||
..color = 0xFF4CAF50 // Colors.green
|
||||
..strokeWidth = 16
|
||||
..strokeCap = StrokeCap.square;
|
||||
|
||||
final SurfacePaintData paintStrokeCapButt = SurfacePaintData()
|
||||
..color = 0xFFFF9800 // Colors.orange
|
||||
..strokeWidth = 16
|
||||
..strokeCap = StrokeCap.butt;
|
||||
|
||||
// test vertical, horizontal, and diagonal lines
|
||||
final List<Offset> points = <Offset>[
|
||||
const Offset(5, 50), const Offset(45, 50),
|
||||
const Offset(100, 5), const Offset(100, 200),
|
||||
const Offset(5, 10), const Offset(100, 200),
|
||||
];
|
||||
final List<Offset> shiftedPoints = points.map((Offset point) => point.translate(50, 50)).toList();
|
||||
final List<Offset> twiceShiftedPoints = shiftedPoints.map((Offset point) => point.translate(50, 50)).toList();
|
||||
|
||||
paintLinesFromPoints(domCanvas, paintStrokeCapRound, points);
|
||||
paintLinesFromPoints(domCanvas, paintStrokeCapSquare, shiftedPoints);
|
||||
paintLinesFromPoints(domCanvas, paintStrokeCapButt, twiceShiftedPoints);
|
||||
|
||||
domDocument.body!.append(domCanvas.rootElement);
|
||||
await matchGoldenFile('canvas_lines_with_strokeCap.png', region: region);
|
||||
});
|
||||
}
|
||||
|
||||
void paintLines(BitmapCanvas canvas) {
|
||||
@ -70,3 +143,10 @@ void paintLines(BitmapCanvas canvas) {
|
||||
paint3.color = 0xFFFF9800; // Colors.orange;
|
||||
canvas.drawLine(const Offset(50, 70), const Offset(150, 70), paint3);
|
||||
}
|
||||
|
||||
void paintLinesFromPoints(BitmapCanvas canvas, SurfacePaintData paint, List<Offset> points) {
|
||||
// points list contains pairs of Offset points, so for loop step is 2
|
||||
for (int i = 0; i < points.length - 1; i += 2) {
|
||||
canvas.drawLine(points[i], points[i + 1], paint);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user