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

Side by Side Diff: sky/sdk/lib/framework/fn.dart

Issue 1145953003: [Effen] Move responsibility for inserting nodes to the OneChildListRenderNodeWrapper. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 7 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 | « no previous file | 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 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:sky' as sky; 10 import 'dart:sky' as sky;
10 import 'reflect.dart' as reflect; 11 import 'reflect.dart' as reflect;
11 import 'layout.dart'; 12 import 'layout.dart';
12 13
13 export 'layout.dart' show Style; 14 export 'layout.dart' show Style;
14 15
15 final sky.Tracing _tracing = sky.window.tracing; 16 final sky.Tracing _tracing = sky.window.tracing;
16 17
17 final bool _shouldLogRenderDuration = false; 18 final bool _shouldLogRenderDuration = false;
18 final bool _shouldTrace = false; 19 final bool _shouldTrace = false;
(...skipping 15 matching lines...) Expand all
34 _key = key == null ? "$runtimeType" : "$runtimeType-$key"; 35 _key = key == null ? "$runtimeType" : "$runtimeType-$key";
35 assert(this is App || _inRenderDirtyComponents); // you should not build the UI tree ahead of time, build it only during build() 36 assert(this is App || _inRenderDirtyComponents); // you should not build the UI tree ahead of time, build it only during build()
36 } 37 }
37 38
38 // Subclasses which implements Nodes that become stateful may return true 39 // Subclasses which implements Nodes that become stateful may return true
39 // if the |old| node has become stateful and should be retained. 40 // if the |old| node has become stateful and should be retained.
40 bool _willSync(UINode old) => false; 41 bool _willSync(UINode old) => false;
41 42
42 bool get interchangeable => false; // if true, then keys can be duplicated 43 bool get interchangeable => false; // if true, then keys can be duplicated
43 44
44 void _sync(UINode old, RenderCSSContainer host, RenderCSS insertBefore); 45 void _sync(UINode old, dynamic slot);
46 // 'slot' is the identifier that the parent RenderNodeWrapper uses to know
47 // where to put this descendant
45 48
46 void _remove() { 49 void _remove() {
47 _defunct = true; 50 _defunct = true;
48 _root = null; 51 _root = null;
49 handleRemoved(); 52 handleRemoved();
50 } 53 }
51 void handleRemoved() { } 54 void handleRemoved() { }
52 55
56 UINode findAncestor(Type targetType) {
57 var ancestor = _parent;
58 while (ancestor != null && !reflectClass(ancestor.runtimeType).isSubtypeOf(r eflectClass(targetType)))
59 ancestor = ancestor._parent;
60 return ancestor;
61 }
62
53 int _nodeDepth; 63 int _nodeDepth;
54 void _ensureDepth() { 64 void _ensureDepth() {
55 if (_nodeDepth == null) { 65 if (_nodeDepth == null) {
56 if (_parent != null) { 66 if (_parent != null) {
57 _parent._ensureDepth(); 67 _parent._ensureDepth();
58 _nodeDepth = _parent._nodeDepth + 1; 68 _nodeDepth = _parent._nodeDepth + 1;
59 } else { 69 } else {
60 _nodeDepth = 0; 70 _nodeDepth = 0;
61 } 71 }
62 } 72 }
(...skipping 15 matching lines...) Expand all
78 String outString = opString.substring(opString.indexOf('.') + 1); 88 String outString = opString.substring(opString.indexOf('.') + 1);
79 _trace('_sync($outString) $key'); 89 _trace('_sync($outString) $key');
80 } 90 }
81 91
82 void _removeChild(UINode node) { 92 void _removeChild(UINode node) {
83 _traceSync(_SyncOperation.REMOVAL, node._key); 93 _traceSync(_SyncOperation.REMOVAL, node._key);
84 node._remove(); 94 node._remove();
85 } 95 }
86 96
87 // Returns the child which should be retained as the child of this node. 97 // Returns the child which should be retained as the child of this node.
88 UINode _syncChild(UINode node, UINode oldNode, RenderCSSContainer host, 98 UINode _syncChild(UINode node, UINode oldNode, dynamic slot) {
89 RenderCSS insertBefore) { 99 assert(node != null);
90
91 assert(oldNode == null || node._key == oldNode._key); 100 assert(oldNode == null || node._key == oldNode._key);
92 101
93 if (node == oldNode) { 102 if (node == oldNode) {
94 _traceSync(_SyncOperation.IDENTICAL, node._key); 103 _traceSync(_SyncOperation.IDENTICAL, node._key);
95 return node; // Nothing to do. Subtrees must be identical. 104 return node; // Nothing to do. Subtrees must be identical.
96 } 105 }
97 106
98 // TODO(rafaelw): This eagerly removes the old DOM. It may be that a 107 // TODO(rafaelw): This eagerly removes the old DOM. It may be that a
99 // new component was built that could re-use some of it. Consider 108 // new component was built that could re-use some of it. Consider
100 // syncing the new VDOM against the old one. 109 // syncing the new VDOM against the old one.
101 if (oldNode != null && node._key != oldNode._key) { 110 if (oldNode != null && node._key != oldNode._key) {
102 _removeChild(oldNode); 111 _removeChild(oldNode);
103 } 112 }
104 113
105 if (node._willSync(oldNode)) { 114 if (node._willSync(oldNode)) {
106 _traceSync(_SyncOperation.STATEFUL, node._key); 115 _traceSync(_SyncOperation.STATEFUL, node._key);
107 oldNode._sync(node, host, insertBefore); 116 oldNode._sync(node, slot);
108 node._defunct = true; 117 node._defunct = true;
109 assert(oldNode._root is RenderCSS); 118 assert(oldNode._root is RenderCSS);
110 return oldNode; 119 return oldNode;
111 } 120 }
112 121
113 assert(!node._defunct); 122 assert(!node._defunct);
114 node._parent = this; 123 node._parent = this;
115 124
116 if (oldNode == null) { 125 if (oldNode == null) {
117 _traceSync(_SyncOperation.INSERTION, node._key); 126 _traceSync(_SyncOperation.INSERTION, node._key);
118 } else { 127 } else {
119 _traceSync(_SyncOperation.STATELESS, node._key); 128 _traceSync(_SyncOperation.STATELESS, node._key);
120 } 129 }
121 node._sync(oldNode, host, insertBefore); 130 node._sync(oldNode, slot);
122 if (oldNode != null) 131 if (oldNode != null)
123 oldNode._defunct = true; 132 oldNode._defunct = true;
124 133
125 assert(node._root is RenderCSS); 134 assert(node._root is RenderCSS);
126 return node; 135 return node;
127 } 136 }
128 } 137 }
129 138
130 abstract class ContentNode extends UINode { 139 abstract class ContentNode extends UINode {
131 UINode content; 140 UINode content;
132 141
133 ContentNode(UINode content) : this.content = content, super(key: content._key) ; 142 ContentNode(UINode content) : this.content = content, super(key: content._key) ;
134 143
135 void _sync(UINode old, RenderCSSContainer host, RenderCSS insertBefore) { 144 void _sync(UINode old, dynamic slot) {
136 UINode oldContent = old == null ? null : (old as ContentNode).content; 145 UINode oldContent = old == null ? null : (old as ContentNode).content;
137 content = _syncChild(content, oldContent, host, insertBefore); 146 content = _syncChild(content, oldContent, slot);
138 assert(content._root != null); 147 assert(content._root != null);
139 _root = content._root; 148 _root = content._root;
140 } 149 }
141 150
142 void _remove() { 151 void _remove() {
143 if (content != null) 152 if (content != null)
144 _removeChild(content); 153 _removeChild(content);
145 super._remove(); 154 super._remove();
146 } 155 }
147 } 156 }
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 target = target._parent; 268 target = target._parent;
260 } 269 }
261 } 270 }
262 271
263 static void _ensureDocumentListener(String eventType) { 272 static void _ensureDocumentListener(String eventType) {
264 if (_registeredEvents.add(eventType)) { 273 if (_registeredEvents.add(eventType)) {
265 sky.document.addEventListener(eventType, _dispatchEvent); 274 sky.document.addEventListener(eventType, _dispatchEvent);
266 } 275 }
267 } 276 }
268 277
269 void _sync(UINode old, RenderCSSContainer host, RenderCSS insertBefore) { 278 void _sync(UINode old, dynamic slot) {
270 for (var type in listeners.keys) { 279 for (var type in listeners.keys) {
271 _ensureDocumentListener(type); 280 _ensureDocumentListener(type);
272 } 281 }
273 282 super._sync(old, slot);
274 super._sync(old, host, insertBefore);
275 } 283 }
276 } 284 }
277 285
278 /* 286 /*
279 * RenderNodeWrappers correspond to a desired state of a RenderCSS. 287 * RenderNodeWrappers correspond to a desired state of a RenderCSS.
280 * They are fully immutable, with one exception: A UINode which is a 288 * They are fully immutable, with one exception: A UINode which is a
281 * Component which lives within an OneChildListRenderNodeWrapper's 289 * Component which lives within an OneChildListRenderNodeWrapper's
282 * children list, may be replaced with the "old" instance if it has 290 * children list, may be replaced with the "old" instance if it has
283 * become stateful. 291 * become stateful.
284 */ 292 */
285 abstract class RenderNodeWrapper extends UINode { 293 abstract class RenderNodeWrapper extends UINode {
286 294
287 static final Map<RenderCSS, RenderNodeWrapper> _nodeMap = 295 static final Map<RenderCSS, RenderNodeWrapper> _nodeMap =
288 new HashMap<RenderCSS, RenderNodeWrapper>(); 296 new HashMap<RenderCSS, RenderNodeWrapper>();
289 297
290 static RenderNodeWrapper _getMounted(RenderCSS node) => _nodeMap[node]; 298 static RenderNodeWrapper _getMounted(RenderCSS node) => _nodeMap[node];
291 299
292 RenderNodeWrapper({ 300 RenderNodeWrapper({
293 Object key, 301 Object key,
294 this.style, 302 this.style,
295 this.inlineStyle 303 this.inlineStyle
296 }) : super(key: key); 304 }) : super(key: key);
297 305
298 final Style style; 306 final Style style;
299 final String inlineStyle; 307 final String inlineStyle;
300 308
301 RenderCSS _createNode(); 309 RenderCSS _createNode();
302 RenderNodeWrapper get _emptyNode; 310 RenderNodeWrapper get _emptyNode;
303 311
304 void _sync(UINode old, RenderCSSContainer host, RenderCSS insertBefore) { 312 void insert(RenderNodeWrapper child, dynamic slot);
313
314 void _sync(UINode old, dynamic slot) {
305 if (old == null) { 315 if (old == null) {
306 _root = _createNode(); 316 _root = _createNode();
307 assert(_root != null); 317 assert(_root != null);
308 host.add(_root, before: insertBefore); 318 var ancestor = findAncestor(RenderNodeWrapper);
319 if (ancestor is RenderNodeWrapper)
320 ancestor.insert(this, slot);
309 old = _emptyNode; 321 old = _emptyNode;
310 } else { 322 } else {
311 _root = old._root; 323 _root = old._root;
312 assert(_root != null); 324 assert(_root != null);
313 } 325 }
314 326
315 _nodeMap[_root] = this; 327 _nodeMap[_root] = this;
316 _syncRenderNode(old); 328 _syncRenderNode(old);
317 } 329 }
318 330
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 assert(_root != null); 369 assert(_root != null);
358 _nodeMap.remove(_root); 370 _nodeMap.remove(_root);
359 super._remove(); 371 super._remove();
360 } 372 }
361 } 373 }
362 374
363 final List<UINode> _emptyList = new List<UINode>(); 375 final List<UINode> _emptyList = new List<UINode>();
364 376
365 abstract class OneChildListRenderNodeWrapper extends RenderNodeWrapper { 377 abstract class OneChildListRenderNodeWrapper extends RenderNodeWrapper {
366 378
379 // In OneChildListRenderNodeWrapper subclasses, slots are RenderCSS nodes
380 // to use as the "insert before" sibling in RenderCSSContainer.add() calls
381
367 final List<UINode> children; 382 final List<UINode> children;
368 383
369 OneChildListRenderNodeWrapper({ 384 OneChildListRenderNodeWrapper({
370 Object key, 385 Object key,
371 List<UINode> children, 386 List<UINode> children,
372 Style style, 387 Style style,
373 String inlineStyle 388 String inlineStyle
374 }) : this.children = children == null ? _emptyList : children, 389 }) : this.children = children == null ? _emptyList : children,
375 super( 390 super(
376 key: key, 391 key: key,
377 style: style, 392 style: style,
378 inlineStyle: inlineStyle 393 inlineStyle: inlineStyle
379 ) { 394 ) {
380 assert(!_debugHasDuplicateIds()); 395 assert(!_debugHasDuplicateIds());
381 } 396 }
382 397
398 void insert(RenderNodeWrapper child, dynamic slot) {
399 assert(slot == null || slot is RenderCSS);
400 _root.add(child._root, before: slot);
401 }
402
383 void _remove() { 403 void _remove() {
384 assert(children != null); 404 assert(children != null);
385 for (var child in children) { 405 for (var child in children) {
386 assert(child != null); 406 assert(child != null);
387 _removeChild(child); 407 _removeChild(child);
388 } 408 }
389 super._remove(); 409 super._remove();
390 } 410 }
391 411
392 bool _debugHasDuplicateIds() { 412 bool _debugHasDuplicateIds() {
(...skipping 23 matching lines...) Expand all
416 436
417 var oldChildren = old.children; 437 var oldChildren = old.children;
418 var oldStartIndex = 0; 438 var oldStartIndex = 0;
419 var oldEndIndex = oldChildren.length; 439 var oldEndIndex = oldChildren.length;
420 440
421 RenderCSS nextSibling = null; 441 RenderCSS nextSibling = null;
422 UINode currentNode = null; 442 UINode currentNode = null;
423 UINode oldNode = null; 443 UINode oldNode = null;
424 444
425 void sync(int atIndex) { 445 void sync(int atIndex) {
426 children[atIndex] = _syncChild(currentNode, oldNode, _root, nextSibling); 446 children[atIndex] = _syncChild(currentNode, oldNode, nextSibling);
427 assert(children[atIndex] != null); 447 assert(children[atIndex] != null);
428 } 448 }
429 449
430 // Scan backwards from end of list while nodes can be directly synced 450 // Scan backwards from end of list while nodes can be directly synced
431 // without reordering. 451 // without reordering.
432 while (endIndex > startIndex && oldEndIndex > oldStartIndex) { 452 while (endIndex > startIndex && oldEndIndex > oldStartIndex) {
433 currentNode = children[endIndex - 1]; 453 currentNode = children[endIndex - 1];
434 oldNode = oldChildren[oldEndIndex - 1]; 454 oldNode = oldChildren[oldEndIndex - 1];
435 455
436 if (currentNode._key != oldNode._key) { 456 if (currentNode._key != oldNode._key) {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 return false; // never re-order these nodes 495 return false; // never re-order these nodes
476 496
477 ensureOldIdMap(); 497 ensureOldIdMap();
478 oldNode = oldNodeIdMap[currentNode._key]; 498 oldNode = oldNodeIdMap[currentNode._key];
479 if (oldNode == null) 499 if (oldNode == null)
480 return false; 500 return false;
481 501
482 oldNodeIdMap[currentNode._key] = null; // mark it reordered 502 oldNodeIdMap[currentNode._key] = null; // mark it reordered
483 assert(_root is RenderCSSContainer); 503 assert(_root is RenderCSSContainer);
484 assert(oldNode._root is RenderCSSContainer); 504 assert(oldNode._root is RenderCSSContainer);
505
485 old._root.remove(oldNode._root); 506 old._root.remove(oldNode._root);
486 _root.add(oldNode._root, before: nextSibling); 507 _root.add(oldNode._root, before: nextSibling);
508
487 return true; 509 return true;
488 } 510 }
489 511
490 // Scan forwards, this time we may re-order; 512 // Scan forwards, this time we may re-order;
491 nextSibling = _root.firstChild; 513 nextSibling = _root.firstChild;
492 while (startIndex < endIndex && oldStartIndex < oldEndIndex) { 514 while (startIndex < endIndex && oldStartIndex < oldEndIndex) {
493 currentNode = children[startIndex]; 515 currentNode = children[startIndex];
494 oldNode = oldChildren[oldStartIndex]; 516 oldNode = oldChildren[oldStartIndex];
495 517
496 if (currentNode._key == oldNode._key) { 518 if (currentNode._key == oldNode._key) {
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
773 bool get _isBuilding => _currentlyBuilding == this; 795 bool get _isBuilding => _currentlyBuilding == this;
774 bool _dirty = true; 796 bool _dirty = true;
775 797
776 UINode _built; 798 UINode _built;
777 final int _order; 799 final int _order;
778 static int _currentOrder = 0; 800 static int _currentOrder = 0;
779 bool _stateful; 801 bool _stateful;
780 static Component _currentlyBuilding; 802 static Component _currentlyBuilding;
781 List<Function> _mountCallbacks; 803 List<Function> _mountCallbacks;
782 List<Function> _unmountCallbacks; 804 List<Function> _unmountCallbacks;
805 dynamic _slot; // cached slot from the last time we were synced
783 806
784 void onDidMount(Function fn) { 807 void onDidMount(Function fn) {
785 if (_mountCallbacks == null) 808 if (_mountCallbacks == null)
786 _mountCallbacks = new List<Function>(); 809 _mountCallbacks = new List<Function>();
787 810
788 _mountCallbacks.add(fn); 811 _mountCallbacks.add(fn);
789 } 812 }
790 813
791 void onDidUnmount(Function fn) { 814 void onDidUnmount(Function fn) {
792 if (_unmountCallbacks == null) 815 if (_unmountCallbacks == null)
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
845 } 868 }
846 869
847 /* There are three cases here: 870 /* There are three cases here:
848 * 1) Building for the first time: 871 * 1) Building for the first time:
849 * assert(_built == null && old == null) 872 * assert(_built == null && old == null)
850 * 2) Re-building (because a dirty flag got set): 873 * 2) Re-building (because a dirty flag got set):
851 * assert(_built != null && old == null) 874 * assert(_built != null && old == null)
852 * 3) Syncing against an old version 875 * 3) Syncing against an old version
853 * assert(_built == null && old != null) 876 * assert(_built == null && old != null)
854 */ 877 */
855 void _sync(UINode old, RenderCSSContainer host, RenderCSS insertBefore) { 878 void _sync(UINode old, dynamic slot) {
856 assert(!_defunct); 879 assert(!_defunct);
857 assert(_built == null || old == null); 880 assert(_built == null || old == null);
858 881
859 Component oldComponent = old as Component; 882 Component oldComponent = old as Component;
860 883
884 _slot = slot;
885
861 var oldBuilt; 886 var oldBuilt;
862 if (oldComponent == null) { 887 if (oldComponent == null) {
863 oldBuilt = _built; 888 oldBuilt = _built;
864 } else { 889 } else {
865 assert(_built == null); 890 assert(_built == null);
866 oldBuilt = oldComponent._built; 891 oldBuilt = oldComponent._built;
867 } 892 }
868 893
869 if (oldBuilt == null) 894 if (oldBuilt == null)
870 _enqueueDidMount(this); 895 _enqueueDidMount(this);
871 896
872 int lastOrder = _currentOrder; 897 int lastOrder = _currentOrder;
873 _currentOrder = _order; 898 _currentOrder = _order;
874 _currentlyBuilding = this; 899 _currentlyBuilding = this;
875 _built = build(); 900 _built = build();
876 _currentlyBuilding = null; 901 _currentlyBuilding = null;
877 _currentOrder = lastOrder; 902 _currentOrder = lastOrder;
878 903
879 _built = _syncChild(_built, oldBuilt, host, insertBefore); 904 _built = _syncChild(_built, oldBuilt, slot);
880 _dirty = false; 905 _dirty = false;
881 _root = _built._root; 906 _root = _built._root;
882 assert(_root != null); 907 assert(_root != null);
883 } 908 }
884 909
885 void _buildIfDirty() { 910 void _buildIfDirty() {
886 if (!_dirty || _defunct) 911 if (!_dirty || _defunct)
887 return; 912 return;
888 913
889 _trace('$_key rebuilding...'); 914 _trace('$_key rebuilding...');
890 _sync(null, _root.parent, _root.parent.childAfter(_root)); 915 assert(_root != null);
916 _sync(null, _slot);
891 } 917 }
892 918
893 void scheduleBuild() { 919 void scheduleBuild() {
894 setState(() {}); 920 setState(() {});
895 } 921 }
896 922
897 void setState(Function fn()) { 923 void setState(Function fn()) {
898 _stateful = true; 924 _stateful = true;
899 fn(); 925 fn();
900 if (_isBuilding || _dirty || _defunct) 926 if (_isBuilding || _dirty || _defunct)
(...skipping 12 matching lines...) Expand all
913 App() : super(stateful: true) { 939 App() : super(stateful: true) {
914 _host = new RenderCSSRoot(this); 940 _host = new RenderCSSRoot(this);
915 _scheduleComponentForRender(this); 941 _scheduleComponentForRender(this);
916 } 942 }
917 943
918 void _buildIfDirty() { 944 void _buildIfDirty() {
919 if (!_dirty || _defunct) 945 if (!_dirty || _defunct)
920 return; 946 return;
921 947
922 _trace('$_key rebuilding...'); 948 _trace('$_key rebuilding...');
923 _sync(null, _host, _root); 949 _sync(null, null);
950 if (_root.parent == null)
951 _host.add(_root);
952 assert(_root.parent == _host);
924 } 953 }
925 } 954 }
926 955
927 class Text extends Component { 956 class Text extends Component {
928 Text(this.data) : super(key: '*text*'); 957 Text(this.data) : super(key: '*text*');
929 final String data; 958 final String data;
930 bool get interchangeable => true; 959 bool get interchangeable => true;
931 UINode build() => new Paragraph(children: [new TextFragment(data)]); 960 UINode build() => new Paragraph(children: [new TextFragment(data)]);
932 } 961 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698