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

Side by Side Diff: sky/sdk/lib/framework/rendering/render_node.dart

Issue 1161003002: Split layout2.dart into several files (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 6 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 import '../node.dart';
6 import 'dart:sky' as sky;
7
8 class ParentData {
9 void detach() {
10 detachSiblings();
11 }
12 void detachSiblings() { } // workaround for lack of inter-class mixins in Dart
13 void merge(ParentData other) {
14 // override this in subclasses to merge in data from other into this
15 assert(other.runtimeType == this.runtimeType);
16 }
17 }
18
19 const kLayoutDirections = 4;
20
21 double clamp({double min: 0.0, double value: 0.0, double max: double.INFINITY}) {
22 assert(min != null);
23 assert(value != null);
24 assert(max != null);
25
26 if (value > max)
27 value = max;
28 if (value < min)
29 value = min;
30 return value;
31 }
32
33 class RenderNodeDisplayList extends sky.PictureRecorder {
34 RenderNodeDisplayList(double width, double height) : super(width, height);
35 void paintChild(RenderNode child, sky.Point position) {
36 save();
37 translate(position.x, position.y);
38 child.paint(this);
39 restore();
40 }
41 }
42
43 abstract class RenderNode extends AbstractNode {
44
45 // LAYOUT
46
47 // parentData is only for use by the RenderNode that actually lays this
48 // node out, and any other nodes who happen to know exactly what
49 // kind of node that is.
50 ParentData parentData;
51 void setParentData(RenderNode child) {
52 // override this to setup .parentData correctly for your class
53 if (child.parentData is! ParentData)
54 child.parentData = new ParentData();
55 }
56
57 void adoptChild(RenderNode child) { // only for use by subclasses
58 // call this whenever you decide a node is a child
59 assert(child != null);
60 setParentData(child);
61 super.adoptChild(child);
62 }
63 void dropChild(RenderNode child) { // only for use by subclasses
64 assert(child != null);
65 assert(child.parentData != null);
66 child.parentData.detach();
67 super.dropChild(child);
68 }
69
70 static List<RenderNode> _nodesNeedingLayout = new List<RenderNode>();
71 static bool _debugDoingLayout = false;
72 bool _needsLayout = true;
73 bool get needsLayout => _needsLayout;
74 RenderNode _relayoutSubtreeRoot;
75 dynamic _constraints;
76 dynamic get constraints => _constraints;
77 bool debugAncestorsAlreadyMarkedNeedsLayout() {
78 if (_relayoutSubtreeRoot == null)
79 return true; // we haven't yet done layout even once, so there's nothing f or us to do
80 RenderNode node = this;
81 while (node != _relayoutSubtreeRoot) {
82 assert(node._relayoutSubtreeRoot == _relayoutSubtreeRoot);
83 assert(node.parent != null);
84 node = node.parent as RenderNode;
85 if (!node._needsLayout)
86 return false;
87 }
88 assert(node._relayoutSubtreeRoot == node);
89 return true;
90 }
91 void markNeedsLayout() {
92 assert(!_debugDoingLayout);
93 assert(!debugDoingPaint);
94 if (_needsLayout) {
95 assert(debugAncestorsAlreadyMarkedNeedsLayout());
96 return;
97 }
98 _needsLayout = true;
99 assert(_relayoutSubtreeRoot != null);
100 if (_relayoutSubtreeRoot != this) {
101 assert(parent is RenderNode);
102 parent.markNeedsLayout();
103 } else {
104 _nodesNeedingLayout.add(this);
105 }
106 }
107 static void flushLayout() {
108 _debugDoingLayout = true;
109 List<RenderNode> dirtyNodes = _nodesNeedingLayout;
110 _nodesNeedingLayout = new List<RenderNode>();
111 dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) {
112 if (node._needsLayout && node.attached)
113 node._doLayout();
114 });
115 _debugDoingLayout = false;
116 }
117 void _doLayout() {
118 try {
119 assert(_relayoutSubtreeRoot == this);
120 performLayout();
121 } catch (e, stack) {
122 print('Exception raised during layout of ${this}: ${e}');
123 print(stack);
124 return;
125 }
126 _needsLayout = false;
127 }
128 void layout(dynamic constraints, { bool parentUsesSize: false }) {
129 RenderNode relayoutSubtreeRoot;
130 if (!parentUsesSize || sizedByParent || parent is! RenderNode)
131 relayoutSubtreeRoot = this;
132 else
133 relayoutSubtreeRoot = parent._relayoutSubtreeRoot;
134 if (!needsLayout && constraints == _constraints && relayoutSubtreeRoot == _r elayoutSubtreeRoot)
135 return;
136 _constraints = constraints;
137 _relayoutSubtreeRoot = relayoutSubtreeRoot;
138 if (sizedByParent)
139 performResize();
140 performLayout();
141 _needsLayout = false;
142 markNeedsPaint();
143 }
144 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)
145 void performResize(); // set the local dimensions, using only the constraints (only called if sizedByParent is true)
146 void performLayout();
147 // Override this to perform relayout without your parent's
148 // involvement.
149 //
150 // This is called during layout. If sizedByParent is true, then
151 // performLayout() should not change your dimensions, only do that
152 // in performResize(). If sizedByParent is false, then set both
153 // your dimensions and do your children's layout here.
154 //
155 // When calling layout() on your children, pass in
156 // "parentUsesSize: true" if your size or layout is dependent on
157 // your child's size.
158
159 // when the parent has rotated (e.g. when the screen has been turned
160 // 90 degrees), immediately prior to layout() being called for the
161 // new dimensions, rotate() is called with the old and new angles.
162 // The next time paint() is called, the coordinate space will have
163 // been rotated N quarter-turns clockwise, where:
164 // N = newAngle-oldAngle
165 // ...but the rendering is expected to remain the same, pixel for
166 // pixel, on the output device. Then, the layout() method or
167 // equivalent will be invoked.
168
169 void rotate({
170 int oldAngle, // 0..3
171 int newAngle, // 0..3
172 Duration time
173 }) { }
174
175
176 // PAINTING
177
178 static bool debugDoingPaint = false;
179 void markNeedsPaint() {
180 assert(!debugDoingPaint);
181 // TODO(abarth): It's very redundant to call this for every node in the
182 // render tree during layout. We should instead compute a summary bit and
183 // call it once at the end of layout.
184 sky.view.scheduleFrame();
185 }
186 void paint(RenderNodeDisplayList canvas) { }
187
188
189 // HIT TESTING
190
191 void handlePointer(sky.PointerEvent event) {
192 // override this if you have a client, to hand it to the client
193 // override this if you want to do anything with the pointer event
194 }
195
196 // RenderNode subclasses are expected to have a method like the
197 // following (with the signature being whatever passes for coordinates
198 // for this particular class):
199 // bool hitTest(HitTestResult result, { sky.Point position }) {
200 // // If (x,y) is not inside this node, then return false. (You
201 // // can assume that the given coordinate is inside your
202 // // dimensions. You only need to check this if you're an
203 // // irregular shape, e.g. if you have a hole.)
204 // // Otherwise:
205 // // For each child that intersects x,y, in z-order starting from the top,
206 // // call hitTest() for that child, passing it /result/, and the coordinate s
207 // // converted to the child's coordinate origin, and stop at the first chil d
208 // // that returns true.
209 // // Then, add yourself to /result/, and return true.
210 // }
211 // You must not add yourself to /result/ if you return false.
212
213 }
214
215 class HitTestResult {
216 final List<RenderNode> path = new List<RenderNode>();
217
218 RenderNode get result => path.first;
219
220 void add(RenderNode node) {
221 path.add(node);
222 }
223 }
224
225
226 // GENERIC MIXIN FOR RENDER NODES WITH ONE CHILD
227
228 abstract class RenderNodeWithChildMixin<ChildType extends RenderNode> {
229 ChildType _child;
230 ChildType get child => _child;
231 void set child (ChildType value) {
232 if (_child != null)
233 dropChild(_child);
234 _child = value;
235 if (_child != null)
236 adoptChild(_child);
237 markNeedsLayout();
238 }
239 }
240
241
242 // GENERIC MIXIN FOR RENDER NODES WITH A LIST OF CHILDREN
243
244 abstract class ContainerParentDataMixin<ChildType extends RenderNode> {
245 ChildType previousSibling;
246 ChildType nextSibling;
247 void detachSiblings() {
248 if (previousSibling != null) {
249 assert(previousSibling.parentData is ContainerParentDataMixin<ChildType>);
250 assert(previousSibling != this);
251 assert(previousSibling.parentData.nextSibling == this);
252 previousSibling.parentData.nextSibling = nextSibling;
253 }
254 if (nextSibling != null) {
255 assert(nextSibling.parentData is ContainerParentDataMixin<ChildType>);
256 assert(nextSibling != this);
257 assert(nextSibling.parentData.previousSibling == this);
258 nextSibling.parentData.previousSibling = previousSibling;
259 }
260 previousSibling = null;
261 nextSibling = null;
262 }
263 }
264
265 abstract class ContainerRenderNodeMixin<ChildType extends RenderNode, ParentData Type extends ContainerParentDataMixin<ChildType>> implements RenderNode {
266 // abstract class that has only InlineNode children
267
268 bool _debugUltimatePreviousSiblingOf(ChildType child, { ChildType equals }) {
269 assert(child.parentData is ParentDataType);
270 while (child.parentData.previousSibling != null) {
271 assert(child.parentData.previousSibling != child);
272 child = child.parentData.previousSibling;
273 assert(child.parentData is ParentDataType);
274 }
275 return child == equals;
276 }
277 bool _debugUltimateNextSiblingOf(ChildType child, { ChildType equals }) {
278 assert(child.parentData is ParentDataType);
279 while (child.parentData.nextSibling != null) {
280 assert(child.parentData.nextSibling != child);
281 child = child.parentData.nextSibling;
282 assert(child.parentData is ParentDataType);
283 }
284 return child == equals;
285 }
286
287 ChildType _firstChild;
288 ChildType _lastChild;
289 void add(ChildType child, { ChildType before }) {
290 assert(child != this);
291 assert(before != this);
292 assert(child != before);
293 assert(child != _firstChild);
294 assert(child != _lastChild);
295 adoptChild(child);
296 assert(child.parentData is ParentDataType);
297 assert(child.parentData.nextSibling == null);
298 assert(child.parentData.previousSibling == null);
299 if (before == null) {
300 // append at the end (_lastChild)
301 child.parentData.previousSibling = _lastChild;
302 if (_lastChild != null) {
303 assert(_lastChild.parentData is ParentDataType);
304 _lastChild.parentData.nextSibling = child;
305 }
306 _lastChild = child;
307 if (_firstChild == null)
308 _firstChild = child;
309 } else {
310 assert(_firstChild != null);
311 assert(_lastChild != null);
312 assert(_debugUltimatePreviousSiblingOf(before, equals: _firstChild));
313 assert(_debugUltimateNextSiblingOf(before, equals: _lastChild));
314 assert(before.parentData is ParentDataType);
315 if (before.parentData.previousSibling == null) {
316 // insert at the start (_firstChild); we'll end up with two or more chil dren
317 assert(before == _firstChild);
318 child.parentData.nextSibling = before;
319 before.parentData.previousSibling = child;
320 _firstChild = child;
321 } else {
322 // insert in the middle; we'll end up with three or more children
323 // set up links from child to siblings
324 child.parentData.previousSibling = before.parentData.previousSibling;
325 child.parentData.nextSibling = before;
326 // set up links from siblings to child
327 assert(child.parentData.previousSibling.parentData is ParentDataType);
328 assert(child.parentData.nextSibling.parentData is ParentDataType);
329 child.parentData.previousSibling.parentData.nextSibling = child;
330 child.parentData.nextSibling.parentData.previousSibling = child;
331 assert(before.parentData.previousSibling == child);
332 }
333 }
334 markNeedsLayout();
335 }
336 void remove(ChildType child) {
337 assert(child.parentData is ParentDataType);
338 assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild));
339 assert(_debugUltimateNextSiblingOf(child, equals: _lastChild));
340 if (child.parentData.previousSibling == null) {
341 assert(_firstChild == child);
342 _firstChild = child.parentData.nextSibling;
343 } else {
344 assert(child.parentData.previousSibling.parentData is ParentDataType);
345 child.parentData.previousSibling.parentData.nextSibling = child.parentData .nextSibling;
346 }
347 if (child.parentData.nextSibling == null) {
348 assert(_lastChild == child);
349 _lastChild = child.parentData.previousSibling;
350 } else {
351 assert(child.parentData.nextSibling.parentData is ParentDataType);
352 child.parentData.nextSibling.parentData.previousSibling = child.parentData .previousSibling;
353 }
354 child.parentData.previousSibling = null;
355 child.parentData.nextSibling = null;
356 dropChild(child);
357 markNeedsLayout();
358 }
359 void redepthChildren() {
360 ChildType child = _firstChild;
361 while (child != null) {
362 redepthChild(child);
363 assert(child.parentData is ParentDataType);
364 child = child.parentData.nextSibling;
365 }
366 }
367 void attachChildren() {
368 ChildType child = _firstChild;
369 while (child != null) {
370 child.attach();
371 assert(child.parentData is ParentDataType);
372 child = child.parentData.nextSibling;
373 }
374 }
375 void detachChildren() {
376 ChildType child = _firstChild;
377 while (child != null) {
378 child.detach();
379 assert(child.parentData is ParentDataType);
380 child = child.parentData.nextSibling;
381 }
382 }
383
384 ChildType get firstChild => _firstChild;
385 ChildType get lastChild => _lastChild;
386 ChildType childAfter(ChildType child) {
387 assert(child.parentData is ParentDataType);
388 return child.parentData.nextSibling;
389 }
390 }
OLDNEW
« no previous file with comments | « sky/sdk/lib/framework/rendering/render_flex.dart ('k') | sky/sdk/lib/framework/rendering/render_paragraph.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698