Commit 0903cb5f authored by Ian Hickson's avatar Ian Hickson

Refactor Inherited to avoid all the tree walks during build.

parent 5494323d
...@@ -566,20 +566,12 @@ class _InactiveElements { ...@@ -566,20 +566,12 @@ class _InactiveElements {
_elements.add(element); _elements.add(element);
} }
void _reactivate(Element element) {
assert(element._debugLifecycleState == _ElementLifecycle.inactive);
element.reactivate();
assert(element._debugLifecycleState == _ElementLifecycle.active);
element.visitChildren(_reactivate);
}
void remove(Element element) { void remove(Element element) {
assert(!_locked); assert(!_locked);
assert(_elements.contains(element)); assert(_elements.contains(element));
assert(element._parent == null); assert(element._parent == null);
_elements.remove(element); _elements.remove(element);
assert(!element._active); assert(!element._active);
_reactivate(element);
} }
} }
...@@ -729,6 +721,7 @@ abstract class Element<T extends Widget> implements BuildContext { ...@@ -729,6 +721,7 @@ abstract class Element<T extends Widget> implements BuildContext {
final GlobalKey key = widget.key; final GlobalKey key = widget.key;
key._register(this); key._register(this);
} }
_updateInheritance();
assert(() { _debugLifecycleState = _ElementLifecycle.active; return true; }); assert(() { _debugLifecycleState = _ElementLifecycle.active; return true; });
} }
...@@ -793,7 +786,7 @@ abstract class Element<T extends Widget> implements BuildContext { ...@@ -793,7 +786,7 @@ abstract class Element<T extends Widget> implements BuildContext {
_slot = newSlot; _slot = newSlot;
} }
Element _findAndActivateElement(GlobalKey key, Widget newWidget) { Element _retakeInactiveElement(GlobalKey key, Widget newWidget) {
Element element = key._currentElement; Element element = key._currentElement;
if (element == null) if (element == null)
return null; return null;
...@@ -809,13 +802,11 @@ abstract class Element<T extends Widget> implements BuildContext { ...@@ -809,13 +802,11 @@ abstract class Element<T extends Widget> implements BuildContext {
Element _inflateWidget(Widget newWidget, dynamic newSlot) { Element _inflateWidget(Widget newWidget, dynamic newSlot) {
Key key = newWidget.key; Key key = newWidget.key;
if (key is GlobalKey) { if (key is GlobalKey) {
Element newChild = _findAndActivateElement(key, newWidget); Element newChild = _retakeInactiveElement(key, newWidget);
if (newChild != null) { if (newChild != null) {
assert(newChild._parent == null); assert(newChild._parent == null);
assert(() { _debugCheckForCycles(newChild); return true; }); assert(() { _debugCheckForCycles(newChild); return true; });
newChild._parent = this; newChild.activate(this, newSlot);
newChild._updateDepth();
newChild.attachRenderObject(newSlot);
Element updatedChild = updateChild(newChild, newWidget, newSlot); Element updatedChild = updateChild(newChild, newWidget, newSlot);
assert(newChild == updatedChild); assert(newChild == updatedChild);
return updatedChild; return updatedChild;
...@@ -847,6 +838,26 @@ abstract class Element<T extends Widget> implements BuildContext { ...@@ -847,6 +838,26 @@ abstract class Element<T extends Widget> implements BuildContext {
_inactiveElements.add(child); // this eventually calls child.deactivate() _inactiveElements.add(child); // this eventually calls child.deactivate()
} }
void activate(Element parent, dynamic newSlot) {
assert(_debugLifecycleState == _ElementLifecycle.inactive);
_reactivate();
_parent = parent;
_updateDepth();
_updateInheritance();
attachRenderObject(newSlot);
assert(_debugLifecycleState == _ElementLifecycle.active);
}
void _reactivate() {
assert(_debugLifecycleState == _ElementLifecycle.inactive);
assert(widget != null);
assert(depth != null);
assert(!_active);
_active = true;
assert(() { _debugLifecycleState = _ElementLifecycle.active; return true; });
visitChildren((Element child) => child._reactivate());
}
void deactivate() { void deactivate() {
assert(_debugLifecycleState == _ElementLifecycle.active); assert(_debugLifecycleState == _ElementLifecycle.active);
assert(widget != null); assert(widget != null);
...@@ -866,15 +877,6 @@ abstract class Element<T extends Widget> implements BuildContext { ...@@ -866,15 +877,6 @@ abstract class Element<T extends Widget> implements BuildContext {
assert(_debugLifecycleState == _ElementLifecycle.inactive); assert(_debugLifecycleState == _ElementLifecycle.inactive);
} }
void reactivate() {
assert(_debugLifecycleState == _ElementLifecycle.inactive);
assert(widget != null);
assert(depth != null);
assert(!_active);
_active = true;
assert(() { _debugLifecycleState = _ElementLifecycle.active; return true; });
}
/// Called when an Element is removed from the tree permanently. /// Called when an Element is removed from the tree permanently.
void unmount() { void unmount() {
assert(_debugLifecycleState == _ElementLifecycle.inactive); assert(_debugLifecycleState == _ElementLifecycle.inactive);
...@@ -890,22 +892,24 @@ abstract class Element<T extends Widget> implements BuildContext { ...@@ -890,22 +892,24 @@ abstract class Element<T extends Widget> implements BuildContext {
RenderObject findRenderObject() => renderObject; RenderObject findRenderObject() => renderObject;
Map<Type, InheritedElement> _inheritedWidgets;
Set<InheritedElement> _dependencies; Set<InheritedElement> _dependencies;
InheritedWidget inheritFromWidgetOfExactType(Type targetType) { InheritedWidget inheritFromWidgetOfExactType(Type targetType) {
Element ancestor = _parent; InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[targetType];
while (ancestor != null && ancestor.widget.runtimeType != targetType)
ancestor = ancestor._parent;
if (ancestor != null) { if (ancestor != null) {
assert(ancestor is InheritedElement); assert(ancestor is InheritedElement);
_dependencies ??= new HashSet<InheritedElement>(); _dependencies ??= new HashSet<InheritedElement>();
_dependencies.add(ancestor); _dependencies.add(ancestor);
InheritedElement typedAncestor = ancestor; ancestor._dependants.add(this);
typedAncestor._dependants.add(this);
return ancestor.widget; return ancestor.widget;
} }
return null; return null;
} }
void _updateInheritance() {
_inheritedWidgets = _parent?._inheritedWidgets;
}
Widget ancestorWidgetOfExactType(Type targetType) { Widget ancestorWidgetOfExactType(Type targetType) {
Element ancestor = _parent; Element ancestor = _parent;
while (ancestor != null && ancestor.widget.runtimeType != targetType) while (ancestor != null && ancestor.widget.runtimeType != targetType)
...@@ -1378,7 +1382,16 @@ class ParentDataElement extends _ProxyElement<ParentDataWidget> { ...@@ -1378,7 +1382,16 @@ 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 HashSet<Element>(); final Set<Element> _dependants = new HashSet<Element>();
void _updateInheritance() {
final Map<Type, InheritedElement> incomingWidgets = _parent?._inheritedWidgets;
if (incomingWidgets != null)
_inheritedWidgets = new Map<Type, InheritedElement>.from(incomingWidgets);
else
_inheritedWidgets = new Map<Type, InheritedElement>();
_inheritedWidgets[widget.runtimeType] = this;
}
void debugDeactivated() { void debugDeactivated() {
assert(() { assert(() {
......
...@@ -21,7 +21,7 @@ class LocaleQuery<T extends LocaleQueryData> extends InheritedWidget { ...@@ -21,7 +21,7 @@ class LocaleQuery<T extends LocaleQueryData> extends InheritedWidget {
/// The data from the closest instance of this class that encloses the given context. /// The data from the closest instance of this class that encloses the given context.
static LocaleQueryData of(BuildContext context) { static LocaleQueryData of(BuildContext context) {
LocaleQuery query = context.inheritFromWidgetOfExactType(LocaleQuery); LocaleQuery query = context.inheritFromWidgetOfExactType(LocaleQuery);
return query == null ? null : query.data; return query?.data;
} }
bool updateShouldNotify(LocaleQuery old) => data != old.data; bool updateShouldNotify(LocaleQuery old) => data != old.data;
......
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