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

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

Issue 1222913013: Introduce BlockViewport. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 5 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
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 'package:sky/mojo/activity.dart' as activity; 10 import 'package:sky/mojo/activity.dart' as activity;
11 11
12 import '../base/debug.dart';
12 import '../base/hit_test.dart'; 13 import '../base/hit_test.dart';
13 import '../rendering/box.dart'; 14 import '../rendering/box.dart';
14 import '../rendering/object.dart'; 15 import '../rendering/object.dart';
15 import '../rendering/sky_binding.dart'; 16 import '../rendering/sky_binding.dart';
16 17
17 export '../rendering/box.dart' show BoxConstraints, BoxDecoration, Border, Borde rSide, EdgeDims; 18 export '../rendering/box.dart' show BoxConstraints, BoxDecoration, Border, Borde rSide, EdgeDims;
18 export '../rendering/flex.dart' show FlexDirection; 19 export '../rendering/flex.dart' show FlexDirection;
19 export '../rendering/object.dart' show Point, Offset, Size, Rect, Color, Paint, Path; 20 export '../rendering/object.dart' show Point, Offset, Size, Rect, Color, Paint, Path;
20 21
21 final bool _shouldLogRenderDuration = false; 22 final bool _shouldLogRenderDuration = false;
22 23
24 typedef Widget Builder();
23 typedef void WidgetTreeWalker(Widget); 25 typedef void WidgetTreeWalker(Widget);
24 26
25 /// A base class for elements of the widget tree 27 /// A base class for elements of the widget tree
26 abstract class Widget { 28 abstract class Widget {
27 29
28 Widget({ String key }) : _key = key { 30 Widget({ String key }) : _key = key {
29 assert(_isConstructedDuringBuild()); 31 assert(_isConstructedDuringBuild());
30 } 32 }
31 33
32 // TODO(jackson): Remove this workaround for limitation of Dart mixins 34 // TODO(jackson): Remove this workaround for limitation of Dart mixins
33 Widget._withKey(String key) : _key = key { 35 Widget._withKey(String key) : _key = key {
34 assert(_isConstructedDuringBuild()); 36 assert(_isConstructedDuringBuild());
35 } 37 }
36 38
37 // you should not build the UI tree ahead of time, build it only during build( ) 39 // you should not build the UI tree ahead of time, build it only during build( )
38 bool _isConstructedDuringBuild() => this is AbstractWidgetRoot || this is App || _inRenderDirtyComponents; 40 bool _isConstructedDuringBuild() => this is AbstractWidgetRoot || this is App || _inRenderDirtyComponents || _inLayoutCallbackBuilder > 0;
39 41
40 String _key; 42 String _key;
41 43
42 /// A semantic identifer for this widget 44 /// A semantic identifer for this widget
43 /// 45 ///
44 /// Keys are used to find matches when synchronizing two widget trees, for 46 /// Keys are used to find matches when synchronizing two widget trees, for
45 /// example after a [Component] rebuilds. Without keys, two widgets can match 47 /// example after a [Component] rebuilds. Without keys, two widgets can match
46 /// if their runtimeType matches. With keys, the keys must match as well. 48 /// if their runtimeType matches. With keys, the keys must match as well.
47 /// Assigning a key to a widget can improve performance by causing the 49 /// Assigning a key to a widget can improve performance by causing the
48 /// framework to sync widgets that share a lot of common structure and can 50 /// framework to sync widgets that share a lot of common structure and can
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 116
115 /// Override this function to learn when this [Widget] leaves the widget tree. 117 /// Override this function to learn when this [Widget] leaves the widget tree.
116 void didUnmount() { } 118 void didUnmount() { }
117 119
118 RenderObject _root; 120 RenderObject _root;
119 121
120 /// The underlying [RenderObject] associated with this [Widget]. 122 /// The underlying [RenderObject] associated with this [Widget].
121 RenderObject get root => _root; 123 RenderObject get root => _root;
122 124
123 // Subclasses which implements Nodes that become stateful may return true 125 // Subclasses which implements Nodes that become stateful may return true
124 // if the |old| node has become stateful and should be retained. 126 // if the node has become stateful and should be retained.
125 // This is called immediately before _sync(). 127 // This is called immediately before _sync().
126 // Component._retainStatefulNodeIfPossible() calls syncFields(). 128 // Component.retainStatefulNodeIfPossible() calls syncFields().
127 bool _retainStatefulNodeIfPossible(Widget old) => false; 129 bool retainStatefulNodeIfPossible(Widget newNode) => false;
128 130
129 void _sync(Widget old, dynamic slot); 131 void _sync(Widget old, dynamic slot);
130 void updateSlot(dynamic newSlot); 132 void updateSlot(dynamic newSlot);
131 // 'slot' is the identifier that the ancestor RenderObjectWrapper uses to know 133 // 'slot' is the identifier that the ancestor RenderObjectWrapper uses to know
132 // where to put this descendant. If you just defer to a child, then make sure 134 // where to put this descendant. If you just defer to a child, then make sure
133 // to pass them the slot. 135 // to pass them the slot.
134 136
135 Widget findAncestor(Type targetType) { 137 Widget findAncestor(Type targetType) {
136 var ancestor = _parent; 138 var ancestor = _parent;
137 while (ancestor != null && !reflectClass(ancestor.runtimeType).isSubtypeOf(r eflectClass(targetType))) 139 while (ancestor != null && !reflectClass(ancestor.runtimeType).isSubtypeOf(r eflectClass(targetType)))
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 // the child in this slot has gone away 175 // the child in this slot has gone away
174 assert(oldNode.mounted); 176 assert(oldNode.mounted);
175 oldNode.detachRoot(); 177 oldNode.detachRoot();
176 removeChild(oldNode); 178 removeChild(oldNode);
177 assert(!oldNode.mounted); 179 assert(!oldNode.mounted);
178 return null; 180 return null;
179 } 181 }
180 182
181 if (oldNode != null) { 183 if (oldNode != null) {
182 if (oldNode.runtimeType == newNode.runtimeType && oldNode.key == newNode.k ey) { 184 if (oldNode.runtimeType == newNode.runtimeType && oldNode.key == newNode.k ey) {
183 if (newNode._retainStatefulNodeIfPossible(oldNode)) { 185 if (oldNode.retainStatefulNodeIfPossible(newNode)) {
184 assert(oldNode.mounted); 186 assert(oldNode.mounted);
185 assert(!newNode.mounted); 187 assert(!newNode.mounted);
186 oldNode.setParent(this); 188 oldNode.setParent(this);
187 oldNode._sync(newNode, slot); 189 oldNode._sync(newNode, slot);
188 assert(oldNode.root is RenderObject); 190 assert(oldNode.root is RenderObject);
189 return oldNode; 191 return oldNode;
190 } else { 192 } else {
191 oldNode.setParent(null); 193 oldNode.setParent(null);
192 } 194 }
193 } else { 195 } else {
(...skipping 19 matching lines...) Expand all
213 if (children.length > 0) { 215 if (children.length > 0) {
214 Widget lastChild = children.removeLast(); 216 Widget lastChild = children.removeLast();
215 String nextStartPrefix = prefix + ' +-'; 217 String nextStartPrefix = prefix + ' +-';
216 String nextPrefix = prefix + ' | '; 218 String nextPrefix = prefix + ' | ';
217 for (Widget child in children) 219 for (Widget child in children)
218 childrenString += child.toString(nextPrefix, nextStartPrefix); 220 childrenString += child.toString(nextPrefix, nextStartPrefix);
219 String lastStartPrefix = prefix + ' \'-'; 221 String lastStartPrefix = prefix + ' \'-';
220 String lastPrefix = prefix + ' '; 222 String lastPrefix = prefix + ' ';
221 childrenString += lastChild.toString(lastPrefix, lastStartPrefix); 223 childrenString += lastChild.toString(lastPrefix, lastStartPrefix);
222 } 224 }
225 return '$startPrefix${toStringName()}\n$childrenString';
226 }
227 String toStringName() {
223 if (key == null) 228 if (key == null)
224 return '$startPrefix$runtimeType(unkeyed)\n$childrenString'; 229 return '$runtimeType(unkeyed; hashCode=$hashCode)';
225 return '$startPrefix$runtimeType("$key")\n$childrenString'; 230 return '$runtimeType("$key"; hashCode=$hashCode)';
226 } 231 }
227 232
228 } 233 }
229 234
230 235
231 // Descendants of TagNode provide a way to tag RenderObjectWrapper and 236 // Descendants of TagNode provide a way to tag RenderObjectWrapper and
232 // Component nodes with annotations, such as event listeners, 237 // Component nodes with annotations, such as event listeners,
233 // stylistic information, etc. 238 // stylistic information, etc.
234 abstract class TagNode extends Widget { 239 abstract class TagNode extends Widget {
235 240
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 void _sync(Widget old, dynamic slot) { 536 void _sync(Widget old, dynamic slot) {
532 assert(!_disqualifiedFromEverAppearingAgain); 537 assert(!_disqualifiedFromEverAppearingAgain);
533 super._sync(old, slot); 538 super._sync(old, slot);
534 } 539 }
535 540
536 Widget syncChild(Widget node, Widget oldNode, dynamic slot) { 541 Widget syncChild(Widget node, Widget oldNode, dynamic slot) {
537 assert(!_disqualifiedFromEverAppearingAgain); 542 assert(!_disqualifiedFromEverAppearingAgain);
538 return super.syncChild(node, oldNode, slot); 543 return super.syncChild(node, oldNode, slot);
539 } 544 }
540 545
541 bool _retainStatefulNodeIfPossible(StatefulComponent old) { 546 bool retainStatefulNodeIfPossible(StatefulComponent newNode) {
542 assert(!_disqualifiedFromEverAppearingAgain); 547 assert(!_disqualifiedFromEverAppearingAgain);
548 assert(newNode != null);
549 assert(runtimeType == newNode.runtimeType);
550 assert(key == newNode.key);
551 assert(_built != null);
552 newNode._disqualifiedFromEverAppearingAgain = true;
543 553
544 if (old == null) 554 newNode._built = _built;
545 return false; 555 _built = null;
546 556
547 assert(runtimeType == old.runtimeType); 557 syncFields(newNode);
548 assert(key == old.key); 558 _dirty = true;
549 559
550 // Make |this|, the newly-created object, into the "old" Component, and kill it
551 _built = old._built;
552 assert(_built != null);
553 _disqualifiedFromEverAppearingAgain = true;
554
555 // Make |old| the "new" component
556 old._built = null;
557 old._dirty = true;
558 old.syncFields(this);
559 return true; 560 return true;
560 } 561 }
561 562
562 // This is called by _retainStatefulNodeIfPossible(), during 563 // This is called by retainStatefulNodeIfPossible(), during
563 // syncChild(), just before _sync() is called. Derived 564 // syncChild(), just before _sync() is called. Derived
564 // classes should override this method to update `this` to 565 // classes should override this method to update `this` to
565 // account for the new values the parent passed to `source`. 566 // account for the new values the parent passed to `source`.
566 // Make sure to call super.syncFields(source) unless you are 567 // Make sure to call super.syncFields(source) unless you are
567 // extending StatefulComponent directly. 568 // extending StatefulComponent directly.
568 void syncFields(Component source); 569 void syncFields(Component source);
569 570
570 void setState(Function fn()) { 571 void setState(Function fn()) {
571 assert(!_disqualifiedFromEverAppearingAgain); 572 assert(!_disqualifiedFromEverAppearingAgain);
572 fn(); 573 fn();
573 scheduleBuild(); 574 scheduleBuild();
574 } 575 }
575 } 576 }
576 577
577 Set<Component> _dirtyComponents = new Set<Component>(); 578 Set<Component> _dirtyComponents = new Set<Component>();
578 bool _buildScheduled = false; 579 bool _buildScheduled = false;
579 bool _inRenderDirtyComponents = false; 580 bool _inRenderDirtyComponents = false;
581 int _inLayoutCallbackBuilder = 0;
582
583 class LayoutCallbackBuilderHandle { bool _active = true; }
584 LayoutCallbackBuilderHandle enterLayoutCallbackBuilder() {
585 if (!inDebugBuild)
586 return null;
587 _inLayoutCallbackBuilder += 1;
588 return new LayoutCallbackBuilderHandle();
589 }
590 void exitLayoutCallbackBuilder(LayoutCallbackBuilderHandle handle) {
591 if (!inDebugBuild)
592 return;
593 assert(handle._active);
594 handle._active = false;
595 _inLayoutCallbackBuilder -= 1;
596 }
580 597
581 List<int> _debugFrameTimes = <int>[]; 598 List<int> _debugFrameTimes = <int>[];
582 599
583 void _absorbDirtyComponents(List<Component> list) { 600 void _absorbDirtyComponents(List<Component> list) {
584 list.addAll(_dirtyComponents); 601 list.addAll(_dirtyComponents);
585 _dirtyComponents.clear(); 602 _dirtyComponents.clear();
586 list.sort((Component a, Component b) => a._order - b._order); 603 list.sort((Component a, Component b) => a._order - b._order);
587 } 604 }
588 605
589 void _buildDirtyComponents() { 606 void _buildDirtyComponents() {
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 RenderObject createNode(); 667 RenderObject createNode();
651 668
652 static final Map<RenderObject, RenderObjectWrapper> _nodeMap = 669 static final Map<RenderObject, RenderObjectWrapper> _nodeMap =
653 new HashMap<RenderObject, RenderObjectWrapper>(); 670 new HashMap<RenderObject, RenderObjectWrapper>();
654 static RenderObjectWrapper _getMounted(RenderObject node) => _nodeMap[node]; 671 static RenderObjectWrapper _getMounted(RenderObject node) => _nodeMap[node];
655 672
656 RenderObjectWrapper _ancestor; 673 RenderObjectWrapper _ancestor;
657 void insertChildRoot(RenderObjectWrapper child, dynamic slot); 674 void insertChildRoot(RenderObjectWrapper child, dynamic slot);
658 void detachChildRoot(RenderObjectWrapper child); 675 void detachChildRoot(RenderObjectWrapper child);
659 676
677 void doRetainStatefulNode(RenderObjectWrapper newNode) {
abarth-chromium 2015/07/08 21:56:20 doRetainStatefulNode -> retainStatefulRenderObject
678 newNode._root = _root;
679 newNode._ancestor = _ancestor;
680 }
681
660 void _sync(RenderObjectWrapper old, dynamic slot) { 682 void _sync(RenderObjectWrapper old, dynamic slot) {
661 // TODO(abarth): We should split RenderObjectWrapper into two pieces so that 683 // TODO(abarth): We should split RenderObjectWrapper into two pieces so that
662 // RenderViewObject doesn't need to inherit all this code it 684 // RenderViewObject doesn't need to inherit all this code it
663 // doesn't need. 685 // doesn't need.
664 assert(parent != null || this is RenderViewWrapper); 686 assert(parent != null || this is RenderViewWrapper);
665 if (old == null) { 687 if (old == null) {
666 _root = createNode(); 688 _root = createNode();
689 assert(_root != null);
667 _ancestor = findAncestor(RenderObjectWrapper); 690 _ancestor = findAncestor(RenderObjectWrapper);
668 if (_ancestor is RenderObjectWrapper) 691 if (_ancestor is RenderObjectWrapper)
669 _ancestor.insertChildRoot(this, slot); 692 _ancestor.insertChildRoot(this, slot);
670 } else { 693 } else {
671 assert(old is RenderObjectWrapper); 694 assert(old is RenderObjectWrapper);
672 _root = old.root; 695 _root = old.root;
673 _ancestor = old._ancestor; 696 _ancestor = old._ancestor;
697 assert(_root != null);
674 } 698 }
675 assert(_root == root); // in case a subclass reintroduces it 699 assert(_root == root); // in case a subclass reintroduces it
676 assert(root != null); 700 assert(root != null);
677 assert(mounted); 701 assert(mounted);
678 _nodeMap[root] = this; 702 _nodeMap[root] = this;
679 syncRenderObject(old); 703 syncRenderObject(old);
680 } 704 }
681 705
682 void updateSlot(dynamic newSlot) { 706 void updateSlot(dynamic newSlot) {
683 // We never use the slot except during sync(), in which 707 // We never use the slot except during sync(), in which
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after
1067 void runApp(App app, { RenderView renderViewOverride, bool enableProfilingLoop: false }) { 1091 void runApp(App app, { RenderView renderViewOverride, bool enableProfilingLoop: false }) {
1068 WidgetSkyBinding.initWidgetSkyBinding(renderViewOverride: renderViewOverride); 1092 WidgetSkyBinding.initWidgetSkyBinding(renderViewOverride: renderViewOverride);
1069 new AppContainer(app); 1093 new AppContainer(app);
1070 if (enableProfilingLoop) { 1094 if (enableProfilingLoop) {
1071 new Timer.periodic(const Duration(milliseconds: 20), (_) { 1095 new Timer.periodic(const Duration(milliseconds: 20), (_) {
1072 app.scheduleBuild(); 1096 app.scheduleBuild();
1073 }); 1097 });
1074 } 1098 }
1075 } 1099 }
1076 1100
1077 typedef Widget Builder();
1078
1079 class RenderBoxToWidgetAdapter extends AbstractWidgetRoot { 1101 class RenderBoxToWidgetAdapter extends AbstractWidgetRoot {
1080 1102
1081 RenderBoxToWidgetAdapter( 1103 RenderBoxToWidgetAdapter(
1082 RenderObjectWithChildMixin<RenderBox> container, 1104 RenderObjectWithChildMixin<RenderBox> container,
1083 this.builder 1105 this.builder
1084 ) : _container = container, super() { 1106 ) : _container = container, super() {
1085 assert(builder != null); 1107 assert(builder != null);
1086 } 1108 }
1087 1109
1088 RenderObjectWithChildMixin<RenderBox> _container; 1110 RenderObjectWithChildMixin<RenderBox> _container;
(...skipping 20 matching lines...) Expand all
1109 if (root.parent == null) { 1131 if (root.parent == null) {
1110 // we haven't attached it yet 1132 // we haven't attached it yet
1111 assert(_container.child == null); 1133 assert(_container.child == null);
1112 _container.child = root; 1134 _container.child = root;
1113 } 1135 }
1114 assert(root.parent == _container); 1136 assert(root.parent == _container);
1115 } 1137 }
1116 1138
1117 Widget build() => builder(); 1139 Widget build() => builder();
1118 } 1140 }
OLDNEW
« sky/sdk/lib/widgets/block_viewport.dart ('K') | « sky/sdk/lib/widgets/block_viewport.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698