diff --git a/lib/web_ui/lib/src/engine/util.dart b/lib/web_ui/lib/src/engine/util.dart index c410c8b2493..d0301e192b8 100644 --- a/lib/web_ui/lib/src/engine/util.dart +++ b/lib/web_ui/lib/src/engine/util.dart @@ -413,10 +413,18 @@ const Set _genericFontFamilies = { /// A default fallback font family in case an unloaded font has been requested. /// -/// For iOS, default to Helvetica, where it should be available, otherwise -/// default to Arial. -final String _fallbackFontFamily = - operatingSystem == OperatingSystem.iOs ? 'Helvetica' : 'Arial'; +/// -apple-system targets San Francisco in Safari (on Mac OS X and iOS), +/// and it targets Neue Helvetica and Lucida Grande on older versions of +/// Mac OS X. It properly selects between San Francisco Text and +/// San Francisco Display depending on the text’s size. +/// +/// For iOS, default to -apple-system, where it should be available, otherwise +/// default to Arial. BlinkMacSystemFont is used for Chrome on iOS. +final String _fallbackFontFamily = _isMacOrIOS ? + '-apple-system, BlinkMacSystemFont' : 'Arial'; + +bool get _isMacOrIOS => operatingSystem == OperatingSystem.iOs || + operatingSystem == OperatingSystem.macOs; /// Create a font-family string appropriate for CSS. /// @@ -426,6 +434,16 @@ String canonicalizeFontFamily(String fontFamily) { if (_genericFontFamilies.contains(fontFamily)) { return fontFamily; } + if (_isMacOrIOS) { + // Unlike Safari, Chrome on iOS does not correctly fallback to cupertino + // on sans-serif. + // Map to San Francisco Text/Display fonts, use -apple-system, + // BlinkMacSystemFont. + if (fontFamily == '.SF Pro Text' || fontFamily == '.SF Pro Display' || + fontFamily == '.SF UI Text' || fontFamily == '.SF UI Display') { + return _fallbackFontFamily; + } + } return '"$fontFamily", $_fallbackFontFamily, sans-serif'; } diff --git a/lib/web_ui/test/text_test.dart b/lib/web_ui/test/text_test.dart index 0c9a5c6c4ca..266d88d1eec 100644 --- a/lib/web_ui/test/text_test.dart +++ b/lib/web_ui/test/text_test.dart @@ -17,6 +17,16 @@ void main() async { await webOnlyInitializeTestDomRenderer(); + String fallback; + setUp(() { + if (operatingSystem == OperatingSystem.macOs || + operatingSystem == OperatingSystem.iOs) { + fallback = '-apple-system, BlinkMacSystemFont'; + } else { + fallback = 'Arial'; + } + }); + test('predictably lays out a single-line paragraph', () { for (double fontSize in [10.0, 20.0, 30.0, 40.0]) { final ParagraphBuilder builder = ParagraphBuilder(ParagraphStyle( @@ -361,9 +371,9 @@ void main() async { expect(paragraph.plainText, isNull); final List spans = paragraph.paragraphElement.querySelectorAll('span'); - expect(spans[0].style.fontFamily, 'Ahem, Arial, sans-serif'); + expect(spans[0].style.fontFamily, 'Ahem, $fallback, sans-serif'); // The nested span here should not set it's family to default sans-serif. - expect(spans[1].style.fontFamily, 'Ahem, Arial, sans-serif'); + expect(spans[1].style.fontFamily, 'Ahem, $fallback, sans-serif'); }, // TODO(nurhan): https://github.com/flutter/flutter/issues/50771 // TODO(nurhan): https://github.com/flutter/flutter/issues/46638 @@ -383,7 +393,7 @@ void main() async { final EngineParagraph paragraph = builder.build(); expect(paragraph.paragraphElement.style.fontFamily, - 'SomeFont, Arial, sans-serif'); + 'SomeFont, $fallback, sans-serif'); debugEmulateFlutterTesterEnvironment = true; }, @@ -422,7 +432,7 @@ void main() async { final EngineParagraph paragraph = builder.build(); expect(paragraph.paragraphElement.style.fontFamily, - '"MyFont 2000", Arial, sans-serif'); + '"MyFont 2000", $fallback, sans-serif'); debugEmulateFlutterTesterEnvironment = true; },