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);
/// New [PaintingContext] objects are created automatically when using
/// [PaintingContext.repaintCompositedChild] and [pushLayer].
class PaintingContext {
PaintingContext._(this._containerLayer, this.canvasBounds)
PaintingContext._(this._containerLayer, this.estimatedBounds)
: assert(_containerLayer != null),
assert(canvasBounds != null);
assert(estimatedBounds != null);
final ContainerLayer _containerLayer;
/// The bounds within which the painting context's [canvas] will record
/// painting commands.
/// An estimate of the bounds within which the painting context's [canvas]
/// will record painting commands. This can be useful for debugging.
///
/// A render object provided with this [PaintingContext] (e.g. in its
/// [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 canvas will allow painting outside these bounds.
///
/// The [canvasBounds] rectangle is in the [canvas] coordinate system.
final Rect canvasBounds;
/// The [estimatedBounds] rectangle is in the [canvas] coordinate system.
final Rect estimatedBounds;
/// Repaint the given render object.
///
......@@ -200,8 +194,6 @@ class PaintingContext {
/// 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
/// returned by this getter.
///
/// Only calls within the [canvasBounds] will be recorded.
Canvas get canvas {
if (_canvas == null)
_startRecording();
......@@ -210,9 +202,9 @@ class PaintingContext {
void _startRecording() {
assert(!_isRecording);
_currentLayer = new PictureLayer(canvasBounds);
_currentLayer = new PictureLayer(estimatedBounds);
_recorder = new ui.PictureRecorder();
_canvas = new Canvas(_recorder, canvasBounds);
_canvas = new Canvas(_recorder);
_containerLayer.append(_currentLayer);
}
......@@ -225,14 +217,14 @@ class PaintingContext {
..style = PaintingStyle.stroke
..strokeWidth = 6.0
..color = debugCurrentRepaintColor.toColor();
canvas.drawRect(canvasBounds.deflate(3.0), paint);
canvas.drawRect(estimatedBounds.deflate(3.0), paint);
}
if (debugPaintLayerBordersEnabled) {
final Paint paint = new Paint()
..style = PaintingStyle.stroke
..strokeWidth = 1.0
..color = const Color(0xFFFF9800);
canvas.drawRect(canvasBounds, paint);
canvas.drawRect(estimatedBounds, paint);
}
return true;
}());
......@@ -284,9 +276,9 @@ class PaintingContext {
}
/// Appends the given layer to the recording, and calls the `painter` callback
/// with that layer, providing the `childPaintBounds` as the paint bounds of
/// the child. Canvas recording commands are not guaranteed to be stored
/// outside of the paint bounds.
/// with that layer, providing the `childPaintBounds` as the estimated paint
/// bounds of the child. The `childPaintBounds` can be used for debugging but
/// have no effect on painting.
///
/// The given layer must be an unattached orphan. (Providing a newly created
/// object, rather than reusing an existing layer, satisfies that
......@@ -309,7 +301,7 @@ class PaintingContext {
assert(painter != null);
_stopRecordingIfNeeded();
_appendLayer(childLayer);
final PaintingContext childContext = new PaintingContext._(childLayer, childPaintBounds ?? canvasBounds);
final PaintingContext childContext = new PaintingContext._(childLayer, childPaintBounds ?? estimatedBounds);
painter(childContext, offset);
childContext._stopRecordingIfNeeded();
}
......@@ -413,7 +405,7 @@ class PaintingContext {
new TransformLayer(transform: effectiveTransform),
painter,
offset,
childPaintBounds: MatrixUtils.inverseTransformRect(effectiveTransform, canvasBounds),
childPaintBounds: MatrixUtils.inverseTransformRect(effectiveTransform, estimatedBounds),
);
} else {
canvas
......@@ -444,7 +436,7 @@ class PaintingContext {
}
@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.
......@@ -2037,17 +2029,8 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
}());
}
/// The bounds within which this render object will paint.
///
/// 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].
/// An estimate of the bounds within which this render object will paint.
/// Useful for debugging flags such as [debugPaintLayerBordersEnabled].
Rect get paintBounds;
/// 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