Commit 838bd631 authored by Jason Simmons's avatar Jason Simmons Committed by GitHub

Control raster cache flags in CustomPaint widgets (#11398)

parent 9f510ebd
...@@ -2064,6 +2064,8 @@ class RenderCustomPaint extends RenderProxyBox { ...@@ -2064,6 +2064,8 @@ class RenderCustomPaint extends RenderProxyBox {
CustomPainter painter, CustomPainter painter,
CustomPainter foregroundPainter, CustomPainter foregroundPainter,
Size preferredSize: Size.zero, Size preferredSize: Size.zero,
this.isComplex: false,
this.willChange: false,
RenderBox child, RenderBox child,
}) : assert(preferredSize != null), }) : assert(preferredSize != null),
_painter = painter, _painter = painter,
...@@ -2153,6 +2155,19 @@ class RenderCustomPaint extends RenderProxyBox { ...@@ -2153,6 +2155,19 @@ class RenderCustomPaint extends RenderProxyBox {
markNeedsLayout(); markNeedsLayout();
} }
/// Whether to hint that this layer's painting should be cached.
///
/// The compositor contains a raster cache that holds bitmaps of layers in
/// order to avoid the cost of repeatedly rendering those layers on each
/// frame. If this flag is not set, then the compositor will apply its own
/// heuristics to decide whether the this layer is complex enough to benefit
/// from caching.
bool isComplex;
/// Whether the raster cache should be told that this painting is likely
/// to change in the next frame.
bool willChange;
@override @override
void attach(PipelineOwner owner) { void attach(PipelineOwner owner) {
super.attach(owner); super.attach(owner);
...@@ -2226,11 +2241,22 @@ class RenderCustomPaint extends RenderProxyBox { ...@@ -2226,11 +2241,22 @@ class RenderCustomPaint extends RenderProxyBox {
@override @override
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (_painter != null) if (_painter != null) {
_paintWithPainter(context.canvas, offset, _painter); _paintWithPainter(context.canvas, offset, _painter);
_setRasterCacheHints(context);
}
super.paint(context, offset); super.paint(context, offset);
if (_foregroundPainter != null) if (_foregroundPainter != null) {
_paintWithPainter(context.canvas, offset, _foregroundPainter); _paintWithPainter(context.canvas, offset, _foregroundPainter);
_setRasterCacheHints(context);
}
}
void _setRasterCacheHints(PaintingContext context) {
if (isComplex)
context.setIsComplexHint();
if (willChange)
context.setWillChangeHint();
} }
} }
......
...@@ -256,7 +256,10 @@ class BackdropFilter extends SingleChildRenderObjectWidget { ...@@ -256,7 +256,10 @@ class BackdropFilter extends SingleChildRenderObjectWidget {
/// ///
/// Custom painters normally size themselves to their child. If they do not have /// Custom painters normally size themselves to their child. If they do not have
/// a child, they attempt to size themselves to the [size], which defaults to /// a child, they attempt to size themselves to the [size], which defaults to
/// [Size.zero]. /// [Size.zero]. [size] must not be null.
///
/// [isComplex] and [willChange] are hints to the compositor's raster cache
/// and must not be null.
/// ///
/// ## Sample code /// ## Sample code
/// ///
...@@ -286,9 +289,18 @@ class BackdropFilter extends SingleChildRenderObjectWidget { ...@@ -286,9 +289,18 @@ class BackdropFilter extends SingleChildRenderObjectWidget {
/// * [Canvas], the class that a custom painter uses to paint. /// * [Canvas], the class that a custom painter uses to paint.
class CustomPaint extends SingleChildRenderObjectWidget { class CustomPaint extends SingleChildRenderObjectWidget {
/// Creates a widget that delegates its painting. /// Creates a widget that delegates its painting.
const CustomPaint({ Key key, this.painter, this.foregroundPainter, this.size: Size.zero, Widget child }) const CustomPaint({
: assert(size != null), Key key,
super(key: key, child: child); this.painter,
this.foregroundPainter,
this.size: Size.zero,
this.isComplex: false,
this.willChange: false,
Widget child
}) : assert(size != null),
assert(isComplex != null),
assert(willChange != null),
super(key: key, child: child);
/// The painter that paints before the children. /// The painter that paints before the children.
final CustomPainter painter; final CustomPainter painter;
...@@ -305,12 +317,27 @@ class CustomPaint extends SingleChildRenderObjectWidget { ...@@ -305,12 +317,27 @@ class CustomPaint extends SingleChildRenderObjectWidget {
/// instead. /// instead.
final Size size; final Size size;
/// Whether the painting is complex enough to benefit from caching.
///
/// The compositor contains a raster cache that holds bitmaps of layers in
/// order to avoid the cost of repeatedly rendering those layers on each
/// frame. If this flag is not set, then the compositor will apply its own
/// heuristics to decide whether the this layer is complex enough to benefit
/// from caching.
final bool isComplex;
/// Whether the raster cache should be told that this painting is likely
/// to change in the next frame.
final bool willChange;
@override @override
RenderCustomPaint createRenderObject(BuildContext context) { RenderCustomPaint createRenderObject(BuildContext context) {
return new RenderCustomPaint( return new RenderCustomPaint(
painter: painter, painter: painter,
foregroundPainter: foregroundPainter, foregroundPainter: foregroundPainter,
preferredSize: size, preferredSize: size,
isComplex: isComplex,
willChange: willChange,
); );
} }
...@@ -319,7 +346,9 @@ class CustomPaint extends SingleChildRenderObjectWidget { ...@@ -319,7 +346,9 @@ class CustomPaint extends SingleChildRenderObjectWidget {
renderObject renderObject
..painter = painter ..painter = painter
..foregroundPainter = foregroundPainter ..foregroundPainter = foregroundPainter
..preferredSize = size; ..preferredSize = size
..isComplex = isComplex
..willChange = willChange;
} }
@override @override
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
class TestCustomPainter extends CustomPainter { class TestCustomPainter extends CustomPainter {
...@@ -77,4 +78,27 @@ void main() { ...@@ -77,4 +78,27 @@ void main() {
expect(target.currentContext.size, Size.zero); expect(target.currentContext.size, Size.zero);
}); });
testWidgets('Raster cache hints', (WidgetTester tester) async {
final GlobalKey target = new GlobalKey();
final List<String> log = <String>[];
await tester.pumpWidget(new CustomPaint(
key: target,
isComplex: true,
painter: new TestCustomPainter(log: log),
));
RenderCustomPaint renderCustom = target.currentContext.findRenderObject();
expect(renderCustom.isComplex, true);
expect(renderCustom.willChange, false);
await tester.pumpWidget(new CustomPaint(
key: target,
willChange: true,
foregroundPainter: new TestCustomPainter(log: log),
));
renderCustom = target.currentContext.findRenderObject();
expect(renderCustom.isComplex, false);
expect(renderCustom.willChange, true);
});
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment