| 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 |