Commit cc3f5767 authored by Yegor's avatar Yegor Committed by GitHub

ThemeData: optimize by removing polymorphism and caching; fix merging (#12249)

* optimize ThemeData: make it monomorphic, memoize result

* address comments

* RLU cache; fix text theme merging

* use FIFO cache for ThemeData; use HashMap to store inherited widgets

* address comments
parent 0189696e
...@@ -353,59 +353,59 @@ class Typography { ...@@ -353,59 +353,59 @@ class Typography {
// TODO(yjbanov): implement font fallback (see "Font stack" at https://material.io/guidelines/style/typography.html) // TODO(yjbanov): implement font fallback (see "Font stack" at https://material.io/guidelines/style/typography.html)
class _MaterialTextColorThemes { class _MaterialTextColorThemes {
static const TextTheme blackMountainView = const TextTheme( static const TextTheme blackMountainView = const TextTheme(
display4: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54), display4: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black54),
display3: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54), display3: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black54),
display2: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54), display2: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black54),
display1: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54), display1: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black54),
headline: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87), headline: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black87),
title : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87), title : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black87),
subhead : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87), subhead : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black87),
body2 : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87), body2 : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black87),
body1 : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87), body1 : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black87),
caption : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54), caption : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black54),
button : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87), button : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black87),
); );
static const TextTheme whiteMountainView = const TextTheme( static const TextTheme whiteMountainView = const TextTheme(
display4: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70), display4: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white70),
display3: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70), display3: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white70),
display2: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70), display2: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white70),
display1: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70), display1: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white70),
headline: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white), headline: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white),
title : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white), title : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white),
subhead : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white), subhead : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white),
body2 : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white), body2 : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white),
body1 : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white), body1 : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white),
caption : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70), caption : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white70),
button : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white), button : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white),
); );
static const TextTheme blackCupertino = const TextTheme( static const TextTheme blackCupertino = const TextTheme(
display4: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black54), display4: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.black54),
display3: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black54), display3: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.black54),
display2: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black54), display2: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.black54),
display1: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black54), display1: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.black54),
headline: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black87), headline: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.black87),
title : const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black87), title : const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.black87),
subhead : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black87), subhead : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.black87),
body2 : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black87), body2 : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.black87),
body1 : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black87), body1 : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.black87),
caption : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black54), caption : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.black54),
button : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black87), button : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.black87),
); );
static const TextTheme whiteCupertino = const TextTheme( static const TextTheme whiteCupertino = const TextTheme(
display4: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white70), display4: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.white70),
display3: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white70), display3: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.white70),
display2: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white70), display2: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.white70),
display1: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white70), display1: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.white70),
headline: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white), headline: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.white),
title : const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white), title : const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.white),
subhead : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white), subhead : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.white),
body2 : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white), body2 : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.white),
body1 : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white), body1 : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.white),
caption : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white70), caption : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.white70),
button : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white), button : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.white),
); );
} }
......
...@@ -3911,9 +3911,9 @@ class InheritedElement extends ProxyElement { ...@@ -3911,9 +3911,9 @@ class InheritedElement extends ProxyElement {
assert(_active); assert(_active);
final Map<Type, InheritedElement> incomingWidgets = _parent?._inheritedWidgets; final Map<Type, InheritedElement> incomingWidgets = _parent?._inheritedWidgets;
if (incomingWidgets != null) if (incomingWidgets != null)
_inheritedWidgets = new Map<Type, InheritedElement>.from(incomingWidgets); _inheritedWidgets = new HashMap<Type, InheritedElement>.from(incomingWidgets);
else else
_inheritedWidgets = <Type, InheritedElement>{}; _inheritedWidgets = new HashMap<Type, InheritedElement>();
_inheritedWidgets[widget.runtimeType] = this; _inheritedWidgets[widget.runtimeType] = this;
} }
......
...@@ -53,12 +53,33 @@ void main() { ...@@ -53,12 +53,33 @@ void main() {
) )
); );
final dynamic localizedTheme = Theme.of(capturedContext); expect(Theme.of(capturedContext), equals(ThemeData.localize(new ThemeData.fallback(), MaterialTextGeometry.englishLike)));
expect('${localizedTheme.runtimeType}', '_LocalizedThemeData');
expect(localizedTheme.delegate, equals(new ThemeData.fallback()));
expect(Theme.of(capturedContext, shadowThemeOnly: true), isNull); expect(Theme.of(capturedContext, shadowThemeOnly: true), isNull);
}); });
testWidgets('ThemeData.localize memoizes the result', (WidgetTester tester) async {
final ThemeData light = new ThemeData.light();
final ThemeData dark = new ThemeData.dark();
// Same input, same output.
expect(
ThemeData.localize(light, MaterialTextGeometry.englishLike),
same(ThemeData.localize(light, MaterialTextGeometry.englishLike)),
);
// Different text geometry, different output.
expect(
ThemeData.localize(light, MaterialTextGeometry.englishLike),
isNot(same(ThemeData.localize(light, MaterialTextGeometry.tall))),
);
// Different base theme, different output.
expect(
ThemeData.localize(light, MaterialTextGeometry.englishLike),
isNot(same(ThemeData.localize(dark, MaterialTextGeometry.englishLike))),
);
});
testWidgets('PopupMenu inherits shadowed app theme', (WidgetTester tester) async { testWidgets('PopupMenu inherits shadowed app theme', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/5572 // Regression test for https://github.com/flutter/flutter/issues/5572
final Key popupMenuButtonKey = new UniqueKey(); final Key popupMenuButtonKey = new UniqueKey();
...@@ -315,6 +336,37 @@ void main() { ...@@ -315,6 +336,37 @@ void main() {
expect(testBuildCalled, 2); expect(testBuildCalled, 2);
}, },
); );
testWidgets('Text geometry set in Theme has higher precedence than that of Localizations', (WidgetTester tester) async {
const double _kMagicFontSize = 4321.0;
final ThemeData fallback = new ThemeData.fallback();
final ThemeData customTheme = fallback.copyWith(
primaryTextTheme: fallback.primaryTextTheme.copyWith(
body1: fallback.primaryTextTheme.body1.copyWith(
fontSize: _kMagicFontSize,
)
),
);
expect(customTheme.primaryTextTheme.body1.fontSize, _kMagicFontSize);
double actualFontSize;
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.ltr,
child: new Theme(
data: customTheme,
child: new Builder(builder: (BuildContext context) {
final ThemeData theme = Theme.of(context);
actualFontSize = theme.primaryTextTheme.body1.fontSize;
return new Text(
'A',
style: theme.primaryTextTheme.body1,
);
}),
),
));
expect(actualFontSize, _kMagicFontSize);
});
} }
int testBuildCalled; int testBuildCalled;
......
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