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

Side by Side Diff: sky/sdk/lib/rendering/object.dart

Issue 1229793002: Provide an API that allows a RenderObject's performLayout() function to call a callback that mutate… (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: 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 unified diff | Download patch
« no previous file with comments | « sky/sdk/lib/rendering/box.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 import 'dart:math' as math; 5 import 'dart:math' as math;
6 import 'dart:sky' as sky; 6 import 'dart:sky' as sky;
7 import 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path; 7 import 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path;
8 8
9 import '../base/hit_test.dart'; 9 import '../base/hit_test.dart';
10 import '../base/node.dart'; 10 import '../base/node.dart';
(...skipping 28 matching lines...) Expand all
39 child._paintOnCanvas(this, point.toOffset()); 39 child._paintOnCanvas(this, point.toOffset());
40 } 40 }
41 } 41 }
42 } 42 }
43 43
44 abstract class Constraints { 44 abstract class Constraints {
45 const Constraints(); 45 const Constraints();
46 bool get isTight; 46 bool get isTight;
47 } 47 }
48 48
49 typedef void LayoutCallback(Constraints constraints);
50
49 abstract class RenderObject extends AbstractNode implements HitTestTarget { 51 abstract class RenderObject extends AbstractNode implements HitTestTarget {
50 52
51 // LAYOUT 53 // LAYOUT
52 54
53 // parentData is only for use by the RenderObject that actually lays this 55 // parentData is only for use by the RenderObject that actually lays this
54 // node out, and any other nodes who happen to know exactly what 56 // node out, and any other nodes who happen to know exactly what
55 // kind of node that is. 57 // kind of node that is.
56 dynamic parentData; // TODO(ianh): change the type of this back to ParentData once the analyzer is cleverer 58 dynamic parentData; // TODO(ianh): change the type of this back to ParentData once the analyzer is cleverer
57 void setupParentData(RenderObject child) { 59 void setupParentData(RenderObject child) {
58 // override this to setup .parentData correctly for your class 60 // override this to setup .parentData correctly for your class
59 assert(!debugDoingLayout); 61 assert(debugCanPerformMutations);
60 assert(!debugDoingPaint);
61 if (child.parentData is! ParentData) 62 if (child.parentData is! ParentData)
62 child.parentData = new ParentData(); 63 child.parentData = new ParentData();
63 } 64 }
64 65
65 void adoptChild(RenderObject child) { // only for use by subclasses 66 void adoptChild(RenderObject child) { // only for use by subclasses
66 // call this whenever you decide a node is a child 67 // call this whenever you decide a node is a child
67 assert(!debugDoingLayout); 68 assert(debugCanPerformMutations);
68 assert(!debugDoingPaint);
69 assert(child != null); 69 assert(child != null);
70 setupParentData(child); 70 setupParentData(child);
71 super.adoptChild(child); 71 super.adoptChild(child);
72 markNeedsLayout(); 72 markNeedsLayout();
73 } 73 }
74 void dropChild(RenderObject child) { // only for use by subclasses 74 void dropChild(RenderObject child) { // only for use by subclasses
75 assert(!debugDoingLayout); 75 assert(debugCanPerformMutations);
76 assert(!debugDoingPaint);
77 assert(child != null); 76 assert(child != null);
78 assert(child.parentData != null); 77 assert(child.parentData != null);
79 child._cleanRelayoutSubtreeRoot(); 78 child._cleanRelayoutSubtreeRoot();
80 child.parentData.detach(); 79 child.parentData.detach();
81 super.dropChild(child); 80 super.dropChild(child);
82 markNeedsLayout(); 81 markNeedsLayout();
83 } 82 }
84 83
85 static List<RenderObject> _nodesNeedingLayout = new List<RenderObject>();
86 static bool _debugDoingLayout = false; 84 static bool _debugDoingLayout = false;
87 static bool get debugDoingLayout => _debugDoingLayout; 85 static bool get debugDoingLayout => _debugDoingLayout;
88 bool _debugDoingThisResize = false; 86 bool _debugDoingThisResize = false;
89 bool get debugDoingThisResize => _debugDoingThisResize; 87 bool get debugDoingThisResize => _debugDoingThisResize;
90 bool _debugDoingThisLayout = false; 88 bool _debugDoingThisLayout = false;
91 bool get debugDoingThisLayout => _debugDoingThisLayout; 89 bool get debugDoingThisLayout => _debugDoingThisLayout;
92 static RenderObject _debugActiveLayout = null; 90 static RenderObject _debugActiveLayout = null;
93 static RenderObject get debugActiveLayout => _debugActiveLayout; 91 static RenderObject get debugActiveLayout => _debugActiveLayout;
92 bool _debugDoingThisLayoutWithCallback = false;
93 bool _debugMutationsLocked = false;
94 bool _debugCanParentUseSize; 94 bool _debugCanParentUseSize;
95 bool get debugCanParentUseSize => _debugCanParentUseSize; 95 bool get debugCanParentUseSize => _debugCanParentUseSize;
96 bool get debugCanPerformMutations {
97 RenderObject node = this;
98 while (true) {
99 if (node._debugDoingThisLayoutWithCallback)
100 return true;
101 if (node._debugMutationsLocked)
102 return false;
103 if (node.parent is! RenderObject)
104 return true;
105 node = node.parent;
106 }
107 }
108
109 static List<RenderObject> _nodesNeedingLayout = new List<RenderObject>();
96 bool _needsLayout = true; 110 bool _needsLayout = true;
97 bool get needsLayout => _needsLayout; 111 bool get needsLayout => _needsLayout;
98 RenderObject _relayoutSubtreeRoot; 112 RenderObject _relayoutSubtreeRoot;
99 Constraints _constraints; 113 Constraints _constraints;
100 Constraints get constraints => _constraints; 114 Constraints get constraints => _constraints;
101 bool debugDoesMeetConstraints(); // override this in a subclass to verify that your state matches the constraints object 115 bool debugDoesMeetConstraints(); // override this in a subclass to verify that your state matches the constraints object
102 bool debugAncestorsAlreadyMarkedNeedsLayout() { 116 bool debugAncestorsAlreadyMarkedNeedsLayout() {
103 if (_relayoutSubtreeRoot == null) 117 if (_relayoutSubtreeRoot == null)
104 return true; // we haven't yet done layout even once, so there's nothing f or us to do 118 return true; // we haven't yet done layout even once, so there's nothing f or us to do
105 RenderObject node = this; 119 RenderObject node = this;
106 while (node != _relayoutSubtreeRoot) { 120 while (node != _relayoutSubtreeRoot) {
107 assert(node._relayoutSubtreeRoot == _relayoutSubtreeRoot); 121 assert(node._relayoutSubtreeRoot == _relayoutSubtreeRoot);
108 assert(node.parent != null); 122 assert(node.parent != null);
109 node = node.parent as RenderObject; 123 node = node.parent as RenderObject;
110 if (!node._needsLayout) 124 if (!node._needsLayout)
111 return false; 125 return false;
112 } 126 }
113 assert(node._relayoutSubtreeRoot == node); 127 assert(node._relayoutSubtreeRoot == node);
114 return true; 128 return true;
115 } 129 }
116 void markNeedsLayout() { 130 void markNeedsLayout() {
117 assert(!debugDoingLayout); 131 assert(debugCanPerformMutations);
118 assert(!debugDoingPaint);
119 if (_needsLayout) { 132 if (_needsLayout) {
120 assert(debugAncestorsAlreadyMarkedNeedsLayout()); 133 assert(debugAncestorsAlreadyMarkedNeedsLayout());
121 return; 134 return;
122 } 135 }
123 _needsLayout = true; 136 _needsLayout = true;
124 assert(_relayoutSubtreeRoot != null); 137 assert(_relayoutSubtreeRoot != null);
125 if (_relayoutSubtreeRoot != this) { 138 if (_relayoutSubtreeRoot != this) {
126 final parent = this.parent; // TODO(ianh): Remove this once the analyzer i s cleverer 139 final parent = this.parent; // TODO(ianh): Remove this once the analyzer i s cleverer
127 assert(parent is RenderObject); 140 assert(parent is RenderObject);
128 parent.markNeedsLayout(); 141 parent.markNeedsLayout();
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 node.layoutWithoutResize(); 173 node.layoutWithoutResize();
161 }); 174 });
162 } finally { 175 } finally {
163 _debugDoingLayout = false; 176 _debugDoingLayout = false;
164 sky.tracing.end('RenderObject.flushLayout'); 177 sky.tracing.end('RenderObject.flushLayout');
165 } 178 }
166 } 179 }
167 void layoutWithoutResize() { 180 void layoutWithoutResize() {
168 try { 181 try {
169 assert(_relayoutSubtreeRoot == this); 182 assert(_relayoutSubtreeRoot == this);
170 _debugCanParentUseSize = false; 183 RenderObject debugPreviousActiveLayout;
171 _debugDoingThisLayout = true; 184 assert(!_debugMutationsLocked);
172 RenderObject debugPreviousActiveLayout = _debugActiveLayout; 185 assert(!_debugDoingThisLayoutWithCallback);
173 _debugActiveLayout = this; 186 assert(() {
187 _debugMutationsLocked = true;
188 _debugCanParentUseSize = false;
189 _debugDoingThisLayout = true;
190 debugPreviousActiveLayout = _debugActiveLayout;
191 _debugActiveLayout = this;
192 return true;
193 });
174 performLayout(); 194 performLayout();
175 _debugActiveLayout = debugPreviousActiveLayout; 195 assert(() {
176 _debugDoingThisLayout = false; 196 _debugActiveLayout = debugPreviousActiveLayout;
177 _debugCanParentUseSize = null; 197 _debugDoingThisLayout = false;
198 _debugCanParentUseSize = null;
199 _debugMutationsLocked = false;
200 return true;
201 });
178 } catch (e) { 202 } catch (e) {
179 print('Exception raised during layout:\n${e}\nContext:\n${this}'); 203 print('Exception raised during layout:\n${e}\nContext:\n${this}');
180 return; 204 return;
181 } 205 }
182 _needsLayout = false; 206 _needsLayout = false;
183 markNeedsPaint(); 207 markNeedsPaint();
184 } 208 }
185 void layout(Constraints constraints, { bool parentUsesSize: false }) { 209 void layout(Constraints constraints, { bool parentUsesSize: false }) {
186 final parent = this.parent; // TODO(ianh): Remove this once the analyzer is cleverer 210 final parent = this.parent; // TODO(ianh): Remove this once the analyzer is cleverer
187 RenderObject relayoutSubtreeRoot; 211 RenderObject relayoutSubtreeRoot;
188 if (!parentUsesSize || sizedByParent || constraints.isTight || parent is! Re nderObject) 212 if (!parentUsesSize || sizedByParent || constraints.isTight || parent is! Re nderObject)
189 relayoutSubtreeRoot = this; 213 relayoutSubtreeRoot = this;
190 else 214 else
191 relayoutSubtreeRoot = parent._relayoutSubtreeRoot; 215 relayoutSubtreeRoot = parent._relayoutSubtreeRoot;
192 assert(parent == this.parent); // TODO(ianh): Remove this once the analyzer is cleverer 216 assert(parent == this.parent); // TODO(ianh): Remove this once the analyzer is cleverer
193 if (!needsLayout && constraints == _constraints && relayoutSubtreeRoot == _r elayoutSubtreeRoot) 217 if (!needsLayout && constraints == _constraints && relayoutSubtreeRoot == _r elayoutSubtreeRoot)
194 return; 218 return;
195 _constraints = constraints; 219 _constraints = constraints;
196 _relayoutSubtreeRoot = relayoutSubtreeRoot; 220 _relayoutSubtreeRoot = relayoutSubtreeRoot;
197 _debugCanParentUseSize = parentUsesSize; 221 assert(!_debugMutationsLocked);
222 assert(!_debugDoingThisLayoutWithCallback);
223 assert(() {
224 _debugMutationsLocked = true;
225 _debugCanParentUseSize = parentUsesSize;
226 return true;
227 });
198 if (sizedByParent) { 228 if (sizedByParent) {
199 _debugDoingThisResize = true; 229 assert(() { _debugDoingThisResize = true; return true; });
200 performResize(); 230 performResize();
201 _debugDoingThisResize = false; 231 assert(() { _debugDoingThisResize = false; return true; });
202 } 232 }
203 _debugDoingThisLayout = true; 233 RenderObject debugPreviousActiveLayout;
204 RenderObject debugPreviousActiveLayout = _debugActiveLayout; 234 assert(() {
205 _debugActiveLayout = this; 235 _debugDoingThisLayout = true;
236 debugPreviousActiveLayout = _debugActiveLayout;
237 _debugActiveLayout = this;
238 return true;
239 });
206 performLayout(); 240 performLayout();
207 _debugActiveLayout = debugPreviousActiveLayout; 241 assert(() {
208 _debugDoingThisLayout = false; 242 _debugActiveLayout = debugPreviousActiveLayout;
209 _debugCanParentUseSize = null; 243 _debugDoingThisLayout = false;
244 _debugCanParentUseSize = null;
245 _debugMutationsLocked = false;
246 return true;
247 });
210 assert(debugDoesMeetConstraints()); 248 assert(debugDoesMeetConstraints());
211 _needsLayout = false; 249 _needsLayout = false;
212 markNeedsPaint(); 250 markNeedsPaint();
213 assert(parent == this.parent); // TODO(ianh): Remove this once the analyzer is cleverer 251 assert(parent == this.parent); // TODO(ianh): Remove this once the analyzer is cleverer
214 } 252 }
215 bool get sizedByParent => false; // return true if the constraints are the onl y input to the sizing algorithm (in particular, child nodes have no impact) 253 bool get sizedByParent => false; // return true if the constraints are the onl y input to the sizing algorithm (in particular, child nodes have no impact)
216 void performResize(); // set the local dimensions, using only the constraints (only called if sizedByParent is true) 254 void performResize(); // set the local dimensions, using only the constraints (only called if sizedByParent is true)
217 void performLayout(); 255 void performLayout();
218 // Override this to perform relayout without your parent's 256 // Override this to perform relayout without your parent's
219 // involvement. 257 // involvement.
220 // 258 //
221 // This is called during layout. If sizedByParent is true, then 259 // This is called during layout. If sizedByParent is true, then
222 // performLayout() should not change your dimensions, only do that 260 // performLayout() should not change your dimensions, only do that
223 // in performResize(). If sizedByParent is false, then set both 261 // in performResize(). If sizedByParent is false, then set both
224 // your dimensions and do your children's layout here. 262 // your dimensions and do your children's layout here.
225 // 263 //
226 // When calling layout() on your children, pass in 264 // When calling layout() on your children, pass in
227 // "parentUsesSize: true" if your size or layout is dependent on 265 // "parentUsesSize: true" if your size or layout is dependent on
228 // your child's size or intrinsic dimensions. 266 // your child's size or intrinsic dimensions.
267 void invokeLayoutCallback(LayoutCallback callback) {
268 assert(_debugMutationsLocked);
269 assert(_debugDoingThisLayout);
270 assert(!_debugDoingThisLayoutWithCallback);
271 assert(() {
272 _debugDoingThisLayoutWithCallback = true;
273 return true;
274 });
275 callback(constraints);
276 assert(() {
277 _debugDoingThisLayoutWithCallback = false;
278 return true;
279 });
280 }
229 281
230 // when the parent has rotated (e.g. when the screen has been turned 282 // when the parent has rotated (e.g. when the screen has been turned
231 // 90 degrees), immediately prior to layout() being called for the 283 // 90 degrees), immediately prior to layout() being called for the
232 // new dimensions, rotate() is called with the old and new angles. 284 // new dimensions, rotate() is called with the old and new angles.
233 // The next time paint() is called, the coordinate space will have 285 // The next time paint() is called, the coordinate space will have
234 // been rotated N quarter-turns clockwise, where: 286 // been rotated N quarter-turns clockwise, where:
235 // N = newAngle-oldAngle 287 // N = newAngle-oldAngle
236 // ...but the rendering is expected to remain the same, pixel for 288 // ...but the rendering is expected to remain the same, pixel for
237 // pixel, on the output device. Then, the layout() method or 289 // pixel, on the output device. Then, the layout() method or
238 // equivalent will be invoked. 290 // equivalent will be invoked.
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 } 580 }
529 void addAll(List<ChildType> children) { 581 void addAll(List<ChildType> children) {
530 if (children != null) 582 if (children != null)
531 for (ChildType child in children) 583 for (ChildType child in children)
532 add(child); 584 add(child);
533 } 585 }
534 void _removeFromChildList(ChildType child) { 586 void _removeFromChildList(ChildType child) {
535 assert(child.parentData is ParentDataType); 587 assert(child.parentData is ParentDataType);
536 assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild)); 588 assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild));
537 assert(_debugUltimateNextSiblingOf(child, equals: _lastChild)); 589 assert(_debugUltimateNextSiblingOf(child, equals: _lastChild));
538 _childCount -= 1;
539 assert(_childCount >= 0); 590 assert(_childCount >= 0);
540 if (child.parentData.previousSibling == null) { 591 if (child.parentData.previousSibling == null) {
541 assert(_firstChild == child); 592 assert(_firstChild == child);
542 _firstChild = child.parentData.nextSibling; 593 _firstChild = child.parentData.nextSibling;
543 } else { 594 } else {
544 assert(child.parentData.previousSibling.parentData is ParentDataType); 595 assert(child.parentData.previousSibling.parentData is ParentDataType);
545 child.parentData.previousSibling.parentData.nextSibling = child.parentData .nextSibling; 596 child.parentData.previousSibling.parentData.nextSibling = child.parentData .nextSibling;
546 } 597 }
547 if (child.parentData.nextSibling == null) { 598 if (child.parentData.nextSibling == null) {
548 assert(_lastChild == child); 599 assert(_lastChild == child);
549 _lastChild = child.parentData.previousSibling; 600 _lastChild = child.parentData.previousSibling;
550 } else { 601 } else {
551 assert(child.parentData.nextSibling.parentData is ParentDataType); 602 assert(child.parentData.nextSibling.parentData is ParentDataType);
552 child.parentData.nextSibling.parentData.previousSibling = child.parentData .previousSibling; 603 child.parentData.nextSibling.parentData.previousSibling = child.parentData .previousSibling;
553 } 604 }
554 child.parentData.previousSibling = null; 605 child.parentData.previousSibling = null;
555 child.parentData.nextSibling = null; 606 child.parentData.nextSibling = null;
607 _childCount -= 1;
556 } 608 }
557 void remove(ChildType child) { 609 void remove(ChildType child) {
558 _removeFromChildList(child); 610 _removeFromChildList(child);
559 dropChild(child); 611 dropChild(child);
560 } 612 }
613 void removeAll() {
614 ChildType child = _firstChild;
615 while (child != null) {
616 assert(child.parentData is ParentDataType);
617 ChildType next = child.parentData.nextSibling;
618 child.parentData.previousSibling = null;
619 child.parentData.nextSibling = null;
620 dropChild(child);
621 child = next;
622 }
623 _firstChild = null;
624 _lastChild = null;
625 _childCount = 0;
626 }
561 void move(ChildType child, { ChildType before }) { 627 void move(ChildType child, { ChildType before }) {
562 assert(child != this); 628 assert(child != this);
563 assert(before != this); 629 assert(before != this);
564 assert(child != before); 630 assert(child != before);
565 assert(child.parent == this); 631 assert(child.parent == this);
566 assert(child.parentData is ParentDataType); 632 assert(child.parentData is ParentDataType);
567 if (child.parentData.nextSibling == before) 633 if (child.parentData.nextSibling == before)
568 return; 634 return;
569 _removeFromChildList(child); 635 _removeFromChildList(child);
570 _addToChildList(child, before: before); 636 _addToChildList(child, before: before);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
614 int count = 1; 680 int count = 1;
615 ChildType child = _firstChild; 681 ChildType child = _firstChild;
616 while (child != null) { 682 while (child != null) {
617 result += '${prefix}child ${count}: ${child.toString(prefix)}'; 683 result += '${prefix}child ${count}: ${child.toString(prefix)}';
618 count += 1; 684 count += 1;
619 child = child.parentData.nextSibling; 685 child = child.parentData.nextSibling;
620 } 686 }
621 return result; 687 return result;
622 } 688 }
623 } 689 }
OLDNEW
« no previous file with comments | « sky/sdk/lib/rendering/box.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698