Chromium Code Reviews| Index: sky/sdk/lib/widgets/widget.dart |
| diff --git a/sky/sdk/lib/widgets/widget.dart b/sky/sdk/lib/widgets/widget.dart |
| index 7bfc3077a34da2f3e083db8794f47f8a1c0e6bb6..b7185c9800e329b9490c66b33a81c3b038e4ec4a 100644 |
| --- a/sky/sdk/lib/widgets/widget.dart |
| +++ b/sky/sdk/lib/widgets/widget.dart |
| @@ -9,6 +9,7 @@ import 'dart:sky' as sky; |
| import 'package:sky/mojo/activity.dart' as activity; |
| +import '../base/debug.dart'; |
| import '../base/hit_test.dart'; |
| import '../rendering/box.dart'; |
| import '../rendering/object.dart'; |
| @@ -20,6 +21,7 @@ export '../rendering/object.dart' show Point, Offset, Size, Rect, Color, Paint, |
| final bool _shouldLogRenderDuration = false; |
| +typedef Widget Builder(); |
| typedef void WidgetTreeWalker(Widget); |
| /// A base class for elements of the widget tree |
| @@ -35,7 +37,7 @@ abstract class Widget { |
| } |
| // you should not build the UI tree ahead of time, build it only during build() |
| - bool _isConstructedDuringBuild() => this is AbstractWidgetRoot || this is App || _inRenderDirtyComponents; |
| + bool _isConstructedDuringBuild() => this is AbstractWidgetRoot || this is App || _inRenderDirtyComponents || _inLayoutCallbackBuilder > 0; |
| String _key; |
| @@ -121,10 +123,10 @@ abstract class Widget { |
| RenderObject get root => _root; |
| // Subclasses which implements Nodes that become stateful may return true |
| - // if the |old| node has become stateful and should be retained. |
| + // if the node has become stateful and should be retained. |
| // This is called immediately before _sync(). |
| - // Component._retainStatefulNodeIfPossible() calls syncFields(). |
| - bool _retainStatefulNodeIfPossible(Widget old) => false; |
| + // Component.retainStatefulNodeIfPossible() calls syncFields(). |
| + bool retainStatefulNodeIfPossible(Widget newNode) => false; |
| void _sync(Widget old, dynamic slot); |
| void updateSlot(dynamic newSlot); |
| @@ -180,7 +182,7 @@ abstract class Widget { |
| if (oldNode != null) { |
| if (oldNode.runtimeType == newNode.runtimeType && oldNode.key == newNode.key) { |
| - if (newNode._retainStatefulNodeIfPossible(oldNode)) { |
| + if (oldNode.retainStatefulNodeIfPossible(newNode)) { |
| assert(oldNode.mounted); |
| assert(!newNode.mounted); |
| oldNode.setParent(this); |
| @@ -220,9 +222,12 @@ abstract class Widget { |
| String lastPrefix = prefix + ' '; |
| childrenString += lastChild.toString(lastPrefix, lastStartPrefix); |
| } |
| + return '$startPrefix${toStringName()}\n$childrenString'; |
| + } |
| + String toStringName() { |
| if (key == null) |
| - return '$startPrefix$runtimeType(unkeyed)\n$childrenString'; |
| - return '$startPrefix$runtimeType("$key")\n$childrenString'; |
| + return '$runtimeType(unkeyed; hashCode=$hashCode)'; |
| + return '$runtimeType("$key"; hashCode=$hashCode)'; |
| } |
| } |
| @@ -538,28 +543,24 @@ abstract class StatefulComponent extends Component { |
| return super.syncChild(node, oldNode, slot); |
| } |
| - bool _retainStatefulNodeIfPossible(StatefulComponent old) { |
| + bool retainStatefulNodeIfPossible(StatefulComponent newNode) { |
| assert(!_disqualifiedFromEverAppearingAgain); |
| + assert(newNode != null); |
| + assert(runtimeType == newNode.runtimeType); |
| + assert(key == newNode.key); |
| + assert(_built != null); |
| + newNode._disqualifiedFromEverAppearingAgain = true; |
| - if (old == null) |
| - return false; |
| - |
| - assert(runtimeType == old.runtimeType); |
| - assert(key == old.key); |
| + newNode._built = _built; |
| + _built = null; |
| - // Make |this|, the newly-created object, into the "old" Component, and kill it |
| - _built = old._built; |
| - assert(_built != null); |
| - _disqualifiedFromEverAppearingAgain = true; |
| + syncFields(newNode); |
| + _dirty = true; |
| - // Make |old| the "new" component |
| - old._built = null; |
| - old._dirty = true; |
| - old.syncFields(this); |
| return true; |
| } |
| - // This is called by _retainStatefulNodeIfPossible(), during |
| + // This is called by retainStatefulNodeIfPossible(), during |
| // syncChild(), just before _sync() is called. Derived |
| // classes should override this method to update `this` to |
| // account for the new values the parent passed to `source`. |
| @@ -577,6 +578,22 @@ abstract class StatefulComponent extends Component { |
| Set<Component> _dirtyComponents = new Set<Component>(); |
| bool _buildScheduled = false; |
| bool _inRenderDirtyComponents = false; |
| +int _inLayoutCallbackBuilder = 0; |
| + |
| +class LayoutCallbackBuilderHandle { bool _active = true; } |
| +LayoutCallbackBuilderHandle enterLayoutCallbackBuilder() { |
| + if (!inDebugBuild) |
| + return null; |
| + _inLayoutCallbackBuilder += 1; |
| + return new LayoutCallbackBuilderHandle(); |
| +} |
| +void exitLayoutCallbackBuilder(LayoutCallbackBuilderHandle handle) { |
| + if (!inDebugBuild) |
| + return; |
| + assert(handle._active); |
| + handle._active = false; |
| + _inLayoutCallbackBuilder -= 1; |
| +} |
| List<int> _debugFrameTimes = <int>[]; |
| @@ -657,6 +674,11 @@ abstract class RenderObjectWrapper extends Widget { |
| void insertChildRoot(RenderObjectWrapper child, dynamic slot); |
| void detachChildRoot(RenderObjectWrapper child); |
| + void doRetainStatefulNode(RenderObjectWrapper newNode) { |
|
abarth-chromium
2015/07/08 21:56:20
doRetainStatefulNode -> retainStatefulRenderObject
|
| + newNode._root = _root; |
| + newNode._ancestor = _ancestor; |
| + } |
| + |
| void _sync(RenderObjectWrapper old, dynamic slot) { |
| // TODO(abarth): We should split RenderObjectWrapper into two pieces so that |
| // RenderViewObject doesn't need to inherit all this code it |
| @@ -664,6 +686,7 @@ abstract class RenderObjectWrapper extends Widget { |
| assert(parent != null || this is RenderViewWrapper); |
| if (old == null) { |
| _root = createNode(); |
| + assert(_root != null); |
| _ancestor = findAncestor(RenderObjectWrapper); |
| if (_ancestor is RenderObjectWrapper) |
| _ancestor.insertChildRoot(this, slot); |
| @@ -671,6 +694,7 @@ abstract class RenderObjectWrapper extends Widget { |
| assert(old is RenderObjectWrapper); |
| _root = old.root; |
| _ancestor = old._ancestor; |
| + assert(_root != null); |
| } |
| assert(_root == root); // in case a subclass reintroduces it |
| assert(root != null); |
| @@ -1074,8 +1098,6 @@ void runApp(App app, { RenderView renderViewOverride, bool enableProfilingLoop: |
| } |
| } |
| -typedef Widget Builder(); |
| - |
| class RenderBoxToWidgetAdapter extends AbstractWidgetRoot { |
| RenderBoxToWidgetAdapter( |