Index: sky/sdk/lib/widgets/widget.dart |
diff --git a/sky/sdk/lib/widgets/widget.dart b/sky/sdk/lib/widgets/widget.dart |
index e96f3d22db5626d9a5c5e2e8480c1eb3a85678ef..11fb763a7db1f1986c907bfe9a7fb4ae705b54b5 100644 |
--- a/sky/sdk/lib/widgets/widget.dart |
+++ b/sky/sdk/lib/widgets/widget.dart |
@@ -90,11 +90,6 @@ abstract class Widget { |
// 'slot' is the identifier that the parent RenderObjectWrapper uses to know |
// where to put this descendant |
- void remove() { |
- _root = null; |
- setParent(null); |
- } |
- |
Widget findAncestor(Type targetType) { |
var ancestor = _parent; |
while (ancestor != null && !reflectClass(ancestor.runtimeType).isSubtypeOf(reflectClass(targetType))) |
@@ -102,10 +97,17 @@ abstract class Widget { |
return ancestor; |
} |
+ void remove() { |
+ _root = null; |
+ setParent(null); |
+ } |
+ |
void removeChild(Widget node) { |
node.remove(); |
} |
+ void detachRoot(); |
+ |
// Returns the child which should be retained as the child of this node. |
Widget syncChild(Widget node, Widget oldNode, dynamic slot) { |
@@ -113,12 +115,14 @@ abstract class Widget { |
if (node == oldNode) { |
assert(node == null || node.mounted); |
+ assert(node is! RenderObjectWrapper || node._ancestor != null); |
return node; // Nothing to do. Subtrees must be identical. |
} |
if (node == null) { |
// the child in this slot has gone away |
assert(oldNode.mounted); |
+ oldNode.detachRoot(); |
removeChild(oldNode); |
assert(!oldNode.mounted); |
return null; |
@@ -138,6 +142,7 @@ abstract class Widget { |
if (oldNode != null && |
(oldNode.runtimeType != node.runtimeType || oldNode.key != node.key)) { |
assert(oldNode.mounted); |
+ oldNode.detachRoot(); |
removeChild(oldNode); |
oldNode = null; |
} |
@@ -148,6 +153,9 @@ abstract class Widget { |
assert(node.root is RenderObject); |
return node; |
} |
+ |
+ String toString() => '$runtimeType($key)'; |
+ |
} |
@@ -175,6 +183,11 @@ abstract class TagNode extends Widget { |
super.remove(); |
} |
+ void detachRoot() { |
+ if (content != null) |
+ content.detachRoot(); |
+ } |
+ |
} |
class ParentDataNode extends TagNode { |
@@ -305,6 +318,12 @@ abstract class Component extends Widget { |
super.remove(); |
} |
+ void detachRoot() { |
+ assert(_built != null); |
+ assert(root != null); |
+ _built.detachRoot(); |
+ } |
+ |
bool _retainStatefulNodeIfPossible(Widget old) { |
assert(!_disqualifiedFromEverAppearingAgain); |
@@ -466,13 +485,14 @@ abstract class RenderObjectWrapper extends Widget { |
RenderObject createNode(); |
- void insert(RenderObjectWrapper child, dynamic slot); |
- |
static final Map<RenderObject, RenderObjectWrapper> _nodeMap = |
new HashMap<RenderObject, RenderObjectWrapper>(); |
- |
static RenderObjectWrapper _getMounted(RenderObject node) => _nodeMap[node]; |
+ RenderObjectWrapper _ancestor; |
+ void insert(RenderObjectWrapper child, dynamic slot); |
+ void detachChildRoot(RenderObjectWrapper child); |
+ |
void _sync(Widget old, dynamic slot) { |
// TODO(abarth): We should split RenderObjectWrapper into two pieces so that |
// RenderViewObject doesn't need to inherit all this code it |
@@ -480,11 +500,14 @@ abstract class RenderObjectWrapper extends Widget { |
assert(parent != null || this is RenderViewWrapper); |
if (old == null) { |
_root = createNode(); |
- var ancestor = findAncestor(RenderObjectWrapper); |
- if (ancestor is RenderObjectWrapper) |
- ancestor.insert(this, slot); |
+ _ancestor = findAncestor(RenderObjectWrapper); |
+ if (_ancestor is RenderObjectWrapper) |
+ _ancestor.insert(this, slot); |
+ else |
+ print("$this has no ancestor"); |
} else { |
_root = old.root; |
+ _ancestor = old._ancestor; |
} |
assert(_root == root); // in case a subclass reintroduces it |
assert(root != null); |
@@ -518,6 +541,13 @@ abstract class RenderObjectWrapper extends Widget { |
_nodeMap.remove(root); |
super.remove(); |
} |
+ |
+ void detachRoot() { |
+ assert(_ancestor != null); |
+ assert(root != null); |
+ _ancestor.detachChildRoot(this); |
+ } |
+ |
} |
abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper { |
@@ -536,17 +566,17 @@ abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper { |
void insert(RenderObjectWrapper child, dynamic slot) { |
final root = this.root; // TODO(ianh): Remove this once the analyzer is cleverer |
- assert(slot == null); |
assert(root is RenderObjectWithChildMixin); |
+ assert(slot == null); |
root.child = child.root; |
assert(root == this.root); // TODO(ianh): Remove this once the analyzer is cleverer |
} |
- void removeChild(Widget node) { |
+ void detachChildRoot(RenderObjectWrapper child) { |
final root = this.root; // TODO(ianh): Remove this once the analyzer is cleverer |
assert(root is RenderObjectWithChildMixin); |
+ assert(root.child == child.root); |
root.child = null; |
- super.removeChild(node); |
assert(root == this.root); // TODO(ianh): Remove this once the analyzer is cleverer |
} |
@@ -579,12 +609,11 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { |
assert(root == this.root); // TODO(ianh): Remove this once the analyzer is cleverer |
} |
- void removeChild(Widget node) { |
+ void detachChildRoot(RenderObjectWrapper child) { |
final root = this.root; // TODO(ianh): Remove this once the analyzer is cleverer |
assert(root is ContainerRenderObjectMixin); |
- assert(node.root.parent == root); |
- root.remove(node.root); |
- super.removeChild(node); |
+ assert(child.root.parent == root); |
+ root.remove(child.root); |
assert(root == this.root); // TODO(ianh): Remove this once the analyzer is cleverer |
} |
@@ -647,6 +676,7 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { |
endIndex--; |
oldEndIndex--; |
sync(endIndex); |
+ nextSibling = children[endIndex].root; |
} |
HashMap<String, Widget> oldNodeIdMap = null; |
@@ -729,7 +759,7 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { |
currentNode = null; |
while (oldStartIndex < oldEndIndex) { |
oldNode = oldChildren[oldStartIndex]; |
- removeChild(oldNode); |
+ syncChild(null, oldNode, null); |
advanceOldStartIndex(); |
} |