Commit 654fc734 authored by Hixie's avatar Hixie

Improvements for Layers logic

- Introduce some new Layer classes.
- Introduce paintChildWith* methods.
- Convert paint() methods to use paintChildWith* where appropriate.
- Fix paintBounds logic in Layer world.
- Introduce Layer.replaceWith(), so that it's clearer what's going on.
- Make RenderObjects have a ContainerLayer, not a PictureLayer.
- Introduce a PaintingContext.replacingLayer() constructor to highlight
  where we are creating a layer just to replace an older one.
- Rename some layer-related methods and fields for clarity:
   requiresCompositing -> hasLayer
   hasCompositedDescendant -> needsCompositing
   updateCompositing -> updateCompositingBits
   _needsCompositingUpdate -> _needsCompositingBitsUpdate
   markNeedsCompositingUpdate -> markNeedsCompositingBitsUpdate
- After updating compositing bits, if we find that the bit changed, we
  now call markNeedsPaint().
- Reorder markNeedsPaint() logic for clarity.
- Make flushPaint() start at the deepest node.
- Make _compositeChild() avoid repainting children with hasLayer that
  aren't dirty, instead it just reuses their existing layer.
- Made RenderView reuse the RenderObject layer instead of having its own.
- Made RenderView have hasLayer set to true.
- Add various asserts and comments.
parent d662f7e6
...@@ -26,15 +26,40 @@ abstract class Layer { ...@@ -26,15 +26,40 @@ abstract class Layer {
if (_parent != null) if (_parent != null)
_parent.remove(this); _parent.remove(this);
} }
void replaceWith(Layer newLayer) {
assert(_parent != null);
assert(newLayer._parent == null);
assert(newLayer._nextSibling == null);
assert(newLayer._previousSibling == null);
newLayer._nextSibling = _nextSibling;
if (_nextSibling != null)
newLayer._nextSibling._previousSibling = newLayer;
newLayer._previousSibling = _previousSibling;
if (_previousSibling != null)
newLayer._previousSibling._nextSibling = newLayer;
newLayer._parent = _parent;
if (_parent._firstChild == this)
_parent._firstChild = newLayer;
if (_parent._lastChild == this)
_parent._lastChild = newLayer;
_nextSibling = null;
_previousSibling = null;
_parent = null;
}
// The paint() methods are temporary. Eventually, Layers won't have
// a paint() method, the entire Layer hierarchy will be handed over
// to the C++ side for processing. Until we implement that, though,
// we instead have the layers paint themselves into a canvas at
// paint time.
void paint(sky.Canvas canvas); void paint(sky.Canvas canvas);
} }
class PictureLayer extends Layer { class PictureLayer extends Layer {
PictureLayer({ Offset offset: Offset.zero, this.size }) PictureLayer({ Offset offset: Offset.zero, this.paintBounds })
: super(offset: offset); : super(offset: offset);
Size size; Rect paintBounds;
sky.Picture picture; sky.Picture picture;
bool _debugPaintLayerBorder(sky.Canvas canvas) { bool _debugPaintLayerBorder(sky.Canvas canvas) {
...@@ -43,12 +68,13 @@ class PictureLayer extends Layer { ...@@ -43,12 +68,13 @@ class PictureLayer extends Layer {
..color = debugPaintLayerBordersColor ..color = debugPaintLayerBordersColor
..strokeWidth = 2.0 ..strokeWidth = 2.0
..setStyle(sky.PaintingStyle.stroke); ..setStyle(sky.PaintingStyle.stroke);
canvas.drawRect(Point.origin & size, border); canvas.drawRect(paintBounds, border);
} }
return true; return true;
} }
void paint(sky.Canvas canvas) { void paint(sky.Canvas canvas) {
assert(picture != null);
canvas.translate(offset.dx, offset.dy); canvas.translate(offset.dx, offset.dy);
canvas.drawPicture(picture); canvas.drawPicture(picture);
assert(_debugPaintLayerBorder(canvas)); assert(_debugPaintLayerBorder(canvas));
...@@ -59,17 +85,11 @@ class PictureLayer extends Layer { ...@@ -59,17 +85,11 @@ class PictureLayer extends Layer {
class ContainerLayer extends Layer { class ContainerLayer extends Layer {
ContainerLayer({ Offset offset: Offset.zero }) : super(offset: offset); ContainerLayer({ Offset offset: Offset.zero }) : super(offset: offset);
void paint(sky.Canvas canvas) { // TODO(ianh): hide firstChild since nobody uses it
Layer child = firstChild;
while (child != null) {
child.paint(canvas);
child = child.nextSibling;
}
}
Layer _firstChild; Layer _firstChild;
Layer get firstChild => _firstChild; Layer get firstChild => _firstChild;
// TODO(ianh): remove _lastChild since nobody uses it
Layer _lastChild; Layer _lastChild;
Layer get lastChild => _lastChild; Layer get lastChild => _lastChild;
...@@ -89,6 +109,7 @@ class ContainerLayer extends Layer { ...@@ -89,6 +109,7 @@ class ContainerLayer extends Layer {
return child == equals; return child == equals;
} }
// TODO(ianh): Remove 'before' and rename the function to 'append' since nobody uses 'before'
void add(Layer child, { Layer before }) { void add(Layer child, { Layer before }) {
assert(child != this); assert(child != this);
assert(before != this); assert(before != this);
...@@ -126,10 +147,11 @@ class ContainerLayer extends Layer { ...@@ -126,10 +147,11 @@ class ContainerLayer extends Layer {
} }
} }
// TODO(ianh): Hide this function since only detach() uses it
void remove(Layer child) { void remove(Layer child) {
assert(child._parent == this);
assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild)); assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild));
assert(_debugUltimateNextSiblingOf(child, equals: _lastChild)); assert(_debugUltimateNextSiblingOf(child, equals: _lastChild));
assert(child._parent == this);
if (child._previousSibling == null) { if (child._previousSibling == null) {
assert(_firstChild == child); assert(_firstChild == child);
_firstChild = child._nextSibling; _firstChild = child._nextSibling;
...@@ -146,6 +168,69 @@ class ContainerLayer extends Layer { ...@@ -146,6 +168,69 @@ class ContainerLayer extends Layer {
child._nextSibling = null; child._nextSibling = null;
child._parent = null; child._parent = null;
} }
void paint(sky.Canvas canvas) {
canvas.translate(offset.dx, offset.dy);
paintChildren(canvas);
canvas.translate(-offset.dx, -offset.dy);
}
void paintChildren(sky.Canvas canvas) {
Layer child = firstChild;
while (child != null) {
child.paint(canvas);
child = child.nextSibling;
}
}
}
class ClipRectLayer extends ContainerLayer {
ClipRectLayer({ Offset offset: Offset.zero, this.clipRect }) : super(offset: offset);
// clipRect is _not_ affected by given offset
Rect clipRect;
void paint(sky.Canvas canvas) {
canvas.save();
canvas.clipRect(clipRect);
canvas.translate(offset.dx, offset.dy);
paintChildren(canvas);
canvas.restore();
}
}
final Paint _disableAntialias = new Paint()..isAntiAlias = false;
class ClipRRectLayer extends ContainerLayer {
ClipRRectLayer({ Offset offset: Offset.zero, this.bounds, this.clipRRect }) : super(offset: offset);
// bounds and clipRRect are _not_ affected by given offset
Rect bounds;
sky.RRect clipRRect;
void paint(sky.Canvas canvas) {
canvas.saveLayer(bounds, _disableAntialias);
canvas.clipRRect(clipRRect);
canvas.translate(offset.dx, offset.dy);
paintChildren(canvas);
canvas.restore();
}
}
class ClipPathLayer extends ContainerLayer {
ClipPathLayer({ Offset offset: Offset.zero, this.bounds, this.clipPath }) : super(offset: offset);
// bounds and clipPath are _not_ affected by given offset
Rect bounds;
Path clipPath;
void paint(sky.Canvas canvas) {
canvas.saveLayer(bounds, _disableAntialias);
canvas.clipPath(clipPath);
canvas.translate(offset.dx, offset.dy);
paintChildren(canvas);
canvas.restore();
}
} }
class TransformLayer extends ContainerLayer { class TransformLayer extends ContainerLayer {
...@@ -157,21 +242,22 @@ class TransformLayer extends ContainerLayer { ...@@ -157,21 +242,22 @@ class TransformLayer extends ContainerLayer {
canvas.save(); canvas.save();
canvas.translate(offset.dx, offset.dy); canvas.translate(offset.dx, offset.dy);
canvas.concat(transform.storage); canvas.concat(transform.storage);
super.paint(canvas); paintChildren(canvas);
canvas.restore(); canvas.restore();
} }
} }
class ClipLayer extends ContainerLayer { class PaintLayer extends ContainerLayer {
ClipLayer({ Offset offset: Offset.zero, this.clipRect }) : super(offset: offset); PaintLayer({ Offset offset: Offset.zero, this.bounds, this.paintSettings }) : super(offset: offset);
Rect clipRect; // bounds is _not_ affected by given offset
Rect bounds;
Paint paintSettings; // TODO(ianh): rename this to 'paint' once paint() is gone
void paint(sky.Canvas canvas) { void paint(sky.Canvas canvas) {
canvas.save(); canvas.saveLayer(bounds, paintSettings);
canvas.translate(offset.dx, offset.dy); canvas.translate(offset.dx, offset.dy);
canvas.clipRect(clipRect); paintChildren(canvas);
super.paint(canvas);
canvas.restore(); canvas.restore();
} }
} }
...@@ -192,10 +278,9 @@ class ColorFilterLayer extends ContainerLayer { ...@@ -192,10 +278,9 @@ class ColorFilterLayer extends ContainerLayer {
Paint paint = new Paint() Paint paint = new Paint()
..color = color ..color = color
..setTransferMode(transferMode); ..setTransferMode(transferMode);
canvas.saveLayer(offset & size, paint); canvas.saveLayer(offset & size, paint);
canvas.translate(offset.dx, offset.dy); canvas.translate(offset.dx, offset.dy);
super.paint(canvas); paintChildren(canvas);
canvas.restore(); canvas.restore();
} }
} }
This diff is collapsed.
...@@ -295,18 +295,12 @@ class RenderOpacity extends RenderProxyBox { ...@@ -295,18 +295,12 @@ class RenderOpacity extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) { if (child != null) {
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.toPoint());
return; else
} context.paintChildWithPaint(child, offset.toPoint(), null, _paint);
context.canvas.saveLayer(null, _paint); // TODO(abarth): layerize
context.paintChild(child, offset.toPoint());
context.canvas.restore();
} }
} }
} }
...@@ -349,11 +343,8 @@ class RenderColorFilter extends RenderProxyBox { ...@@ -349,11 +343,8 @@ class RenderColorFilter extends RenderProxyBox {
} }
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) { if (child != null)
context.canvas.saveLayer(offset & size, _paint); // TODO(abarth): layerize context.paintChildWithPaint(child, offset.toPoint(), offset & size, _paint);
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
} }
} }
...@@ -362,7 +353,7 @@ class RenderClipRect extends RenderProxyBox { ...@@ -362,7 +353,7 @@ class RenderClipRect extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) if (child != null)
context.paintChildWithClip(child, offset.toPoint(), Offset.zero & size); context.paintChildWithClipRect(child, offset.toPoint(), offset & size);
} }
} }
...@@ -393,16 +384,11 @@ class RenderClipRRect extends RenderProxyBox { ...@@ -393,16 +384,11 @@ class RenderClipRRect extends RenderProxyBox {
markNeedsPaint(); markNeedsPaint();
} }
final Paint _paint = new Paint()..isAntiAlias = false;
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) { if (child != null) {
Rect rect = offset & size; Rect rect = offset & size;
context.canvas.saveLayer(rect, _paint); // TODO(abarth): layerize
sky.RRect rrect = new sky.RRect()..setRectXY(rect, xRadius, yRadius); sky.RRect rrect = new sky.RRect()..setRectXY(rect, xRadius, yRadius);
context.canvas.clipRRect(rrect); context.paintChildWithClipRRect(child, offset.toPoint(), rect, rrect);
context.paintChild(child, offset.toPoint());
context.canvas.restore();
} }
} }
} }
...@@ -410,8 +396,6 @@ class RenderClipRRect extends RenderProxyBox { ...@@ -410,8 +396,6 @@ class RenderClipRRect extends RenderProxyBox {
class RenderClipOval extends RenderProxyBox { class RenderClipOval extends RenderProxyBox {
RenderClipOval({ RenderBox child }) : super(child); RenderClipOval({ RenderBox child }) : super(child);
final Paint _paint = new Paint()..isAntiAlias = false;
Rect _cachedRect; Rect _cachedRect;
Path _cachedPath; Path _cachedPath;
...@@ -426,10 +410,7 @@ class RenderClipOval extends RenderProxyBox { ...@@ -426,10 +410,7 @@ 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 rect = offset & size;
context.canvas.saveLayer(rect, _paint); // TODO(abarth): layerize context.paintChildWithClipPath(child, offset.toPoint(), rect, _getPath(rect));
context.canvas.clipPath(_getPath(rect));
context.paintChild(child, offset.toPoint());
context.canvas.restore();
} }
} }
} }
...@@ -561,11 +542,8 @@ class RenderTransform extends RenderProxyBox { ...@@ -561,11 +542,8 @@ class RenderTransform extends RenderProxyBox {
} }
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
context.canvas.save(); if (child != null)
context.canvas.translate(offset.dx, offset.dy); context.paintChildWithTransform(child, offset.toPoint(), _transform);
context.canvas.concat(_transform.storage);
super.paint(context, Offset.zero);
context.canvas.restore();
} }
void applyPaintTransform(Matrix4 transform) { void applyPaintTransform(Matrix4 transform) {
......
...@@ -72,7 +72,7 @@ class SkyBinding { ...@@ -72,7 +72,7 @@ class SkyBinding {
} }
void beginFrame(double timeStamp) { void beginFrame(double timeStamp) {
RenderObject.flushLayout(); RenderObject.flushLayout();
_renderView.updateCompositing(); _renderView.updateCompositingBits();
RenderObject.flushPaint(); RenderObject.flushPaint();
_renderView.paintFrame(); _renderView.paintFrame();
_renderView.compositeFrame(); _renderView.compositeFrame();
......
...@@ -42,8 +42,6 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> ...@@ -42,8 +42,6 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
markNeedsLayout(); markNeedsLayout();
} }
ContainerLayer _rootLayer;
// We never call layout() on this class, so this should never get // We never call layout() on this class, so this should never get
// checked. (This class is laid out using scheduleInitialLayout().) // checked. (This class is laid out using scheduleInitialLayout().)
bool debugDoesMeetConstraints() { assert(false); return false; } bool debugDoesMeetConstraints() { assert(false); return false; }
...@@ -79,6 +77,8 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> ...@@ -79,6 +77,8 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
return true; return true;
} }
bool get hasLayer => true;
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.toPoint());
...@@ -88,12 +88,9 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> ...@@ -88,12 +88,9 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
sky.tracing.begin('RenderView.paintFrame'); sky.tracing.begin('RenderView.paintFrame');
try { try {
final double devicePixelRatio = sky.view.devicePixelRatio; final double devicePixelRatio = sky.view.devicePixelRatio;
Matrix4 transform = new Matrix4.diagonal3Values(devicePixelRatio, devicePixelRatio, 1.0); Matrix4 logicalToDeviceZoom = new Matrix4.diagonal3Values(devicePixelRatio, devicePixelRatio, 1.0);
_rootLayer = new TransformLayer(transform: transform); ContainerLayer rootLayer = new TransformLayer(transform: logicalToDeviceZoom);
PaintingContext context = new PaintingContext(Offset.zero, size); initialPaint(rootLayer, size);
_rootLayer.add(context.layer);
context.paintChild(child, Point.origin);
context.endRecording();
} finally { } finally {
sky.tracing.end('RenderView.paintFrame'); sky.tracing.end('RenderView.paintFrame');
} }
...@@ -102,9 +99,12 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> ...@@ -102,9 +99,12 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
void compositeFrame() { void compositeFrame() {
sky.tracing.begin('RenderView.compositeFrame'); sky.tracing.begin('RenderView.compositeFrame');
try { try {
// Eventually we will want to pass the entire layer tree to the C++ side.
// For now, however, we take the layer tree and paint it into a Canvas,
// which we then hand to the C++ side.
sky.PictureRecorder recorder = new sky.PictureRecorder(); sky.PictureRecorder recorder = new sky.PictureRecorder();
sky.Canvas canvas = new sky.Canvas(recorder, Point.origin & (size * sky.view.devicePixelRatio)); sky.Canvas canvas = new sky.Canvas(recorder, Point.origin & (size * sky.view.devicePixelRatio));
_rootLayer.paint(canvas); layer.paint(canvas);
sky.view.picture = recorder.endRecording(); sky.view.picture = recorder.endRecording();
} finally { } finally {
sky.tracing.end('RenderView.compositeFrame'); sky.tracing.end('RenderView.compositeFrame');
......
...@@ -122,13 +122,10 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox ...@@ -122,13 +122,10 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox
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) {
context.canvas.save();
context.canvas.clipRect(offset & size);
}
context.paintChild(child, (offset - roundedScrollOffset).toPoint());
if (_needsClip) if (_needsClip)
context.canvas.restore(); context.paintChildWithClipRect(child, (offset - roundedScrollOffset).toPoint(), offset & size);
else
context.paintChild(child, (offset - roundedScrollOffset).toPoint());
} }
} }
......
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