Commit b9716b84 authored by Ian Hickson's avatar Ian Hickson

Reimplement Inherited.notifyDescendants to use a registration list

...instead of a deep walk.
parent 0911e5d3
...@@ -105,6 +105,18 @@ class WidgetFlutterBinding extends BindingBase with Scheduler, Gesturer, Rendere ...@@ -105,6 +105,18 @@ class WidgetFlutterBinding extends BindingBase with Scheduler, Gesturer, Rendere
_dirtyElements.add(element); _dirtyElements.add(element);
} }
static int _elementSort(BuildableElement a, BuildableElement b) {
if (a.depth < b.depth)
return -1;
if (b.depth < a.depth)
return 1;
if (b.dirty && !a.dirty)
return -1;
if (a.dirty && !b.dirty)
return 1;
return 0;
}
/// Builds all the elements that were marked as dirty using schedule(), in depth order. /// Builds all the elements that were marked as dirty using schedule(), in depth order.
/// If elements are marked as dirty while this runs, they must be deeper than the algorithm /// If elements are marked as dirty while this runs, they must be deeper than the algorithm
/// has yet reached. /// has yet reached.
...@@ -114,14 +126,14 @@ class WidgetFlutterBinding extends BindingBase with Scheduler, Gesturer, Rendere ...@@ -114,14 +126,14 @@ class WidgetFlutterBinding extends BindingBase with Scheduler, Gesturer, Rendere
return; return;
Timeline.startSync('Build'); Timeline.startSync('Build');
BuildableElement.lockState(() { BuildableElement.lockState(() {
_dirtyElements.sort((BuildableElement a, BuildableElement b) => a.depth - b.depth); _dirtyElements.sort(_elementSort);
int dirtyCount = _dirtyElements.length; int dirtyCount = _dirtyElements.length;
int index = 0; int index = 0;
while (index < dirtyCount) { while (index < dirtyCount) {
_dirtyElements[index].rebuild(); _dirtyElements[index].rebuild();
index += 1; index += 1;
if (dirtyCount < _dirtyElements.length) { if (dirtyCount < _dirtyElements.length) {
_dirtyElements.sort((BuildableElement a, BuildableElement b) => a.depth - b.depth); _dirtyElements.sort(_elementSort);
dirtyCount = _dirtyElements.length; dirtyCount = _dirtyElements.length;
} }
} }
......
...@@ -554,6 +554,7 @@ class _InactiveElements { ...@@ -554,6 +554,7 @@ class _InactiveElements {
element.deactivate(); element.deactivate();
assert(element._debugLifecycleState == _ElementLifecycle.inactive); assert(element._debugLifecycleState == _ElementLifecycle.inactive);
element.visitChildren(_deactivate); element.visitChildren(_deactivate);
assert(() { element.debugDeactivated(); return true; });
} }
void add(Element element) { void add(Element element) {
...@@ -851,10 +852,20 @@ abstract class Element<T extends Widget> implements BuildContext { ...@@ -851,10 +852,20 @@ abstract class Element<T extends Widget> implements BuildContext {
assert(widget != null); assert(widget != null);
assert(depth != null); assert(depth != null);
assert(_active); assert(_active);
if (_dependencies != null) {
for (InheritedElement dependency in _dependencies)
dependency._dependants.remove(this);
_dependencies.clear();
}
_active = false; _active = false;
assert(() { _debugLifecycleState = _ElementLifecycle.inactive; return true; }); assert(() { _debugLifecycleState = _ElementLifecycle.inactive; return true; });
} }
/// Called after children have been deactivated.
void debugDeactivated() {
assert(_debugLifecycleState == _ElementLifecycle.inactive);
}
void reactivate() { void reactivate() {
assert(_debugLifecycleState == _ElementLifecycle.inactive); assert(_debugLifecycleState == _ElementLifecycle.inactive);
assert(widget != null); assert(widget != null);
...@@ -879,12 +890,20 @@ abstract class Element<T extends Widget> implements BuildContext { ...@@ -879,12 +890,20 @@ abstract class Element<T extends Widget> implements BuildContext {
RenderObject findRenderObject() => renderObject; RenderObject findRenderObject() => renderObject;
Set<Type> _dependencies; Set<InheritedElement> _dependencies;
InheritedWidget inheritFromWidgetOfExactType(Type targetType) { InheritedWidget inheritFromWidgetOfExactType(Type targetType) {
if (_dependencies == null) Element ancestor = _parent;
_dependencies = new Set<Type>(); while (ancestor != null && ancestor.widget.runtimeType != targetType)
_dependencies.add(targetType); ancestor = ancestor._parent;
return ancestorWidgetOfExactType(targetType); if (ancestor != null) {
assert(ancestor is InheritedElement);
_dependencies ??= new Set<InheritedElement>();
_dependencies.add(ancestor);
InheritedElement typedAncestor = ancestor;
typedAncestor._dependants.add(this);
return ancestor.widget;
}
return null;
} }
Widget ancestorWidgetOfExactType(Type targetType) { Widget ancestorWidgetOfExactType(Type targetType) {
...@@ -1359,19 +1378,30 @@ class ParentDataElement extends _ProxyElement<ParentDataWidget> { ...@@ -1359,19 +1378,30 @@ class ParentDataElement extends _ProxyElement<ParentDataWidget> {
class InheritedElement extends _ProxyElement<InheritedWidget> { class InheritedElement extends _ProxyElement<InheritedWidget> {
InheritedElement(InheritedWidget widget) : super(widget); InheritedElement(InheritedWidget widget) : super(widget);
Set<Element> _dependants = new Set<Element>();
void debugDeactivated() {
assert(() {
assert(_dependants.isEmpty);
return true;
});
super.debugDeactivated();
}
void notifyDescendants(InheritedWidget oldWidget) { void notifyDescendants(InheritedWidget oldWidget) {
if (!widget.updateShouldNotify(oldWidget)) if (!widget.updateShouldNotify(oldWidget))
return; return;
final Type ourRuntimeType = widget.runtimeType; final Type ourRuntimeType = widget.runtimeType;
void notifyChildren(Element child) { for (Element dependant in _dependants) {
if (child._dependencies != null && dependant.dependenciesChanged(ourRuntimeType);
child._dependencies.contains(ourRuntimeType)) { assert(() {
child.dependenciesChanged(ourRuntimeType); // check that it really is our descendant
} Element ancestor = dependant._parent;
if (child.runtimeType != ourRuntimeType) while (ancestor != this && ancestor != null)
child.visitChildren(notifyChildren); ancestor = ancestor._parent;
return ancestor == this;
});
} }
visitChildren(notifyChildren);
} }
} }
......
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