未验证 提交 91ec9451 编写于 作者: F Ferhat 提交者: GitHub

[web] Optimize BitmapCanvas. Fixes overallocation of canvas elements (#22856)

上级 c5b01843
......@@ -108,15 +108,19 @@ class BitmapCanvas extends EngineCanvas {
/// uses global transform of canvas to compute ratio.
final double _density;
final RenderStrategy _renderStrategy;
/// Allocates a canvas with enough memory to paint a picture within the given
/// [bounds].
///
/// This canvas can be reused by pictures with different paint bounds as long
/// as the [Rect.size] of the bounds fully fit within the size used to
/// initialize this canvas.
BitmapCanvas(this._bounds, {double density = 1.0})
BitmapCanvas(this._bounds, RenderStrategy renderStrategy,
{double density = 1.0})
: assert(_bounds != null), // ignore: unnecessary_null_comparison
_density = density,
_renderStrategy = renderStrategy,
_widthInBitmapPixels = _widthToPhysical(_bounds.width),
_heightInBitmapPixels = _heightToPhysical(_bounds.height),
_canvasPool = _CanvasPool(_widthToPhysical(_bounds.width),
......@@ -134,7 +138,7 @@ class BitmapCanvas extends EngineCanvas {
/// Constructs bitmap canvas to capture image data.
factory BitmapCanvas.imageData(ui.Rect bounds) {
BitmapCanvas bitmapCanvas = BitmapCanvas(bounds);
BitmapCanvas bitmapCanvas = BitmapCanvas(bounds, RenderStrategy());
bitmapCanvas._preserveImageData = true;
return bitmapCanvas;
}
......@@ -331,19 +335,30 @@ class BitmapCanvas extends EngineCanvas {
/// - Pictures typically have large rect/rounded rectangles as background
/// prefer DOM if canvas has not been allocated yet.
///
bool _useDomForRendering(SurfacePaintData paint) =>
bool _useDomForRenderingFill(SurfacePaintData paint) =>
(_preserveImageData == false && _contains3dTransform) ||
(_childOverdraw && _canvasPool._canvas == null &&
paint.maskFilter == null &&
paint.shader == null &&
paint.style != ui.PaintingStyle.stroke);
/// Same as [_useDomForRenderingFill] but allows stroke as well.
///
/// DOM canvas is generated for simple strokes using borders.
bool _useDomForRenderingFillAndStroke(SurfacePaintData paint) =>
(_preserveImageData == false && _contains3dTransform) ||
((_childOverdraw || _renderStrategy.hasImageElements ||
_renderStrategy.hasParagraphs) &&
_canvasPool._canvas == null &&
paint.maskFilter == null &&
paint.shader == null);
@override
void drawColor(ui.Color color, ui.BlendMode blendMode) {
final SurfacePaintData paintData = SurfacePaintData()
..color = color
..blendMode = blendMode;
if (_useDomForRendering(paintData)) {
if (_useDomForRenderingFill(paintData)) {
drawRect(_computeScreenBounds(_canvasPool._currentTransform), paintData);
} else {
_canvasPool.drawColor(color, blendMode);
......@@ -352,7 +367,7 @@ class BitmapCanvas extends EngineCanvas {
@override
void drawLine(ui.Offset p1, ui.Offset p2, SurfacePaintData paint) {
if (_useDomForRendering(paint)) {
if (_useDomForRenderingFill(paint)) {
final SurfacePath path = SurfacePath()
..moveTo(p1.dx, p1.dy)
..lineTo(p2.dx, p2.dy);
......@@ -368,7 +383,7 @@ class BitmapCanvas extends EngineCanvas {
@override
void drawPaint(SurfacePaintData paint) {
if (_useDomForRendering(paint)) {
if (_useDomForRenderingFill(paint)) {
drawRect(_computeScreenBounds(_canvasPool._currentTransform), paint);
} else {
ui.Rect? shaderBounds = (paint.shader != null) ?
......@@ -381,7 +396,7 @@ class BitmapCanvas extends EngineCanvas {
@override
void drawRect(ui.Rect rect, SurfacePaintData paint) {
if (_useDomForRendering(paint)) {
if (_useDomForRenderingFillAndStroke(paint)) {
html.HtmlElement element = _buildDrawRectElement(
rect, paint, 'draw-rect', _canvasPool._currentTransform);
_drawElement(
......@@ -418,12 +433,14 @@ class BitmapCanvas extends EngineCanvas {
if (blendMode != null) {
element.style.mixBlendMode = _stringForBlendMode(blendMode) ?? '';
}
// Switch to preferring DOM from now on.
_childOverdraw = true;
}
@override
void drawRRect(ui.RRect rrect, SurfacePaintData paint) {
final ui.Rect rect = rrect.outerRect;
if (_useDomForRendering(paint)) {
if (_useDomForRenderingFillAndStroke(paint)) {
html.HtmlElement element = _buildDrawRectElement(
rect, paint, 'draw-rrect', _canvasPool._currentTransform);
_applyRRectBorderRadius(element.style, rrect);
......@@ -448,7 +465,7 @@ class BitmapCanvas extends EngineCanvas {
@override
void drawOval(ui.Rect rect, SurfacePaintData paint) {
if (_useDomForRendering(paint)) {
if (_useDomForRenderingFill(paint)) {
html.HtmlElement element = _buildDrawRectElement(
rect, paint, 'draw-oval', _canvasPool._currentTransform);
_drawElement(
......@@ -468,7 +485,7 @@ class BitmapCanvas extends EngineCanvas {
@override
void drawCircle(ui.Offset c, double radius, SurfacePaintData paint) {
ui.Rect rect = ui.Rect.fromCircle(center: c, radius: radius);
if (_useDomForRendering(paint)) {
if (_useDomForRenderingFillAndStroke(paint)) {
html.HtmlElement element = _buildDrawRectElement(
rect, paint, 'draw-circle', _canvasPool._currentTransform);
_drawElement(
......@@ -487,7 +504,7 @@ class BitmapCanvas extends EngineCanvas {
@override
void drawPath(ui.Path path, SurfacePaintData paint) {
if (_useDomForRendering(paint)) {
if (_useDomForRenderingFill(paint)) {
final Matrix4 transform = _canvasPool._currentTransform;
final SurfacePath surfacePath = path as SurfacePath;
final ui.Rect? pathAsLine = surfacePath.toStraightLine();
......@@ -510,6 +527,11 @@ class BitmapCanvas extends EngineCanvas {
drawRect(pathAsRect, paint);
return;
}
final ui.RRect ? pathAsRRect = surfacePath.toRoundedRect();
if (pathAsRRect != null) {
drawRRect(pathAsRRect, paint);
return;
}
final ui.Rect pathBounds = surfacePath.getBounds();
html.Element svgElm = _pathToSvgElement(
surfacePath, paint, '${pathBounds.right}', '${pathBounds.bottom}');
......
......@@ -186,7 +186,7 @@ html.HtmlElement _buildDrawRectElement(ui.Rect rect, SurfacePaintData paint, Str
style
..width = '${right - left - strokeWidth}px'
..height = '${bottom - top - strokeWidth}px'
..border = '${strokeWidth}px solid $cssColor';
..border = '${_borderStrokeToCssUnit(strokeWidth)} solid $cssColor';
} else {
style
..width = '${right - left}px'
......@@ -204,18 +204,26 @@ void _applyRRectBorderRadius(html.CssStyleDeclaration style, ui.RRect rrect) {
rrect.trRadiusX == rrect.trRadiusY &&
rrect.blRadiusX == rrect.blRadiusY &&
rrect.brRadiusX == rrect.brRadiusY) {
style.borderRadius = '${rrect.blRadiusX.toStringAsFixed(3)}px';
style.borderRadius = '${_borderStrokeToCssUnit(rrect.blRadiusX)}';
return;
}
// Non-uniform. Apply each corner radius.
style.borderTopLeftRadius = '${rrect.tlRadiusX.toStringAsFixed(3)}px '
'${rrect.tlRadiusY.toStringAsFixed(3)}px';
style.borderTopRightRadius = '${rrect.trRadiusX.toStringAsFixed(3)}px '
'${rrect.trRadiusY.toStringAsFixed(3)}px';
style.borderBottomLeftRadius = '${rrect.blRadiusX.toStringAsFixed(3)}px '
'${rrect.blRadiusY.toStringAsFixed(3)}px';
style.borderBottomRightRadius = '${rrect.brRadiusX.toStringAsFixed(3)}px '
'${rrect.brRadiusY.toStringAsFixed(3)}px';
style.borderTopLeftRadius = '${_borderStrokeToCssUnit(rrect.tlRadiusX)} '
'${_borderStrokeToCssUnit(rrect.tlRadiusY)}';
style.borderTopRightRadius = '${_borderStrokeToCssUnit(rrect.trRadiusX)} '
'${_borderStrokeToCssUnit(rrect.trRadiusY)}';
style.borderBottomLeftRadius = '${_borderStrokeToCssUnit(rrect.blRadiusX)} '
'${_borderStrokeToCssUnit(rrect.blRadiusY)}';
style.borderBottomRightRadius = '${_borderStrokeToCssUnit(rrect.brRadiusX)} '
'${_borderStrokeToCssUnit(rrect.brRadiusY)}';
}
String _borderStrokeToCssUnit(double value) {
if (value == 0) {
// TODO: hairline nees to take into account both dpi and density.
value = 1.0;
}
return '${value.toStringAsFixed(3)}px';
}
html.Element _pathToSvgElement(SurfacePath path, SurfacePaintData paint,
......
......@@ -346,8 +346,9 @@ class PersistedPicture extends PersistedLeafSurface {
}
final bool didRequireBitmap =
existingSurface.picture.recordingCanvas!.hasArbitraryPaint;
final bool requiresBitmap = picture.recordingCanvas!.hasArbitraryPaint;
existingSurface.picture.recordingCanvas!.renderStrategy.hasArbitraryPaint;
final bool requiresBitmap =
picture.recordingCanvas!.renderStrategy.hasArbitraryPaint;
if (didRequireBitmap != requiresBitmap) {
// Switching canvas types is always expensive.
return 1.0;
......@@ -388,7 +389,7 @@ class PersistedPicture extends PersistedLeafSurface {
Matrix4? get localTransformInverse => null;
void applyPaint(EngineCanvas? oldCanvas) {
if (picture.recordingCanvas!.hasArbitraryPaint) {
if (picture.recordingCanvas!.renderStrategy.hasArbitraryPaint) {
_applyBitmapPaint(oldCanvas);
} else {
_applyDomPaint(oldCanvas);
......@@ -515,7 +516,8 @@ class PersistedPicture extends PersistedLeafSurface {
if (_debugShowCanvasReuseStats) {
DebugCanvasReuseOverlay.instance.createdCount++;
}
final BitmapCanvas canvas = BitmapCanvas(bounds, density: _density);
final BitmapCanvas canvas = BitmapCanvas(bounds,
picture.recordingCanvas!.renderStrategy, density: _density);
canvas.setElementCache(_elementCache);
if (_debugExplainSurfaceStats) {
_surfaceStatsFor(this)
......
......@@ -20,7 +20,8 @@ double _measureBorderRadius(double x, double y) {
}
class RawRecordingCanvas extends BitmapCanvas implements ui.PictureRecorder {
RawRecordingCanvas(ui.Size size) : super(ui.Offset.zero & size);
RawRecordingCanvas(ui.Size size) : super(ui.Offset.zero & size,
RenderStrategy());
@override
void dispose() {
......@@ -77,17 +78,14 @@ class RecordingCanvas {
RecordingCanvas(ui.Rect? bounds)
: _paintBounds = _PaintBounds(bounds ?? ui.Rect.largest);
/// Whether this canvas is doing arbitrary paint operations not expressible
/// via DOM elements.
bool get hasArbitraryPaint => _hasArbitraryPaint;
bool _hasArbitraryPaint = false;
final RenderStrategy renderStrategy = RenderStrategy();
/// Forces arbitrary paint even for simple pictures.
///
/// This is useful for testing bitmap canvas when otherwise the compositor
/// would prefer a DOM canvas.
void debugEnforceArbitraryPaint() {
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
}
/// Whether this canvas contain drawing operations.
......@@ -210,7 +208,7 @@ class RecordingCanvas {
void saveLayerWithoutBounds(SurfacePaint paint) {
assert(!_recordingEnded);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
// TODO(het): Implement this correctly using another canvas.
_commands.add(const PaintSave());
_paintBounds.saveTransformsAndClip();
......@@ -219,7 +217,7 @@ class RecordingCanvas {
void saveLayer(ui.Rect bounds, SurfacePaint paint) {
assert(!_recordingEnded);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
// TODO(het): Implement this correctly using another canvas.
_commands.add(const PaintSave());
_paintBounds.saveTransformsAndClip();
......@@ -268,7 +266,7 @@ class RecordingCanvas {
void skew(double sx, double sy) {
assert(!_recordingEnded);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
_paintBounds.skew(sx, sy);
_commands.add(PaintSkew(sx, sy));
}
......@@ -284,7 +282,7 @@ class RecordingCanvas {
// Since this refers to inverse, can't shrink paintBounds.
break;
}
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
_commands.add(command);
}
......@@ -292,7 +290,7 @@ class RecordingCanvas {
assert(!_recordingEnded);
final PaintClipRRect command = PaintClipRRect(rrect);
_paintBounds.clipRect(rrect.outerRect, command);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
_commands.add(command);
}
......@@ -300,7 +298,7 @@ class RecordingCanvas {
assert(!_recordingEnded);
final PaintClipPath command = PaintClipPath(path as SurfacePath);
_paintBounds.clipRect(path.getBounds(), command);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
_commands.add(command);
}
......@@ -329,14 +327,14 @@ class RecordingCanvas {
math.max(p1.dy, p2.dy) + paintSpread,
command,
);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
_didDraw = true;
_commands.add(command);
}
void drawPaint(SurfacePaint paint) {
assert(!_recordingEnded);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
_didDraw = true;
final PaintDrawPaint command = PaintDrawPaint(paint.paintData);
_paintBounds.grow(_paintBounds.maxPaintBounds, command);
......@@ -346,7 +344,7 @@ class RecordingCanvas {
void drawRect(ui.Rect rect, SurfacePaint paint) {
assert(!_recordingEnded);
if (paint.shader != null) {
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
}
_didDraw = true;
final double paintSpread = _getPaintSpread(paint);
......@@ -362,7 +360,7 @@ class RecordingCanvas {
void drawRRect(ui.RRect rrect, SurfacePaint paint) {
assert(!_recordingEnded);
if (paint.shader != null || !rrect.webOnlyUniformRadii) {
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
}
_didDraw = true;
final double paintSpread = _getPaintSpread(paint);
......@@ -414,7 +412,7 @@ class RecordingCanvas {
return; // Some inner radius is overlapping some outer radius
}
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
_didDraw = true;
final double paintSpread = _getPaintSpread(paint);
final PaintDrawDRRect command =
......@@ -431,7 +429,7 @@ class RecordingCanvas {
void drawOval(ui.Rect rect, SurfacePaint paint) {
assert(!_recordingEnded);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
_didDraw = true;
final double paintSpread = _getPaintSpread(paint);
final PaintDrawOval command = PaintDrawOval(rect, paint.paintData);
......@@ -445,7 +443,7 @@ class RecordingCanvas {
void drawCircle(ui.Offset c, double radius, SurfacePaint paint) {
assert(!_recordingEnded);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
_didDraw = true;
final double paintSpread = _getPaintSpread(paint);
final PaintDrawCircle command = PaintDrawCircle(c, radius, paint.paintData);
......@@ -479,7 +477,7 @@ class RecordingCanvas {
}
SurfacePath sPath = path as SurfacePath;
if (!sPath.pathRef.isEmpty) {
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
_didDraw = true;
ui.Rect pathBounds = sPath.getBounds();
final double paintSpread = _getPaintSpread(paint);
......@@ -498,7 +496,8 @@ class RecordingCanvas {
void drawImage(ui.Image image, ui.Offset offset, SurfacePaint paint) {
assert(!_recordingEnded);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
renderStrategy.hasImageElements = true;
_didDraw = true;
final double left = offset.dx;
final double top = offset.dy;
......@@ -511,7 +510,8 @@ class RecordingCanvas {
void drawImageRect(
ui.Image image, ui.Rect src, ui.Rect dst, SurfacePaint paint) {
assert(!_recordingEnded);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
renderStrategy.hasImageElements = true;
_didDraw = true;
final PaintDrawImageRect command =
PaintDrawImageRect(image, src, dst, paint.paintData);
......@@ -529,8 +529,9 @@ class RecordingCanvas {
_didDraw = true;
if (engineParagraph.hasArbitraryPaint) {
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
}
renderStrategy.hasParagraphs = true;
final double left = offset.dx;
final double top = offset.dy;
final PaintDrawParagraph command =
......@@ -548,7 +549,7 @@ class RecordingCanvas {
void drawShadow(ui.Path path, ui.Color color, double elevation,
bool transparentOccluder) {
assert(!_recordingEnded);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
_didDraw = true;
final ui.Rect shadowRect =
computePenumbraBounds(path.getBounds(), elevation);
......@@ -561,7 +562,7 @@ class RecordingCanvas {
void drawVertices(
SurfaceVertices vertices, ui.BlendMode blendMode, SurfacePaint paint) {
assert(!_recordingEnded);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
_didDraw = true;
final PaintDrawVertices command =
PaintDrawVertices(vertices, blendMode, paint.paintData);
......@@ -572,7 +573,7 @@ class RecordingCanvas {
void drawRawPoints(
ui.PointMode pointMode, Float32List points, SurfacePaint paint) {
assert(!_recordingEnded);
_hasArbitraryPaint = true;
renderStrategy.hasArbitraryPaint = true;
_didDraw = true;
final PaintDrawPoints command =
PaintDrawPoints(pointMode, points, paint.paintData);
......@@ -1910,3 +1911,21 @@ double _getPaintSpread(SurfacePaint paint) {
}
return spread;
}
/// Contains metrics collected by recording canvas to provide data for
/// rendering heuristics (canvas use vs DOM).
class RenderStrategy {
/// Whether paint commands contain image elements.
bool hasImageElements = false;
/// Whether paint commands contain paragraphs.
bool hasParagraphs = false;
/// Whether paint commands are doing arbitrary operations
/// not expressible via pure DOM elements.
///
/// This is used to decide whether to use simplified DomCanvas.
bool hasArbitraryPaint = false;
RenderStrategy();
}
......@@ -29,7 +29,7 @@ void testMain() {
{ui.Rect canvasSize, ui.VoidCallback whenDone}) {
canvasSize ??= const ui.Rect.fromLTWH(0, 0, 100, 100);
test(description, () {
testFn(BitmapCanvas(canvasSize));
testFn(BitmapCanvas(canvasSize, RenderStrategy()));
testFn(DomCanvas(domRenderer.createElement('flt-picture')));
testFn(mockCanvas = MockEngineCanvas());
if (whenDone != null) {
......
......@@ -682,7 +682,7 @@ class MockPersistedPicture extends PersistedPicture {
int updateCount = 0;
int applyPaintCount = 0;
final BitmapCanvas _fakeCanvas = BitmapCanvas(const Rect.fromLTRB(0, 0, 10, 10));
final BitmapCanvas _fakeCanvas = BitmapCanvas(const Rect.fromLTRB(0, 0, 10, 10), RenderStrategy());
@override
EngineCanvas get debugCanvas {
......
......@@ -22,7 +22,7 @@ void testMain() async {
BitmapCanvas canvas;
setUp(() {
canvas = BitmapCanvas(region);
canvas = BitmapCanvas(region, RenderStrategy());
});
tearDown(() {
......
......@@ -25,7 +25,8 @@ void testMain() async {
Future<void> _checkScreenshot(RecordingCanvas rc, String fileName,
{Rect region = const Rect.fromLTWH(0, 0, 500, 500),
double maxDiffRatePercent = 0.0, bool write = false}) async {
final EngineCanvas engineCanvas = BitmapCanvas(screenRect);
final EngineCanvas engineCanvas = BitmapCanvas(screenRect,
RenderStrategy());
rc.endRecording();
rc.apply(engineCanvas, screenRect);
......
......@@ -25,7 +25,8 @@ void testMain() async {
// Commit a recording canvas to a bitmap, and compare with the expected
Future<void> _checkScreenshot(engine.RecordingCanvas rc, String fileName,
{Rect region = const Rect.fromLTWH(0, 0, 500, 500)}) async {
final engine.EngineCanvas engineCanvas = engine.BitmapCanvas(screenRect);
final engine.EngineCanvas engineCanvas = engine.BitmapCanvas(screenRect,
engine.RenderStrategy());
rc.endRecording();
rc.apply(engineCanvas, screenRect);
......
......@@ -25,7 +25,8 @@ void testMain() async {
// Commit a recording canvas to a bitmap, and compare with the expected
Future<void> _checkScreenshot(engine.RecordingCanvas rc, String fileName,
{Rect region = const Rect.fromLTWH(0, 0, 500, 500)}) async {
final engine.EngineCanvas engineCanvas = engine.BitmapCanvas(screenRect);
final engine.EngineCanvas engineCanvas = engine.BitmapCanvas(screenRect,
engine.RenderStrategy());
rc.endRecording();
rc.apply(engineCanvas, screenRect);
......
......@@ -30,7 +30,8 @@ void testMain() async {
{Rect region = const Rect.fromLTWH(0, 0, 500, 500),
double maxDiffRatePercent = 0.0, bool setupPerspective = false,
bool write = false}) async {
final EngineCanvas engineCanvas = BitmapCanvas(screenRect);
final EngineCanvas engineCanvas = BitmapCanvas(screenRect,
RenderStrategy());
rc.endRecording();
rc.apply(engineCanvas, screenRect);
......
......@@ -23,7 +23,7 @@ void testMain() async {
BitmapCanvas canvas;
setUp(() {
canvas = BitmapCanvas(region);
canvas = BitmapCanvas(region, RenderStrategy());
});
tearDown(() {
......
......@@ -77,7 +77,8 @@ void testMain() async {
}
test('renders pixels that are not aligned inside the canvas', () async {
canvas = BitmapCanvas(const Rect.fromLTWH(0, 0, 60, 60));
canvas = BitmapCanvas(const Rect.fromLTWH(0, 0, 60, 60),
RenderStrategy());
drawMisalignedLines(canvas);
......@@ -92,7 +93,8 @@ void testMain() async {
// shift its position back to 0.0 and at the same time it will it will
// compensate by shifting the contents of the canvas in the opposite
// direction.
canvas = BitmapCanvas(const Rect.fromLTWH(0.5, 0.5, 60, 60));
canvas = BitmapCanvas(const Rect.fromLTWH(0.5, 0.5, 60, 60),
RenderStrategy());
canvas.clipRect(const Rect.fromLTWH(0, 0, 50, 50), ClipOp.intersect);
drawMisalignedLines(canvas);
......@@ -103,7 +105,8 @@ void testMain() async {
});
test('fill the whole canvas with color even when transformed', () async {
canvas = BitmapCanvas(const Rect.fromLTWH(0, 0, 50, 50));
canvas = BitmapCanvas(const Rect.fromLTWH(0, 0, 50, 50),
RenderStrategy());
canvas.clipRect(const Rect.fromLTWH(0, 0, 50, 50), ClipOp.intersect);
canvas.translate(25, 25);
canvas.drawColor(const Color.fromRGBO(0, 255, 0, 1.0), BlendMode.src);
......@@ -116,7 +119,8 @@ void testMain() async {
});
test('fill the whole canvas with paint even when transformed', () async {
canvas = BitmapCanvas(const Rect.fromLTWH(0, 0, 50, 50));
canvas = BitmapCanvas(const Rect.fromLTWH(0, 0, 50, 50),
RenderStrategy());
canvas.clipRect(const Rect.fromLTWH(0, 0, 50, 50), ClipOp.intersect);
canvas.translate(25, 25);
canvas.drawPaint(SurfacePaintData()
......@@ -160,7 +164,7 @@ void testMain() async {
final Rect innerClip = Rect.fromLTRB(0.5, canvasSize.bottom / 2 + 0.5,
canvasSize.right, canvasSize.bottom);
canvas = BitmapCanvas(canvasSize);
canvas = BitmapCanvas(canvasSize, RenderStrategy());
canvas.debugChildOverdraw = true;
canvas.clipRect(outerClip, ClipOp.intersect);
canvas.drawParagraph(paragraph, const Offset(8.5, 8.5));
......@@ -201,7 +205,7 @@ void testMain() async {
final Rect canvasSize = Offset.zero & Size(500, 500);
canvas = BitmapCanvas(canvasSize);
canvas = BitmapCanvas(canvasSize, RenderStrategy());
canvas.debugChildOverdraw = true;
final SurfacePaintData pathPaint = SurfacePaintData()
......
......@@ -25,7 +25,8 @@ void testMain() async {
Future<void> _checkScreenshot(RecordingCanvas rc, String fileName,
{Rect region = const Rect.fromLTWH(0, 0, 500, 500),
double maxDiffRatePercent = 0.0}) async {
final EngineCanvas engineCanvas = BitmapCanvas(screenRect);
final EngineCanvas engineCanvas = BitmapCanvas(screenRect,
RenderStrategy());
rc.endRecording();
rc.apply(engineCanvas, screenRect);
......
......@@ -22,7 +22,7 @@ void testMain() async {
BitmapCanvas canvas;
setUp(() {
canvas = BitmapCanvas(region);
canvas = BitmapCanvas(region, RenderStrategy());
});
tearDown(() {
......
......@@ -21,7 +21,8 @@ void main() {
void testMain() async {
// Commit a recording canvas to a bitmap, and compare with the expected
Future<void> _checkScreenshot(RecordingCanvas rc, String fileName, ui.Rect screenRect, {bool write = false}) async {
final EngineCanvas engineCanvas = BitmapCanvas(screenRect);
final EngineCanvas engineCanvas = BitmapCanvas(screenRect,
RenderStrategy());
rc.endRecording();
rc.apply(engineCanvas, screenRect);
......
......@@ -22,7 +22,7 @@ void testMain() async {
BitmapCanvas canvas;
setUp(() {
canvas = BitmapCanvas(region);
canvas = BitmapCanvas(region, RenderStrategy());
});
tearDown(() {
......
......@@ -34,7 +34,8 @@ void testMain() async {
// Regression test for https://github.com/flutter/flutter/issues/51514
test('Canvas is reused and z-index doesn\'t leak across paints', () async {
final EngineCanvas engineCanvas = BitmapCanvas(screenRect);
final EngineCanvas engineCanvas = BitmapCanvas(screenRect,
RenderStrategy());
const Rect region = Rect.fromLTWH(0, 0, 500, 500);
// Draw first frame into engine canvas.
......
......@@ -31,7 +31,8 @@ void testMain() async {
const Radius someFixedRadius = Radius.circular(10);
setUp(() {
canvas = BitmapCanvas(const Rect.fromLTWH(0, 0, 500, 100));
canvas = BitmapCanvas(const Rect.fromLTWH(0, 0, 500, 100),
RenderStrategy());
canvas.translate(10, 10); // Center
});
......
......@@ -22,7 +22,7 @@ void testMain() async {
BitmapCanvas canvas;
setUp(() {
canvas = BitmapCanvas(region);
canvas = BitmapCanvas(region, RenderStrategy());
});
tearDown(() {
......
......@@ -23,7 +23,7 @@ void testMain() async {
BitmapCanvas canvas;
setUp(() {
canvas = BitmapCanvas(region);
canvas = BitmapCanvas(region, RenderStrategy());
});
tearDown(() {
......
......@@ -22,7 +22,7 @@ void testMain() async {
BitmapCanvas canvas;
setUp(() {
canvas = BitmapCanvas(region);
canvas = BitmapCanvas(region, RenderStrategy());
});
tearDown(() {
......
......@@ -570,7 +570,7 @@ void _testCullRectComputation() {
final RecordingCanvas canvas = recorder.beginRecording(outerClip);
canvas.drawParagraph(paragraph, const Offset(8.5, 8.5));
final Picture picture = recorder.endRecording();
expect(canvas.hasArbitraryPaint, false);
expect(canvas.renderStrategy.hasArbitraryPaint, false);
builder.addPicture(
Offset.zero,
......@@ -584,7 +584,7 @@ void _testCullRectComputation() {
final RecordingCanvas canvas = recorder.beginRecording(innerClip);
canvas.drawParagraph(paragraph, Offset(8.5, 8.5 + innerClip.top));
final Picture picture = recorder.endRecording();
expect(canvas.hasArbitraryPaint, false);
expect(canvas.renderStrategy.hasArbitraryPaint, false);
builder.addPicture(
Offset.zero,
......
......@@ -21,7 +21,8 @@ void testMain() async {
Future<void> testPath(Path path, String scubaFileName) async {
const Rect canvasBounds = Rect.fromLTWH(0, 0, 600, 800);
final BitmapCanvas bitmapCanvas = BitmapCanvas(canvasBounds);
final BitmapCanvas bitmapCanvas = BitmapCanvas(canvasBounds,
RenderStrategy());
final RecordingCanvas canvas = RecordingCanvas(canvasBounds);
Paint paint = Paint()
......
......@@ -26,7 +26,8 @@ void testMain() async {
Future<void> _checkScreenshot(RecordingCanvas rc, String fileName,
{Rect region = const Rect.fromLTWH(0, 0, 500, 500),
bool write = false}) async {
final EngineCanvas engineCanvas = BitmapCanvas(screenRect);
final EngineCanvas engineCanvas = BitmapCanvas(screenRect,
RenderStrategy());
rc.endRecording();
rc.apply(engineCanvas, screenRect);
......
......@@ -29,7 +29,8 @@ void testMain() async {
Future<void> _checkScreenshot(RecordingCanvas rc, String fileName,
{Rect region = const Rect.fromLTWH(0, 0, 500, 240),
double maxDiffRatePercent = 0.0, bool write: false}) async {
final EngineCanvas engineCanvas = BitmapCanvas(screenRect);
final EngineCanvas engineCanvas = BitmapCanvas(screenRect,
RenderStrategy());
rc.endRecording();
rc.apply(engineCanvas, screenRect);
......
......@@ -36,7 +36,7 @@ void testMain() async {
Offset(shaderRect.right, shaderRect.bottom),
[Color(0xFFcfdfd2), Color(0xFF042a85)]);
rc.drawRect(shaderRect, paint);
expect(rc.hasArbitraryPaint, isTrue);
expect(rc.renderStrategy.hasArbitraryPaint, isTrue);
await canvasScreenshot(rc, 'linear_gradient_rect',
region: screenRect,
maxDiffRatePercent: 0.01);
......@@ -64,7 +64,7 @@ void testMain() async {
rc.drawOval(shaderRect, paint);
yOffset += 120;
}
expect(rc.hasArbitraryPaint, isTrue);
expect(rc.renderStrategy.hasArbitraryPaint, isTrue);
await canvasScreenshot(rc, 'linear_gradient_oval_matrix',
region: screenRect,
maxDiffRatePercent: 0.2);
......@@ -80,7 +80,7 @@ void testMain() async {
Offset(shaderRect.right, shaderRect.bottom),
[Color(0xFFcfdfd2), Color(0xFF042a85)]);
rc.drawRRect(RRect.fromRectAndRadius(shaderRect, Radius.circular(16)), paint);
expect(rc.hasArbitraryPaint, isTrue);
expect(rc.renderStrategy.hasArbitraryPaint, isTrue);
await canvasScreenshot(rc, 'linear_gradient_rounded_rect',
region: screenRect,
maxDiffRatePercent: 0.1);
......@@ -108,7 +108,7 @@ void testMain() async {
rc.drawOval(shaderRect, paint);
yOffset += 120;
}
expect(rc.hasArbitraryPaint, isTrue);
expect(rc.renderStrategy.hasArbitraryPaint, isTrue);
await canvasScreenshot(rc, 'linear_gradient_tiled_repeated_rect',
region: screenRect);
});
......@@ -135,7 +135,7 @@ void testMain() async {
rc.drawOval(shaderRect, paint);
yOffset += 120;
}
expect(rc.hasArbitraryPaint, isTrue);
expect(rc.renderStrategy.hasArbitraryPaint, isTrue);
await canvasScreenshot(rc, 'linear_gradient_tiled_mirrored_rect',
region: screenRect);
});
......
......@@ -28,7 +28,8 @@ void testMain() async {
// Commit a recording canvas to a bitmap, and compare with the expected
Future<void> _checkScreenshot(RecordingCanvas rc, String fileName,
{Rect region = const Rect.fromLTWH(0, 0, 500, 500)}) async {
final EngineCanvas engineCanvas = BitmapCanvas(screenRect);
final EngineCanvas engineCanvas = BitmapCanvas(screenRect,
RenderStrategy());
rc.endRecording();
rc.apply(engineCanvas, screenRect);
......
......@@ -21,7 +21,8 @@ void testMain() async {
Future<void> testPath(Path path, String scubaFileName, {Paint paint, double maxDiffRatePercent = null}) async {
const Rect canvasBounds = Rect.fromLTWH(0, 0, 600, 800);
final BitmapCanvas bitmapCanvas = BitmapCanvas(canvasBounds);
final BitmapCanvas bitmapCanvas = BitmapCanvas(canvasBounds,
RenderStrategy());
final RecordingCanvas canvas = RecordingCanvas(canvasBounds);
paint ??= Paint()
......
......@@ -26,7 +26,8 @@ void testMain() async {
Future<void> _checkScreenshot(RecordingCanvas rc, String fileName,
{Rect region = const Rect.fromLTWH(0, 0, 500, 500),
double maxDiffRatePercent = null}) async {
final EngineCanvas engineCanvas = BitmapCanvas(screenRect);
final EngineCanvas engineCanvas = BitmapCanvas(screenRect,
RenderStrategy());
rc.endRecording();
rc.apply(engineCanvas, screenRect);
......
......@@ -30,7 +30,8 @@ void testMain() async {
{ Rect region = const Rect.fromLTWH(0, 0, 500, 500),
bool write = false }) async {
final EngineCanvas engineCanvas = BitmapCanvas(screenRect);
final EngineCanvas engineCanvas = BitmapCanvas(screenRect,
RenderStrategy());
// Draws the estimated bounds so we can spot the bug in Scuba.
engineCanvas
......
......@@ -13,7 +13,8 @@ import 'package:test/test.dart';
Future<void> canvasScreenshot(RecordingCanvas rc, String fileName,
{ui.Rect region = const ui.Rect.fromLTWH(0, 0, 600, 800),
double maxDiffRatePercent = 0.0, bool write: false}) async {
final EngineCanvas engineCanvas = BitmapCanvas(region);
final EngineCanvas engineCanvas = BitmapCanvas(region,
RenderStrategy());
rc.endRecording();
rc.apply(engineCanvas, region);
......
......@@ -101,7 +101,7 @@ void testEachCanvas(String description, CanvasTest body,
try {
TextMeasurementService.initialize(rulerCacheCapacity: 2);
WebExperiments.instance.useCanvasText = false;
return body(BitmapCanvas(bounds));
return body(BitmapCanvas(bounds, RenderStrategy()));
} finally {
WebExperiments.instance.useCanvasText = null;
TextMeasurementService.clearCache();
......@@ -111,7 +111,7 @@ void testEachCanvas(String description, CanvasTest body,
try {
TextMeasurementService.initialize(rulerCacheCapacity: 2);
WebExperiments.instance.useCanvasText = true;
await body(BitmapCanvas(bounds));
await body(BitmapCanvas(bounds, RenderStrategy()));
} finally {
WebExperiments.instance.useCanvasText = null;
TextMeasurementService.clearCache();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册