Commit 4fb5bcd8 authored by Adam Barth's avatar Adam Barth

Merge pull request #486 from abarth/painting_context

Refactor PaintingContext
parents c882d423 fc576814
...@@ -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
///
/// This getter can return a different canvas object after painting child
/// render objects using this canvas because draw operations before and after
/// a child might need to be recorded in separate compositing layers.
PaintingCanvas get canvas => _canvas;
void _startRecording(Rect paintBounds) { /// The canvas on which to paint.
assert(_currentLayer == null); ///
assert(_recorder == null); /// The current canvas can change whenever you paint a child using this
assert(_canvas == null); /// context, which means it's fragile to hold a reference to the canvas
_currentLayer = new PictureLayer(paintBounds: paintBounds); /// returned by this getter.
PaintingCanvas get canvas {
if (_canvas == null)
_startRecording();
return _canvas;
}
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
/// and inserted into the containerLayer. If the child does not require
/// compositing, the child will be painted into the current canvas.
/// ///
/// Note: After calling this function, the current canvas might change. /// Statistics overlays are always composited because they're drawn by the
void paintChild(RenderObject child, Point childPosition) { /// compositor.
assert(debugCanPaintChild(child)); void pushStatistics(Offset offset, int optionsMask, int rasterizerThreshold, Size size) {
final Offset childOffset = childPosition.toOffset(); _stopRecordingIfNeeded();
if (!child.hasLayer) { StatisticsLayer statisticsLayer = new StatisticsLayer(
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
/// compositing layer. Otherwise, the clip will be applied by the canvas.
/// ///
/// Note: clipRect is in the parent's coordinate space /// This function will call painter synchronously with a painting context that
void paintChildWithClipRect(RenderObject child, Point childPosition, Rect clipRect) { /// is clipped by the given clip. The given clip should not incorporate the
assert(debugCanPaintChild(child)); /// painting offset.
final Offset childOffset = childPosition.toOffset(); void pushClipRect(bool needsCompositing, Offset offset, Rect clipRect, PaintingContextCallback painter) {
if (!child.needsCompositing) { if (needsCompositing) {
_stopRecordingIfNeeded();
ClipRectLayer clipLayer = new ClipRectLayer(clipRect: clipRect);
_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
/// compositing layer. Otherwise, the clip will be applied by the canvas.
/// ///
/// Note: clipRRect is in the parent's coordinate space /// This function will call painter synchronously with a painting context that
void paintChildWithClipRRect(RenderObject child, Point childPosition, Rect bounds, ui.RRect clipRRect) { /// is clipped by the given clip. The given clip should not incorporate the
assert(debugCanPaintChild(child)); /// painting offset.
final Offset childOffset = childPosition.toOffset(); void pushClipRRect(bool needsCompositing, Offset offset, Rect bounds, ui.RRect clipRRect, PaintingContextCallback painter) {
if (!child.needsCompositing) { if (needsCompositing) {
canvas.saveLayer(bounds, _disableAntialias); _stopRecordingIfNeeded();
ClipRRectLayer clipLayer = new ClipRRectLayer(bounds: bounds, clipRRect: clipRRect);
_appendLayer(clipLayer, offset);
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