Commit e6f34f86 authored by Hixie's avatar Hixie

Abstract out syncChildren().

The core of MultiChildRenderObjectWrapper.syncRenderObject() could
apply to any subclass that uses a flat child list, so this abstracts
it out into the superclass.

(Also, instead of requiring the callbacks of RenderBlockViewport to
constrain their results, we just constrain it for them. Makes things a
bit easier for users of that class.)
parent 07d96a23
......@@ -272,7 +272,8 @@ class RenderBlockViewport extends RenderBlockBase {
result = intrinsicCallback(constraints);
if (result == null)
result = constrainer(0.0);
assert(constrainer(result) == result);
else
result = constrainer(result);
} finally {
_inCallback = false;
}
......
......@@ -979,6 +979,7 @@ abstract class RenderObjectWrapper extends Widget {
}
void syncRenderObject(RenderObjectWrapper old) {
assert(old == null || old.renderObject == renderObject);
ParentData parentData = null;
Widget ancestor = parent;
while (ancestor != null && ancestor is! RenderObjectWrapper) {
......@@ -998,134 +999,8 @@ abstract class RenderObjectWrapper extends Widget {
}
}
void dependenciesChanged() {
// called by Inherited.sync()
syncRenderObject(this);
}
void remove() {
assert(renderObject != null);
_nodeMap.remove(renderObject);
super.remove();
}
void detachRenderObject() {
assert(_ancestor != null);
assert(renderObject != null);
_ancestor.detachChildRenderObject(this);
}
}
abstract class LeafRenderObjectWrapper extends RenderObjectWrapper {
LeafRenderObjectWrapper({ Key key }) : super(key: key);
void insertChildRenderObject(RenderObjectWrapper child, dynamic slot) {
assert(false);
}
void detachChildRenderObject(RenderObjectWrapper child) {
assert(false);
}
}
abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper {
OneChildRenderObjectWrapper({ Key key, Widget child })
: _child = child, super(key: key);
Widget _child;
Widget get child => _child;
void walkChildren(WidgetTreeWalker walker) {
if (child != null)
walker(child);
}
void syncRenderObject(RenderObjectWrapper old) {
super.syncRenderObject(old);
Widget oldChild = old == null ? null : (old as OneChildRenderObjectWrapper).child;
Widget newChild = child;
_child = syncChild(newChild, oldChild, null);
assert((newChild == null && child == null) || (newChild != null && child.parent == this));
assert(oldChild == null || child == oldChild || oldChild.parent == null);
}
void insertChildRenderObject(RenderObjectWrapper child, dynamic slot) {
final renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
assert(renderObject is RenderObjectWithChildMixin);
assert(slot == null);
renderObject.child = child.renderObject;
assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
}
void detachChildRenderObject(RenderObjectWrapper child) {
final renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
assert(renderObject is RenderObjectWithChildMixin);
assert(renderObject.child == child.renderObject);
renderObject.child = null;
assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
}
}
abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {
// In MultiChildRenderObjectWrapper subclasses, slots are the Widget
// nodes whose RenderObjects are to be used as the "insert before"
// sibling in ContainerRenderObjectMixin.add() calls
MultiChildRenderObjectWrapper({ Key key, List<Widget> children })
: this.children = children == null ? const [] : children,
super(key: key) {
assert(!_debugHasDuplicateIds());
}
final List<Widget> children;
void walkChildren(WidgetTreeWalker walker) {
for (Widget child in children)
walker(child);
}
void insertChildRenderObject(RenderObjectWrapper child, Widget slot) {
final renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
RenderObject nextSibling = slot != null ? slot.renderObject : null;
assert(nextSibling == null || nextSibling is RenderObject);
assert(renderObject is ContainerRenderObjectMixin);
renderObject.add(child.renderObject, before: nextSibling);
assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
}
void detachChildRenderObject(RenderObjectWrapper child) {
final renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
assert(renderObject is ContainerRenderObjectMixin);
assert(child.renderObject.parent == renderObject);
renderObject.remove(child.renderObject);
assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
}
bool _debugHasDuplicateIds() {
var idSet = new HashSet<Key>();
for (var child in children) {
assert(child != null);
if (child.key == null)
continue; // when these nodes are reordered, we just reassign the data
if (!idSet.add(child.key)) {
throw '''If multiple keyed nodes exist as children of another node, they must have unique keys. $this has duplicate child key "${child.key}".''';
}
}
return false;
}
void syncRenderObject(MultiChildRenderObjectWrapper old) {
super.syncRenderObject(old);
final ContainerRenderObjectMixin renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
assert(renderObject is ContainerRenderObjectMixin);
assert(old == null || old.renderObject == renderObject);
// for use by subclasses that manage their children using lists
void syncChildren(List<Widget> newChildren, List<Widget> oldChildren) {
// This attempts to diff the new child list (this.children) with
// the old child list (old.children), and update our renderObject
......@@ -1158,8 +1033,9 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {
// 6. Sync null with any items in the list of keys that are still
// mounted.
final List<Widget> newChildren = children;
final List<Widget> oldChildren = old == null ? const <Widget>[] : old.children;
final ContainerRenderObjectMixin renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
assert(renderObject is ContainerRenderObjectMixin);
int childrenTop = 0;
int newChildrenBottom = newChildren.length-1;
int oldChildrenBottom = oldChildren.length-1;
......@@ -1260,6 +1136,133 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {
assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
}
void dependenciesChanged() {
// called by Inherited.sync()
syncRenderObject(this);
}
void remove() {
assert(renderObject != null);
_nodeMap.remove(renderObject);
super.remove();
}
void detachRenderObject() {
assert(_ancestor != null);
assert(renderObject != null);
_ancestor.detachChildRenderObject(this);
}
}
abstract class LeafRenderObjectWrapper extends RenderObjectWrapper {
LeafRenderObjectWrapper({ Key key }) : super(key: key);
void insertChildRenderObject(RenderObjectWrapper child, dynamic slot) {
assert(false);
}
void detachChildRenderObject(RenderObjectWrapper child) {
assert(false);
}
}
abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper {
OneChildRenderObjectWrapper({ Key key, Widget child })
: _child = child, super(key: key);
Widget _child;
Widget get child => _child;
void walkChildren(WidgetTreeWalker walker) {
if (child != null)
walker(child);
}
void syncRenderObject(RenderObjectWrapper old) {
super.syncRenderObject(old);
Widget oldChild = old == null ? null : (old as OneChildRenderObjectWrapper).child;
Widget newChild = child;
_child = syncChild(newChild, oldChild, null);
assert((newChild == null && child == null) || (newChild != null && child.parent == this));
assert(oldChild == null || child == oldChild || oldChild.parent == null);
}
void insertChildRenderObject(RenderObjectWrapper child, dynamic slot) {
final renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
assert(renderObject is RenderObjectWithChildMixin);
assert(slot == null);
renderObject.child = child.renderObject;
assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
}
void detachChildRenderObject(RenderObjectWrapper child) {
final renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
assert(renderObject is RenderObjectWithChildMixin);
assert(renderObject.child == child.renderObject);
renderObject.child = null;
assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
}
}
abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {
// In MultiChildRenderObjectWrapper subclasses, slots are the Widget
// nodes whose RenderObjects are to be used as the "insert before"
// sibling in ContainerRenderObjectMixin.add() calls
MultiChildRenderObjectWrapper({ Key key, List<Widget> children })
: this.children = children == null ? const [] : children,
super(key: key) {
assert(!_debugHasDuplicateIds());
}
final List<Widget> children;
void walkChildren(WidgetTreeWalker walker) {
for (Widget child in children)
walker(child);
}
void insertChildRenderObject(RenderObjectWrapper child, Widget slot) {
final renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
RenderObject nextSibling = slot != null ? slot.renderObject : null;
assert(nextSibling == null || nextSibling is RenderObject);
assert(renderObject is ContainerRenderObjectMixin);
renderObject.add(child.renderObject, before: nextSibling);
assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
}
void detachChildRenderObject(RenderObjectWrapper child) {
final renderObject = this.renderObject; // TODO(ianh): Remove this once the analyzer is cleverer
assert(renderObject is ContainerRenderObjectMixin);
assert(child.renderObject.parent == renderObject);
renderObject.remove(child.renderObject);
assert(renderObject == this.renderObject); // TODO(ianh): Remove this once the analyzer is cleverer
}
bool _debugHasDuplicateIds() {
var idSet = new HashSet<Key>();
for (var child in children) {
assert(child != null);
if (child.key == null)
continue; // when these nodes are reordered, we just reassign the data
if (!idSet.add(child.key)) {
throw '''If multiple keyed nodes exist as children of another node, they must have unique keys. $this has duplicate child key "${child.key}".''';
}
}
return false;
}
void syncRenderObject(MultiChildRenderObjectWrapper old) {
super.syncRenderObject(old);
syncChildren(children, old == null ? const <Widget>[] : old.children);
}
}
class WidgetSkyBinding extends SkyBinding {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment