Commit e4ac5189 authored by Hixie's avatar Hixie

Port clipping to the new layer world.

- Add Canvas.getSaveCount()
- Make RenderClipRect call context.paintChildWithClip instead of doing the clipping itself
- Make ClipLayer take a Rect instead of a Size
- Make PaintingContext.canvas read-only
- Add PaintingContext.paintChildWithClip()
- Minor rearrangings of code and style tweaks
parent db3d632a
...@@ -825,7 +825,7 @@ class RenderOpacity extends RenderProxyBox { ...@@ -825,7 +825,7 @@ class RenderOpacity extends RenderProxyBox {
return; return;
} }
context.canvas.saveLayer(null, _paint); context.canvas.saveLayer(null, _paint); // TODO(abarth): layerize
context.paintChild(child, offset.toPoint()); context.paintChild(child, offset.toPoint());
context.canvas.restore(); context.canvas.restore();
} }
...@@ -871,7 +871,7 @@ class RenderColorFilter extends RenderProxyBox { ...@@ -871,7 +871,7 @@ 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); context.canvas.saveLayer(offset & size, _paint); // TODO(abarth): layerize
context.paintChild(child, offset.toPoint()); context.paintChild(child, offset.toPoint());
context.canvas.restore(); context.canvas.restore();
} }
...@@ -882,12 +882,8 @@ class RenderClipRect extends RenderProxyBox { ...@@ -882,12 +882,8 @@ class RenderClipRect extends RenderProxyBox {
RenderClipRect({ RenderBox child }) : super(child); RenderClipRect({ RenderBox child }) : super(child);
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
if (child != null) { if (child != null)
context.canvas.save(); context.paintChildWithClip(child, offset.toPoint(), Offset.zero & size);
context.canvas.clipRect(offset & size);
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
} }
} }
...@@ -923,7 +919,7 @@ class RenderClipRRect extends RenderProxyBox { ...@@ -923,7 +919,7 @@ 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 = offset & size;
context.canvas.saveLayer(rect, _paint); 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.canvas.clipRRect(rrect);
context.paintChild(child, offset.toPoint()); context.paintChild(child, offset.toPoint());
...@@ -951,7 +947,7 @@ class RenderClipOval extends RenderProxyBox { ...@@ -951,7 +947,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); context.canvas.saveLayer(rect, _paint); // TODO(abarth): layerize
context.canvas.clipPath(_getPath(rect)); context.canvas.clipPath(_getPath(rect));
context.paintChild(child, offset.toPoint()); context.paintChild(child, offset.toPoint());
context.canvas.restore(); context.canvas.restore();
......
...@@ -163,14 +163,14 @@ class TransformLayer extends ContainerLayer { ...@@ -163,14 +163,14 @@ class TransformLayer extends ContainerLayer {
} }
class ClipLayer extends ContainerLayer { class ClipLayer extends ContainerLayer {
ClipLayer({ Offset offset: Offset.zero, this.size }) : super(offset: offset); ClipLayer({ Offset offset: Offset.zero, this.clipRect }) : super(offset: offset);
Size size; Rect clipRect;
void paint(sky.Canvas canvas) { void paint(sky.Canvas canvas) {
canvas.save(); canvas.save();
canvas.translate(offset.dx, offset.dy); canvas.translate(offset.dx, offset.dy);
canvas.clipRect(Point.origin & size); canvas.clipRect(clipRect);
super.paint(canvas); super.paint(canvas);
canvas.restore(); canvas.restore();
} }
......
...@@ -30,50 +30,92 @@ class ParentData { ...@@ -30,50 +30,92 @@ class ParentData {
class PaintingCanvas extends sky.Canvas { class PaintingCanvas extends sky.Canvas {
PaintingCanvas(sky.PictureRecorder recorder, Rect bounds) : super(recorder, bounds); PaintingCanvas(sky.PictureRecorder recorder, Rect bounds) : super(recorder, bounds);
// TODO(ianh): Just use sky.Canvas everywhere instead
} }
class PaintingContext { class PaintingContext {
PaintingCanvas canvas;
PictureLayer get layer => _layer; // A PaintingContext wraps a canvas, so that the canvas can be
PictureLayer _layer; // hot-swapped whenever we need to start a new layer.
sky.PictureRecorder _recorder; // Don't keep a reference to the PaintingContext.canvas, since it
// can change dynamically after any call to this object's methods.
PaintingContext(Offset offest, Size size) { PaintingContext(Offset offest, Size size) {
_startRecording(offest, size); _startRecording(offest, size);
} }
PaintingContext.forTesting(this.canvas); PaintingCanvas _canvas;
PaintingCanvas get canvas => _canvas;
PictureLayer _layer;
PictureLayer get layer => _layer;
sky.PictureRecorder _recorder;
PaintingContext.forTesting(this._canvas);
void _startRecording(Offset offset, Size size) { void _startRecording(Offset offset, Size size) {
assert(_layer == null); assert(_layer == null);
assert(_recorder == null); assert(_recorder == null);
assert(canvas == null); assert(_canvas == null);
_layer = new PictureLayer(offset: offset, size: size); _layer = new PictureLayer(offset: offset, size: size);
_recorder = new sky.PictureRecorder(); _recorder = new sky.PictureRecorder();
canvas = new PaintingCanvas(_recorder, Point.origin & size); _canvas = new PaintingCanvas(_recorder, Point.origin & size);
} }
void endRecording() { void endRecording() {
assert(_layer != null); assert(_layer != null);
assert(_recorder != null); assert(_recorder != null);
assert(canvas != null); assert(_canvas != null);
canvas = null;
_layer.picture = _recorder.endRecording(); _layer.picture = _recorder.endRecording();
_recorder = null;
_layer = null; _layer = null;
_recorder = null;
_canvas = null;
}
bool debugCanPaintChild() {
// 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);
return true;
} }
void paintChild(RenderObject child, Point point) { void paintChild(RenderObject child, Point point) {
assert(debugCanPaintChild());
final Offset offset = point.toOffset(); final Offset offset = point.toOffset();
if (!child.requiresCompositing) {
child._paintWithContext(this, offset);
} else {
_compositeChild(child, offset, layer.parent, layer.nextSibling);
}
}
if (!child.requiresCompositing) void paintChildWithClip(RenderObject child, Point point, Rect clipRect) {
return child._paintWithContext(this, offset); assert(debugCanPaintChild());
_compositChild(child, offset, layer.parent, layer.nextSibling); final Offset offset = point.toOffset();
if (!child.hasCompositedDescendant) {
// If none of the descendants require compositing, then we don't
// need to use a new layer here, because at no point will any of
// the children introduce a new layer of their own.
canvas.save();
canvas.clipRect(clipRect.shift(offset));
child._paintWithContext(this, offset);
canvas.restore();
} else {
// At least one of the descendants requires compositing. We
// therefore introduce a new layer to do the clipping, so that
// when the children are split into a new layer, the clip is not
// lost, as it would if we didn't introduce a new layer.
ClipLayer clip = new ClipLayer(offset: offset, clipRect: clipRect);
layer.parent.add(clip, before: layer.nextSibling);
_compositeChild(child, Offset.zero, clip, null);
}
} }
void _compositChild(RenderObject child, Offset offset, ContainerLayer parentLayer, Layer nextSibling) { void _compositeChild(RenderObject child, Offset offset, ContainerLayer parentLayer, Layer nextSibling) {
final PictureLayer originalLayer = _layer; final PictureLayer originalLayer = _layer;
endRecording(); endRecording();
...@@ -88,6 +130,7 @@ class PaintingContext { ...@@ -88,6 +130,7 @@ class PaintingContext {
originalLayer.parent.add(layer, before: context.layer.nextSibling); originalLayer.parent.add(layer, before: context.layer.nextSibling);
context.endRecording(); context.endRecording();
} }
} }
abstract class Constraints { abstract class Constraints {
...@@ -417,16 +460,14 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget { ...@@ -417,16 +460,14 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
_needsPaint = true; _needsPaint = true;
_nodesNeedingPaint.add(this); _nodesNeedingPaint.add(this);
scheduler.ensureVisualUpdate(); scheduler.ensureVisualUpdate();
} else if (parent == null) { } else if (parent is! RenderObject) {
// we're the root of the render tree (probably a RenderView)
_needsPaint = true; _needsPaint = true;
scheduler.ensureVisualUpdate(); scheduler.ensureVisualUpdate();
} else { } else {
assert(parent != null); // parent always exists on this path because the root node is a RenderView, which sets createNewDisplayList.
if (parent is RenderObject) {
(parent as RenderObject).markNeedsPaint(); // TODO(ianh): remove the cast once the analyzer is cleverer (parent as RenderObject).markNeedsPaint(); // TODO(ianh): remove the cast once the analyzer is cleverer
} }
} }
}
static void flushPaint() { static void flushPaint() {
sky.tracing.begin('RenderObject.flushPaint'); sky.tracing.begin('RenderObject.flushPaint');
......
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