mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
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
This commit is contained in:
parent
28ed6e686a
commit
5ceb52a0e1
@ -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)
|
||||
return child._paintWithContext(this, offset);
|
||||
_compositChild(child, offset, layer.parent, layer.nextSibling);
|
||||
if (!child.requiresCompositing) {
|
||||
child._paintWithContext(this, offset);
|
||||
} else {
|
||||
_compositeChild(child, offset, layer.parent, layer.nextSibling);
|
||||
}
|
||||
}
|
||||
|
||||
void _compositChild(RenderObject child, Offset offset, ContainerLayer parentLayer, 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 _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)");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user