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 'app.dart'; | 7 import 'app.dart'; |
8 import 'dart:async'; | 8 import 'dart:async'; |
9 import 'dart:collection'; | 9 import 'dart:collection'; |
10 import 'dart:mirrors'; | 10 import 'dart:mirrors'; |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 return ancestor; | 109 return ancestor; |
110 } | 110 } |
111 | 111 |
112 void removeChild(UINode node) { | 112 void removeChild(UINode node) { |
113 node.remove(); | 113 node.remove(); |
114 } | 114 } |
115 | 115 |
116 // Returns the child which should be retained as the child of this node. | 116 // Returns the child which should be retained as the child of this node. |
117 UINode syncChild(UINode node, UINode oldNode, dynamic slot) { | 117 UINode syncChild(UINode node, UINode oldNode, dynamic slot) { |
118 | 118 |
| 119 assert(oldNode is! Component || !oldNode._disqualifiedFromEverAppearingAgain
); |
| 120 |
119 if (node == oldNode) { | 121 if (node == oldNode) { |
120 assert(node == null || node.mounted); | 122 assert(node == null || node.mounted); |
121 return node; // Nothing to do. Subtrees must be identical. | 123 return node; // Nothing to do. Subtrees must be identical. |
122 } | 124 } |
123 | 125 |
124 if (node == null) { | 126 if (node == null) { |
125 // the child in this slot has gone away | 127 // the child in this slot has gone away |
126 assert(oldNode.mounted); | 128 assert(oldNode.mounted); |
127 removeChild(oldNode); | 129 removeChild(oldNode); |
128 assert(!oldNode.mounted); | 130 assert(!oldNode.mounted); |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 } | 326 } |
325 | 327 |
326 void remove() { | 328 void remove() { |
327 assert(root != null); | 329 assert(root != null); |
328 _nodeMap.remove(root); | 330 _nodeMap.remove(root); |
329 super.remove(); | 331 super.remove(); |
330 } | 332 } |
331 } | 333 } |
332 | 334 |
333 abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper { | 335 abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper { |
334 final UINode child; | 336 UINode _child; |
| 337 UINode get child => _child; |
335 | 338 |
336 OneChildRenderObjectWrapper({ this.child, Object key }) : super(key: key); | 339 OneChildRenderObjectWrapper({ UINode child, Object key }) : _child = child, su
per(key: key); |
337 | 340 |
338 void syncRenderObject(RenderObjectWrapper old) { | 341 void syncRenderObject(RenderObjectWrapper old) { |
339 super.syncRenderObject(old); | 342 super.syncRenderObject(old); |
340 UINode oldChild = old == null ? null : (old as OneChildRenderObjectWrapper).
child; | 343 UINode oldChild = old == null ? null : (old as OneChildRenderObjectWrapper).
child; |
341 syncChild(child, oldChild, null); | 344 _child = syncChild(child, oldChild, null); |
342 } | 345 } |
343 | 346 |
344 void insert(RenderObjectWrapper child, dynamic slot) { | 347 void insert(RenderObjectWrapper child, dynamic slot) { |
345 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer | 348 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer |
346 assert(slot == null); | 349 assert(slot == null); |
347 assert(root is RenderObjectWithChildMixin); | 350 assert(root is RenderObjectWithChildMixin); |
348 root.child = child.root; | 351 root.child = child.root; |
349 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer | 352 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer |
350 } | 353 } |
351 | 354 |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
524 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer | 527 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer |
525 assert(slot == null || slot is RenderObject); | 528 assert(slot == null || slot is RenderObject); |
526 assert(root is ContainerRenderObjectMixin); | 529 assert(root is ContainerRenderObjectMixin); |
527 root.add(child.root, before: slot); | 530 root.add(child.root, before: slot); |
528 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer | 531 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer |
529 } | 532 } |
530 | 533 |
531 void removeChild(UINode node) { | 534 void removeChild(UINode node) { |
532 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer | 535 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer |
533 assert(root is ContainerRenderObjectMixin); | 536 assert(root is ContainerRenderObjectMixin); |
| 537 assert(node.root.parent == root); |
534 root.remove(node.root); | 538 root.remove(node.root); |
535 super.removeChild(node); | 539 super.removeChild(node); |
536 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer | 540 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer |
537 } | 541 } |
538 | 542 |
539 void remove() { | 543 void remove() { |
540 assert(children != null); | 544 assert(children != null); |
541 for (var child in children) { | 545 for (var child in children) { |
542 assert(child != null); | 546 assert(child != null); |
543 removeChild(child); | 547 removeChild(child); |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
776 root.src = src; | 780 root.src = src; |
777 root.requestedSize = size; | 781 root.requestedSize = size; |
778 } | 782 } |
779 | 783 |
780 void insert(RenderObjectWrapper child, dynamic slot) { | 784 void insert(RenderObjectWrapper child, dynamic slot) { |
781 assert(false); | 785 assert(false); |
782 // Image does not support having children currently | 786 // Image does not support having children currently |
783 } | 787 } |
784 } | 788 } |
785 | 789 |
786 List<Component> _dirtyComponents = new List<Component>(); | 790 Set<Component> _dirtyComponents = new Set<Component>(); |
787 bool _buildScheduled = false; | 791 bool _buildScheduled = false; |
788 bool _inRenderDirtyComponents = false; | 792 bool _inRenderDirtyComponents = false; |
789 | 793 |
790 void _buildDirtyComponents() { | 794 void _buildDirtyComponents() { |
791 //_tracing.begin('fn::_buildDirtyComponents'); | 795 //_tracing.begin('fn::_buildDirtyComponents'); |
792 | 796 |
793 Stopwatch sw; | 797 Stopwatch sw; |
794 if (_shouldLogRenderDuration) | 798 if (_shouldLogRenderDuration) |
795 sw = new Stopwatch()..start(); | 799 sw = new Stopwatch()..start(); |
796 | 800 |
797 try { | 801 try { |
798 _inRenderDirtyComponents = true; | 802 _inRenderDirtyComponents = true; |
799 | 803 |
800 _dirtyComponents.sort((a, b) => a._order - b._order); | 804 List<Component> sortedDirtyComponents = _dirtyComponents.toList(); |
801 for (var comp in _dirtyComponents) { | 805 sortedDirtyComponents.sort((Component a, Component b) => a._order - b._order
); |
| 806 for (var comp in sortedDirtyComponents) { |
802 comp._buildIfDirty(); | 807 comp._buildIfDirty(); |
803 } | 808 } |
804 | 809 |
805 _dirtyComponents.clear(); | 810 _dirtyComponents.clear(); |
806 _buildScheduled = false; | 811 _buildScheduled = false; |
807 } finally { | 812 } finally { |
808 _inRenderDirtyComponents = false; | 813 _inRenderDirtyComponents = false; |
809 } | 814 } |
810 | 815 |
811 UINode._notifyMountStatusChanged(); | 816 UINode._notifyMountStatusChanged(); |
(...skipping 13 matching lines...) Expand all Loading... |
825 if (!_buildScheduled) { | 830 if (!_buildScheduled) { |
826 _buildScheduled = true; | 831 _buildScheduled = true; |
827 new Future.microtask(_buildDirtyComponents); | 832 new Future.microtask(_buildDirtyComponents); |
828 } | 833 } |
829 } | 834 } |
830 | 835 |
831 abstract class Component extends UINode { | 836 abstract class Component extends UINode { |
832 bool get _isBuilding => _currentlyBuilding == this; | 837 bool get _isBuilding => _currentlyBuilding == this; |
833 bool _dirty = true; | 838 bool _dirty = true; |
834 | 839 |
| 840 bool _disqualifiedFromEverAppearingAgain = false; |
| 841 |
835 UINode _built; | 842 UINode _built; |
836 final int _order; | 843 final int _order; |
837 static int _currentOrder = 0; | 844 static int _currentOrder = 0; |
838 bool _stateful; | 845 bool _stateful; |
839 static Component _currentlyBuilding; | 846 static Component _currentlyBuilding; |
840 List<Function> _mountCallbacks; | 847 List<Function> _mountCallbacks; |
841 List<Function> _unmountCallbacks; | 848 List<Function> _unmountCallbacks; |
842 dynamic _slot; // cached slot from the last time we were synced | 849 dynamic _slot; // cached slot from the last time we were synced |
843 | 850 |
844 void onDidMount(Function fn) { | 851 void onDidMount(Function fn) { |
(...skipping 12 matching lines...) Expand all Loading... |
857 | 864 |
858 Component({ Object key, bool stateful }) | 865 Component({ Object key, bool stateful }) |
859 : _stateful = stateful != null ? stateful : false, | 866 : _stateful = stateful != null ? stateful : false, |
860 _order = _currentOrder + 1, | 867 _order = _currentOrder + 1, |
861 super(key: key); | 868 super(key: key); |
862 | 869 |
863 Component.fromArgs(Object key, bool stateful) | 870 Component.fromArgs(Object key, bool stateful) |
864 : this(key: key, stateful: stateful); | 871 : this(key: key, stateful: stateful); |
865 | 872 |
866 void _didMount() { | 873 void _didMount() { |
| 874 assert(!_disqualifiedFromEverAppearingAgain); |
867 super._didMount(); | 875 super._didMount(); |
868 if (_mountCallbacks != null) | 876 if (_mountCallbacks != null) |
869 for (Function fn in _mountCallbacks) | 877 for (Function fn in _mountCallbacks) |
870 fn(); | 878 fn(); |
871 } | 879 } |
872 | 880 |
873 void _didUnmount() { | 881 void _didUnmount() { |
874 super._didUnmount(); | 882 super._didUnmount(); |
875 if (_unmountCallbacks != null) | 883 if (_unmountCallbacks != null) |
876 for (Function fn in _unmountCallbacks) | 884 for (Function fn in _unmountCallbacks) |
877 fn(); | 885 fn(); |
878 } | 886 } |
879 | 887 |
880 // TODO(rafaelw): It seems wrong to expose DOM at all. This is presently | 888 // TODO(rafaelw): It seems wrong to expose DOM at all. This is presently |
881 // needed to get sizing info. | 889 // needed to get sizing info. |
882 RenderObject getRoot() => root; | 890 RenderObject getRoot() => root; |
883 | 891 |
884 void remove() { | 892 void remove() { |
885 assert(_built != null); | 893 assert(_built != null); |
886 assert(root != null); | 894 assert(root != null); |
887 removeChild(_built); | 895 removeChild(_built); |
888 _built = null; | 896 _built = null; |
889 super.remove(); | 897 super.remove(); |
890 } | 898 } |
891 | 899 |
892 bool _willSync(UINode old) { | 900 bool _willSync(UINode old) { |
| 901 assert(!_disqualifiedFromEverAppearingAgain); |
| 902 |
893 Component oldComponent = old as Component; | 903 Component oldComponent = old as Component; |
894 if (oldComponent == null || !oldComponent._stateful) | 904 if (oldComponent == null || !oldComponent._stateful) |
895 return false; | 905 return false; |
896 | 906 |
897 // Make |this| the "old" Component | 907 // Make |this| the "old" Component |
898 _stateful = false; | 908 _stateful = false; |
899 _built = oldComponent._built; | 909 _built = oldComponent._built; |
900 assert(_built != null); | 910 assert(_built != null); |
| 911 _disqualifiedFromEverAppearingAgain = true; |
901 | 912 |
902 // Make |oldComponent| the "new" component | 913 // Make |oldComponent| the "new" component |
903 reflect.copyPublicFields(this, oldComponent); | 914 reflect.copyPublicFields(this, oldComponent); |
904 oldComponent._built = null; | 915 oldComponent._built = null; |
905 oldComponent._dirty = true; | 916 oldComponent._dirty = true; |
906 return true; | 917 return true; |
907 } | 918 } |
908 | 919 |
909 /* There are three cases here: | 920 /* There are three cases here: |
910 * 1) Building for the first time: | 921 * 1) Building for the first time: |
911 * assert(_built == null && old == null) | 922 * assert(_built == null && old == null) |
912 * 2) Re-building (because a dirty flag got set): | 923 * 2) Re-building (because a dirty flag got set): |
913 * assert(_built != null && old == null) | 924 * assert(_built != null && old == null) |
914 * 3) Syncing against an old version | 925 * 3) Syncing against an old version |
915 * assert(_built == null && old != null) | 926 * assert(_built == null && old != null) |
916 */ | 927 */ |
917 void _sync(UINode old, dynamic slot) { | 928 void _sync(UINode old, dynamic slot) { |
918 assert(_built == null || old == null); | 929 assert(_built == null || old == null); |
| 930 assert(!_disqualifiedFromEverAppearingAgain); |
919 | 931 |
920 Component oldComponent = old as Component; | 932 Component oldComponent = old as Component; |
921 | 933 |
922 _slot = slot; | 934 _slot = slot; |
923 | 935 |
924 var oldBuilt; | 936 var oldBuilt; |
925 if (oldComponent == null) { | 937 if (oldComponent == null) { |
926 oldBuilt = _built; | 938 oldBuilt = _built; |
927 } else { | 939 } else { |
928 assert(_built == null); | 940 assert(_built == null); |
929 oldBuilt = oldComponent._built; | 941 oldBuilt = oldComponent._built; |
930 } | 942 } |
931 | 943 |
932 int lastOrder = _currentOrder; | 944 int lastOrder = _currentOrder; |
933 _currentOrder = _order; | 945 _currentOrder = _order; |
934 _currentlyBuilding = this; | 946 _currentlyBuilding = this; |
935 _built = build(); | 947 _built = build(); |
936 assert(_built != null); | 948 assert(_built != null); |
937 _currentlyBuilding = null; | 949 _currentlyBuilding = null; |
938 _currentOrder = lastOrder; | 950 _currentOrder = lastOrder; |
939 | 951 |
940 _built = syncChild(_built, oldBuilt, slot); | 952 _built = syncChild(_built, oldBuilt, slot); |
941 assert(_built != null); | 953 assert(_built != null); |
942 _dirty = false; | 954 _dirty = false; |
943 root = _built.root; | 955 root = _built.root; |
944 assert(root != null); | 956 assert(root != null); |
945 } | 957 } |
946 | 958 |
947 void _buildIfDirty() { | 959 void _buildIfDirty() { |
| 960 assert(!_disqualifiedFromEverAppearingAgain); |
948 if (!_dirty || !_mounted) | 961 if (!_dirty || !_mounted) |
949 return; | 962 return; |
950 | 963 |
951 assert(root != null); | 964 assert(root != null); |
952 _sync(null, _slot); | 965 _sync(null, _slot); |
953 } | 966 } |
954 | 967 |
955 void scheduleBuild() { | 968 void scheduleBuild() { |
956 setState(() {}); | 969 setState(() {}); |
957 } | 970 } |
958 | 971 |
959 void setState(Function fn()) { | 972 void setState(Function fn()) { |
| 973 assert(!_disqualifiedFromEverAppearingAgain); |
960 _stateful = true; | 974 _stateful = true; |
961 fn(); | 975 fn(); |
962 if (_isBuilding || _dirty || !_mounted) | 976 if (_isBuilding || _dirty || !_mounted) |
963 return; | 977 return; |
964 | 978 |
965 _dirty = true; | 979 _dirty = true; |
966 _scheduleComponentForRender(this); | 980 _scheduleComponentForRender(this); |
967 } | 981 } |
968 | 982 |
969 UINode build(); | 983 UINode build(); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1060 assert(root.parent is RenderView); | 1074 assert(root.parent is RenderView); |
1061 } | 1075 } |
1062 } | 1076 } |
1063 | 1077 |
1064 class Text extends Component { | 1078 class Text extends Component { |
1065 Text(this.data) : super(key: '*text*'); | 1079 Text(this.data) : super(key: '*text*'); |
1066 final String data; | 1080 final String data; |
1067 bool get interchangeable => true; | 1081 bool get interchangeable => true; |
1068 UINode build() => new Paragraph(text: data); | 1082 UINode build() => new Paragraph(text: data); |
1069 } | 1083 } |
OLD | NEW |