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 {
// TODO(yjbanov): implement font fallback (see "Font stack" at https://material.io/guidelines/style/typography.html)
class _MaterialTextColorThemes {
static const TextTheme blackMountainView = const TextTheme(
display4: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54),
display3: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54),
display2: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54),
display1: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54),
headline: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87),
title : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87),
subhead : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87),
body2 : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87),
body1 : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87),
caption : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black54),
button : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.black87),
display4: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black54),
display3: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black54),
display2: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black54),
display1: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black54),
headline: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black87),
title : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black87),
subhead : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black87),
body2 : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black87),
body1 : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black87),
caption : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black54),
button : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.black87),
);
static const TextTheme whiteMountainView = const TextTheme(
display4: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70),
display3: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70),
display2: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70),
display1: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70),
headline: const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white),
title : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white),
subhead : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white),
body2 : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white),
body1 : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white),
caption : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white70),
button : const TextStyle(fontFamily: 'Roboto', inherit: false, color: Colors.white),
display4: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white70),
display3: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white70),
display2: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white70),
display1: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white70),
headline: const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white),
title : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white),
subhead : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white),
body2 : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white),
body1 : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white),
caption : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white70),
button : const TextStyle(fontFamily: 'Roboto', inherit: true, color: Colors.white),
);
static const TextTheme blackCupertino = const TextTheme(
display4: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black54),
display3: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black54),
display2: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black54),
display1: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black54),
headline: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black87),
title : const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.black87),
subhead : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black87),
body2 : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black87),
body1 : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black87),
caption : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black54),
button : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.black87),
display4: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.black54),
display3: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.black54),
display2: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.black54),
display1: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.black54),
headline: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.black87),
title : const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.black87),
subhead : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.black87),
body2 : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.black87),
body1 : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.black87),
caption : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.black54),
button : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.black87),
);
static const TextTheme whiteCupertino = const TextTheme(
display4: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white70),
display3: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white70),
display2: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white70),
display1: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white70),
headline: const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white),
title : const TextStyle(fontFamily: '.SF UI Display', inherit: false, color: Colors.white),
subhead : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white),
body2 : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white),
body1 : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white),
caption : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white70),
button : const TextStyle(fontFamily: '.SF UI Text', inherit: false, color: Colors.white),
display4: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.white70),
display3: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.white70),
display2: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.white70),
display1: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.white70),
headline: const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.white),
title : const TextStyle(fontFamily: '.SF UI Display', inherit: true, color: Colors.white),
subhead : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.white),
body2 : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.white),
body1 : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.white),
caption : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.white70),
button : const TextStyle(fontFamily: '.SF UI Text', inherit: true, color: Colors.white),
);
}
......
......@@ -3911,9 +3911,9 @@ class InheritedElement extends ProxyElement {
assert(_active);
final Map<Type, InheritedElement> incomingWidgets = _parent?._inheritedWidgets;
if (incomingWidgets != null)
_inheritedWidgets = new Map<Type, InheritedElement>.from(incomingWidgets);
_inheritedWidgets = new HashMap<Type, InheritedElement>.from(incomingWidgets);
else
_inheritedWidgets = <Type, InheritedElement>{};
_inheritedWidgets = new HashMap<Type, InheritedElement>();
_inheritedWidgets[widget.runtimeType] = this;
}
......
......@@ -53,12 +53,33 @@ void main() {
)
);
final dynamic localizedTheme = Theme.of(capturedContext);
expect('${localizedTheme.runtimeType}', '_LocalizedThemeData');
expect(localizedTheme.delegate, equals(new ThemeData.fallback()));
expect(Theme.of(capturedContext), equals(ThemeData.localize(new ThemeData.fallback(), MaterialTextGeometry.englishLike)));
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 {
// Regression test for https://github.com/flutter/flutter/issues/5572
final Key popupMenuButtonKey = new UniqueKey();
......@@ -315,6 +336,37 @@ void main() {
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;
......
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