Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(358)

Unified Diff: sky/sdk/lib/rendering/object.dart

Issue 1216833003: Make rendering use PaintingNodes for increased efficiency. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Feedback fixes plus missing critical line that makes it work Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sky/sdk/lib/rendering/object.dart
diff --git a/sky/sdk/lib/rendering/object.dart b/sky/sdk/lib/rendering/object.dart
index b384d029deb69cd6a74e850ff5500b1c7c57906b..724bb840679557a1d4c543dfbe142a2311494a4d 100644
--- a/sky/sdk/lib/rendering/object.dart
+++ b/sky/sdk/lib/rendering/object.dart
@@ -27,10 +27,21 @@ class ParentData {
}
class PaintingCanvas extends sky.Canvas {
- PaintingCanvas(sky.PictureRecorder recorder, Size bounds) : super(recorder, bounds);
+ PaintingCanvas(sky.PictureRecorder recorder, Rect bounds) : super(recorder, bounds);
+ List<RenderObject> _descendentsWithPaintingCanvases; // used by RenderObject._updatePaintingCanvas() to find out which RenderObjects to ask to paint
void paintChild(RenderObject child, Point point) {
- child.paint(this, point.toOffset());
+ if (child.createNewDisplayList) {
+ if (_descendentsWithPaintingCanvases == null)
+ _descendentsWithPaintingCanvases = new List<RenderObject>();
abarth-chromium 2015/07/06 20:50:58 You can simplify this pattern by writing: final L
iansf 2015/07/07 20:36:47 Done.
+ assert(!_descendentsWithPaintingCanvases.contains(child));
+ _descendentsWithPaintingCanvases.add(child);
+ translate(point.x, point.y);
+ drawPaintingNode(child._paintingNode);
+ translate(-point.x, -point.y);
abarth-chromium 2015/07/06 20:50:58 It looks like drawPaintingNode should take a Point
iansf 2015/07/07 20:36:47 Done.
+ } else {
+ child._paintOnCanvas(this, point.toOffset());
+ }
}
}
@@ -138,6 +149,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
assert(_relayoutSubtreeRoot == null);
_relayoutSubtreeRoot = this;
_nodesNeedingLayout.add(this);
+ _nodesNeedingPaint.add(this);
scheduler.ensureVisualUpdate();
}
static void flushLayout() {
@@ -238,11 +250,77 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
// PAINTING
- static bool debugDoingPaint = false;
+ static List<RenderObject> _nodesNeedingPaint = new List<RenderObject>();
+ static bool _debugDoingPaint = false;
+ static bool get debugDoingPaint => _debugDoingPaint;
+
+ sky.PaintingNode _paintingNode = new sky.PaintingNode(); // only set if createNewDisplayList is true
abarth-chromium 2015/07/06 20:50:58 Without |final|, this call to new will happen all
iansf 2015/07/07 21:11:22 I made this final -- it's never reassigned.
+ sky.PaintingNode get paintingNode => _paintingNode;
+ bool _needsPaint = true;
+ bool get needsPaint => _needsPaint;
+ bool get createNewDisplayList => true;
abarth-chromium 2015/07/06 20:50:58 I'm not sure we want the default behavior to be to
iansf 2015/07/07 21:11:23 Done.
+
void markNeedsPaint() {
assert(!debugDoingPaint);
- scheduler.ensureVisualUpdate();
+ if (_needsPaint) return;
+ if (createNewDisplayList) {
+ _needsPaint = true;
+ _nodesNeedingPaint.add(this);
+ scheduler.ensureVisualUpdate();
+ } else if (parent != null) {
+ if (parent is RenderObject) {
+ (parent as RenderObject).markNeedsPaint(); // TODO(ianh): remove the cast once the analyzer is cleverer
+ }
+ }
}
+
+ static void flushPaint() {
+ _debugDoingPaint = true;
+ List<RenderObject> dirtyNodes = _nodesNeedingPaint;
+ _nodesNeedingPaint = new List<RenderObject>();
+ dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) {
+ if (node._needsPaint && node.attached)
+ node._updatePaintingCanvas();
+ });
+ assert(_nodesNeedingPaint.length == 0);
+ _debugDoingPaint = false;
abarth-chromium 2015/07/06 20:50:58 We should wrap the body of this function in a try
iansf 2015/07/07 20:36:47 Done.
+ }
+
+ void _updatePaintingCanvas() {
+ assert(!_needsLayout);
+ assert(createNewDisplayList);
+ sky.PictureRecorder recorder = new sky.PictureRecorder();
+ PaintingCanvas canvas = new PaintingCanvas(recorder, paintBounds);
+ _needsPaint = false;
+ try {
+ _paintOnCanvas(canvas, Offset.zero);
+ } catch (e, stack) {
abarth-chromium 2015/07/06 20:50:58 Capturing the stack here is going to be too expens
Hixie 2015/07/06 21:13:42 If you change this make sure the equivalent code i
iansf 2015/07/07 20:36:47 Done.
iansf 2015/07/07 20:36:47 Done.
+ print('Exception raised during _updatePaintingCanvas:\n${e}\nContext:\n${this}');
+ print(stack);
+ return;
+ }
+ assert(!_needsLayout); // check that the paint() method didn't mark us dirty again
+ assert(!_needsPaint); // check that the paint() method didn't mark us dirty again
+ _paintingNode.setBackingDrawable(recorder.endRecordingAsDrawable());
+
+ if (canvas._descendentsWithPaintingCanvases != null) {
+ canvas._descendentsWithPaintingCanvases.forEach((node) {
abarth-chromium 2015/07/06 20:50:57 We should use a for-each loop rather than calling
iansf 2015/07/07 20:36:47 Done.
+ assert(node.attached == attached);
+ if (node._needsPaint)
+ node._updatePaintingCanvas();
+ });
+ }
+
+ }
+
+ void _paintOnCanvas(PaintingCanvas canvas, Offset offset) {
+ _needsPaint = false;
abarth-chromium 2015/07/06 20:50:58 Why do we set _needsPaint = false both here and on
iansf 2015/07/07 20:36:47 Done.
+ paint(canvas, offset);
+ assert(!_needsPaint);
+ }
+
+ Rect get paintBounds;
+
void paint(PaintingCanvas canvas, Offset offset) { }

Powered by Google App Engine
This is Rietveld 408576698