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

Side by Side Diff: sky/sdk/lib/widgets/widget.dart

Issue 1185413002: Key refactor, part 1: remove the dependence on the runtimeType in keys, otherwise they'll get overl… (Closed) Base URL: https://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
« 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 import 'dart:async'; 5 import 'dart:async';
6 import 'dart:collection'; 6 import 'dart:collection';
7 import 'dart:mirrors'; 7 import 'dart:mirrors';
8 import 'dart:sky' as sky; 8 import 'dart:sky' as sky;
9 9
10 import '../app/view.dart'; 10 import '../app/view.dart';
11 import '../rendering/box.dart'; 11 import '../rendering/box.dart';
12 import '../rendering/object.dart'; 12 import '../rendering/object.dart';
13 13
14 export '../rendering/box.dart' show BoxConstraints, BoxDecoration, Border, Borde rSide, EdgeDims; 14 export '../rendering/box.dart' show BoxConstraints, BoxDecoration, Border, Borde rSide, EdgeDims;
15 export '../rendering/flex.dart' show FlexDirection; 15 export '../rendering/flex.dart' show FlexDirection;
16 export '../rendering/object.dart' show Point, Size, Rect, Color, Paint, Path; 16 export '../rendering/object.dart' show Point, Size, Rect, Color, Paint, Path;
17 17
18 final bool _shouldLogRenderDuration = false; 18 final bool _shouldLogRenderDuration = false;
19 19
20 // All Effen nodes derive from Widget. All nodes have a _parent, a _key and 20 // All Effen nodes derive from Widget. All nodes have a _parent, a _key and
21 // can be sync'd. 21 // can be sync'd.
22 abstract class Widget { 22 abstract class Widget {
23 23
24 Widget({ String key }) { 24 Widget({ String key }) {
25 _key = key == null ? "$runtimeType" : "$runtimeType-$key"; 25 _key = key != null ? key : runtimeType.toString();
26 assert(this is AbstractWidgetRoot || _inRenderDirtyComponents); // you shoul d not build the UI tree ahead of time, build it only during build() 26 assert(this is AbstractWidgetRoot || _inRenderDirtyComponents); // you shoul d not build the UI tree ahead of time, build it only during build()
27 } 27 }
28 28
29 String _key; 29 String _key;
30 String get key => _key; 30 String get key => _key;
31 31
32 Widget _parent; 32 Widget _parent;
33 Widget get parent => _parent; 33 Widget get parent => _parent;
34 34
35 bool _mounted = false; 35 bool _mounted = false;
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
117 } 117 }
118 118
119 if (node == null) { 119 if (node == null) {
120 // the child in this slot has gone away 120 // the child in this slot has gone away
121 assert(oldNode.mounted); 121 assert(oldNode.mounted);
122 removeChild(oldNode); 122 removeChild(oldNode);
123 assert(!oldNode.mounted); 123 assert(!oldNode.mounted);
124 return null; 124 return null;
125 } 125 }
126 126
127 if (oldNode != null && node._key == oldNode._key && node._retainStatefulNode IfPossible(oldNode)) { 127 if (oldNode != null && oldNode.runtimeType == node.runtimeType && node.key = = oldNode.key && node._retainStatefulNodeIfPossible(oldNode)) {
128 assert(oldNode.mounted); 128 assert(oldNode.mounted);
129 assert(!node.mounted); 129 assert(!node.mounted);
130 oldNode._sync(node, slot); 130 oldNode._sync(node, slot);
131 assert(oldNode.root is RenderObject); 131 assert(oldNode.root is RenderObject);
132 return oldNode; 132 return oldNode;
133 } 133 }
134 134
135 if (oldNode != null && node._key != oldNode._key) { 135 if (oldNode != null && (oldNode.runtimeType != node.runtimeType || node.key != oldNode.key)) {
136 assert(oldNode.mounted); 136 assert(oldNode.mounted);
137 removeChild(oldNode); 137 removeChild(oldNode);
138 oldNode = null; 138 oldNode = null;
139 } 139 }
140 140
141 assert(!node.mounted); 141 assert(!node.mounted);
142 node.setParent(this); 142 node.setParent(this);
143 node._sync(oldNode, slot); 143 node._sync(oldNode, slot);
144 assert(node.root is RenderObject); 144 assert(node.root is RenderObject);
145 return node; 145 return node;
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 super.remove(); 300 super.remove();
301 } 301 }
302 302
303 bool _retainStatefulNodeIfPossible(Widget old) { 303 bool _retainStatefulNodeIfPossible(Widget old) {
304 assert(!_disqualifiedFromEverAppearingAgain); 304 assert(!_disqualifiedFromEverAppearingAgain);
305 305
306 Component oldComponent = old as Component; 306 Component oldComponent = old as Component;
307 if (oldComponent == null || !oldComponent._stateful) 307 if (oldComponent == null || !oldComponent._stateful)
308 return false; 308 return false;
309 309
310 assert(runtimeType == oldComponent.runtimeType);
310 assert(key == oldComponent.key); 311 assert(key == oldComponent.key);
311 312
312 // Make |this|, the newly-created object, into the "old" Component, and kill it 313 // Make |this|, the newly-created object, into the "old" Component, and kill it
313 _stateful = false; 314 _stateful = false;
314 _built = oldComponent._built; 315 _built = oldComponent._built;
315 assert(_built != null); 316 assert(_built != null);
316 _disqualifiedFromEverAppearingAgain = true; 317 _disqualifiedFromEverAppearingAgain = true;
317 318
318 // Make |oldComponent| the "new" component 319 // Make |oldComponent| the "new" component
319 oldComponent._built = null; 320 oldComponent._built = null;
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 507
507 void remove() { 508 void remove() {
508 assert(root != null); 509 assert(root != null);
509 _nodeMap.remove(root); 510 _nodeMap.remove(root);
510 super.remove(); 511 super.remove();
511 } 512 }
512 } 513 }
513 514
514 abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper { 515 abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper {
515 516
516 OneChildRenderObjectWrapper({ Widget child, String key }) 517 OneChildRenderObjectWrapper({ String key, Widget child })
517 : _child = child, super(key: key); 518 : _child = child, super(key: key);
518 519
519 Widget _child; 520 Widget _child;
520 Widget get child => _child; 521 Widget get child => _child;
521 522
522 void syncRenderObject(RenderObjectWrapper old) { 523 void syncRenderObject(RenderObjectWrapper old) {
523 super.syncRenderObject(old); 524 super.syncRenderObject(old);
524 Widget oldChild = old == null ? null : (old as OneChildRenderObjectWrapper). child; 525 Widget oldChild = old == null ? null : (old as OneChildRenderObjectWrapper). child;
525 _child = syncChild(child, oldChild, null); 526 _child = syncChild(child, oldChild, null);
526 } 527 }
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 super.remove(); 589 super.remove();
589 } 590 }
590 591
591 bool _debugHasDuplicateIds() { 592 bool _debugHasDuplicateIds() {
592 var idSet = new HashSet<String>(); 593 var idSet = new HashSet<String>();
593 for (var child in children) { 594 for (var child in children) {
594 assert(child != null); 595 assert(child != null);
595 if (child.interchangeable) 596 if (child.interchangeable)
596 continue; // when these nodes are reordered, we just reassign the data 597 continue; // when these nodes are reordered, we just reassign the data
597 598
598 if (!idSet.add(child._key)) { 599 if (!idSet.add(child.key)) {
599 throw '''If multiple non-interchangeable nodes of the same type exist as children 600 throw '''If multiple non-interchangeable nodes exist as children of anot her node, they must have unique keys. Duplicate: "${child.key}"''';
600 of another node, they must have unique keys.
601 Duplicate: "${child._key}"''';
602 } 601 }
603 } 602 }
604 return false; 603 return false;
605 } 604 }
606 605
607 void syncRenderObject(MultiChildRenderObjectWrapper old) { 606 void syncRenderObject(MultiChildRenderObjectWrapper old) {
608 super.syncRenderObject(old); 607 super.syncRenderObject(old);
609 608
610 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev erer 609 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev erer
611 if (root is! ContainerRenderObjectMixin) 610 if (root is! ContainerRenderObjectMixin)
(...skipping 14 matching lines...) Expand all
626 children[atIndex] = syncChild(currentNode, oldNode, nextSibling); 625 children[atIndex] = syncChild(currentNode, oldNode, nextSibling);
627 assert(children[atIndex] != null); 626 assert(children[atIndex] != null);
628 } 627 }
629 628
630 // Scan backwards from end of list while nodes can be directly synced 629 // Scan backwards from end of list while nodes can be directly synced
631 // without reordering. 630 // without reordering.
632 while (endIndex > startIndex && oldEndIndex > oldStartIndex) { 631 while (endIndex > startIndex && oldEndIndex > oldStartIndex) {
633 currentNode = children[endIndex - 1]; 632 currentNode = children[endIndex - 1];
634 oldNode = oldChildren[oldEndIndex - 1]; 633 oldNode = oldChildren[oldEndIndex - 1];
635 634
636 if (currentNode._key != oldNode._key) { 635 if (currentNode.runtimeType != oldNode.runtimeType || currentNode.key != o ldNode.key) {
637 break; 636 break;
638 } 637 }
639 638
640 endIndex--; 639 endIndex--;
641 oldEndIndex--; 640 oldEndIndex--;
642 sync(endIndex); 641 sync(endIndex);
643 } 642 }
644 643
645 HashMap<String, Widget> oldNodeIdMap = null; 644 HashMap<String, Widget> oldNodeIdMap = null;
646 645
647 bool oldNodeReordered(String key) { 646 bool oldNodeReordered(String key) {
648 return oldNodeIdMap != null && 647 return oldNodeIdMap != null &&
649 oldNodeIdMap.containsKey(key) && 648 oldNodeIdMap.containsKey(key) &&
650 oldNodeIdMap[key] == null; 649 oldNodeIdMap[key] == null;
651 } 650 }
652 651
653 void advanceOldStartIndex() { 652 void advanceOldStartIndex() {
654 oldStartIndex++; 653 oldStartIndex++;
655 while (oldStartIndex < oldEndIndex && 654 while (oldStartIndex < oldEndIndex &&
656 oldNodeReordered(oldChildren[oldStartIndex]._key)) { 655 oldNodeReordered(oldChildren[oldStartIndex].key)) {
657 oldStartIndex++; 656 oldStartIndex++;
658 } 657 }
659 } 658 }
660 659
661 void ensureOldIdMap() { 660 void ensureOldIdMap() {
662 if (oldNodeIdMap != null) 661 if (oldNodeIdMap != null)
663 return; 662 return;
664 663
665 oldNodeIdMap = new HashMap<String, Widget>(); 664 oldNodeIdMap = new HashMap<String, Widget>();
666 for (int i = oldStartIndex; i < oldEndIndex; i++) { 665 for (int i = oldStartIndex; i < oldEndIndex; i++) {
667 var node = oldChildren[i]; 666 var node = oldChildren[i];
668 if (!node.interchangeable) 667 if (!node.interchangeable)
669 oldNodeIdMap.putIfAbsent(node._key, () => node); 668 oldNodeIdMap.putIfAbsent(node.key, () => node);
670 } 669 }
671 } 670 }
672 671
673 bool searchForOldNode() { 672 bool searchForOldNode() {
674 if (currentNode.interchangeable) 673 if (currentNode.interchangeable)
675 return false; // never re-order these nodes 674 return false; // never re-order these nodes
676 675
677 ensureOldIdMap(); 676 ensureOldIdMap();
678 oldNode = oldNodeIdMap[currentNode._key]; 677 oldNode = oldNodeIdMap[currentNode.key];
679 if (oldNode == null) 678 if (oldNode == null)
680 return false; 679 return false;
681 680
682 oldNodeIdMap[currentNode._key] = null; // mark it reordered 681 oldNodeIdMap[currentNode.key] = null; // mark it reordered
683 assert(root is ContainerRenderObjectMixin); 682 assert(root is ContainerRenderObjectMixin);
684 assert(old.root is ContainerRenderObjectMixin); 683 assert(old.root is ContainerRenderObjectMixin);
685 assert(oldNode.root != null); 684 assert(oldNode.root != null);
686 685
687 (old.root as ContainerRenderObjectMixin).remove(oldNode.root); // TODO(ian h): Remove cast once the analyzer is cleverer 686 (old.root as ContainerRenderObjectMixin).remove(oldNode.root); // TODO(ian h): Remove cast once the analyzer is cleverer
688 root.add(oldNode.root, before: nextSibling); 687 root.add(oldNode.root, before: nextSibling);
689 688
690 return true; 689 return true;
691 } 690 }
692 691
693 // Scan forwards, this time we may re-order; 692 // Scan forwards, this time we may re-order;
694 nextSibling = root.firstChild; 693 nextSibling = root.firstChild;
695 while (startIndex < endIndex && oldStartIndex < oldEndIndex) { 694 while (startIndex < endIndex && oldStartIndex < oldEndIndex) {
696 currentNode = children[startIndex]; 695 currentNode = children[startIndex];
697 oldNode = oldChildren[oldStartIndex]; 696 oldNode = oldChildren[oldStartIndex];
698 697
699 if (currentNode._key == oldNode._key) { 698 if (currentNode.runtimeType == oldNode.runtimeType && currentNode.key == o ldNode.key) {
700 assert(currentNode.runtimeType == oldNode.runtimeType);
701 nextSibling = root.childAfter(nextSibling); 699 nextSibling = root.childAfter(nextSibling);
702 sync(startIndex); 700 sync(startIndex);
703 startIndex++; 701 startIndex++;
704 advanceOldStartIndex(); 702 advanceOldStartIndex();
705 continue; 703 continue;
706 } 704 }
707 705
708 oldNode = null; 706 oldNode = null;
709 searchForOldNode(); 707 searchForOldNode();
710 sync(startIndex); 708 sync(startIndex);
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
837 if (root.parent == null) { 835 if (root.parent == null) {
838 // we haven't attached it yet 836 // we haven't attached it yet
839 assert(_container.child == null); 837 assert(_container.child == null);
840 _container.child = root; 838 _container.child = root;
841 } 839 }
842 assert(root.parent == _container); 840 assert(root.parent == _container);
843 } 841 }
844 842
845 Widget build() => builder(); 843 Widget build() => builder();
846 } 844 }
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