Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit bd2c146

Browse files
authored
[web] Prioritize split font fallbacks over monolythic ones. (#56187)
Moves "split" font fallbacks (woff2) over "monolythic" ones (ttf) when resolving fonts. Fixes flutter/flutter#157763 It makes flutter web prefer "Noto Color Emoji" over "Noto Sans Symbols" when rendering emoji, for example. This also changes the methods that process the font lists so they *return* the fonts they processed, instead of causing a side effect on an incoming array. --- CIPD Upload log ``` 398 sets covering 22287 ranges Uploading fallback fonts to CIPD with hash 0570a0ea824083da79de07b131fc5df7f55dad4d6cba2ee704912ce7e4ce812a Enumerating files to zip... Instance: flutter/flutter_font_fallbacks:6jWhR90elvOjT1bwCe57CrNWbsGrvOzMONf9_bS8w5IC Setting new fallback fonts deps version to 0570a0ea824083da79de07b131fc5df7f55dad4d6cba2ee704912ce7e4ce812a ``` Link to uploaded bundle: * https://chrome-infra-packages.appspot.com/p/flutter/flutter_font_fallbacks/+/6jWhR90elvOjT1bwCe57CrNWbsGrvOzMONf9_bS8w5IC --- [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent 40e3d70 commit bd2c146

File tree

4 files changed

+1940
-1902
lines changed

4 files changed

+1940
-1902
lines changed

DEPS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -958,7 +958,7 @@ deps = {
958958
'packages': [
959959
{
960960
'package': 'flutter/flutter_font_fallbacks',
961-
'version': '91f2de34d4a309816a182ce7552201d95388e2e0bceea951a6dd04693ed6fe30'
961+
'version': '0570a0ea824083da79de07b131fc5df7f55dad4d6cba2ee704912ce7e4ce812a'
962962
}
963963
],
964964
'dep_type': 'cipd',

lib/web_ui/dev/roll_fallback_fonts.dart

Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -61,23 +61,20 @@ class RollFallbackFontsCommand extends Command<bool>
6161

6262
Future<void> _generateFallbackFontData() async {
6363
final http.Client client = http.Client();
64-
final List<String> fallbackFonts = <String>[];
65-
final Map<String, Uri> urlForFamily = <String, Uri>{};
66-
await _addApiFallbackFonts(client, fallbackFonts, urlForFamily);
67-
await _addSplitFallbackFonts(client, fallbackFonts, urlForFamily);
64+
final List<_FontInfo> fallbackFontInfo = <_FontInfo>[
65+
...await _processSplitFallbackFonts(client, splitFallbackFonts),
66+
...await _processFallbackFonts(client, apiFallbackFonts),
67+
];
68+
final List<_Font> fallbackFontData = <_Font>[];
6869

6970
final Map<String, String> charsetForFamily = <String, String>{};
7071
final io.Directory fontDir = await io.Directory.systemTemp.createTemp('flutter_fallback_fonts');
7172
print('Downloading fonts into temp directory: ${fontDir.path}');
7273
final AccumulatorSink<crypto.Digest> hashSink = AccumulatorSink<crypto.Digest>();
7374
final ByteConversionSink hasher = crypto.sha256.startChunkedConversion(hashSink);
74-
for (final String family in fallbackFonts) {
75+
76+
for (final (:family, :uri) in fallbackFontInfo) {
7577
print('Downloading $family...');
76-
final Uri? uri = urlForFamily[family];
77-
if (uri == null) {
78-
throw ToolExit('Unable to determine URL to download $family. '
79-
'Check if it is still hosted on Google Fonts.');
80-
}
8178
final http.Response fontResponse = await client.get(uri);
8279
if (fontResponse.statusCode != 200) {
8380
throw ToolExit('Failed to download font for $family');
@@ -112,12 +109,11 @@ class RollFallbackFontsCommand extends Command<bool>
112109

113110
final StringBuffer sb = StringBuffer();
114111

115-
final List<_Font> fonts = <_Font>[];
116-
117-
for (final String family in fallbackFonts) {
112+
int index = 0;
113+
for (final _FontInfo fontInfo in fallbackFontInfo) {
118114
final List<int> starts = <int>[];
119115
final List<int> ends = <int>[];
120-
final String charset = charsetForFamily[family]!;
116+
final String charset = charsetForFamily[fontInfo.family]!;
121117
for (final String range in charset.split(' ')) {
122118
// Range is one hexadecimal number or two, separated by `-`.
123119
final List<String> parts = range.split('-');
@@ -130,10 +126,10 @@ class RollFallbackFontsCommand extends Command<bool>
130126
ends.add(last);
131127
}
132128

133-
fonts.add(_Font(family, fonts.length, starts, ends));
129+
fallbackFontData.add(_Font(fontInfo, index++, starts, ends));
134130
}
135131

136-
final String fontSetsCode = _computeEncodedFontSets(fonts);
132+
final String fontSetsCode = _computeEncodedFontSets(fallbackFontData);
137133

138134
sb.writeln('// Copyright 2013 The Flutter Authors. All rights reserved.');
139135
sb.writeln('// Use of this source code is governed by a BSD-style license '
@@ -146,9 +142,9 @@ class RollFallbackFontsCommand extends Command<bool>
146142
sb.writeln();
147143
sb.writeln('List<NotoFont> getFallbackFontList() => <NotoFont>[');
148144

149-
for (final _Font font in fonts) {
150-
final String family = font.family;
151-
final String urlString = urlForFamily[family]!.toString();
145+
for (final _Font font in fallbackFontData) {
146+
final String family = font.info.family;
147+
final String urlString = font.info.uri.toString();
152148
if (!urlString.startsWith(expectedUrlPrefix)) {
153149
throw ToolExit(
154150
'Unexpected url format received from Google Fonts API: $urlString.');
@@ -307,14 +303,14 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
307303
]);
308304
}
309305

310-
Future<void> _addApiFallbackFonts(
306+
Future<List<_FontInfo>> _processFallbackFonts(
311307
http.Client client,
312-
List<String> fallbackFonts,
313-
Map<String, Uri> urlForFamily,
308+
List<String> requestedFonts,
314309
) async {
315310
if (apiKey.isEmpty) {
316311
throw UsageException('No Google Fonts API key provided', argParser.usage);
317312
}
313+
final List<_FontInfo> processedFonts = <_FontInfo>[];
318314
final http.Response response = await client.get(Uri.parse(
319315
'https://www.googleapis.com/webfonts/v1/webfonts?key=$apiKey'));
320316
if (response.statusCode != 200) {
@@ -327,22 +323,25 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
327323
.cast<Map<String, dynamic>>();
328324
for (final Map<String, Object?> fontData in fontDatas) {
329325
final String family = fontData['family']! as String;
330-
if (apiFallbackFonts.contains(family)) {
326+
if (requestedFonts.contains(family)) {
331327
final files = fontData['files']! as Map<String, Object?>;
332328
final Uri uri = Uri.parse(files['regular']! as String)
333329
.replace(scheme: 'https');
334-
urlForFamily[family] = uri;
335-
fallbackFonts.add(family);
330+
processedFonts.add((
331+
family: family,
332+
uri: uri,
333+
));
336334
}
337335
}
336+
return processedFonts;
338337
}
339338

340-
Future<void> _addSplitFallbackFonts(
339+
Future<List<_FontInfo>> _processSplitFallbackFonts(
341340
http.Client client,
342-
List<String> fallbackFonts,
343-
Map<String, Uri> urlForFamily,
341+
List<String> requestedFonts,
344342
) async {
345-
for (final String font in splitFallbackFonts) {
343+
final List<_FontInfo> processedFonts = <_FontInfo>[];
344+
for (final String font in requestedFonts) {
346345
final String modifiedFontName = font.replaceAll(' ', '+');
347346
final Uri cssUri = Uri.parse(
348347
'https://fonts.googleapis.com/css2?family=$modifiedFontName');
@@ -358,13 +357,17 @@ OTHER DEALINGS IN THE FONT SOFTWARE.
358357
final UriCollector uriCollector = UriCollector();
359358
stylesheet.visit(uriCollector);
360359
int familyCount = 0;
360+
// Give each font shard a unique family name.
361361
for (final Uri uri in uriCollector.uris) {
362-
final String fontName = '$font $familyCount';
363-
fallbackFonts.add(fontName);
364-
urlForFamily[fontName] = uri;
362+
final String family = '$font $familyCount';
363+
processedFonts.add((
364+
family: family,
365+
uri: uri,
366+
));
365367
familyCount += 1;
366368
}
367369
}
370+
return processedFonts;
368371
}
369372
}
370373

@@ -551,10 +554,13 @@ Future<bool> _checkForLicenseAttribution(
551554
return licenseString.contains(attributionString);
552555
}
553556

557+
// The basic information of a font: its [family] (name) and [uri].
558+
typedef _FontInfo = ({String family, Uri uri});
559+
554560
class _Font {
555-
_Font(this.family, this.index, this.starts, this.ends);
561+
_Font(this.info, this.index, this.starts, this.ends);
556562

557-
final String family;
563+
final _FontInfo info;
558564
final int index;
559565
final List<int> starts;
560566
final List<int> ends; // inclusive ends
@@ -566,9 +572,9 @@ class _Font {
566572
String.fromCharCodes(
567573
'$index'.codeUnits.map((int ch) => ch - 48 + 0x2080));
568574

569-
String get _shortName => family.startsWith('Noto Sans ')
570-
? family.substring('Noto Sans '.length)
571-
: family;
575+
String get _shortName => info.family.startsWith('Noto Sans ')
576+
? info.family.substring('Noto Sans '.length)
577+
: info.family;
572578
}
573579

574580
/// The boundary of a range of a font.

0 commit comments

Comments
 (0)