Commit fc576814 authored by Adam Barth's avatar Adam Barth

Refactor PaintingContext

This patch simplifies PaintingContext with several goals:

1) We now call a callback instead of assuming the caller has a single child to
   paint. This change will let us handle render objects that wish to paint more
   than one child.
2) We now avoid creating lots of empty picture layers because we don't eagerly
   start recording pictures. Instead, we wait for the first caller to touch the
   canvas before creating the picture recorder.
3) We now are more consistent about which values have incorporated the painting
   offset.
parent 5734821f
...@@ -282,7 +282,7 @@ class RenderSectorRing extends RenderSectorWithChildren { ...@@ -282,7 +282,7 @@ class RenderSectorRing extends RenderSectorWithChildren {
super.paint(context, offset); super.paint(context, offset);
RenderSector child = firstChild; RenderSector child = firstChild;
while (child != null) { while (child != null) {
context.paintChild(child, offset.toPoint()); context.paintChild(child, offset);
final SectorChildListParentData childParentData = child.parentData; final SectorChildListParentData childParentData = child.parentData;
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
...@@ -388,7 +388,7 @@ class RenderSectorSlice extends RenderSectorWithChildren { ...@@ -388,7 +388,7 @@ class RenderSectorSlice extends RenderSectorWithChildren {
RenderSector child = firstChild; RenderSector child = firstChild;
while (child != null) { while (child != null) {
assert(child.parentData is SectorChildListParentData); assert(child.parentData is SectorChildListParentData);
context.paintChild(child, offset.toPoint()); context.paintChild(child, offset);
final SectorChildListParentData childParentData = child.parentData; final SectorChildListParentData childParentData = child.parentData;
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
...@@ -470,7 +470,7 @@ class RenderBoxToRenderSectorAdapter extends RenderBox with RenderObjectWithChil ...@@ -470,7 +470,7 @@ class RenderBoxToRenderSectorAdapter extends RenderBox with RenderObjectWithChil
if (child != null) { if (child != null) {
Rect bounds = offset & size; Rect bounds = offset & size;
// we move the offset to the center of the circle for the RenderSectors // we move the offset to the center of the circle for the RenderSectors
context.paintChild(child, bounds.center); context.paintChild(child, bounds.center.toOffset());
} }
} }
......
...@@ -232,7 +232,7 @@ class _RenderTabBar extends RenderBox with ...@@ -232,7 +232,7 @@ class _RenderTabBar extends RenderBox with
RenderBox child = firstChild; RenderBox child = firstChild;
while (child != null) { while (child != null) {
final _TabBarParentData childParentData = child.parentData; final _TabBarParentData childParentData = child.parentData;
context.paintChild(child, childParentData.position + offset); context.paintChild(child, childParentData.offset + offset);
if (index++ == selectedIndex) if (index++ == selectedIndex)
_paintIndicator(context.canvas, child, offset); _paintIndicator(context.canvas, child, offset);
child = childParentData.nextSibling; child = childParentData.nextSibling;
......
...@@ -287,6 +287,8 @@ class BoxHitTestEntry extends HitTestEntry { ...@@ -287,6 +287,8 @@ class BoxHitTestEntry extends HitTestEntry {
/// Parent data used by [RenderBox] and its subclasses /// Parent data used by [RenderBox] and its subclasses
class BoxParentData extends ParentData { class BoxParentData extends ParentData {
// TODO(abarth): Switch to using an Offset rather than a Point here. This
// value is really the offset from the parent.
Point _position = Point.origin; Point _position = Point.origin;
/// The point at which to paint the child in the parent's coordinate system /// The point at which to paint the child in the parent's coordinate system
Point get position => _position; Point get position => _position;
...@@ -294,6 +296,7 @@ class BoxParentData extends ParentData { ...@@ -294,6 +296,7 @@ class BoxParentData extends ParentData {
assert(RenderObject.debugDoingLayout); assert(RenderObject.debugDoingLayout);
_position = value; _position = value;
} }
Offset get offset => _position.toOffset();
String toString() => 'position=$position'; String toString() => 'position=$position';
} }
...@@ -771,7 +774,7 @@ abstract class RenderBoxContainerDefaultsMixin<ChildType extends RenderBox, Pare ...@@ -771,7 +774,7 @@ abstract class RenderBoxContainerDefaultsMixin<ChildType extends RenderBox, Pare
RenderBox child = firstChild; RenderBox child = firstChild;
while (child != null) { while (child != null) {
final ParentDataType childParentData = child.parentData; final ParentDataType childParentData = child.parentData;
context.paintChild(child, childParentData.position + offset); context.paintChild(child, childParentData.offset + offset);
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
} }
......
...@@ -44,7 +44,9 @@ class PaintingCanvas extends Canvas { ...@@ -44,7 +44,9 @@ class PaintingCanvas extends Canvas {
// TODO(ianh): Just use ui.Canvas everywhere instead // TODO(ianh): Just use ui.Canvas everywhere instead
} }
/// A place to paint typedef void PaintingContextCallback(PaintingContext context, Offset offset);
/// A place to paint.
/// ///
/// Rather than holding a canvas directly, render objects paint using a painting /// Rather than holding a canvas directly, render objects paint using a painting
/// context. The painting context has a canvas, which receives the /// context. The painting context has a canvas, which receives the
...@@ -57,190 +59,211 @@ class PaintingCanvas extends Canvas { ...@@ -57,190 +59,211 @@ class PaintingCanvas extends Canvas {
/// not hold a reference to the canvas across operations that might paint /// not hold a reference to the canvas across operations that might paint
/// child render objects. /// child render objects.
class PaintingContext { class PaintingContext {
/// Construct a painting context at a given offset with the given bounds PaintingContext._(this._containerLayer, this._paintBounds);
PaintingContext.withOffset(Offset offset, Rect paintBounds) {
_containerLayer = new ContainerLayer(offset: offset); final ContainerLayer _containerLayer;
_startRecording(paintBounds); final Rect _paintBounds;
/// Repaint the given render object.
///
/// The render object must have a composited layer and must be in need of
/// painting. The render object's layer is re-used, along with any layers in
/// the subtree that don't need to be repainted.
static void repaintCompositedChild(RenderObject child) {
assert(child.hasLayer);
assert(child.needsPaint);
child._layer ??= new ContainerLayer();
child._layer.removeAllChildren();
PaintingContext childContext = new PaintingContext._(child._layer, child.paintBounds);
child._paintWithContext(childContext, Offset.zero);
childContext._stopRecordingIfNeeded();
}
/// Paint a child render object.
///
/// If the child has its own composited layer, the child will be composited
/// into the layer subtree associated with this painting context. Otherwise,
/// the child will be painted into the current PictureLayer for this context.
void paintChild(RenderObject child, Offset offset) {
if (child.hasLayer) {
_stopRecordingIfNeeded();
_compositeChild(child, offset);
} else {
child._paintWithContext(this, offset);
}
} }
/// Construct a painting context for painting into the given layer with the given bounds void _compositeChild(RenderObject child, Offset offset) {
PaintingContext.withLayer(ContainerLayer containerLayer, Rect paintBounds) { assert(!_isRecording);
_containerLayer = containerLayer; assert(child.hasLayer);
_startRecording(paintBounds);
// Create a layer for our child, and paint the child into it.
if (child.needsPaint) {
repaintCompositedChild(child);
} else {
assert(child._layer != null);
child._layer.detach();
}
_appendLayer(child._layer, offset);
} }
/// A backdoor for testing that lets the test set a specific canvas void _appendLayer(Layer layer, Offset offset) {
PaintingContext.forTesting(this._canvas); assert(!_isRecording);
layer.offset = offset;
_containerLayer.append(layer);
}
ContainerLayer _containerLayer; bool get _isRecording {
/// The layer contain all the composting layers that will be used for this context final bool hasCanvas = (_canvas != null);
ContainerLayer get containerLayer => _containerLayer; assert(() {
if (hasCanvas) {
assert(_currentLayer != null);
assert(_recorder != null);
assert(_canvas != null);
} else {
assert(_currentLayer == null);
assert(_recorder == null);
assert(_canvas == null);
}
return true;
});
return hasCanvas;
}
// Recording state
PictureLayer _currentLayer; PictureLayer _currentLayer;
ui.PictureRecorder _recorder; ui.PictureRecorder _recorder;
PaintingCanvas _canvas; PaintingCanvas _canvas;
/// The canvas on which to paint
/// The canvas on which to paint.
/// ///
/// This getter can return a different canvas object after painting child /// The current canvas can change whenever you paint a child using this
/// render objects using this canvas because draw operations before and after /// context, which means it's fragile to hold a reference to the canvas
/// a child might need to be recorded in separate compositing layers. /// returned by this getter.
PaintingCanvas get canvas => _canvas; PaintingCanvas get canvas {
if (_canvas == null)
void _startRecording(Rect paintBounds) { _startRecording();
assert(_currentLayer == null); return _canvas;
assert(_recorder == null); }
assert(_canvas == null);
_currentLayer = new PictureLayer(paintBounds: paintBounds); void _startRecording() {
assert(!_isRecording);
_currentLayer = new PictureLayer(paintBounds: _paintBounds);
_recorder = new ui.PictureRecorder(); _recorder = new ui.PictureRecorder();
_canvas = new PaintingCanvas(_recorder, paintBounds); _canvas = new PaintingCanvas(_recorder, _paintBounds);
_containerLayer.append(_currentLayer); _containerLayer.append(_currentLayer);
} }
/// Stop recording draw operations into the current compositing layer void _stopRecordingIfNeeded() {
void endRecording() { if (!_isRecording)
assert(_currentLayer != null); return;
assert(_recorder != null);
assert(_canvas != null);
_currentLayer.picture = _recorder.endRecording(); _currentLayer.picture = _recorder.endRecording();
_currentLayer = null; _currentLayer = null;
_recorder = null; _recorder = null;
_canvas = null; _canvas = null;
} }
/// Whether the canvas is in a state that permits drawing the given child static final Paint _disableAntialias = new Paint()..isAntiAlias = false;
bool debugCanPaintChild(RenderObject child) {
// You need to use layers if you are applying transforms, clips,
// or similar, to a child. To do so, use the paintChildWith*()
// methods below.
// (commented out for now because we haven't ported everything yet)
assert(canvas.getSaveCount() == 1 || !child.needsCompositing);
return true;
}
/// Paint a child render object at the given position /// Push a statistics overlay.
/// ///
/// If the child needs compositing, a new composited layer will be created /// Statistics overlays are always composited because they're drawn by the
/// and inserted into the containerLayer. If the child does not require /// compositor.
/// compositing, the child will be painted into the current canvas. void pushStatistics(Offset offset, int optionsMask, int rasterizerThreshold, Size size) {
/// _stopRecordingIfNeeded();
/// Note: After calling this function, the current canvas might change. StatisticsLayer statisticsLayer = new StatisticsLayer(
void paintChild(RenderObject child, Point childPosition) {
assert(debugCanPaintChild(child));
final Offset childOffset = childPosition.toOffset();
if (!child.hasLayer) {
insertChild(child, childOffset);
} else {
compositeChild(child, childOffset: childOffset, parentLayer: _containerLayer);
}
}
void paintStatistics(int optionsMask, int rasterizerThreshold, Offset offset, Size size) {
StatisticsLayer statsLayer = new StatisticsLayer(
offset: offset,
paintBounds: new Rect.fromLTWH(0.0, 0.0, size.width, size.height), paintBounds: new Rect.fromLTWH(0.0, 0.0, size.width, size.height),
optionsMask : optionsMask, optionsMask: optionsMask,
rasterizerThreshold : rasterizerThreshold rasterizerThreshold: rasterizerThreshold
); );
_containerLayer.append(statsLayer); _appendLayer(statisticsLayer, offset);
} }
// Below we have various variants of the paintChild() method, which /// Push a rectangular clip rect.
// do additional work, such as clipping or transforming, at the same
// time as painting the children.
// If none of the descendants require compositing, then these don't
// need to use a new layer, because at no point will any of the
// children introduce a new layer of their own. In that case, we
// just use regular canvas commands to do the work.
// If at least one of the descendants requires compositing, though,
// we introduce a new layer to do the work, so that when the
// children are split into a new layer, the work (e.g. clip) is not
// lost, as it would if we didn't introduce a new layer.
static final Paint _disableAntialias = new Paint()..isAntiAlias = false;
/// Paint a child with a rectangular clip
/// ///
/// If the child needs compositing, the clip will be applied by a /// This function will call painter synchronously with a painting context that
/// compositing layer. Otherwise, the clip will be applied by the canvas. /// is clipped by the given clip. The given clip should not incorporate the
/// /// painting offset.
/// Note: clipRect is in the parent's coordinate space void pushClipRect(bool needsCompositing, Offset offset, Rect clipRect, PaintingContextCallback painter) {
void paintChildWithClipRect(RenderObject child, Point childPosition, Rect clipRect) { if (needsCompositing) {
assert(debugCanPaintChild(child)); _stopRecordingIfNeeded();
final Offset childOffset = childPosition.toOffset(); ClipRectLayer clipLayer = new ClipRectLayer(clipRect: clipRect);
if (!child.needsCompositing) { _appendLayer(clipLayer, offset);
PaintingContext childContext = new PaintingContext._(clipLayer, clipRect);
painter(childContext, Offset.zero);
childContext._stopRecordingIfNeeded();
} else {
canvas.save(); canvas.save();
canvas.clipRect(clipRect); canvas.clipRect(clipRect.shift(offset));
insertChild(child, childOffset); painter(this, offset);
canvas.restore(); canvas.restore();
} else {
ClipRectLayer clipLayer = new ClipRectLayer(offset: childOffset, clipRect: clipRect);
_containerLayer.append(clipLayer);
compositeChild(child, parentLayer: clipLayer);
} }
} }
/// Paint a child with a rounded-rectangular clip /// Push a rounded-rect clip rect.
/// ///
/// If the child needs compositing, the clip will be applied by a /// This function will call painter synchronously with a painting context that
/// compositing layer. Otherwise, the clip will be applied by the canvas. /// is clipped by the given clip. The given clip should not incorporate the
/// /// painting offset.
/// Note: clipRRect is in the parent's coordinate space void pushClipRRect(bool needsCompositing, Offset offset, Rect bounds, ui.RRect clipRRect, PaintingContextCallback painter) {
void paintChildWithClipRRect(RenderObject child, Point childPosition, Rect bounds, ui.RRect clipRRect) { if (needsCompositing) {
assert(debugCanPaintChild(child)); _stopRecordingIfNeeded();
final Offset childOffset = childPosition.toOffset(); ClipRRectLayer clipLayer = new ClipRRectLayer(bounds: bounds, clipRRect: clipRRect);
if (!child.needsCompositing) { _appendLayer(clipLayer, offset);
canvas.saveLayer(bounds, _disableAntialias); PaintingContext childContext = new PaintingContext._(clipLayer, bounds);
painter(childContext, Offset.zero);
childContext._stopRecordingIfNeeded();
} else {
canvas.saveLayer(bounds.shift(offset), _disableAntialias);
// TODO(abarth): Remove this translation once RRect.shift works again.
canvas.translate(offset.dx, offset.dy);
canvas.clipRRect(clipRRect); canvas.clipRRect(clipRRect);
insertChild(child, childOffset); painter(this, Offset.zero);
canvas.restore(); canvas.restore();
} else {
ClipRRectLayer clipLayer = new ClipRRectLayer(offset: childOffset, bounds: bounds, clipRRect: clipRRect);
_containerLayer.append(clipLayer);
compositeChild(child, parentLayer: clipLayer);
} }
} }
/// Paint a child with a clip path /// Push a path clip.
///
/// If the child needs compositing, the clip will be applied by a
/// compositing layer. Otherwise, the clip will be applied by the canvas.
/// ///
/// Note: bounds and clipPath are in the parent's coordinate space /// This function will call painter synchronously with a painting context that
void paintChildWithClipPath(RenderObject child, Point childPosition, Rect bounds, Path clipPath) { /// is clipped by the given clip. The given clip should not incorporate the
assert(debugCanPaintChild(child)); /// painting offset.
final Offset childOffset = childPosition.toOffset(); void pushClipPath(bool needsCompositing, Offset offset, Rect bounds, Path clipPath, PaintingContextCallback painter) {
if (!child.needsCompositing) { if (needsCompositing) {
canvas.saveLayer(bounds, _disableAntialias); _stopRecordingIfNeeded();
canvas.clipPath(clipPath); ClipPathLayer clipLayer = new ClipPathLayer(bounds: bounds, clipPath: clipPath);
canvas.translate(childOffset.dx, childOffset.dy); _appendLayer(clipLayer, offset);
insertChild(child, Offset.zero); PaintingContext childContext = new PaintingContext._(clipLayer, bounds);
canvas.restore(); painter(childContext, Offset.zero);
childContext._stopRecordingIfNeeded();
} else { } else {
ClipPathLayer clipLayer = new ClipPathLayer(offset: childOffset, bounds: bounds, clipPath: clipPath); canvas.saveLayer(bounds.shift(offset), _disableAntialias);
_containerLayer.append(clipLayer); canvas.clipPath(clipPath.shift(offset));
compositeChild(child, parentLayer: clipLayer); painter(this, offset);
canvas.restore();
} }
} }
/// Paint a child with a transform /// Push a transform.
/// ///
/// If the child needs compositing, the transform will be applied by a /// This function will call painter synchronously with a painting context that
/// compositing layer. Otherwise, the transform will be applied by the canvas. /// is transformed by the given transform. The given transform should not
void paintChildWithTransform(RenderObject child, Point childPosition, Matrix4 transform) { /// incorporate the painting offset.
assert(debugCanPaintChild(child)); void pushTransform(bool needsCompositing, Offset offset, Matrix4 transform, PaintingContextCallback painter) {
final Offset childOffset = childPosition.toOffset(); if (needsCompositing) {
if (!child.needsCompositing) { _stopRecordingIfNeeded();
TransformLayer transformLayer = new TransformLayer(transform: transform);
_appendLayer(transformLayer, offset);
PaintingContext childContext = new PaintingContext._(transformLayer, _paintBounds);
painter(childContext, Offset.zero);
childContext._stopRecordingIfNeeded();
} else {
Matrix4 offsetMatrix = new Matrix4.translationValues(offset.dx, offset.dy, 0.0);
Matrix4 trasnformWithOffset = offsetMatrix * transform;
canvas.save(); canvas.save();
canvas.translate(childOffset.dx, childOffset.dy); canvas.concat(trasnformWithOffset.storage);
canvas.concat(transform.storage); painter(this, Offset.zero);
insertChild(child, Offset.zero);
canvas.restore(); canvas.restore();
} else {
TransformLayer transformLayer = new TransformLayer(offset: childOffset, transform: transform);
_containerLayer.append(transformLayer);
compositeChild(child, parentLayer: transformLayer);
} }
} }
...@@ -251,29 +274,23 @@ class PaintingContext { ...@@ -251,29 +274,23 @@ class PaintingContext {
..isAntiAlias = false; ..isAntiAlias = false;
} }
/// Paint a child with an opacity /// Push an opacity layer.
/// ///
/// If the child needs compositing, the blending operation will be applied by /// This function will call painter synchronously with a painting context that
/// a compositing layer. Otherwise, the blending operation will be applied by /// will be blended with the given alpha value.
/// the canvas. void pushOpacity(bool needsCompositing, Offset offset, Rect bounds, int alpha, PaintingContextCallback painter) {
void paintChildWithOpacity(RenderObject child, if (needsCompositing) {
Point childPosition, _stopRecordingIfNeeded();
Rect bounds, OpacityLayer opacityLayer = new OpacityLayer(bounds: bounds, alpha: alpha);
int alpha) { _appendLayer(opacityLayer, offset);
assert(debugCanPaintChild(child)); PaintingContext childContext = new PaintingContext._(opacityLayer, bounds);
final Offset childOffset = childPosition.toOffset(); painter(childContext, Offset.zero);
if (!child.needsCompositing) { childContext._stopRecordingIfNeeded();
canvas.saveLayer(bounds, _getPaintForAlpha(alpha));
canvas.translate(childOffset.dx, childOffset.dy);
insertChild(child, Offset.zero);
canvas.restore();
} else { } else {
OpacityLayer paintLayer = new OpacityLayer( // TODO(abarth): pushOpacity should require bounds.
offset: childOffset, canvas.saveLayer(bounds?.shift(offset), _getPaintForAlpha(alpha));
bounds: bounds, painter(this, offset);
alpha: alpha); canvas.restore();
_containerLayer.append(paintLayer);
compositeChild(child, parentLayer: paintLayer);
} }
} }
...@@ -285,77 +302,20 @@ class PaintingContext { ...@@ -285,77 +302,20 @@ class PaintingContext {
..shader = shaderCallback(bounds); ..shader = shaderCallback(bounds);
} }
void paintChildWithShaderMask(RenderObject child, /// Push a shader mask.
Point childPosition,
Rect bounds,
ShaderCallback shaderCallback,
TransferMode transferMode) {
assert(debugCanPaintChild(child));
final Offset childOffset = childPosition.toOffset();
if (!child.needsCompositing) {
canvas.saveLayer(bounds, new Paint());
canvas.translate(childOffset.dx, childOffset.dy);
insertChild(child, Offset.zero);
Paint shaderPaint = _getPaintForShaderMask(bounds, shaderCallback, transferMode);
canvas.drawRect(Offset.zero & new Size(bounds.width, bounds.height), shaderPaint);
canvas.restore();
} else {
// TODO(hansmuller) support compositing ShaderMasks
assert('Support for compositing ShaderMasks is TBD' is String);
}
}
/// Instructs the child to draw itself onto this context at the given offset
/// ///
/// Do not call directly. This function is visible so that it can be /// This function will call painter synchronously with a painting context that
/// overridden in tests. /// will be masked with the given shader.
void insertChild(RenderObject child, Offset offset) {
child._paintWithContext(this, offset);
}
/// Instructs the child to paint itself into a new composited layer using this context
/// ///
/// Do not call directly. This function is visible so that it can be /// WARNING: This function does not yet support compositing.
/// overridden in tests. void pushShaderMask(bool needsCompositing, Offset offset, Rect bounds, ShaderCallback shaderCallback, TransferMode transferMode, PaintingContextCallback painter) {
void compositeChild(RenderObject child, { Offset childOffset: Offset.zero, ContainerLayer parentLayer }) { assert(!needsCompositing); // TODO(abarth): Implement compositing for shader masks.
// This ends the current layer and starts a new layer for the canvas.saveLayer(bounds.shift(offset), _disableAntialias);
// remainder of our rendering. It also creates a new layer for the painter(this, offset);
// child, and inserts that layer into the given parentLayer, which Paint shaderPaint = _getPaintForShaderMask(bounds, shaderCallback, transferMode);
// must either be our current layer's parent layer, or at least canvas.drawRect(bounds, shaderPaint);
// must have our current layer's parent layer as an ancestor. canvas.restore();
final PictureLayer originalLayer = _currentLayer;
assert(() {
assert(parentLayer != null);
assert(originalLayer != null);
assert(originalLayer.parent != null);
ContainerLayer ancestor = parentLayer;
while (ancestor != null && ancestor != originalLayer.parent)
ancestor = ancestor.parent;
assert(ancestor == originalLayer.parent);
assert(originalLayer.parent == _containerLayer);
return true;
});
// End our current layer.
endRecording();
// Create a layer for our child, and paint the child into it.
if (child.needsPaint || !child.hasLayer) {
PaintingContext newContext = new PaintingContext.withOffset(childOffset, child.paintBounds);
child._layer = newContext.containerLayer;
child._paintWithContext(newContext, Offset.zero);
newContext.endRecording();
} else {
assert(child._layer != null);
child._layer.detach();
child._layer.offset = childOffset;
}
parentLayer.append(child._layer);
// Start a new layer for anything that remains of our own paint.
_startRecording(originalLayer.paintBounds);
} }
} }
/// An encapsulation of a renderer and a paint() method. /// An encapsulation of a renderer and a paint() method.
...@@ -972,7 +932,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget { ...@@ -972,7 +932,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
for (RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => b.depth - a.depth)) { for (RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => b.depth - a.depth)) {
assert(node._needsPaint); assert(node._needsPaint);
if (node.attached) if (node.attached)
node._repaint(); PaintingContext.repaintCompositedChild(node);
}; };
assert(_nodesNeedingPaint.length == 0); assert(_nodesNeedingPaint.length == 0);
} finally { } finally {
...@@ -997,15 +957,6 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget { ...@@ -997,15 +957,6 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
assert(_needsPaint); assert(_needsPaint);
_nodesNeedingPaint.add(this); _nodesNeedingPaint.add(this);
} }
void _repaint() {
assert(hasLayer);
assert(_layer != null);
_layer.removeAllChildren();
PaintingContext context = new PaintingContext.withLayer(_layer, paintBounds);
_layer = context._containerLayer;
_paintWithContext(context, Offset.zero);
context.endRecording();
}
void _paintWithContext(PaintingContext context, Offset offset) { void _paintWithContext(PaintingContext context, Offset offset) {
assert(!_debugDoingThisPaint); assert(!_debugDoingThisPaint);
assert(!_needsLayout); assert(!_needsLayout);
......
...@@ -131,7 +131,7 @@ class RenderOverflowBox extends RenderBox with RenderObjectWithChildMixin<Render ...@@ -131,7 +131,7 @@ class RenderOverflowBox extends RenderBox with RenderObjectWithChildMixin<Render
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) if (child != null)
context.paintChild(child, offset.toPoint()); context.paintChild(child, offset);
} }
void debugDescribeSettings(List<String> settings) { void debugDescribeSettings(List<String> settings) {
...@@ -198,7 +198,7 @@ class RenderSizedOverflowBox extends RenderBox with RenderObjectWithChildMixin<R ...@@ -198,7 +198,7 @@ class RenderSizedOverflowBox extends RenderBox with RenderObjectWithChildMixin<R
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) if (child != null)
context.paintChild(child, offset.toPoint()); context.paintChild(child, offset);
} }
} }
......
...@@ -77,7 +77,7 @@ class RenderProxyBox extends RenderBox with RenderObjectWithChildMixin<RenderBox ...@@ -77,7 +77,7 @@ class RenderProxyBox extends RenderBox with RenderObjectWithChildMixin<RenderBox
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) if (child != null)
context.paintChild(child, offset.toPoint()); context.paintChild(child, offset);
} }
} }
...@@ -501,10 +501,12 @@ class RenderOpacity extends RenderProxyBox { ...@@ -501,10 +501,12 @@ class RenderOpacity extends RenderProxyBox {
int a = _alpha; int a = _alpha;
if (a == 0) if (a == 0)
return; return;
if (a == 255) if (a == 255) {
context.paintChild(child, offset.toPoint()); context.paintChild(child, offset);
else return;
context.paintChildWithOpacity(child, offset.toPoint(), null, a); }
// TODO(abarth): We should pass bounds here.
context.pushOpacity(needsCompositing, offset, null, a, super.paint);
} }
} }
...@@ -540,7 +542,7 @@ class RenderShaderMask extends RenderProxyBox { ...@@ -540,7 +542,7 @@ class RenderShaderMask extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) if (child != null)
context.paintChildWithShaderMask(child, offset.toPoint(), offset & size, _shaderCallback, _transferMode); context.pushShaderMask(needsCompositing, offset, Point.origin & size, _shaderCallback, _transferMode, super.paint);
} }
} }
...@@ -552,7 +554,7 @@ class RenderClipRect extends RenderProxyBox { ...@@ -552,7 +554,7 @@ class RenderClipRect extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) if (child != null)
context.paintChildWithClipRect(child, offset.toPoint(), offset & size); context.pushClipRect(needsCompositing, offset, Point.origin & size, super.paint);
} }
} }
...@@ -598,9 +600,9 @@ class RenderClipRRect extends RenderProxyBox { ...@@ -598,9 +600,9 @@ class RenderClipRRect extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) { if (child != null) {
Rect rect = offset & size; Rect rect = Point.origin & size;
ui.RRect rrect = new ui.RRect.fromRectXY(rect, xRadius, yRadius); ui.RRect rrect = new ui.RRect.fromRectXY(rect, xRadius, yRadius);
context.paintChildWithClipRRect(child, offset.toPoint(), rect, rrect); context.pushClipRRect(needsCompositing, offset, rect, rrect, super.paint);
} }
} }
} }
...@@ -615,7 +617,7 @@ class RenderClipOval extends RenderProxyBox { ...@@ -615,7 +617,7 @@ class RenderClipOval extends RenderProxyBox {
Rect _cachedRect; Rect _cachedRect;
Path _cachedPath; Path _cachedPath;
Path _getPath(Rect rect) { Path _getClipPath(Rect rect) {
if (rect != _cachedRect) { if (rect != _cachedRect) {
_cachedRect = rect; _cachedRect = rect;
_cachedPath = new Path()..addOval(_cachedRect); _cachedPath = new Path()..addOval(_cachedRect);
...@@ -634,8 +636,8 @@ class RenderClipOval extends RenderProxyBox { ...@@ -634,8 +636,8 @@ class RenderClipOval extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) { if (child != null) {
Rect rect = offset & size; Rect bounds = Point.origin & size;
context.paintChildWithClipPath(child, offset.toPoint(), rect, _getPath(rect)); context.pushClipPath(needsCompositing, offset, bounds, _getClipPath(bounds), super.paint);
} }
} }
} }
...@@ -863,7 +865,7 @@ class RenderTransform extends RenderProxyBox { ...@@ -863,7 +865,7 @@ class RenderTransform extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) if (child != null)
context.paintChildWithTransform(child, offset.toPoint(), _effectiveTransform); context.pushTransform(needsCompositing, offset, _effectiveTransform, super.paint);
} }
void applyPaintTransform(Matrix4 transform) { void applyPaintTransform(Matrix4 transform) {
......
...@@ -56,7 +56,7 @@ abstract class RenderShiftedBox extends RenderBox with RenderObjectWithChildMixi ...@@ -56,7 +56,7 @@ abstract class RenderShiftedBox extends RenderBox with RenderObjectWithChildMixi
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) { if (child != null) {
final BoxParentData childParentData = child.parentData; final BoxParentData childParentData = child.parentData;
context.paintChild(child, childParentData.position + offset); context.paintChild(child, childParentData.offset + offset);
} }
} }
......
...@@ -489,6 +489,6 @@ class RenderIndexedStack extends RenderStackBase { ...@@ -489,6 +489,6 @@ class RenderIndexedStack extends RenderStackBase {
return; return;
RenderBox child = _childAtIndex(); RenderBox child = _childAtIndex();
final StackParentData childParentData = child.parentData; final StackParentData childParentData = child.parentData;
context.paintChild(child, childParentData.position + offset); context.paintChild(child, childParentData.offset + offset);
} }
} }
...@@ -54,6 +54,6 @@ class RenderStatisticsBox extends RenderBox { ...@@ -54,6 +54,6 @@ class RenderStatisticsBox extends RenderBox {
} }
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
context.paintStatistics(optionsMask, rasterizerThreshold, offset, size); context.pushStatistics(offset, optionsMask, rasterizerThreshold, size);
} }
} }
...@@ -110,7 +110,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> ...@@ -110,7 +110,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) if (child != null)
context.paintChild(child, offset.toPoint()); context.paintChild(child, offset);
} }
/// Uploads the composited layer tree to the engine /// Uploads the composited layer tree to the engine
......
...@@ -146,12 +146,15 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox ...@@ -146,12 +146,15 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) { if (child != null) {
Offset roundedScrollOffset = _scrollOffsetRoundedToIntegerDevicePixels; Offset roundedScrollOffset = _scrollOffsetRoundedToIntegerDevicePixels;
bool _needsClip = offset < Offset.zero || bool _needsClip = offset < Offset.zero
!(offset & size).contains(((offset - roundedScrollOffset) & child.size).bottomRight); || !(offset & size).contains(((offset - roundedScrollOffset) & child.size).bottomRight);
if (_needsClip) if (_needsClip) {
context.paintChildWithClipRect(child, (offset - roundedScrollOffset).toPoint(), offset & size); context.pushClipRect(needsCompositing, offset, Point.origin & size, (PaintingContext context, Offset offset) {
else context.paintChild(child, offset - roundedScrollOffset);
context.paintChild(child, (offset - roundedScrollOffset).toPoint()); });
} else {
context.paintChild(child, offset - roundedScrollOffset);
}
} }
} }
......
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