Unverified Commit 18713e0c authored by gaaclarke's avatar gaaclarke Committed by GitHub

Made Directionality forego dependency tracking for better performance. (#102336)

parent 1c80e29b
...@@ -80,12 +80,69 @@ export 'package:flutter/services.dart' show ...@@ -80,12 +80,69 @@ export 'package:flutter/services.dart' show
// BIDIRECTIONAL TEXT SUPPORT // BIDIRECTIONAL TEXT SUPPORT
/// An [InheritedElement] that has hundreds of dependencies but will
/// infrequently change. This provides a performance tradeoff where building
/// the [Widget]s is faster but performing updates is slower.
///
/// | | _UbiquitiousInheritedElement | InheritedElement |
/// |---------------------|------------------------------|------------------|
/// | insert (best case) | O(1) | O(1) |
/// | insert (worst case) | O(1) | O(n) |
/// | search (best case) | O(n) | O(1) |
/// | search (worst case) | O(n) | O(n) |
///
/// Insert happens when building the [Widget] tree, search happens when updating
/// [Widget]s.
class _UbiquitousInheritedElement extends InheritedElement {
/// Creates an element that uses the given widget as its configuration.
_UbiquitousInheritedElement(super.widget);
@override
void setDependencies(Element dependent, Object? value) {
// This is where the cost of [InheritedElement] is incurred during build
// time of the widget tree. Omitting this bookkeeping is where the
// performance savings come from.
assert(value == null);
}
@override
Object? getDependencies(Element dependent) {
return null;
}
@override
void notifyClients(InheritedWidget oldWidget) {
_recurseChildren(this, (Element element) {
if (element.doesDependOnInheritedElement(this)) {
notifyDependent(oldWidget, element);
}
});
}
static void _recurseChildren(Element element, ElementVisitor visitor) {
element.visitChildren((Element child) {
_recurseChildren(child, visitor);
});
visitor(element);
}
}
/// See also:
///
/// * [_UbiquitousInheritedElement], the [Element] for [_UbiquitousInheritedWidget].
abstract class _UbiquitousInheritedWidget extends InheritedWidget {
const _UbiquitousInheritedWidget({super.key, required super.child});
@override
InheritedElement createElement() => _UbiquitousInheritedElement(this);
}
/// A widget that determines the ambient directionality of text and /// A widget that determines the ambient directionality of text and
/// text-direction-sensitive render objects. /// text-direction-sensitive render objects.
/// ///
/// For example, [Padding] depends on the [Directionality] to resolve /// For example, [Padding] depends on the [Directionality] to resolve
/// [EdgeInsetsDirectional] objects into absolute [EdgeInsets] objects. /// [EdgeInsetsDirectional] objects into absolute [EdgeInsets] objects.
class Directionality extends InheritedWidget { class Directionality extends _UbiquitousInheritedWidget {
/// Creates a widget that determines the directionality of text and /// Creates a widget that determines the directionality of text and
/// text-direction-sensitive render objects. /// text-direction-sensitive render objects.
/// ///
......
...@@ -4197,6 +4197,11 @@ abstract class Element extends DiagnosticableTree implements BuildContext { ...@@ -4197,6 +4197,11 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
return true; return true;
} }
/// Returns `true` if [dependOnInheritedElement] was previously called with [ancestor].
@protected
bool doesDependOnInheritedElement(InheritedElement ancestor) =>
_dependencies != null && _dependencies!.contains(ancestor);
@override @override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object? aspect }) { InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object? aspect }) {
assert(ancestor != null); assert(ancestor != null);
......
...@@ -1694,6 +1694,30 @@ The findRenderObject() method was called for the following element: ...@@ -1694,6 +1694,30 @@ The findRenderObject() method was called for the following element:
expect(inheritedElement.hashCode, identityHashCode(inheritedElement)); expect(inheritedElement.hashCode, identityHashCode(inheritedElement));
}); });
testWidgets('doesDependOnInheritedElement', (WidgetTester tester) async {
final _TestInheritedElement ancestor =
_TestInheritedElement(const Directionality(
textDirection: TextDirection.ltr,
child: Placeholder(),
));
final _TestInheritedElement child =
_TestInheritedElement(const Directionality(
textDirection: TextDirection.ltr,
child: Placeholder(),
));
expect(child.doesDependOnInheritedElement(ancestor), isFalse);
child.dependOnInheritedElement(ancestor);
expect(child.doesDependOnInheritedElement(ancestor), isTrue);
});
}
class _TestInheritedElement extends InheritedElement {
_TestInheritedElement(super.widget);
@override
bool doesDependOnInheritedElement(InheritedElement element) {
return super.doesDependOnInheritedElement(element);
}
} }
class _WidgetWithNoVisitChildren extends StatelessWidget { class _WidgetWithNoVisitChildren extends StatelessWidget {
......
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