OLD | NEW |
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 '../node.dart'; | 5 import '../node.dart'; |
6 import '../scheduler.dart' as scheduler; | 6 import '../scheduler.dart' as scheduler; |
7 import 'dart:math' as math; | 7 import 'dart:math' as math; |
8 import 'dart:sky' as sky; | 8 import 'dart:sky' as sky; |
9 | 9 |
10 class ParentData { | 10 class ParentData { |
11 void detach() { | 11 void detach() { |
12 detachSiblings(); | 12 detachSiblings(); |
13 } | 13 } |
14 void detachSiblings() { } // workaround for lack of inter-class mixins in Dart | 14 void detachSiblings() { } // workaround for lack of inter-class mixins in Dart |
15 void merge(ParentData other) { | 15 void merge(ParentData other) { |
16 // override this in subclasses to merge in data from other into this | 16 // override this in subclasses to merge in data from other into this |
17 assert(other.runtimeType == this.runtimeType); | 17 assert(other.runtimeType == this.runtimeType); |
18 } | 18 } |
19 } | 19 } |
20 | 20 |
21 const kLayoutDirections = 4; | 21 const kLayoutDirections = 4; |
22 | 22 |
23 double clamp({double min: 0.0, double value: 0.0, double max: double.INFINITY})
{ | 23 double clamp({double min: 0.0, double value: 0.0, double max: double.INFINITY})
{ |
24 assert(min != null); | 24 assert(min != null); |
25 assert(value != null); | 25 assert(value != null); |
26 assert(max != null); | 26 assert(max != null); |
27 return math.max(min, math.min(max, value)); | 27 return math.max(min, math.min(max, value)); |
28 } | 28 } |
29 | 29 |
30 class RenderNodeDisplayList extends sky.PictureRecorder { | 30 class RenderObjectDisplayList extends sky.PictureRecorder { |
31 RenderNodeDisplayList(double width, double height) : super(width, height); | 31 RenderObjectDisplayList(double width, double height) : super(width, height); |
32 void paintChild(RenderNode child, sky.Point position) { | 32 void paintChild(RenderObject child, sky.Point position) { |
33 translate(position.x, position.y); | 33 translate(position.x, position.y); |
34 child.paint(this); | 34 child.paint(this); |
35 translate(-position.x, -position.y); | 35 translate(-position.x, -position.y); |
36 } | 36 } |
37 } | 37 } |
38 | 38 |
39 abstract class RenderNode extends AbstractNode { | 39 abstract class RenderObject extends AbstractNode { |
40 | 40 |
41 // LAYOUT | 41 // LAYOUT |
42 | 42 |
43 // parentData is only for use by the RenderNode that actually lays this | 43 // parentData is only for use by the RenderObject that actually lays this |
44 // node out, and any other nodes who happen to know exactly what | 44 // node out, and any other nodes who happen to know exactly what |
45 // kind of node that is. | 45 // kind of node that is. |
46 ParentData parentData; | 46 ParentData parentData; |
47 void setParentData(RenderNode child) { | 47 void setParentData(RenderObject child) { |
48 // override this to setup .parentData correctly for your class | 48 // override this to setup .parentData correctly for your class |
49 if (child.parentData is! ParentData) | 49 if (child.parentData is! ParentData) |
50 child.parentData = new ParentData(); | 50 child.parentData = new ParentData(); |
51 } | 51 } |
52 | 52 |
53 void adoptChild(RenderNode child) { // only for use by subclasses | 53 void adoptChild(RenderObject child) { // only for use by subclasses |
54 // call this whenever you decide a node is a child | 54 // call this whenever you decide a node is a child |
55 assert(child != null); | 55 assert(child != null); |
56 setParentData(child); | 56 setParentData(child); |
57 super.adoptChild(child); | 57 super.adoptChild(child); |
58 } | 58 } |
59 void dropChild(RenderNode child) { // only for use by subclasses | 59 void dropChild(RenderObject child) { // only for use by subclasses |
60 assert(child != null); | 60 assert(child != null); |
61 assert(child.parentData != null); | 61 assert(child.parentData != null); |
62 child.parentData.detach(); | 62 child.parentData.detach(); |
63 super.dropChild(child); | 63 super.dropChild(child); |
64 } | 64 } |
65 | 65 |
66 static List<RenderNode> _nodesNeedingLayout = new List<RenderNode>(); | 66 static List<RenderObject> _nodesNeedingLayout = new List<RenderObject>(); |
67 static bool _debugDoingLayout = false; | 67 static bool _debugDoingLayout = false; |
68 bool _needsLayout = true; | 68 bool _needsLayout = true; |
69 bool get needsLayout => _needsLayout; | 69 bool get needsLayout => _needsLayout; |
70 RenderNode _relayoutSubtreeRoot; | 70 RenderObject _relayoutSubtreeRoot; |
71 dynamic _constraints; | 71 dynamic _constraints; |
72 dynamic get constraints => _constraints; | 72 dynamic get constraints => _constraints; |
73 bool debugAncestorsAlreadyMarkedNeedsLayout() { | 73 bool debugAncestorsAlreadyMarkedNeedsLayout() { |
74 if (_relayoutSubtreeRoot == null) | 74 if (_relayoutSubtreeRoot == null) |
75 return true; // we haven't yet done layout even once, so there's nothing f
or us to do | 75 return true; // we haven't yet done layout even once, so there's nothing f
or us to do |
76 RenderNode node = this; | 76 RenderObject node = this; |
77 while (node != _relayoutSubtreeRoot) { | 77 while (node != _relayoutSubtreeRoot) { |
78 assert(node._relayoutSubtreeRoot == _relayoutSubtreeRoot); | 78 assert(node._relayoutSubtreeRoot == _relayoutSubtreeRoot); |
79 assert(node.parent != null); | 79 assert(node.parent != null); |
80 node = node.parent as RenderNode; | 80 node = node.parent as RenderObject; |
81 if (!node._needsLayout) | 81 if (!node._needsLayout) |
82 return false; | 82 return false; |
83 } | 83 } |
84 assert(node._relayoutSubtreeRoot == node); | 84 assert(node._relayoutSubtreeRoot == node); |
85 return true; | 85 return true; |
86 } | 86 } |
87 void markNeedsLayout() { | 87 void markNeedsLayout() { |
88 assert(!_debugDoingLayout); | 88 assert(!_debugDoingLayout); |
89 assert(!debugDoingPaint); | 89 assert(!debugDoingPaint); |
90 if (_needsLayout) { | 90 if (_needsLayout) { |
91 assert(debugAncestorsAlreadyMarkedNeedsLayout()); | 91 assert(debugAncestorsAlreadyMarkedNeedsLayout()); |
92 return; | 92 return; |
93 } | 93 } |
94 _needsLayout = true; | 94 _needsLayout = true; |
95 assert(_relayoutSubtreeRoot != null); | 95 assert(_relayoutSubtreeRoot != null); |
96 if (_relayoutSubtreeRoot != this) { | 96 if (_relayoutSubtreeRoot != this) { |
97 assert(parent is RenderNode); | 97 assert(parent is RenderObject); |
98 parent.markNeedsLayout(); | 98 parent.markNeedsLayout(); |
99 } else { | 99 } else { |
100 _nodesNeedingLayout.add(this); | 100 _nodesNeedingLayout.add(this); |
101 scheduler.ensureVisualUpdate(); | 101 scheduler.ensureVisualUpdate(); |
102 } | 102 } |
103 } | 103 } |
104 static void flushLayout() { | 104 static void flushLayout() { |
105 _debugDoingLayout = true; | 105 _debugDoingLayout = true; |
106 List<RenderNode> dirtyNodes = _nodesNeedingLayout; | 106 List<RenderObject> dirtyNodes = _nodesNeedingLayout; |
107 _nodesNeedingLayout = new List<RenderNode>(); | 107 _nodesNeedingLayout = new List<RenderObject>(); |
108 dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) { | 108 dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) { |
109 if (node._needsLayout && node.attached) | 109 if (node._needsLayout && node.attached) |
110 node._doLayout(); | 110 node._doLayout(); |
111 }); | 111 }); |
112 _debugDoingLayout = false; | 112 _debugDoingLayout = false; |
113 } | 113 } |
114 void _doLayout() { | 114 void _doLayout() { |
115 try { | 115 try { |
116 assert(_relayoutSubtreeRoot == this); | 116 assert(_relayoutSubtreeRoot == this); |
117 performLayout(); | 117 performLayout(); |
118 } catch (e, stack) { | 118 } catch (e, stack) { |
119 print('Exception raised during layout of ${this}: ${e}'); | 119 print('Exception raised during layout of ${this}: ${e}'); |
120 print(stack); | 120 print(stack); |
121 return; | 121 return; |
122 } | 122 } |
123 _needsLayout = false; | 123 _needsLayout = false; |
124 } | 124 } |
125 void layout(dynamic constraints, { bool parentUsesSize: false }) { | 125 void layout(dynamic constraints, { bool parentUsesSize: false }) { |
126 RenderNode relayoutSubtreeRoot; | 126 RenderObject relayoutSubtreeRoot; |
127 if (!parentUsesSize || sizedByParent || parent is! RenderNode) | 127 if (!parentUsesSize || sizedByParent || parent is! RenderObject) |
128 relayoutSubtreeRoot = this; | 128 relayoutSubtreeRoot = this; |
129 else | 129 else |
130 relayoutSubtreeRoot = parent._relayoutSubtreeRoot; | 130 relayoutSubtreeRoot = parent._relayoutSubtreeRoot; |
131 if (!needsLayout && constraints == _constraints && relayoutSubtreeRoot == _r
elayoutSubtreeRoot) | 131 if (!needsLayout && constraints == _constraints && relayoutSubtreeRoot == _r
elayoutSubtreeRoot) |
132 return; | 132 return; |
133 _constraints = constraints; | 133 _constraints = constraints; |
134 _relayoutSubtreeRoot = relayoutSubtreeRoot; | 134 _relayoutSubtreeRoot = relayoutSubtreeRoot; |
135 if (sizedByParent) | 135 if (sizedByParent) |
136 performResize(); | 136 performResize(); |
137 performLayout(); | 137 performLayout(); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 }) { } | 170 }) { } |
171 | 171 |
172 | 172 |
173 // PAINTING | 173 // PAINTING |
174 | 174 |
175 static bool debugDoingPaint = false; | 175 static bool debugDoingPaint = false; |
176 void markNeedsPaint() { | 176 void markNeedsPaint() { |
177 assert(!debugDoingPaint); | 177 assert(!debugDoingPaint); |
178 scheduler.ensureVisualUpdate(); | 178 scheduler.ensureVisualUpdate(); |
179 } | 179 } |
180 void paint(RenderNodeDisplayList canvas) { } | 180 void paint(RenderObjectDisplayList canvas) { } |
181 | 181 |
182 | 182 |
183 // EVENTS | 183 // EVENTS |
184 | 184 |
185 void handleEvent(sky.Event event) { | 185 void handleEvent(sky.Event event) { |
186 // override this if you have a client, to hand it to the client | 186 // override this if you have a client, to hand it to the client |
187 // override this if you want to do anything with the event | 187 // override this if you want to do anything with the event |
188 } | 188 } |
189 | 189 |
190 | 190 |
191 // HIT TESTING | 191 // HIT TESTING |
192 | 192 |
193 // RenderNode subclasses are expected to have a method like the | 193 // RenderObject subclasses are expected to have a method like the |
194 // following (with the signature being whatever passes for coordinates | 194 // following (with the signature being whatever passes for coordinates |
195 // for this particular class): | 195 // for this particular class): |
196 // bool hitTest(HitTestResult result, { sky.Point position }) { | 196 // bool hitTest(HitTestResult result, { sky.Point position }) { |
197 // // If (x,y) is not inside this node, then return false. (You | 197 // // If (x,y) is not inside this node, then return false. (You |
198 // // can assume that the given coordinate is inside your | 198 // // can assume that the given coordinate is inside your |
199 // // dimensions. You only need to check this if you're an | 199 // // dimensions. You only need to check this if you're an |
200 // // irregular shape, e.g. if you have a hole.) | 200 // // irregular shape, e.g. if you have a hole.) |
201 // // Otherwise: | 201 // // Otherwise: |
202 // // For each child that intersects x,y, in z-order starting from the top, | 202 // // For each child that intersects x,y, in z-order starting from the top, |
203 // // call hitTest() for that child, passing it /result/, and the coordinate
s | 203 // // call hitTest() for that child, passing it /result/, and the coordinate
s |
204 // // converted to the child's coordinate origin, and stop at the first chil
d | 204 // // converted to the child's coordinate origin, and stop at the first chil
d |
205 // // that returns true. | 205 // // that returns true. |
206 // // Then, add yourself to /result/, and return true. | 206 // // Then, add yourself to /result/, and return true. |
207 // } | 207 // } |
208 // You must not add yourself to /result/ if you return false. | 208 // You must not add yourself to /result/ if you return false. |
209 | 209 |
210 } | 210 } |
211 | 211 |
212 class HitTestResult { | 212 class HitTestResult { |
213 final List<RenderNode> path = new List<RenderNode>(); | 213 final List<RenderObject> path = new List<RenderObject>(); |
214 | 214 |
215 RenderNode get result => path.first; | 215 RenderObject get result => path.first; |
216 | 216 |
217 void add(RenderNode node) { | 217 void add(RenderObject node) { |
218 path.add(node); | 218 path.add(node); |
219 } | 219 } |
220 } | 220 } |
221 | 221 |
222 | 222 |
223 // GENERIC MIXIN FOR RENDER NODES WITH ONE CHILD | 223 // GENERIC MIXIN FOR RENDER NODES WITH ONE CHILD |
224 | 224 |
225 abstract class RenderNodeWithChildMixin<ChildType extends RenderNode> { | 225 abstract class RenderObjectWithChildMixin<ChildType extends RenderObject> { |
226 ChildType _child; | 226 ChildType _child; |
227 ChildType get child => _child; | 227 ChildType get child => _child; |
228 void set child (ChildType value) { | 228 void set child (ChildType value) { |
229 if (_child != null) | 229 if (_child != null) |
230 dropChild(_child); | 230 dropChild(_child); |
231 _child = value; | 231 _child = value; |
232 if (_child != null) | 232 if (_child != null) |
233 adoptChild(_child); | 233 adoptChild(_child); |
234 markNeedsLayout(); | 234 markNeedsLayout(); |
235 } | 235 } |
236 void attachChildren() { | 236 void attachChildren() { |
237 if (_child != null) | 237 if (_child != null) |
238 _child.attach(); | 238 _child.attach(); |
239 } | 239 } |
240 void detachChildren() { | 240 void detachChildren() { |
241 if (_child != null) | 241 if (_child != null) |
242 _child.detach(); | 242 _child.detach(); |
243 } | 243 } |
244 } | 244 } |
245 | 245 |
246 | 246 |
247 // GENERIC MIXIN FOR RENDER NODES WITH A LIST OF CHILDREN | 247 // GENERIC MIXIN FOR RENDER NODES WITH A LIST OF CHILDREN |
248 | 248 |
249 abstract class ContainerParentDataMixin<ChildType extends RenderNode> { | 249 abstract class ContainerParentDataMixin<ChildType extends RenderObject> { |
250 ChildType previousSibling; | 250 ChildType previousSibling; |
251 ChildType nextSibling; | 251 ChildType nextSibling; |
252 void detachSiblings() { | 252 void detachSiblings() { |
253 if (previousSibling != null) { | 253 if (previousSibling != null) { |
254 assert(previousSibling.parentData is ContainerParentDataMixin<ChildType>); | 254 assert(previousSibling.parentData is ContainerParentDataMixin<ChildType>); |
255 assert(previousSibling != this); | 255 assert(previousSibling != this); |
256 assert(previousSibling.parentData.nextSibling == this); | 256 assert(previousSibling.parentData.nextSibling == this); |
257 previousSibling.parentData.nextSibling = nextSibling; | 257 previousSibling.parentData.nextSibling = nextSibling; |
258 } | 258 } |
259 if (nextSibling != null) { | 259 if (nextSibling != null) { |
260 assert(nextSibling.parentData is ContainerParentDataMixin<ChildType>); | 260 assert(nextSibling.parentData is ContainerParentDataMixin<ChildType>); |
261 assert(nextSibling != this); | 261 assert(nextSibling != this); |
262 assert(nextSibling.parentData.previousSibling == this); | 262 assert(nextSibling.parentData.previousSibling == this); |
263 nextSibling.parentData.previousSibling = previousSibling; | 263 nextSibling.parentData.previousSibling = previousSibling; |
264 } | 264 } |
265 previousSibling = null; | 265 previousSibling = null; |
266 nextSibling = null; | 266 nextSibling = null; |
267 } | 267 } |
268 } | 268 } |
269 | 269 |
270 abstract class ContainerRenderNodeMixin<ChildType extends RenderNode, ParentData
Type extends ContainerParentDataMixin<ChildType>> implements RenderNode { | 270 abstract class ContainerRenderObjectMixin<ChildType extends RenderObject, Parent
DataType extends ContainerParentDataMixin<ChildType>> implements RenderObject { |
271 // abstract class that has only InlineNode children | 271 // abstract class that has only InlineNode children |
272 | 272 |
273 bool _debugUltimatePreviousSiblingOf(ChildType child, { ChildType equals }) { | 273 bool _debugUltimatePreviousSiblingOf(ChildType child, { ChildType equals }) { |
274 assert(child.parentData is ParentDataType); | 274 assert(child.parentData is ParentDataType); |
275 while (child.parentData.previousSibling != null) { | 275 while (child.parentData.previousSibling != null) { |
276 assert(child.parentData.previousSibling != child); | 276 assert(child.parentData.previousSibling != child); |
277 child = child.parentData.previousSibling; | 277 child = child.parentData.previousSibling; |
278 assert(child.parentData is ParentDataType); | 278 assert(child.parentData is ParentDataType); |
279 } | 279 } |
280 return child == equals; | 280 return child == equals; |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 } | 386 } |
387 } | 387 } |
388 | 388 |
389 ChildType get firstChild => _firstChild; | 389 ChildType get firstChild => _firstChild; |
390 ChildType get lastChild => _lastChild; | 390 ChildType get lastChild => _lastChild; |
391 ChildType childAfter(ChildType child) { | 391 ChildType childAfter(ChildType child) { |
392 assert(child.parentData is ParentDataType); | 392 assert(child.parentData is ParentDataType); |
393 return child.parentData.nextSibling; | 393 return child.parentData.nextSibling; |
394 } | 394 } |
395 } | 395 } |
OLD | NEW |