Unverified Commit 0434ae22 authored by Jason Simmons's avatar Jason Simmons Committed by GitHub

Do not apply the canvas bounds as a cull rectangle when recording a Skia picture (#14027)

The picture may need to draw outside the bounds (specifically for shadows)

Fixes https://github.com/flutter/flutter/issues/12618
parent a67df9e1
...@@ -59,25 +59,19 @@ typedef void PaintingContextCallback(PaintingContext context, Offset offset); ...@@ -59,25 +59,19 @@ typedef void PaintingContextCallback(PaintingContext context, Offset offset);
/// New [PaintingContext] objects are created automatically when using /// New [PaintingContext] objects are created automatically when using
/// [PaintingContext.repaintCompositedChild] and [pushLayer]. /// [PaintingContext.repaintCompositedChild] and [pushLayer].
class PaintingContext { class PaintingContext {
PaintingContext._(this._containerLayer, this.canvasBounds) PaintingContext._(this._containerLayer, this.estimatedBounds)
: assert(_containerLayer != null), : assert(_containerLayer != null),
assert(canvasBounds != null); assert(estimatedBounds != null);
final ContainerLayer _containerLayer; final ContainerLayer _containerLayer;
/// The bounds within which the painting context's [canvas] will record /// An estimate of the bounds within which the painting context's [canvas]
/// painting commands. /// will record painting commands. This can be useful for debugging.
/// ///
/// A render object provided with this [PaintingContext] (e.g. in its /// The canvas will allow painting outside these bounds.
/// [RenderObject.paint] method) is permitted to paint outside the region that
/// the render object occupies during layout, but is not permitted to paint
/// outside these canvas paints bounds. These paint bounds are used to
/// construct memory-efficient composited layers, which means attempting to
/// paint outside these bounds can attempt to write to pixels that do not
/// exist in the composited layer.
/// ///
/// The [canvasBounds] rectangle is in the [canvas] coordinate system. /// The [estimatedBounds] rectangle is in the [canvas] coordinate system.
final Rect canvasBounds; final Rect estimatedBounds;
/// Repaint the given render object. /// Repaint the given render object.
/// ///
...@@ -200,8 +194,6 @@ class PaintingContext { ...@@ -200,8 +194,6 @@ class PaintingContext {
/// The current canvas can change whenever you paint a child using this /// The current canvas can change whenever you paint a child using this
/// context, which means it's fragile to hold a reference to the canvas /// context, which means it's fragile to hold a reference to the canvas
/// returned by this getter. /// returned by this getter.
///
/// Only calls within the [canvasBounds] will be recorded.
Canvas get canvas { Canvas get canvas {
if (_canvas == null) if (_canvas == null)
_startRecording(); _startRecording();
...@@ -210,9 +202,9 @@ class PaintingContext { ...@@ -210,9 +202,9 @@ class PaintingContext {
void _startRecording() { void _startRecording() {
assert(!_isRecording); assert(!_isRecording);
_currentLayer = new PictureLayer(canvasBounds); _currentLayer = new PictureLayer(estimatedBounds);
_recorder = new ui.PictureRecorder(); _recorder = new ui.PictureRecorder();
_canvas = new Canvas(_recorder, canvasBounds); _canvas = new Canvas(_recorder);
_containerLayer.append(_currentLayer); _containerLayer.append(_currentLayer);
} }
...@@ -225,14 +217,14 @@ class PaintingContext { ...@@ -225,14 +217,14 @@ class PaintingContext {
..style = PaintingStyle.stroke ..style = PaintingStyle.stroke
..strokeWidth = 6.0 ..strokeWidth = 6.0
..color = debugCurrentRepaintColor.toColor(); ..color = debugCurrentRepaintColor.toColor();
canvas.drawRect(canvasBounds.deflate(3.0), paint); canvas.drawRect(estimatedBounds.deflate(3.0), paint);
} }
if (debugPaintLayerBordersEnabled) { if (debugPaintLayerBordersEnabled) {
final Paint paint = new Paint() final Paint paint = new Paint()
..style = PaintingStyle.stroke ..style = PaintingStyle.stroke
..strokeWidth = 1.0 ..strokeWidth = 1.0
..color = const Color(0xFFFF9800); ..color = const Color(0xFFFF9800);
canvas.drawRect(canvasBounds, paint); canvas.drawRect(estimatedBounds, paint);
} }
return true; return true;
}()); }());
...@@ -284,9 +276,9 @@ class PaintingContext { ...@@ -284,9 +276,9 @@ class PaintingContext {
} }
/// Appends the given layer to the recording, and calls the `painter` callback /// Appends the given layer to the recording, and calls the `painter` callback
/// with that layer, providing the `childPaintBounds` as the paint bounds of /// with that layer, providing the `childPaintBounds` as the estimated paint
/// the child. Canvas recording commands are not guaranteed to be stored /// bounds of the child. The `childPaintBounds` can be used for debugging but
/// outside of the paint bounds. /// have no effect on painting.
/// ///
/// The given layer must be an unattached orphan. (Providing a newly created /// The given layer must be an unattached orphan. (Providing a newly created
/// object, rather than reusing an existing layer, satisfies that /// object, rather than reusing an existing layer, satisfies that
...@@ -309,7 +301,7 @@ class PaintingContext { ...@@ -309,7 +301,7 @@ class PaintingContext {
assert(painter != null); assert(painter != null);
_stopRecordingIfNeeded(); _stopRecordingIfNeeded();
_appendLayer(childLayer); _appendLayer(childLayer);
final PaintingContext childContext = new PaintingContext._(childLayer, childPaintBounds ?? canvasBounds); final PaintingContext childContext = new PaintingContext._(childLayer, childPaintBounds ?? estimatedBounds);
painter(childContext, offset); painter(childContext, offset);
childContext._stopRecordingIfNeeded(); childContext._stopRecordingIfNeeded();
} }
...@@ -413,7 +405,7 @@ class PaintingContext { ...@@ -413,7 +405,7 @@ class PaintingContext {
new TransformLayer(transform: effectiveTransform), new TransformLayer(transform: effectiveTransform),
painter, painter,
offset, offset,
childPaintBounds: MatrixUtils.inverseTransformRect(effectiveTransform, canvasBounds), childPaintBounds: MatrixUtils.inverseTransformRect(effectiveTransform, estimatedBounds),
); );
} else { } else {
canvas canvas
...@@ -444,7 +436,7 @@ class PaintingContext { ...@@ -444,7 +436,7 @@ class PaintingContext {
} }
@override @override
String toString() => '$runtimeType#$hashCode(layer: $_containerLayer, canvas bounds: $canvasBounds)'; String toString() => '$runtimeType#$hashCode(layer: $_containerLayer, canvas bounds: $estimatedBounds)';
} }
/// An abstract set of layout constraints. /// An abstract set of layout constraints.
...@@ -2037,17 +2029,8 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im ...@@ -2037,17 +2029,8 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
}()); }());
} }
/// The bounds within which this render object will paint. /// An estimate of the bounds within which this render object will paint.
/// /// Useful for debugging flags such as [debugPaintLayerBordersEnabled].
/// A render object and its descendants are permitted to paint outside the
/// region it occupies during layout, but they are not permitted to paint
/// outside these paints bounds. These paint bounds are used to construct
/// memory-efficient composited layers, which means attempting to paint
/// outside these bounds can attempt to write to pixels that do not exist in
/// this render object's composited layer.
///
/// The [paintBounds] are only actually enforced when the render object is a
/// repaint boundary; see [isRepaintBoundary].
Rect get paintBounds; Rect get paintBounds;
/// Override this method to paint debugging information. /// Override this method to paint debugging information.
......
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