提交 5ceb52a0 编写于 作者: H 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
上级 28ed6e68
......@@ -47,6 +47,13 @@ void Canvas::restore()
m_canvas->restore();
}
int Canvas::getSaveCount()
{
if (!m_canvas)
return 0;
return m_canvas->getSaveCount();
}
void Canvas::translate(float dx, float dy)
{
if (!m_canvas)
......
......@@ -63,6 +63,7 @@ public:
void save();
void saveLayer(const Rect& bounds, const Paint& paint);
void restore();
int getSaveCount();
void translate(float dx, float dy);
void scale(float sx, float sy);
......
......@@ -11,6 +11,7 @@
// TODO(jackson): Paint should be optional, but making it optional causes crash
void saveLayer(Rect bounds, /* optional */ Paint paint);
void restore();
int getSaveCount(); // returns 1 for a clean canvas; each call to save() or saveLayer() increments it, and each call to restore() decrements it.
void translate(float dx, float dy);
void scale(float sx, float sy);
......
......@@ -805,7 +805,7 @@ class RenderOpacity extends RenderProxyBox {
Paint _cachedPaint;
Paint get _paint {
if (_cachedPaint == null) {
_cachedPaint = new Paint()
_cachedPaint = new Paint()
..color = new Color.fromARGB(_alpha, 0, 0, 0)
..setTransferMode(sky.TransferMode.srcOver)
..isAntiAlias = false;
......@@ -825,7 +825,7 @@ class RenderOpacity extends RenderProxyBox {
return;
}
context.canvas.saveLayer(null, _paint);
context.canvas.saveLayer(null, _paint); // TODO(abarth): layerize
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
......@@ -871,7 +871,7 @@ class RenderColorFilter extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) {
if (child != null) {
context.canvas.saveLayer(offset & size, _paint);
context.canvas.saveLayer(offset & size, _paint); // TODO(abarth): layerize
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
......@@ -882,12 +882,8 @@ class RenderClipRect extends RenderProxyBox {
RenderClipRect({ RenderBox child }) : super(child);
void paint(PaintingContext context, Offset offset) {
if (child != null) {
context.canvas.save();
context.canvas.clipRect(offset & size);
context.paintChild(child, offset.toPoint());
context.canvas.restore();
}
if (child != null)
context.paintChildWithClip(child, offset.toPoint(), Offset.zero & size);
}
}
......@@ -923,7 +919,7 @@ class RenderClipRRect extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) {
if (child != null) {
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);
context.canvas.clipRRect(rrect);
context.paintChild(child, offset.toPoint());
......@@ -951,7 +947,7 @@ class RenderClipOval extends RenderProxyBox {
void paint(PaintingContext context, Offset offset) {
if (child != null) {
Rect rect = offset & size;
context.canvas.saveLayer(rect, _paint);
context.canvas.saveLayer(rect, _paint); // TODO(abarth): layerize
context.canvas.clipPath(_getPath(rect));
context.paintChild(child, offset.toPoint());
context.canvas.restore();
......
......@@ -163,14 +163,14 @@ class TransformLayer 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) {
canvas.save();
canvas.translate(offset.dx, offset.dy);
canvas.clipRect(Point.origin & size);
canvas.clipRect(clipRect);
super.paint(canvas);
canvas.restore();
}
......
......@@ -30,50 +30,92 @@ class ParentData {
class PaintingCanvas extends sky.Canvas {
PaintingCanvas(sky.PictureRecorder recorder, Rect bounds) : super(recorder, bounds);
// TODO(ianh): Just use sky.Canvas everywhere instead
}
class PaintingContext {
PaintingCanvas canvas;
PictureLayer get layer => _layer;
PictureLayer _layer;
// A PaintingContext wraps a canvas, so that the canvas can be
// 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) {
_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) {
assert(_layer == null);
assert(_recorder == null);
assert(canvas == null);
assert(_canvas == null);
_layer = new PictureLayer(offset: offset, size: size);
_recorder = new sky.PictureRecorder();
canvas = new PaintingCanvas(_recorder, Point.origin & size);
_canvas = new PaintingCanvas(_recorder, Point.origin & size);
}
void endRecording() {
assert(_layer != null);
assert(_recorder != null);
assert(canvas != null);
canvas = null;
assert(_canvas != null);
_layer.picture = _recorder.endRecording();
_recorder = 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) {
assert(debugCanPaintChild());
final Offset offset = point.toOffset();
if (!child.requiresCompositing) {
child._paintWithContext(this, offset);
} else {
_compositeChild(child, offset, layer.parent, layer.nextSibling);
}
}
if (!child.requiresCompositing)
return child._paintWithContext(this, offset);
_compositChild(child, offset, layer.parent, layer.nextSibling);
void paintChildWithClip(RenderObject child, Point point, Rect clipRect) {
assert(debugCanPaintChild());
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;
endRecording();
......@@ -88,6 +130,7 @@ class PaintingContext {
originalLayer.parent.add(layer, before: context.layer.nextSibling);
context.endRecording();
}
}
abstract class Constraints {
......@@ -417,14 +460,12 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
_needsPaint = true;
_nodesNeedingPaint.add(this);
scheduler.ensureVisualUpdate();
} else if (parent == null) {
} else if (parent is! RenderObject) {
// we're the root of the render tree (probably a RenderView)
_needsPaint = true;
scheduler.ensureVisualUpdate();
} 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
}
}
......
......@@ -26,18 +26,25 @@ class TestPaintingCanvas extends PaintingCanvas {
logger("${indent} ${s}");
}
int _saveCount = 1;
void save() {
log("save");
_saveCount += 1;
}
void saveLayer(Rect bounds, Paint paint) {
log("saveLayer($bounds, $paint)");
_saveCount += 1;
}
void restore() {
log("restore");
_saveCount -= 1;
}
int getSaveCount() => _saveCount;
void translate(double dx, double dy) {
log("translate($dx, $dy)");
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册