| 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 library fn; | 5 library fn; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 import 'dart:mirrors'; | 9 import 'dart:mirrors'; |
| 10 import 'dart:sky' as sky; | 10 import 'dart:sky' as sky; |
| 11 import 'reflect.dart' as reflect; | 11 import 'reflect.dart' as reflect; |
| 12 import 'layout2.dart'; | 12 import 'layout2.dart'; |
| 13 | 13 |
| 14 final sky.Tracing _tracing = sky.window.tracing; | 14 final sky.Tracing _tracing = sky.window.tracing; |
| 15 | 15 |
| 16 final bool _shouldLogRenderDuration = false; | 16 final bool _shouldLogRenderDuration = false; |
| 17 final bool _shouldTrace = false; | 17 final bool _shouldTrace = false; |
| 18 | 18 |
| 19 enum _SyncOperation { IDENTICAL, INSERTION, STATEFUL, STATELESS, REMOVAL } | 19 enum _SyncOperation { IDENTICAL, INSERTION, STATEFUL, STATELESS, REMOVAL } |
| 20 | 20 |
| 21 /* | 21 /* |
| 22 * All Effen nodes derive from UINode. All nodes have a _parent, a _key and | 22 * All Effen nodes derive from UINode. All nodes have a _parent, a _key and |
| 23 * can be sync'd. | 23 * can be sync'd. |
| 24 */ | 24 */ |
| 25 abstract class UINode { | 25 abstract class UINode { |
| 26 String _key; | 26 String _key; |
| 27 UINode _parent; | 27 UINode _parent; |
| 28 UINode get parent => _parent; | 28 UINode get parent => _parent; |
| 29 RenderCSS _root; | 29 RenderCSS root; |
| 30 bool _defunct = false; | 30 bool _defunct = false; |
| 31 | 31 |
| 32 UINode({ Object key }) { | 32 UINode({ Object key }) { |
| 33 _key = key == null ? "$runtimeType" : "$runtimeType-$key"; | 33 _key = key == null ? "$runtimeType" : "$runtimeType-$key"; |
| 34 assert(this is App || _inRenderDirtyComponents); // you should not build the
UI tree ahead of time, build it only during build() | 34 assert(this is App || _inRenderDirtyComponents); // you should not build the
UI tree ahead of time, build it only during build() |
| 35 } | 35 } |
| 36 | 36 |
| 37 // Subclasses which implements Nodes that become stateful may return true | 37 // Subclasses which implements Nodes that become stateful may return true |
| 38 // if the |old| node has become stateful and should be retained. | 38 // if the |old| node has become stateful and should be retained. |
| 39 bool _willSync(UINode old) => false; | 39 bool _willSync(UINode old) => false; |
| 40 | 40 |
| 41 bool get interchangeable => false; // if true, then keys can be duplicated | 41 bool get interchangeable => false; // if true, then keys can be duplicated |
| 42 | 42 |
| 43 void _sync(UINode old, dynamic slot); | 43 void _sync(UINode old, dynamic slot); |
| 44 // 'slot' is the identifier that the parent RenderNodeWrapper uses to know | 44 // 'slot' is the identifier that the parent RenderNodeWrapper uses to know |
| 45 // where to put this descendant | 45 // where to put this descendant |
| 46 | 46 |
| 47 void _remove() { | 47 void _remove() { |
| 48 _defunct = true; | 48 _defunct = true; |
| 49 _root = null; | 49 root = null; |
| 50 handleRemoved(); | 50 handleRemoved(); |
| 51 } | 51 } |
| 52 void handleRemoved() { } | 52 void handleRemoved() { } |
| 53 | 53 |
| 54 UINode findAncestor(Type targetType) { | 54 UINode findAncestor(Type targetType) { |
| 55 var ancestor = _parent; | 55 var ancestor = _parent; |
| 56 while (ancestor != null && !reflectClass(ancestor.runtimeType).isSubtypeOf(r
eflectClass(targetType))) | 56 while (ancestor != null && !reflectClass(ancestor.runtimeType).isSubtypeOf(r
eflectClass(targetType))) |
| 57 ancestor = ancestor._parent; | 57 ancestor = ancestor._parent; |
| 58 return ancestor; | 58 return ancestor; |
| 59 } | 59 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 80 | 80 |
| 81 void _traceSync(_SyncOperation op, String key) { | 81 void _traceSync(_SyncOperation op, String key) { |
| 82 if (!_shouldTrace) | 82 if (!_shouldTrace) |
| 83 return; | 83 return; |
| 84 | 84 |
| 85 String opString = op.toString().toLowerCase(); | 85 String opString = op.toString().toLowerCase(); |
| 86 String outString = opString.substring(opString.indexOf('.') + 1); | 86 String outString = opString.substring(opString.indexOf('.') + 1); |
| 87 _trace('_sync($outString) $key'); | 87 _trace('_sync($outString) $key'); |
| 88 } | 88 } |
| 89 | 89 |
| 90 void _removeChild(UINode node) { | 90 void removeChild(UINode node) { |
| 91 _traceSync(_SyncOperation.REMOVAL, node._key); | 91 _traceSync(_SyncOperation.REMOVAL, node._key); |
| 92 node._remove(); | 92 node._remove(); |
| 93 } | 93 } |
| 94 | 94 |
| 95 // Returns the child which should be retained as the child of this node. | 95 // Returns the child which should be retained as the child of this node. |
| 96 UINode _syncChild(UINode node, UINode oldNode, dynamic slot) { | 96 UINode _syncChild(UINode node, UINode oldNode, dynamic slot) { |
| 97 assert(node != null); | 97 assert(node != null); |
| 98 assert(oldNode == null || node._key == oldNode._key); | 98 assert(oldNode == null || node._key == oldNode._key); |
| 99 | 99 |
| 100 if (node == oldNode) { | 100 if (node == oldNode) { |
| 101 _traceSync(_SyncOperation.IDENTICAL, node._key); | 101 _traceSync(_SyncOperation.IDENTICAL, node._key); |
| 102 return node; // Nothing to do. Subtrees must be identical. | 102 return node; // Nothing to do. Subtrees must be identical. |
| 103 } | 103 } |
| 104 | 104 |
| 105 // TODO(rafaelw): This eagerly removes the old DOM. It may be that a | 105 // TODO(rafaelw): This eagerly removes the old DOM. It may be that a |
| 106 // new component was built that could re-use some of it. Consider | 106 // new component was built that could re-use some of it. Consider |
| 107 // syncing the new VDOM against the old one. | 107 // syncing the new VDOM against the old one. |
| 108 if (oldNode != null && node._key != oldNode._key) { | 108 if (oldNode != null && node._key != oldNode._key) { |
| 109 _removeChild(oldNode); | 109 removeChild(oldNode); |
| 110 } | 110 } |
| 111 | 111 |
| 112 if (node._willSync(oldNode)) { | 112 if (node._willSync(oldNode)) { |
| 113 _traceSync(_SyncOperation.STATEFUL, node._key); | 113 _traceSync(_SyncOperation.STATEFUL, node._key); |
| 114 oldNode._sync(node, slot); | 114 oldNode._sync(node, slot); |
| 115 node._defunct = true; | 115 node._defunct = true; |
| 116 assert(oldNode._root is RenderCSS); | 116 assert(oldNode.root is RenderCSS); |
| 117 return oldNode; | 117 return oldNode; |
| 118 } | 118 } |
| 119 | 119 |
| 120 assert(!node._defunct); | 120 assert(!node._defunct); |
| 121 node._parent = this; | 121 node._parent = this; |
| 122 | 122 |
| 123 if (oldNode == null) { | 123 if (oldNode == null) { |
| 124 _traceSync(_SyncOperation.INSERTION, node._key); | 124 _traceSync(_SyncOperation.INSERTION, node._key); |
| 125 } else { | 125 } else { |
| 126 _traceSync(_SyncOperation.STATELESS, node._key); | 126 _traceSync(_SyncOperation.STATELESS, node._key); |
| 127 } | 127 } |
| 128 node._sync(oldNode, slot); | 128 node._sync(oldNode, slot); |
| 129 if (oldNode != null) | 129 if (oldNode != null) |
| 130 oldNode._defunct = true; | 130 oldNode._defunct = true; |
| 131 | 131 |
| 132 assert(node._root is RenderCSS); | 132 assert(node.root is RenderCSS); |
| 133 return node; | 133 return node; |
| 134 } | 134 } |
| 135 } | 135 } |
| 136 | 136 |
| 137 abstract class ContentNode extends UINode { | 137 abstract class ContentNode extends UINode { |
| 138 UINode content; | 138 UINode content; |
| 139 | 139 |
| 140 ContentNode(UINode content) : this.content = content, super(key: content._key)
; | 140 ContentNode(UINode content) : this.content = content, super(key: content._key)
; |
| 141 | 141 |
| 142 void _sync(UINode old, dynamic slot) { | 142 void _sync(UINode old, dynamic slot) { |
| 143 UINode oldContent = old == null ? null : (old as ContentNode).content; | 143 UINode oldContent = old == null ? null : (old as ContentNode).content; |
| 144 content = _syncChild(content, oldContent, slot); | 144 content = _syncChild(content, oldContent, slot); |
| 145 assert(content._root != null); | 145 assert(content.root != null); |
| 146 _root = content._root; | 146 root = content.root; |
| 147 } | 147 } |
| 148 | 148 |
| 149 void _remove() { | 149 void _remove() { |
| 150 if (content != null) | 150 if (content != null) |
| 151 _removeChild(content); | 151 removeChild(content); |
| 152 super._remove(); | 152 super._remove(); |
| 153 } | 153 } |
| 154 } | 154 } |
| 155 | 155 |
| 156 class StyleNode extends ContentNode { | 156 class StyleNode extends ContentNode { |
| 157 final Style style; | 157 final Style style; |
| 158 | 158 |
| 159 StyleNode(UINode content, this.style): super(content); | 159 StyleNode(UINode content, this.style): super(content); |
| 160 } | 160 } |
| 161 | 161 |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 | 297 |
| 298 RenderNodeWrapper({ | 298 RenderNodeWrapper({ |
| 299 Object key, | 299 Object key, |
| 300 this.style, | 300 this.style, |
| 301 this.inlineStyle | 301 this.inlineStyle |
| 302 }) : super(key: key); | 302 }) : super(key: key); |
| 303 | 303 |
| 304 final Style style; | 304 final Style style; |
| 305 final String inlineStyle; | 305 final String inlineStyle; |
| 306 | 306 |
| 307 RenderCSS _createNode(); | 307 RenderCSS createNode(); |
| 308 RenderNodeWrapper get _emptyNode; | 308 RenderNodeWrapper get emptyNode; |
| 309 | 309 |
| 310 void insert(RenderNodeWrapper child, dynamic slot); | 310 void insert(RenderNodeWrapper child, dynamic slot); |
| 311 | 311 |
| 312 void _sync(UINode old, dynamic slot) { | 312 void _sync(UINode old, dynamic slot) { |
| 313 if (old == null) { | 313 if (old == null) { |
| 314 _root = _createNode(); | 314 root = createNode(); |
| 315 assert(_root != null); | 315 assert(root != null); |
| 316 var ancestor = findAncestor(RenderNodeWrapper); | 316 var ancestor = findAncestor(RenderNodeWrapper); |
| 317 if (ancestor is RenderNodeWrapper) | 317 if (ancestor is RenderNodeWrapper) |
| 318 ancestor.insert(this, slot); | 318 ancestor.insert(this, slot); |
| 319 old = _emptyNode; | 319 old = emptyNode; |
| 320 } else { | 320 } else { |
| 321 _root = old._root; | 321 root = old.root; |
| 322 assert(_root != null); | 322 assert(root != null); |
| 323 } | 323 } |
| 324 | 324 |
| 325 _nodeMap[_root] = this; | 325 _nodeMap[root] = this; |
| 326 _syncRenderNode(old); | 326 syncRenderNode(old); |
| 327 } | 327 } |
| 328 | 328 |
| 329 void _syncRenderNode(RenderNodeWrapper old) { | 329 void syncRenderNode(RenderNodeWrapper old) { |
| 330 RenderNodeWrapper oldRenderNodeWrapper = old as RenderNodeWrapper; | 330 RenderNodeWrapper oldRenderNodeWrapper = old as RenderNodeWrapper; |
| 331 | 331 |
| 332 List<Style> styles = new List<Style>(); | 332 List<Style> styles = new List<Style>(); |
| 333 if (style != null) | 333 if (style != null) |
| 334 styles.add(style); | 334 styles.add(style); |
| 335 ParentData parentData = null; | 335 ParentData parentData = null; |
| 336 UINode parent = _parent; | 336 UINode parent = _parent; |
| 337 while (parent != null && parent is! RenderNodeWrapper) { | 337 while (parent != null && parent is! RenderNodeWrapper) { |
| 338 if (parent is StyleNode && parent.style != null) | 338 if (parent is StyleNode && parent.style != null) |
| 339 styles.add(parent.style); | 339 styles.add(parent.style); |
| 340 else | 340 else |
| 341 if (parent is ParentDataNode && parent.parentData != null) { | 341 if (parent is ParentDataNode && parent.parentData != null) { |
| 342 if (parentData != null) | 342 if (parentData != null) |
| 343 parentData.merge(parent.parentData); // this will throw if the types a
ren't the same | 343 parentData.merge(parent.parentData); // this will throw if the types a
ren't the same |
| 344 else | 344 else |
| 345 parentData = parent.parentData; | 345 parentData = parent.parentData; |
| 346 } | 346 } |
| 347 parent = parent._parent; | 347 parent = parent._parent; |
| 348 } | 348 } |
| 349 _root.updateStyles(styles); | 349 root.updateStyles(styles); |
| 350 if (parentData != null) { | 350 if (parentData != null) { |
| 351 assert(_root.parentData != null); | 351 assert(root.parentData != null); |
| 352 _root.parentData.merge(parentData); // this will throw if the types aren't
approriate | 352 root.parentData.merge(parentData); // this will throw if the types aren't
approriate |
| 353 assert(parent != null); | 353 assert(parent != null); |
| 354 assert(parent._root != null); | 354 assert(parent.root != null); |
| 355 parent._root.markNeedsLayout(); | 355 parent.root.markNeedsLayout(); |
| 356 } | 356 } |
| 357 _root.updateInlineStyle(inlineStyle); | 357 root.updateInlineStyle(inlineStyle); |
| 358 } | 358 } |
| 359 | 359 |
| 360 void _removeChild(UINode node) { | 360 void removeChild(UINode node) { |
| 361 assert(_root is RenderCSSContainer); | 361 assert(root is RenderCSSContainer); |
| 362 _root.remove(node._root); | 362 root.remove(node.root); |
| 363 super._removeChild(node); | 363 super.removeChild(node); |
| 364 } | 364 } |
| 365 | 365 |
| 366 void _remove() { | 366 void _remove() { |
| 367 assert(_root != null); | 367 assert(root != null); |
| 368 _nodeMap.remove(_root); | 368 _nodeMap.remove(root); |
| 369 super._remove(); | 369 super._remove(); |
| 370 } | 370 } |
| 371 } | 371 } |
| 372 | 372 |
| 373 final List<UINode> _emptyList = new List<UINode>(); | 373 final List<UINode> _emptyList = new List<UINode>(); |
| 374 | 374 |
| 375 abstract class OneChildListRenderNodeWrapper extends RenderNodeWrapper { | 375 abstract class OneChildListRenderNodeWrapper extends RenderNodeWrapper { |
| 376 | 376 |
| 377 // In OneChildListRenderNodeWrapper subclasses, slots are RenderCSS nodes | 377 // In OneChildListRenderNodeWrapper subclasses, slots are RenderCSS nodes |
| 378 // to use as the "insert before" sibling in RenderCSSContainer.add() calls | 378 // to use as the "insert before" sibling in RenderCSSContainer.add() calls |
| 379 | 379 |
| 380 final List<UINode> children; | 380 final List<UINode> children; |
| 381 | 381 |
| 382 OneChildListRenderNodeWrapper({ | 382 OneChildListRenderNodeWrapper({ |
| 383 Object key, | 383 Object key, |
| 384 List<UINode> children, | 384 List<UINode> children, |
| 385 Style style, | 385 Style style, |
| 386 String inlineStyle | 386 String inlineStyle |
| 387 }) : this.children = children == null ? _emptyList : children, | 387 }) : this.children = children == null ? _emptyList : children, |
| 388 super( | 388 super( |
| 389 key: key, | 389 key: key, |
| 390 style: style, | 390 style: style, |
| 391 inlineStyle: inlineStyle | 391 inlineStyle: inlineStyle |
| 392 ) { | 392 ) { |
| 393 assert(!_debugHasDuplicateIds()); | 393 assert(!_debugHasDuplicateIds()); |
| 394 } | 394 } |
| 395 | 395 |
| 396 void insert(RenderNodeWrapper child, dynamic slot) { | 396 void insert(RenderNodeWrapper child, dynamic slot) { |
| 397 assert(slot == null || slot is RenderCSS); | 397 assert(slot == null || slot is RenderCSS); |
| 398 _root.add(child._root, before: slot); | 398 root.add(child.root, before: slot); |
| 399 } | 399 } |
| 400 | 400 |
| 401 void _remove() { | 401 void _remove() { |
| 402 assert(children != null); | 402 assert(children != null); |
| 403 for (var child in children) { | 403 for (var child in children) { |
| 404 assert(child != null); | 404 assert(child != null); |
| 405 _removeChild(child); | 405 removeChild(child); |
| 406 } | 406 } |
| 407 super._remove(); | 407 super._remove(); |
| 408 } | 408 } |
| 409 | 409 |
| 410 bool _debugHasDuplicateIds() { | 410 bool _debugHasDuplicateIds() { |
| 411 var idSet = new HashSet<String>(); | 411 var idSet = new HashSet<String>(); |
| 412 for (var child in children) { | 412 for (var child in children) { |
| 413 assert(child != null); | 413 assert(child != null); |
| 414 if (child.interchangeable) | 414 if (child.interchangeable) |
| 415 continue; // when these nodes are reordered, we just reassign the data | 415 continue; // when these nodes are reordered, we just reassign the data |
| 416 | 416 |
| 417 if (!idSet.add(child._key)) { | 417 if (!idSet.add(child._key)) { |
| 418 throw '''If multiple non-interchangeable nodes of the same type exist as
children | 418 throw '''If multiple non-interchangeable nodes of the same type exist as
children |
| 419 of another node, they must have unique keys. | 419 of another node, they must have unique keys. |
| 420 Duplicate: "${child._key}"'''; | 420 Duplicate: "${child._key}"'''; |
| 421 } | 421 } |
| 422 } | 422 } |
| 423 return false; | 423 return false; |
| 424 } | 424 } |
| 425 | 425 |
| 426 void _syncRenderNode(OneChildListRenderNodeWrapper old) { | 426 void syncRenderNode(OneChildListRenderNodeWrapper old) { |
| 427 super._syncRenderNode(old); | 427 super.syncRenderNode(old); |
| 428 | 428 |
| 429 if (_root is! RenderCSSContainer) | 429 if (root is! RenderCSSContainer) |
| 430 return; | 430 return; |
| 431 | 431 |
| 432 var startIndex = 0; | 432 var startIndex = 0; |
| 433 var endIndex = children.length; | 433 var endIndex = children.length; |
| 434 | 434 |
| 435 var oldChildren = old.children; | 435 var oldChildren = old.children; |
| 436 var oldStartIndex = 0; | 436 var oldStartIndex = 0; |
| 437 var oldEndIndex = oldChildren.length; | 437 var oldEndIndex = oldChildren.length; |
| 438 | 438 |
| 439 RenderCSS nextSibling = null; | 439 RenderCSS nextSibling = null; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 bool searchForOldNode() { | 491 bool searchForOldNode() { |
| 492 if (currentNode.interchangeable) | 492 if (currentNode.interchangeable) |
| 493 return false; // never re-order these nodes | 493 return false; // never re-order these nodes |
| 494 | 494 |
| 495 ensureOldIdMap(); | 495 ensureOldIdMap(); |
| 496 oldNode = oldNodeIdMap[currentNode._key]; | 496 oldNode = oldNodeIdMap[currentNode._key]; |
| 497 if (oldNode == null) | 497 if (oldNode == null) |
| 498 return false; | 498 return false; |
| 499 | 499 |
| 500 oldNodeIdMap[currentNode._key] = null; // mark it reordered | 500 oldNodeIdMap[currentNode._key] = null; // mark it reordered |
| 501 assert(_root is RenderCSSContainer); | 501 assert(root is RenderCSSContainer); |
| 502 assert(oldNode._root is RenderCSSContainer); | 502 assert(oldNode.root is RenderCSSContainer); |
| 503 | 503 |
| 504 old._root.remove(oldNode._root); | 504 old.root.remove(oldNode.root); |
| 505 _root.add(oldNode._root, before: nextSibling); | 505 root.add(oldNode.root, before: nextSibling); |
| 506 | 506 |
| 507 return true; | 507 return true; |
| 508 } | 508 } |
| 509 | 509 |
| 510 // Scan forwards, this time we may re-order; | 510 // Scan forwards, this time we may re-order; |
| 511 nextSibling = _root.firstChild; | 511 nextSibling = root.firstChild; |
| 512 while (startIndex < endIndex && oldStartIndex < oldEndIndex) { | 512 while (startIndex < endIndex && oldStartIndex < oldEndIndex) { |
| 513 currentNode = children[startIndex]; | 513 currentNode = children[startIndex]; |
| 514 oldNode = oldChildren[oldStartIndex]; | 514 oldNode = oldChildren[oldStartIndex]; |
| 515 | 515 |
| 516 if (currentNode._key == oldNode._key) { | 516 if (currentNode._key == oldNode._key) { |
| 517 assert(currentNode.runtimeType == oldNode.runtimeType); | 517 assert(currentNode.runtimeType == oldNode.runtimeType); |
| 518 nextSibling = _root.childAfter(nextSibling); | 518 nextSibling = root.childAfter(nextSibling); |
| 519 sync(startIndex); | 519 sync(startIndex); |
| 520 startIndex++; | 520 startIndex++; |
| 521 advanceOldStartIndex(); | 521 advanceOldStartIndex(); |
| 522 continue; | 522 continue; |
| 523 } | 523 } |
| 524 | 524 |
| 525 oldNode = null; | 525 oldNode = null; |
| 526 searchForOldNode(); | 526 searchForOldNode(); |
| 527 sync(startIndex); | 527 sync(startIndex); |
| 528 startIndex++; | 528 startIndex++; |
| 529 } | 529 } |
| 530 | 530 |
| 531 // New insertions | 531 // New insertions |
| 532 oldNode = null; | 532 oldNode = null; |
| 533 while (startIndex < endIndex) { | 533 while (startIndex < endIndex) { |
| 534 currentNode = children[startIndex]; | 534 currentNode = children[startIndex]; |
| 535 sync(startIndex); | 535 sync(startIndex); |
| 536 startIndex++; | 536 startIndex++; |
| 537 } | 537 } |
| 538 | 538 |
| 539 // Removals | 539 // Removals |
| 540 currentNode = null; | 540 currentNode = null; |
| 541 while (oldStartIndex < oldEndIndex) { | 541 while (oldStartIndex < oldEndIndex) { |
| 542 oldNode = oldChildren[oldStartIndex]; | 542 oldNode = oldChildren[oldStartIndex]; |
| 543 _removeChild(oldNode); | 543 removeChild(oldNode); |
| 544 advanceOldStartIndex(); | 544 advanceOldStartIndex(); |
| 545 } | 545 } |
| 546 } | 546 } |
| 547 } | 547 } |
| 548 | 548 |
| 549 class Container extends OneChildListRenderNodeWrapper { | 549 class Container extends OneChildListRenderNodeWrapper { |
| 550 | 550 |
| 551 RenderCSSContainer _root; | 551 RenderCSSContainer root; |
| 552 RenderCSSContainer _createNode() => new RenderCSSContainer(this); | 552 RenderCSSContainer createNode() => new RenderCSSContainer(this); |
| 553 | 553 |
| 554 static final Container _emptyContainer = new Container(); | 554 static final Container _emptyContainer = new Container(); |
| 555 | 555 |
| 556 RenderNodeWrapper get _emptyNode => _emptyContainer; | 556 RenderNodeWrapper get emptyNode => _emptyContainer; |
| 557 | 557 |
| 558 Container({ | 558 Container({ |
| 559 Object key, | 559 Object key, |
| 560 List<UINode> children, | 560 List<UINode> children, |
| 561 Style style, | 561 Style style, |
| 562 String inlineStyle | 562 String inlineStyle |
| 563 }) : super( | 563 }) : super( |
| 564 key: key, | 564 key: key, |
| 565 children: children, | 565 children: children, |
| 566 style: style, | 566 style: style, |
| 567 inlineStyle: inlineStyle | 567 inlineStyle: inlineStyle |
| 568 ); | 568 ); |
| 569 } | 569 } |
| 570 | 570 |
| 571 class Paragraph extends OneChildListRenderNodeWrapper { | 571 class Paragraph extends OneChildListRenderNodeWrapper { |
| 572 | 572 |
| 573 RenderCSSParagraph _root; | 573 RenderCSSParagraph root; |
| 574 RenderCSSParagraph _createNode() => new RenderCSSParagraph(this); | 574 RenderCSSParagraph createNode() => new RenderCSSParagraph(this); |
| 575 | 575 |
| 576 static final Paragraph _emptyContainer = new Paragraph(); | 576 static final Paragraph _emptyContainer = new Paragraph(); |
| 577 | 577 |
| 578 RenderNodeWrapper get _emptyNode => _emptyContainer; | 578 RenderNodeWrapper get emptyNode => _emptyContainer; |
| 579 | 579 |
| 580 Paragraph({ | 580 Paragraph({ |
| 581 Object key, | 581 Object key, |
| 582 List<UINode> children, | 582 List<UINode> children, |
| 583 Style style, | 583 Style style, |
| 584 String inlineStyle | 584 String inlineStyle |
| 585 }) : super( | 585 }) : super( |
| 586 key: key, | 586 key: key, |
| 587 children: children, | 587 children: children, |
| 588 style: style, | 588 style: style, |
| 589 inlineStyle: inlineStyle | 589 inlineStyle: inlineStyle |
| 590 ); | 590 ); |
| 591 } | 591 } |
| 592 | 592 |
| 593 class FlexContainer extends OneChildListRenderNodeWrapper { | 593 class FlexContainer extends OneChildListRenderNodeWrapper { |
| 594 | 594 |
| 595 RenderCSSFlex _root; | 595 RenderCSSFlex root; |
| 596 RenderCSSFlex _createNode() => new RenderCSSFlex(this, this.direction); | 596 RenderCSSFlex createNode() => new RenderCSSFlex(this, this.direction); |
| 597 | 597 |
| 598 static final FlexContainer _emptyContainer = new FlexContainer(); | 598 static final FlexContainer _emptyContainer = new FlexContainer(); |
| 599 // direction doesn't matter if it's empty | 599 // direction doesn't matter if it's empty |
| 600 | 600 |
| 601 RenderNodeWrapper get _emptyNode => _emptyContainer; | 601 RenderNodeWrapper get emptyNode => _emptyContainer; |
| 602 | 602 |
| 603 final FlexDirection direction; | 603 final FlexDirection direction; |
| 604 | 604 |
| 605 FlexContainer({ | 605 FlexContainer({ |
| 606 Object key, | 606 Object key, |
| 607 List<UINode> children, | 607 List<UINode> children, |
| 608 Style style, | 608 Style style, |
| 609 String inlineStyle, | 609 String inlineStyle, |
| 610 this.direction: FlexDirection.Row | 610 this.direction: FlexDirection.Row |
| 611 }) : super( | 611 }) : super( |
| 612 key: key, | 612 key: key, |
| 613 children: children, | 613 children: children, |
| 614 style: style, | 614 style: style, |
| 615 inlineStyle: inlineStyle | 615 inlineStyle: inlineStyle |
| 616 ); | 616 ); |
| 617 | 617 |
| 618 void _syncRenderNode(UINode old) { | 618 void syncRenderNode(UINode old) { |
| 619 super._syncRenderNode(old); | 619 super.syncRenderNode(old); |
| 620 _root.direction = direction; | 620 root.direction = direction; |
| 621 } | 621 } |
| 622 } | 622 } |
| 623 | 623 |
| 624 class FillStackContainer extends OneChildListRenderNodeWrapper { | 624 class FillStackContainer extends OneChildListRenderNodeWrapper { |
| 625 | 625 |
| 626 RenderCSSStack _root; | 626 RenderCSSStack root; |
| 627 RenderCSSStack _createNode() => new RenderCSSStack(this); | 627 RenderCSSStack createNode() => new RenderCSSStack(this); |
| 628 | 628 |
| 629 static final FillStackContainer _emptyContainer = new FillStackContainer(); | 629 static final FillStackContainer _emptyContainer = new FillStackContainer(); |
| 630 | 630 |
| 631 RenderNodeWrapper get _emptyNode => _emptyContainer; | 631 RenderNodeWrapper get emptyNode => _emptyContainer; |
| 632 | 632 |
| 633 FillStackContainer({ | 633 FillStackContainer({ |
| 634 Object key, | 634 Object key, |
| 635 List<UINode> children, | 635 List<UINode> children, |
| 636 Style style, | 636 Style style, |
| 637 String inlineStyle | 637 String inlineStyle |
| 638 }) : super( | 638 }) : super( |
| 639 key: key, | 639 key: key, |
| 640 children: _positionNodesToFill(children), | 640 children: _positionNodesToFill(children), |
| 641 style: style, | 641 style: style, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 652 if (input == null) | 652 if (input == null) |
| 653 return null; | 653 return null; |
| 654 return input.map((node) { | 654 return input.map((node) { |
| 655 return new ParentDataNode(node, _fillParentData); | 655 return new ParentDataNode(node, _fillParentData); |
| 656 }).toList(); | 656 }).toList(); |
| 657 } | 657 } |
| 658 } | 658 } |
| 659 | 659 |
| 660 class TextFragment extends RenderNodeWrapper { | 660 class TextFragment extends RenderNodeWrapper { |
| 661 | 661 |
| 662 RenderCSSInline _root; | 662 RenderCSSInline root; |
| 663 RenderCSSInline _createNode() => new RenderCSSInline(this, this.data); | 663 RenderCSSInline createNode() => new RenderCSSInline(this, this.data); |
| 664 | 664 |
| 665 static final TextFragment _emptyText = new TextFragment(''); | 665 static final TextFragment _emptyText = new TextFragment(''); |
| 666 | 666 |
| 667 RenderNodeWrapper get _emptyNode => _emptyText; | 667 RenderNodeWrapper get emptyNode => _emptyText; |
| 668 | 668 |
| 669 final String data; | 669 final String data; |
| 670 | 670 |
| 671 TextFragment(this.data, { | 671 TextFragment(this.data, { |
| 672 Object key, | 672 Object key, |
| 673 Style style, | 673 Style style, |
| 674 String inlineStyle | 674 String inlineStyle |
| 675 }) : super( | 675 }) : super( |
| 676 key: key, | 676 key: key, |
| 677 style: style, | 677 style: style, |
| 678 inlineStyle: inlineStyle | 678 inlineStyle: inlineStyle |
| 679 ); | 679 ); |
| 680 | 680 |
| 681 void _syncRenderNode(UINode old) { | 681 void syncRenderNode(UINode old) { |
| 682 super._syncRenderNode(old); | 682 super.syncRenderNode(old); |
| 683 _root.data = data; | 683 root.data = data; |
| 684 } | 684 } |
| 685 } | 685 } |
| 686 | 686 |
| 687 class Image extends RenderNodeWrapper { | 687 class Image extends RenderNodeWrapper { |
| 688 | 688 |
| 689 RenderCSSImage _root; | 689 RenderCSSImage root; |
| 690 RenderCSSImage _createNode() => new RenderCSSImage(this, this.src, this.width,
this.height); | 690 RenderCSSImage createNode() => new RenderCSSImage(this, this.src, this.width,
this.height); |
| 691 | 691 |
| 692 static final Image _emptyImage = new Image(); | 692 static final Image _emptyImage = new Image(); |
| 693 | 693 |
| 694 RenderNodeWrapper get _emptyNode => _emptyImage; | 694 RenderNodeWrapper get emptyNode => _emptyImage; |
| 695 | 695 |
| 696 final String src; | 696 final String src; |
| 697 final int width; | 697 final int width; |
| 698 final int height; | 698 final int height; |
| 699 | 699 |
| 700 Image({ | 700 Image({ |
| 701 Object key, | 701 Object key, |
| 702 Style style, | 702 Style style, |
| 703 String inlineStyle, | 703 String inlineStyle, |
| 704 this.width, | 704 this.width, |
| 705 this.height, | 705 this.height, |
| 706 this.src | 706 this.src |
| 707 }) : super( | 707 }) : super( |
| 708 key: key, | 708 key: key, |
| 709 style: style, | 709 style: style, |
| 710 inlineStyle: inlineStyle | 710 inlineStyle: inlineStyle |
| 711 ); | 711 ); |
| 712 | 712 |
| 713 void _syncRenderNode(UINode old) { | 713 void syncRenderNode(UINode old) { |
| 714 super._syncRenderNode(old); | 714 super.syncRenderNode(old); |
| 715 _root.configure(this.src, this.width, this.height); | 715 root.configure(this.src, this.width, this.height); |
| 716 } | 716 } |
| 717 } | 717 } |
| 718 | 718 |
| 719 | 719 |
| 720 Set<Component> _mountedComponents = new HashSet<Component>(); | 720 Set<Component> _mountedComponents = new HashSet<Component>(); |
| 721 Set<Component> _unmountedComponents = new HashSet<Component>(); | 721 Set<Component> _unmountedComponents = new HashSet<Component>(); |
| 722 | 722 |
| 723 void _enqueueDidMount(Component c) { | 723 void _enqueueDidMount(Component c) { |
| 724 assert(!_notifingMountStatus); | 724 assert(!_notifingMountStatus); |
| 725 _mountedComponents.add(c); | 725 _mountedComponents.add(c); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 830 _mountCallbacks.forEach((fn) => fn()); | 830 _mountCallbacks.forEach((fn) => fn()); |
| 831 } | 831 } |
| 832 | 832 |
| 833 void _didUnmount() { | 833 void _didUnmount() { |
| 834 if (_unmountCallbacks != null) | 834 if (_unmountCallbacks != null) |
| 835 _unmountCallbacks.forEach((fn) => fn()); | 835 _unmountCallbacks.forEach((fn) => fn()); |
| 836 } | 836 } |
| 837 | 837 |
| 838 // TODO(rafaelw): It seems wrong to expose DOM at all. This is presently | 838 // TODO(rafaelw): It seems wrong to expose DOM at all. This is presently |
| 839 // needed to get sizing info. | 839 // needed to get sizing info. |
| 840 RenderCSS getRoot() => _root; | 840 RenderCSS getRoot() => root; |
| 841 | 841 |
| 842 void _remove() { | 842 void _remove() { |
| 843 assert(_built != null); | 843 assert(_built != null); |
| 844 assert(_root != null); | 844 assert(root != null); |
| 845 _removeChild(_built); | 845 removeChild(_built); |
| 846 _built = null; | 846 _built = null; |
| 847 _enqueueDidUnmount(this); | 847 _enqueueDidUnmount(this); |
| 848 super._remove(); | 848 super._remove(); |
| 849 } | 849 } |
| 850 | 850 |
| 851 bool _willSync(UINode old) { | 851 bool _willSync(UINode old) { |
| 852 Component oldComponent = old as Component; | 852 Component oldComponent = old as Component; |
| 853 if (oldComponent == null || !oldComponent._stateful) | 853 if (oldComponent == null || !oldComponent._stateful) |
| 854 return false; | 854 return false; |
| 855 | 855 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 894 | 894 |
| 895 int lastOrder = _currentOrder; | 895 int lastOrder = _currentOrder; |
| 896 _currentOrder = _order; | 896 _currentOrder = _order; |
| 897 _currentlyBuilding = this; | 897 _currentlyBuilding = this; |
| 898 _built = build(); | 898 _built = build(); |
| 899 _currentlyBuilding = null; | 899 _currentlyBuilding = null; |
| 900 _currentOrder = lastOrder; | 900 _currentOrder = lastOrder; |
| 901 | 901 |
| 902 _built = _syncChild(_built, oldBuilt, slot); | 902 _built = _syncChild(_built, oldBuilt, slot); |
| 903 _dirty = false; | 903 _dirty = false; |
| 904 _root = _built._root; | 904 root = _built.root; |
| 905 assert(_root != null); | 905 assert(root != null); |
| 906 } | 906 } |
| 907 | 907 |
| 908 void _buildIfDirty() { | 908 void _buildIfDirty() { |
| 909 if (!_dirty || _defunct) | 909 if (!_dirty || _defunct) |
| 910 return; | 910 return; |
| 911 | 911 |
| 912 _trace('$_key rebuilding...'); | 912 _trace('$_key rebuilding...'); |
| 913 assert(_root != null); | 913 assert(root != null); |
| 914 _sync(null, _slot); | 914 _sync(null, _slot); |
| 915 } | 915 } |
| 916 | 916 |
| 917 void scheduleBuild() { | 917 void scheduleBuild() { |
| 918 setState(() {}); | 918 setState(() {}); |
| 919 } | 919 } |
| 920 | 920 |
| 921 void setState(Function fn()) { | 921 void setState(Function fn()) { |
| 922 _stateful = true; | 922 _stateful = true; |
| 923 fn(); | 923 fn(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 938 _host = new RenderCSSRoot(this); | 938 _host = new RenderCSSRoot(this); |
| 939 _scheduleComponentForRender(this); | 939 _scheduleComponentForRender(this); |
| 940 } | 940 } |
| 941 | 941 |
| 942 void _buildIfDirty() { | 942 void _buildIfDirty() { |
| 943 if (!_dirty || _defunct) | 943 if (!_dirty || _defunct) |
| 944 return; | 944 return; |
| 945 | 945 |
| 946 _trace('$_key rebuilding...'); | 946 _trace('$_key rebuilding...'); |
| 947 _sync(null, null); | 947 _sync(null, null); |
| 948 if (_root.parent == null) | 948 if (root.parent == null) |
| 949 _host.add(_root); | 949 _host.add(root); |
| 950 assert(_root.parent == _host); | 950 assert(root.parent == _host); |
| 951 } | 951 } |
| 952 } | 952 } |
| 953 | 953 |
| 954 class Text extends Component { | 954 class Text extends Component { |
| 955 Text(this.data) : super(key: '*text*'); | 955 Text(this.data) : super(key: '*text*'); |
| 956 final String data; | 956 final String data; |
| 957 bool get interchangeable => true; | 957 bool get interchangeable => true; |
| 958 UINode build() => new Paragraph(children: [new TextFragment(data)]); | 958 UINode build() => new Paragraph(children: [new TextFragment(data)]); |
| 959 } | 959 } |
| OLD | NEW |