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 {
if (_parent != null)
_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);
}
class PictureLayer extends Layer {
PictureLayer({ Offset offset: Offset.zero, this.size })
PictureLayer({ Offset offset: Offset.zero, this.paintBounds })
: super(offset: offset);
Size size;
Rect paintBounds;
sky.Picture picture;
bool _debugPaintLayerBorder(sky.Canvas canvas) {
......@@ -43,12 +68,13 @@ class PictureLayer extends Layer {
..color = debugPaintLayerBordersColor
..strokeWidth = 2.0
..setStyle(sky.PaintingStyle.stroke);
canvas.drawRect(Point.origin & size, border);
canvas.drawRect(paintBounds, border);
}
return true;
}
void paint(sky.Canvas canvas) {
assert(picture != null);
canvas.translate(offset.dx, offset.dy);
canvas.drawPicture(picture);
assert(_debugPaintLayerBorder(canvas));
......@@ -59,17 +85,11 @@ class PictureLayer extends Layer {
class ContainerLayer extends Layer {
ContainerLayer({ Offset offset: Offset.zero }) : super(offset: offset);
void paint(sky.Canvas canvas) {
Layer child = firstChild;
while (child != null) {
child.paint(canvas);
child = child.nextSibling;
}
}
// TODO(ianh): hide firstChild since nobody uses it
Layer _firstChild;
Layer get firstChild => _firstChild;
// TODO(ianh): remove _lastChild since nobody uses it
Layer _lastChild;
Layer get lastChild => _lastChild;
......@@ -89,6 +109,7 @@ class ContainerLayer extends Layer {
return child == equals;
}
// TODO(ianh): Remove 'before' and rename the function to 'append' since nobody uses 'before'
void add(Layer child, { Layer before }) {
assert(child != this);
assert(before != this);
......@@ -126,10 +147,11 @@ class ContainerLayer extends Layer {
}
}
// TODO(ianh): Hide this function since only detach() uses it
void remove(Layer child) {
assert(child._parent == this);
assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild));
assert(_debugUltimateNextSiblingOf(child, equals: _lastChild));
assert(child._parent == this);
if (child._previousSibling == null) {
assert(_firstChild == child);
_firstChild = child._nextSibling;
......@@ -146,6 +168,69 @@ class ContainerLayer extends Layer {
child._nextSibling = 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 {
......@@ -157,21 +242,22 @@ class TransformLayer extends ContainerLayer {
canvas.save();
canvas.translate(offset.dx, offset.dy);
canvas.concat(transform.storage);
super.paint(canvas);
paintChildren(canvas);
canvas.restore();
}
}
class ClipLayer extends ContainerLayer {
ClipLayer({ Offset offset: Offset.zero, this.clipRect }) : super(offset: offset);
class PaintLayer extends ContainerLayer {
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) {
canvas.save();
canvas.saveLayer(bounds, paintSettings);
canvas.translate(offset.dx, offset.dy);
canvas.clipRect(clipRect);
super.paint(canvas);
paintChildren(canvas);
canvas.restore();
}
}
......@@ -192,10 +278,9 @@ class ColorFilterLayer extends ContainerLayer {
Paint paint = new Paint()
..color = color
..setTransferMode(transferMode);
canvas.saveLayer(offset & size, paint);
canvas.translate(offset.dx, offset.dy);
super.paint(canvas);
paintChildren(canvas);
canvas.restore();
}
}
This diff is collapsed.
......@@ -295,18 +295,12 @@ class RenderOpacity extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) {
if (child != null) {
int a = _alpha;
if (a == 0)
return;
if (a == 255) {
if (a == 255)
context.paintChild(child, offset.toPoint());
return;
}
context.canvas.saveLayer(null, _paint); // TODO(abarth): layerize
context.paintChild(child, offset.toPoint());
context.canvas.restore();
else
context.paintChildWithPaint(child, offset.toPoint(), null, _paint);
}
}
}
......@@ -349,11 +343,8 @@ class RenderColorFilter extends RenderProxyBox {
}
void paint(PaintingContext context, Offset offset) {
if (child != null) {
context.canvas.saveLayer(offset & size, _paint); // TODO(abarth): layerize
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
if (child != null)
context.paintChildWithPaint(child, offset.toPoint(), offset & size, _paint);
}
}
......@@ -362,7 +353,7 @@ class RenderClipRect extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) {
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 {
markNeedsPaint();
}
final Paint _paint = new Paint()..isAntiAlias = false;
void paint(PaintingContext context, Offset offset) {
if (child != null) {
Rect rect = offset & size;
context.canvas.saveLayer(rect, _paint); // TODO(abarth): layerize
sky.RRect rrect = new sky.RRect()..setRectXY(rect, xRadius, yRadius);
context.canvas.clipRRect(rrect);
context.paintChild(child, offset.toPoint());
context.canvas.restore();
context.paintChildWithClipRRect(child, offset.toPoint(), rect, rrect);
}
}
}
......@@ -410,8 +396,6 @@ class RenderClipRRect extends RenderProxyBox {
class RenderClipOval extends RenderProxyBox {
RenderClipOval({ RenderBox child }) : super(child);
final Paint _paint = new Paint()..isAntiAlias = false;
Rect _cachedRect;
Path _cachedPath;
......@@ -426,10 +410,7 @@ class RenderClipOval extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) {
if (child != null) {
Rect rect = offset & size;
context.canvas.saveLayer(rect, _paint); // TODO(abarth): layerize
context.canvas.clipPath(_getPath(rect));
context.paintChild(child, offset.toPoint());
context.canvas.restore();
context.paintChildWithClipPath(child, offset.toPoint(), rect, _getPath(rect));
}
}
}
......@@ -561,11 +542,8 @@ class RenderTransform extends RenderProxyBox {
}
void paint(PaintingContext context, Offset offset) {
context.canvas.save();
context.canvas.translate(offset.dx, offset.dy);
context.canvas.concat(_transform.storage);
super.paint(context, Offset.zero);
context.canvas.restore();
if (child != null)
context.paintChildWithTransform(child, offset.toPoint(), _transform);
}
void applyPaintTransform(Matrix4 transform) {
......
......@@ -72,7 +72,7 @@ class SkyBinding {
}
void beginFrame(double timeStamp) {
RenderObject.flushLayout();
_renderView.updateCompositing();
_renderView.updateCompositingBits();
RenderObject.flushPaint();
_renderView.paintFrame();
_renderView.compositeFrame();
......
......@@ -42,8 +42,6 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
markNeedsLayout();
}
ContainerLayer _rootLayer;
// We never call layout() on this class, so this should never get
// checked. (This class is laid out using scheduleInitialLayout().)
bool debugDoesMeetConstraints() { assert(false); return false; }
......@@ -79,6 +77,8 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
return true;
}
bool get hasLayer => true;
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChild(child, offset.toPoint());
......@@ -88,12 +88,9 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
sky.tracing.begin('RenderView.paintFrame');
try {
final double devicePixelRatio = sky.view.devicePixelRatio;
Matrix4 transform = new Matrix4.diagonal3Values(devicePixelRatio, devicePixelRatio, 1.0);
_rootLayer = new TransformLayer(transform: transform);
PaintingContext context = new PaintingContext(Offset.zero, size);
_rootLayer.add(context.layer);
context.paintChild(child, Point.origin);
context.endRecording();
Matrix4 logicalToDeviceZoom = new Matrix4.diagonal3Values(devicePixelRatio, devicePixelRatio, 1.0);
ContainerLayer rootLayer = new TransformLayer(transform: logicalToDeviceZoom);
initialPaint(rootLayer, size);
} finally {
sky.tracing.end('RenderView.paintFrame');
}
......@@ -102,9 +99,12 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
void compositeFrame() {
sky.tracing.begin('RenderView.compositeFrame');
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.Canvas canvas = new sky.Canvas(recorder, Point.origin & (size * sky.view.devicePixelRatio));
_rootLayer.paint(canvas);
layer.paint(canvas);
sky.view.picture = recorder.endRecording();
} finally {
sky.tracing.end('RenderView.compositeFrame');
......
......@@ -122,13 +122,10 @@ class RenderViewport extends RenderBox with RenderObjectWithChildMixin<RenderBox
Offset roundedScrollOffset = _scrollOffsetRoundedToIntegerDevicePixels;
bool _needsClip = offset < Offset.zero ||
!(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)
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