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 {
super.paint(context, offset);
RenderSector child = firstChild;
while (child != null) {
context.paintChild(child, offset.toPoint());
context.paintChild(child, offset);
final SectorChildListParentData childParentData = child.parentData;
child = childParentData.nextSibling;
}
......@@ -388,7 +388,7 @@ class RenderSectorSlice extends RenderSectorWithChildren {
RenderSector child = firstChild;
while (child != null) {
assert(child.parentData is SectorChildListParentData);
context.paintChild(child, offset.toPoint());
context.paintChild(child, offset);
final SectorChildListParentData childParentData = child.parentData;
child = childParentData.nextSibling;
}
......@@ -470,7 +470,7 @@ class RenderBoxToRenderSectorAdapter extends RenderBox with RenderObjectWithChil
if (child != null) {
Rect bounds = offset & size;
// 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
RenderBox child = firstChild;
while (child != null) {
final _TabBarParentData childParentData = child.parentData;
context.paintChild(child, childParentData.position + offset);
context.paintChild(child, childParentData.offset + offset);
if (index++ == selectedIndex)
_paintIndicator(context.canvas, child, offset);
child = childParentData.nextSibling;
......
......@@ -287,6 +287,8 @@ class BoxHitTestEntry extends HitTestEntry {
/// Parent data used by [RenderBox] and its subclasses
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;
/// The point at which to paint the child in the parent's coordinate system
Point get position => _position;
......@@ -294,6 +296,7 @@ class BoxParentData extends ParentData {
assert(RenderObject.debugDoingLayout);
_position = value;
}
Offset get offset => _position.toOffset();
String toString() => 'position=$position';
}
......@@ -771,7 +774,7 @@ abstract class RenderBoxContainerDefaultsMixin<ChildType extends RenderBox, Pare
RenderBox child = firstChild;
while (child != null) {
final ParentDataType childParentData = child.parentData;
context.paintChild(child, childParentData.position + offset);
context.paintChild(child, childParentData.offset + offset);
child = childParentData.nextSibling;
}
}
......
......@@ -44,7 +44,9 @@ class PaintingCanvas extends Canvas {
// 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
/// context. The painting context has a canvas, which receives the
......@@ -57,190 +59,211 @@ class PaintingCanvas extends Canvas {
/// not hold a reference to the canvas across operations that might paint
/// child render objects.
class PaintingContext {
/// Construct a painting context at a given offset with the given bounds
PaintingContext.withOffset(Offset offset, Rect paintBounds) {
_containerLayer = new ContainerLayer(offset: offset);
_startRecording(paintBounds);
PaintingContext._(this._containerLayer, this._paintBounds);
final ContainerLayer _containerLayer;
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
PaintingContext.withLayer(ContainerLayer containerLayer, Rect paintBounds) {
_containerLayer = containerLayer;
_startRecording(paintBounds);
void _compositeChild(RenderObject child, Offset offset) {
assert(!_isRecording);
assert(child.hasLayer);
// 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
PaintingContext.forTesting(this._canvas);
void _appendLayer(Layer layer, Offset offset) {
assert(!_isRecording);
layer.offset = offset;
_containerLayer.append(layer);
}
ContainerLayer _containerLayer;
/// The layer contain all the composting layers that will be used for this context
ContainerLayer get containerLayer => _containerLayer;
bool get _isRecording {
final bool hasCanvas = (_canvas != null);
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;
ui.PictureRecorder _recorder;
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
/// 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) {
assert(_currentLayer == null);
assert(_recorder == null);
assert(_canvas == null);
_currentLayer = new PictureLayer(paintBounds: paintBounds);
/// 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.
PaintingCanvas get canvas {
if (_canvas == null)
_startRecording();
return _canvas;
}
void _startRecording() {
assert(!_isRecording);
_currentLayer = new PictureLayer(paintBounds: _paintBounds);
_recorder = new ui.PictureRecorder();
_canvas = new PaintingCanvas(_recorder, paintBounds);
_canvas = new PaintingCanvas(_recorder, _paintBounds);
_containerLayer.append(_currentLayer);
}
/// Stop recording draw operations into the current compositing layer
void endRecording() {
assert(_currentLayer != null);
assert(_recorder != null);
assert(_canvas != null);
void _stopRecordingIfNeeded() {
if (!_isRecording)
return;
_currentLayer.picture = _recorder.endRecording();
_currentLayer = null;
_recorder = null;
_canvas = null;
}
/// Whether the canvas is in a state that permits drawing the given child
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;
}
static final Paint _disableAntialias = new Paint()..isAntiAlias = false;
/// 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.
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,
/// Statistics overlays are always composited because they're drawn by the
/// compositor.
void pushStatistics(Offset offset, int optionsMask, int rasterizerThreshold, Size size) {
_stopRecordingIfNeeded();
StatisticsLayer statisticsLayer = new StatisticsLayer(
paintBounds: new Rect.fromLTWH(0.0, 0.0, size.width, size.height),
optionsMask : optionsMask,
rasterizerThreshold : rasterizerThreshold
optionsMask: optionsMask,
rasterizerThreshold: rasterizerThreshold
);
_containerLayer.append(statsLayer);
_appendLayer(statisticsLayer, offset);
}
// Below we have various variants of the paintChild() method, which
// 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
/// Push a rectangular 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: clipRect is in the parent's coordinate space
void paintChildWithClipRect(RenderObject child, Point childPosition, Rect clipRect) {
assert(debugCanPaintChild(child));
final Offset childOffset = childPosition.toOffset();
if (!child.needsCompositing) {
/// This function will call painter synchronously with a painting context that
/// is clipped by the given clip. The given clip should not incorporate the
/// painting offset.
void pushClipRect(bool needsCompositing, Offset offset, Rect clipRect, PaintingContextCallback painter) {
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.clipRect(clipRect);
insertChild(child, childOffset);
canvas.clipRect(clipRect.shift(offset));
painter(this, offset);
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
void paintChildWithClipRRect(RenderObject child, Point childPosition, Rect bounds, ui.RRect clipRRect) {
assert(debugCanPaintChild(child));
final Offset childOffset = childPosition.toOffset();
if (!child.needsCompositing) {
canvas.saveLayer(bounds, _disableAntialias);
/// This function will call painter synchronously with a painting context that
/// is clipped by the given clip. The given clip should not incorporate the
/// painting offset.
void pushClipRRect(bool needsCompositing, Offset offset, Rect bounds, ui.RRect clipRRect, PaintingContextCallback painter) {
if (needsCompositing) {
_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);
insertChild(child, childOffset);
painter(this, Offset.zero);
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
///
/// If the child needs compositing, the clip will be applied by a
/// compositing layer. Otherwise, the clip will be applied by the canvas.
/// Push a path clip.
///
/// Note: bounds and clipPath are in the parent's coordinate space
void paintChildWithClipPath(RenderObject child, Point childPosition, Rect bounds, Path clipPath) {
assert(debugCanPaintChild(child));
final Offset childOffset = childPosition.toOffset();
if (!child.needsCompositing) {
canvas.saveLayer(bounds, _disableAntialias);
canvas.clipPath(clipPath);
canvas.translate(childOffset.dx, childOffset.dy);
insertChild(child, Offset.zero);
canvas.restore();
/// This function will call painter synchronously with a painting context that
/// is clipped by the given clip. The given clip should not incorporate the
/// painting offset.
void pushClipPath(bool needsCompositing, Offset offset, Rect bounds, Path clipPath, PaintingContextCallback painter) {
if (needsCompositing) {
_stopRecordingIfNeeded();
ClipPathLayer clipLayer = new ClipPathLayer(bounds: bounds, clipPath: clipPath);
_appendLayer(clipLayer, offset);
PaintingContext childContext = new PaintingContext._(clipLayer, bounds);
painter(childContext, Offset.zero);
childContext._stopRecordingIfNeeded();
} else {
ClipPathLayer clipLayer = new ClipPathLayer(offset: childOffset, bounds: bounds, clipPath: clipPath);
_containerLayer.append(clipLayer);
compositeChild(child, parentLayer: clipLayer);
canvas.saveLayer(bounds.shift(offset), _disableAntialias);
canvas.clipPath(clipPath.shift(offset));
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
/// compositing layer. Otherwise, the transform will be applied by the canvas.
void paintChildWithTransform(RenderObject child, Point childPosition, Matrix4 transform) {
assert(debugCanPaintChild(child));
final Offset childOffset = childPosition.toOffset();
if (!child.needsCompositing) {
/// This function will call painter synchronously with a painting context that
/// is transformed by the given transform. The given transform should not
/// incorporate the painting offset.
void pushTransform(bool needsCompositing, Offset offset, Matrix4 transform, PaintingContextCallback painter) {
if (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.translate(childOffset.dx, childOffset.dy);
canvas.concat(transform.storage);
insertChild(child, Offset.zero);
canvas.concat(trasnformWithOffset.storage);
painter(this, Offset.zero);
canvas.restore();
} else {
TransformLayer transformLayer = new TransformLayer(offset: childOffset, transform: transform);
_containerLayer.append(transformLayer);
compositeChild(child, parentLayer: transformLayer);
}
}
......@@ -251,29 +274,23 @@ class PaintingContext {
..isAntiAlias = false;
}
/// Paint a child with an opacity
/// Push an opacity layer.
///
/// If the child needs compositing, the blending operation will be applied by
/// a compositing layer. Otherwise, the blending operation will be applied by
/// the canvas.
void paintChildWithOpacity(RenderObject child,
Point childPosition,
Rect bounds,
int alpha) {
assert(debugCanPaintChild(child));
final Offset childOffset = childPosition.toOffset();
if (!child.needsCompositing) {
canvas.saveLayer(bounds, _getPaintForAlpha(alpha));
canvas.translate(childOffset.dx, childOffset.dy);
insertChild(child, Offset.zero);
canvas.restore();
/// This function will call painter synchronously with a painting context that
/// will be blended with the given alpha value.
void pushOpacity(bool needsCompositing, Offset offset, Rect bounds, int alpha, PaintingContextCallback painter) {
if (needsCompositing) {
_stopRecordingIfNeeded();
OpacityLayer opacityLayer = new OpacityLayer(bounds: bounds, alpha: alpha);
_appendLayer(opacityLayer, offset);
PaintingContext childContext = new PaintingContext._(opacityLayer, bounds);
painter(childContext, Offset.zero);
childContext._stopRecordingIfNeeded();
} else {
OpacityLayer paintLayer = new OpacityLayer(
offset: childOffset,
bounds: bounds,
alpha: alpha);
_containerLayer.append(paintLayer);
compositeChild(child, parentLayer: paintLayer);
// TODO(abarth): pushOpacity should require bounds.
canvas.saveLayer(bounds?.shift(offset), _getPaintForAlpha(alpha));
painter(this, offset);
canvas.restore();
}
}
......@@ -285,77 +302,20 @@ class PaintingContext {
..shader = shaderCallback(bounds);
}
void paintChildWithShaderMask(RenderObject child,
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
/// Push a shader mask.
///
/// Do not call directly. This function is visible so that it can be
/// overridden in tests.
void insertChild(RenderObject child, Offset offset) {
child._paintWithContext(this, offset);
}
/// Instructs the child to paint itself into a new composited layer using this context
/// This function will call painter synchronously with a painting context that
/// will be masked with the given shader.
///
/// Do not call directly. This function is visible so that it can be
/// overridden in tests.
void compositeChild(RenderObject child, { Offset childOffset: Offset.zero, ContainerLayer parentLayer }) {
// This ends the current layer and starts a new layer for the
// remainder of our rendering. It also creates a new layer for the
// child, and inserts that layer into the given parentLayer, which
// must either be our current layer's parent layer, or at least
// must have our current layer's parent layer as an ancestor.
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);
/// WARNING: This function does not yet support compositing.
void pushShaderMask(bool needsCompositing, Offset offset, Rect bounds, ShaderCallback shaderCallback, TransferMode transferMode, PaintingContextCallback painter) {
assert(!needsCompositing); // TODO(abarth): Implement compositing for shader masks.
canvas.saveLayer(bounds.shift(offset), _disableAntialias);
painter(this, offset);
Paint shaderPaint = _getPaintForShaderMask(bounds, shaderCallback, transferMode);
canvas.drawRect(bounds, shaderPaint);
canvas.restore();
}
}
/// An encapsulation of a renderer and a paint() method.
......@@ -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)) {
assert(node._needsPaint);
if (node.attached)
node._repaint();
PaintingContext.repaintCompositedChild(node);
};
assert(_nodesNeedingPaint.length == 0);
} finally {
......@@ -997,15 +957,6 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
assert(_needsPaint);
_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) {
assert(!_debugDoingThisPaint);
assert(!_needsLayout);
......
......@@ -131,7 +131,7 @@ class RenderOverflowBox extends RenderBox with RenderObjectWithChildMixin<Render
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChild(child, offset.toPoint());
context.paintChild(child, offset);
}
void debugDescribeSettings(List<String> settings) {
......@@ -198,7 +198,7 @@ class RenderSizedOverflowBox extends RenderBox with RenderObjectWithChildMixin<R
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChild(child, offset.toPoint());
context.paintChild(child, offset);
}
}
......
......@@ -77,7 +77,7 @@ class RenderProxyBox extends RenderBox with RenderObjectWithChildMixin<RenderBox
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChild(child, offset.toPoint());
context.paintChild(child, offset);
}
}
......@@ -501,10 +501,12 @@ class RenderOpacity extends RenderProxyBox {
int a = _alpha;
if (a == 0)
return;
if (a == 255)
context.paintChild(child, offset.toPoint());
else
context.paintChildWithOpacity(child, offset.toPoint(), null, a);
if (a == 255) {
context.paintChild(child, offset);
return;
}
// TODO(abarth): We should pass bounds here.
context.pushOpacity(needsCompositing, offset, null, a, super.paint);
}
}
......@@ -540,7 +542,7 @@ class RenderShaderMask extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) {
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 {
void paint(PaintingContext context, Offset offset) {
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 {
void paint(PaintingContext context, Offset offset) {
if (child != null) {
Rect rect = offset & size;
Rect rect = Point.origin & size;
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 {
Rect _cachedRect;
Path _cachedPath;
Path _getPath(Rect rect) {
Path _getClipPath(Rect rect) {
if (rect != _cachedRect) {
_cachedRect = rect;
_cachedPath = new Path()..addOval(_cachedRect);
......@@ -634,8 +636,8 @@ class RenderClipOval extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) {
if (child != null) {
Rect rect = offset & size;
context.paintChildWithClipPath(child, offset.toPoint(), rect, _getPath(rect));
Rect bounds = Point.origin & size;
context.pushClipPath(needsCompositing, offset, bounds, _getClipPath(bounds), super.paint);
}
}
}
......@@ -863,7 +865,7 @@ class RenderTransform extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChildWithTransform(child, offset.toPoint(), _effectiveTransform);
context.pushTransform(needsCompositing, offset, _effectiveTransform, super.paint);
}
void applyPaintTransform(Matrix4 transform) {
......
......@@ -56,7 +56,7 @@ abstract class RenderShiftedBox extends RenderBox with RenderObjectWithChildMixi
void paint(PaintingContext context, Offset offset) {
if (child != null) {
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 {
return;
RenderBox child = _childAtIndex();
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 {
}
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>
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChild(child, offset.toPoint());
context.paintChild(child, offset);
}
/// Uploads the composited layer tree to the engine
......
......@@ -146,12 +146,15 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox
void paint(PaintingContext context, Offset offset) {
if (child != null) {
Offset roundedScrollOffset = _scrollOffsetRoundedToIntegerDevicePixels;
bool _needsClip = offset < Offset.zero ||
!(offset & size).contains(((offset - roundedScrollOffset) & child.size).bottomRight);
if (_needsClip)
context.paintChildWithClipRect(child, (offset - roundedScrollOffset).toPoint(), offset & size);
else
context.paintChild(child, (offset - roundedScrollOffset).toPoint());
bool _needsClip = offset < Offset.zero
|| !(offset & size).contains(((offset - roundedScrollOffset) & child.size).bottomRight);
if (_needsClip) {
context.pushClipRect(needsCompositing, offset, Point.origin & size, (PaintingContext context, Offset offset) {
context.paintChild(child, offset - roundedScrollOffset);
});
} 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