download fonts concurrently with wasm (flutter/engine#36813)
This commit is contained in:
@@ -447,12 +447,7 @@ class FallbackFontDownloadQueue {
|
||||
final Uint8List bytes = downloadedData[url]!;
|
||||
FontFallbackData.instance.registerFallbackFont(font.name, bytes);
|
||||
if (pendingFonts.isEmpty) {
|
||||
_fontsLoading = renderer.fontCollection.ensureFontsLoaded();
|
||||
try {
|
||||
await _fontsLoading;
|
||||
} finally {
|
||||
_fontsLoading = null;
|
||||
}
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
sendFontChangeMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
@@ -22,36 +23,29 @@ const String _robotoUrl =
|
||||
|
||||
/// Manages the fonts used in the Skia-based backend.
|
||||
class SkiaFontCollection implements FontCollection {
|
||||
final Set<String> _registeredFontFamilies = <String>{};
|
||||
final Set<String> _downloadedFontFamilies = <String>{};
|
||||
|
||||
/// Fonts that started the download process.
|
||||
/// Fonts that started the download process, but are not yet registered.
|
||||
///
|
||||
/// Once downloaded successfully, this map is cleared and the resulting
|
||||
/// [RegisteredFont]s are added to [_downloadedFonts].
|
||||
final List<Future<RegisteredFont?>> _pendingFonts = <Future<RegisteredFont?>>[];
|
||||
/// /// Once downloaded successfully, this map is cleared and the resulting
|
||||
/// [UnregisteredFont]s are added to [_registeredFonts].
|
||||
final List<UnregisteredFont> _unregisteredFonts = <UnregisteredFont>[];
|
||||
|
||||
/// Fonts that have been downloaded and parsed into [SkTypeface].
|
||||
///
|
||||
/// These fonts may not yet have been registered with the [fontProvider]. This
|
||||
/// happens after [ensureFontsLoaded] completes.
|
||||
final List<RegisteredFont> _downloadedFonts = <RegisteredFont>[];
|
||||
final List<RegisteredFont> _registeredFonts = <RegisteredFont>[];
|
||||
|
||||
/// Returns fonts that have been downloaded and parsed.
|
||||
/// Returns fonts that have been downloaded, registered, and parsed.
|
||||
///
|
||||
/// This should only be used in tests.
|
||||
List<RegisteredFont>? get debugDownloadedFonts {
|
||||
List<RegisteredFont>? get debugRegisteredFonts {
|
||||
if (!assertionsEnabled) {
|
||||
return null;
|
||||
}
|
||||
return _downloadedFonts;
|
||||
return _registeredFonts;
|
||||
}
|
||||
|
||||
final Map<String, List<SkFont>> familyToFontMap = <String, List<SkFont>>{};
|
||||
|
||||
@override
|
||||
Future<void> ensureFontsLoaded() async {
|
||||
await _loadFonts();
|
||||
|
||||
void _registerWithFontProvider() {
|
||||
if (fontProvider != null) {
|
||||
fontProvider!.delete();
|
||||
fontProvider = null;
|
||||
@@ -59,7 +53,7 @@ class SkiaFontCollection implements FontCollection {
|
||||
fontProvider = canvasKit.TypefaceFontProvider.Make();
|
||||
familyToFontMap.clear();
|
||||
|
||||
for (final RegisteredFont font in _downloadedFonts) {
|
||||
for (final RegisteredFont font in _registeredFonts) {
|
||||
fontProvider!.registerFont(font.bytes, font.family);
|
||||
familyToFontMap
|
||||
.putIfAbsent(font.family, () => <SkFont>[])
|
||||
@@ -75,21 +69,6 @@ class SkiaFontCollection implements FontCollection {
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads all of the unloaded fonts in [_pendingFonts] and adds them
|
||||
/// to [_downloadedFonts].
|
||||
Future<void> _loadFonts() async {
|
||||
if (_pendingFonts.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final List<RegisteredFont?> loadedFonts = await Future.wait(_pendingFonts);
|
||||
for (final RegisteredFont? font in loadedFonts) {
|
||||
if (font != null) {
|
||||
_downloadedFonts.add(font);
|
||||
}
|
||||
}
|
||||
_pendingFonts.clear();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> loadFontFromList(Uint8List list, {String? fontFamily}) async {
|
||||
if (fontFamily == null) {
|
||||
@@ -103,8 +82,8 @@ class SkiaFontCollection implements FontCollection {
|
||||
final SkTypeface? typeface =
|
||||
canvasKit.Typeface.MakeFreeTypeFaceFromData(list.buffer);
|
||||
if (typeface != null) {
|
||||
_downloadedFonts.add(RegisteredFont(list, fontFamily, typeface));
|
||||
await ensureFontsLoaded();
|
||||
_registeredFonts.add(RegisteredFont(list, fontFamily, typeface));
|
||||
_registerWithFontProvider();
|
||||
} else {
|
||||
printWarning('Failed to parse font family "$fontFamily"');
|
||||
return;
|
||||
@@ -113,7 +92,7 @@ class SkiaFontCollection implements FontCollection {
|
||||
|
||||
/// Loads fonts from `FontManifest.json`.
|
||||
@override
|
||||
Future<void> registerFonts(AssetManager assetManager) async {
|
||||
Future<void> downloadAssetFonts(AssetManager assetManager) async {
|
||||
ByteData byteData;
|
||||
|
||||
try {
|
||||
@@ -134,6 +113,8 @@ class SkiaFontCollection implements FontCollection {
|
||||
'There was a problem trying to load FontManifest.json');
|
||||
}
|
||||
|
||||
final List<Future<UnregisteredFont?>> pendingFonts = <Future<UnregisteredFont?>>[];
|
||||
|
||||
for (final Map<String, dynamic> fontFamily
|
||||
in fontManifest.cast<Map<String, dynamic>>()) {
|
||||
final String family = fontFamily.readString('family');
|
||||
@@ -141,58 +122,25 @@ class SkiaFontCollection implements FontCollection {
|
||||
for (final dynamic fontAssetItem in fontAssets) {
|
||||
final Map<String, dynamic> fontAsset = fontAssetItem as Map<String, dynamic>;
|
||||
final String asset = fontAsset.readString('asset');
|
||||
_registerFont(assetManager.getAssetUrl(asset), family);
|
||||
_downloadFont(pendingFonts, assetManager.getAssetUrl(asset), family);
|
||||
}
|
||||
}
|
||||
|
||||
/// We need a default fallback font for CanvasKit, in order to
|
||||
/// avoid crashing while laying out text with an unregistered font. We chose
|
||||
/// Roboto to match Android.
|
||||
if (!_isFontFamilyRegistered('Roboto')) {
|
||||
if (!_isFontFamilyDownloaded('Roboto')) {
|
||||
// Download Roboto and add it to the font buffers.
|
||||
_registerFont(_robotoUrl, 'Roboto');
|
||||
_downloadFont(pendingFonts, _robotoUrl, 'Roboto');
|
||||
}
|
||||
|
||||
final List<UnregisteredFont?> completedPendingFonts = await Future.wait(pendingFonts);
|
||||
_unregisteredFonts.addAll(completedPendingFonts.whereType<UnregisteredFont>());
|
||||
}
|
||||
|
||||
/// Whether the [fontFamily] was registered and/or loaded.
|
||||
bool _isFontFamilyRegistered(String fontFamily) {
|
||||
return _registeredFontFamilies.contains(fontFamily);
|
||||
}
|
||||
|
||||
/// Loads the Ahem font, unless it's already been loaded using
|
||||
/// `FontManifest.json` (see [registerFonts]).
|
||||
///
|
||||
/// `FontManifest.json` has higher priority than the default test font URLs.
|
||||
/// This allows customizing test environments where fonts are loaded from
|
||||
/// different URLs.
|
||||
@override
|
||||
void debugRegisterTestFonts() {
|
||||
if (!_isFontFamilyRegistered(ahemFontFamily)) {
|
||||
_registerFont(ahemFontUrl, ahemFontFamily);
|
||||
}
|
||||
if (!_isFontFamilyRegistered(robotoFontFamily)) {
|
||||
_registerFont(robotoTestFontUrl, robotoFontFamily);
|
||||
}
|
||||
if (!_isFontFamilyRegistered(robotoVariableFontFamily)) {
|
||||
_registerFont(robotoVariableTestFontUrl, robotoVariableFontFamily);
|
||||
}
|
||||
|
||||
// Ahem must be added to font fallbacks list regardless of where it was
|
||||
// downloaded from.
|
||||
FontFallbackData.instance.globalFontFallbacks.add(ahemFontFamily);
|
||||
}
|
||||
|
||||
void _registerFont(String url, String family) {
|
||||
Future<RegisteredFont?> downloadFont() async {
|
||||
ByteBuffer buffer;
|
||||
try {
|
||||
buffer = await httpFetch(url).then(_getArrayBuffer);
|
||||
} catch (e) {
|
||||
printWarning('Failed to load font $family at $url');
|
||||
printWarning(e.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
void registerDownloadedFonts() {
|
||||
RegisteredFont? makeRegisterFont(ByteBuffer buffer, String url, String family) {
|
||||
final Uint8List bytes = buffer.asUint8List();
|
||||
final SkTypeface? typeface =
|
||||
canvasKit.Typeface.MakeFreeTypeFaceFromData(bytes.buffer);
|
||||
@@ -205,8 +153,72 @@ class SkiaFontCollection implements FontCollection {
|
||||
}
|
||||
}
|
||||
|
||||
_registeredFontFamilies.add(family);
|
||||
_pendingFonts.add(downloadFont());
|
||||
for (final UnregisteredFont unregisteredFont in _unregisteredFonts) {
|
||||
final RegisteredFont? registeredFont = makeRegisterFont(
|
||||
unregisteredFont.bytes,
|
||||
unregisteredFont.url,
|
||||
unregisteredFont.family
|
||||
);
|
||||
if (registeredFont != null) {
|
||||
_registeredFonts.add(registeredFont);
|
||||
}
|
||||
}
|
||||
|
||||
_unregisteredFonts.clear();
|
||||
_registerWithFontProvider();
|
||||
}
|
||||
|
||||
/// Whether the [fontFamily] was registered and/or loaded.
|
||||
bool _isFontFamilyDownloaded(String fontFamily) {
|
||||
return _downloadedFontFamilies.contains(fontFamily);
|
||||
}
|
||||
|
||||
/// Loads the Ahem font, unless it's already been loaded using
|
||||
/// `FontManifest.json` (see [downloadAssetFonts]).
|
||||
///
|
||||
/// `FontManifest.json` has higher priority than the default test font URLs.
|
||||
/// This allows customizing test environments where fonts are loaded from
|
||||
/// different URLs.
|
||||
@override
|
||||
Future<void> debugDownloadTestFonts() async {
|
||||
final List<Future<UnregisteredFont?>> pendingFonts = <Future<UnregisteredFont?>>[];
|
||||
if (!_isFontFamilyDownloaded(ahemFontFamily)) {
|
||||
_downloadFont(pendingFonts, ahemFontUrl, ahemFontFamily);
|
||||
}
|
||||
if (!_isFontFamilyDownloaded(robotoFontFamily)) {
|
||||
_downloadFont(pendingFonts, robotoTestFontUrl, robotoFontFamily);
|
||||
}
|
||||
if (!_isFontFamilyDownloaded(robotoVariableFontFamily)) {
|
||||
_downloadFont(pendingFonts, robotoVariableTestFontUrl, robotoVariableFontFamily);
|
||||
}
|
||||
|
||||
final List<UnregisteredFont?> completedPendingFonts = await Future.wait(pendingFonts);
|
||||
_unregisteredFonts.addAll(completedPendingFonts.whereType<UnregisteredFont>());
|
||||
|
||||
// Ahem must be added to font fallbacks list regardless of where it was
|
||||
// downloaded from.
|
||||
FontFallbackData.instance.globalFontFallbacks.add(ahemFontFamily);
|
||||
}
|
||||
|
||||
void _downloadFont(
|
||||
List<Future<UnregisteredFont?>> waitUnregisteredFonts,
|
||||
String url,
|
||||
String family
|
||||
) {
|
||||
Future<UnregisteredFont?> downloadFont() async {
|
||||
ByteBuffer buffer;
|
||||
try {
|
||||
buffer = await httpFetch(url).then(_getArrayBuffer);
|
||||
return UnregisteredFont(buffer, url, family);
|
||||
} catch (e) {
|
||||
printWarning('Failed to load font $family at $url');
|
||||
printWarning(e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
_downloadedFontFamilies.add(family);
|
||||
waitUnregisteredFonts.add(downloadFont());
|
||||
}
|
||||
|
||||
|
||||
@@ -249,3 +261,11 @@ class RegisteredFont {
|
||||
/// This is used to determine which code points are supported by this font.
|
||||
final SkTypeface typeface;
|
||||
}
|
||||
|
||||
/// Represents a font that has been downloaded but not registered.
|
||||
class UnregisteredFont {
|
||||
const UnregisteredFont(this.bytes, this.url, this.family);
|
||||
final ByteBuffer bytes;
|
||||
final String url;
|
||||
final String family;
|
||||
}
|
||||
|
||||
@@ -2,14 +2,33 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'assets.dart';
|
||||
|
||||
abstract class FontCollection {
|
||||
|
||||
/// Fonts loaded with [loadFontFromList] do not need to be registered
|
||||
/// with [registerDownloadedFonts]. Fonts are both downloaded and registered
|
||||
/// with [loadFontFromList] calls.
|
||||
Future<void> loadFontFromList(Uint8List list, {String? fontFamily});
|
||||
Future<void> ensureFontsLoaded();
|
||||
Future<void> registerFonts(AssetManager assetManager);
|
||||
void debugRegisterTestFonts();
|
||||
|
||||
/// Completes when fonts from FontManifest.json have been downloaded.
|
||||
Future<void> downloadAssetFonts(AssetManager assetManager);
|
||||
|
||||
/// Registers both downloaded fonts and fallback fonts with the TypefaceFontProvider.
|
||||
///
|
||||
/// Downloading of fonts happens separately from registering of fonts so that
|
||||
/// the download step can happen concurrently with the initalization of the renderer.
|
||||
///
|
||||
/// The correct order of calls to register downloaded fonts:
|
||||
/// 1) [downloadAssetFonts]
|
||||
/// 2) [registerDownloadedFonts]
|
||||
///
|
||||
/// For fallbackFonts, call registerFallbackFont (see font_fallbacks.dart)
|
||||
/// for each fallback font before calling [registerDownloadedFonts]
|
||||
void registerDownloadedFonts();
|
||||
FutureOr<void> debugDownloadTestFonts();
|
||||
void clear();
|
||||
}
|
||||
|
||||
@@ -204,11 +204,12 @@ Future<void> initializeEngineServices({
|
||||
}
|
||||
};
|
||||
|
||||
await renderer.initialize();
|
||||
|
||||
assetManager ??= const AssetManager();
|
||||
await _setAssetManager(assetManager);
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
_setAssetManager(assetManager);
|
||||
|
||||
Future<void> initializeRendererCallback () async => renderer.initialize();
|
||||
await Future.wait<void>(<Future<void>>[initializeRendererCallback(), _downloadAssetFonts()]);
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
_initializationState = DebugEngineInitializationState.initializedServices;
|
||||
}
|
||||
|
||||
@@ -243,22 +244,24 @@ Future<void> initializeEngineUi() async {
|
||||
AssetManager get assetManager => _assetManager!;
|
||||
AssetManager? _assetManager;
|
||||
|
||||
Future<void> _setAssetManager(AssetManager assetManager) async {
|
||||
void _setAssetManager(AssetManager assetManager) {
|
||||
assert(assetManager != null, 'Cannot set assetManager to null');
|
||||
if (assetManager == _assetManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
_assetManager = assetManager;
|
||||
}
|
||||
|
||||
Future<void> _downloadAssetFonts() async {
|
||||
renderer.fontCollection.clear();
|
||||
|
||||
if (_assetManager != null) {
|
||||
await renderer.fontCollection.registerFonts(assetManager);
|
||||
await renderer.fontCollection.downloadAssetFonts(_assetManager!);
|
||||
}
|
||||
|
||||
if (ui.debugEmulateFlutterTesterEnvironment) {
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,17 +17,17 @@ import 'layout_service.dart';
|
||||
/// This class is responsible for registering and loading fonts.
|
||||
///
|
||||
/// Once an asset manager has been set in the framework, call
|
||||
/// [registerFonts] with it to register fonts declared in the
|
||||
/// [downloadAssetFonts] with it to register fonts declared in the
|
||||
/// font manifest. If test fonts are enabled, then call
|
||||
/// [registerTestFonts] as well.
|
||||
/// [debugDownloadTestFonts] as well.
|
||||
class HtmlFontCollection implements FontCollection {
|
||||
FontManager? _assetFontManager;
|
||||
FontManager? _testFontManager;
|
||||
|
||||
/// Reads the font manifest using the [assetManager] and registers all of the
|
||||
/// Reads the font manifest using the [assetManager] and downloads all of the
|
||||
/// fonts declared within.
|
||||
@override
|
||||
Future<void> registerFonts(AssetManager assetManager) async {
|
||||
Future<void> downloadAssetFonts(AssetManager assetManager) async {
|
||||
ByteData byteData;
|
||||
|
||||
try {
|
||||
@@ -67,10 +67,11 @@ class HtmlFontCollection implements FontCollection {
|
||||
descriptors[descriptor] = '${fontAsset[descriptor]}';
|
||||
}
|
||||
}
|
||||
_assetFontManager!.registerAsset(
|
||||
_assetFontManager!.downloadAsset(
|
||||
family!, 'url(${assetManager.getAssetUrl(asset)})', descriptors);
|
||||
}
|
||||
}
|
||||
await _assetFontManager!.downloadAllFonts();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -81,24 +82,23 @@ class HtmlFontCollection implements FontCollection {
|
||||
return _assetFontManager!._loadFontFaceBytes(fontFamily, list);
|
||||
}
|
||||
|
||||
/// Registers fonts that are used by tests.
|
||||
/// Downloads fonts that are used by tests.
|
||||
@override
|
||||
void debugRegisterTestFonts() {
|
||||
Future<void> debugDownloadTestFonts() async {
|
||||
_testFontManager = FontManager();
|
||||
_testFontManager!.registerAsset(
|
||||
_testFontManager!.downloadAsset(
|
||||
ahemFontFamily, 'url($ahemFontUrl)', const <String, String>{});
|
||||
_testFontManager!.registerAsset(robotoFontFamily,
|
||||
_testFontManager!.downloadAsset(robotoFontFamily,
|
||||
'url($robotoTestFontUrl)', const <String, String>{});
|
||||
_testFontManager!.registerAsset(robotoVariableFontFamily,
|
||||
_testFontManager!.downloadAsset(robotoVariableFontFamily,
|
||||
'url($robotoVariableTestFontUrl)', const <String, String>{});
|
||||
await _testFontManager!.downloadAllFonts();
|
||||
}
|
||||
|
||||
/// Returns a [Future] that completes when the registered fonts are loaded
|
||||
/// and ready to be used.
|
||||
@override
|
||||
Future<void> ensureFontsLoaded() async {
|
||||
await _assetFontManager?.ensureFontsLoaded();
|
||||
await _testFontManager?.ensureFontsLoaded();
|
||||
void registerDownloadedFonts() {
|
||||
_assetFontManager?.registerDownloadedFonts();
|
||||
_testFontManager?.registerDownloadedFonts();
|
||||
}
|
||||
|
||||
/// Unregister all fonts that have been registered.
|
||||
@@ -124,7 +124,12 @@ class FontManager {
|
||||
|
||||
FontManager._();
|
||||
|
||||
final List<Future<void>> _fontLoadingFutures = <Future<void>>[];
|
||||
/// Fonts that started the downloading process. Once the fonts have downloaded
|
||||
/// without error, they are moved to [_downloadedFonts]. Those fonts
|
||||
/// are subsequently registered by [registerDownloadedFonts].
|
||||
final List<Future<DomFontFace?>> _fontLoadingFutures = <Future<DomFontFace?>>[];
|
||||
|
||||
final List<DomFontFace> _downloadedFonts = <DomFontFace>[];
|
||||
|
||||
// Regular expression to detect a string with no punctuations.
|
||||
// For example font family 'Ahem!' does not fall into this category
|
||||
@@ -167,7 +172,7 @@ class FontManager {
|
||||
///
|
||||
/// * https://developer.mozilla.org/en-US/docs/Web/CSS/font-family#Valid_family_names
|
||||
/// * https://drafts.csswg.org/css-fonts-3/#font-family-prop
|
||||
void registerAsset(
|
||||
void downloadAsset(
|
||||
String family,
|
||||
String asset,
|
||||
Map<String, String> descriptors,
|
||||
@@ -187,19 +192,37 @@ class FontManager {
|
||||
String asset,
|
||||
Map<String, String> descriptors,
|
||||
) {
|
||||
Future<DomFontFace?> fontFaceLoad(DomFontFace fontFace) async {
|
||||
try {
|
||||
final DomFontFace loadedFontFace = await fontFace.load();
|
||||
return loadedFontFace;
|
||||
} catch (e) {
|
||||
printWarning('Error while trying to load font family "$family":\n$e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// try/catch because `new FontFace` can crash with an improper font family.
|
||||
try {
|
||||
final DomFontFace fontFace = createDomFontFace(family, asset, descriptors);
|
||||
_fontLoadingFutures.add(fontFace.load().then((_) {
|
||||
domDocument.fonts!.add(fontFace);
|
||||
}, onError: (dynamic e) {
|
||||
printWarning('Error while trying to load font family "$family":\n$e');
|
||||
}));
|
||||
_fontLoadingFutures.add(fontFaceLoad(fontFace));
|
||||
} catch (e) {
|
||||
printWarning('Error while loading font family "$family":\n$e');
|
||||
}
|
||||
}
|
||||
|
||||
void registerDownloadedFonts() {
|
||||
if (_downloadedFonts.isEmpty) {
|
||||
return;
|
||||
}
|
||||
_downloadedFonts.forEach(domDocument.fonts!.add);
|
||||
}
|
||||
|
||||
|
||||
Future<void> downloadAllFonts() async {
|
||||
final List<DomFontFace?> loadedFonts = await Future.wait(_fontLoadingFutures);
|
||||
_downloadedFonts.addAll(loadedFonts.whereType<DomFontFace>());
|
||||
}
|
||||
|
||||
// Loads a font from bytes, surfacing errors through the future.
|
||||
Future<void> _loadFontFaceBytes(String family, Uint8List list) {
|
||||
// Since these fonts are loaded by user code, surface the error
|
||||
@@ -219,12 +242,6 @@ class FontManager {
|
||||
throw Exception(exception.toString());
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns a [Future] that completes when all fonts that have been
|
||||
/// registered with this font manager have been loaded and are ready to use.
|
||||
Future<void> ensureFontsLoaded() {
|
||||
return Future.wait(_fontLoadingFutures);
|
||||
}
|
||||
}
|
||||
|
||||
/// A font manager that works without using the CSS Font Loading API.
|
||||
@@ -241,8 +258,18 @@ class _PolyfillFontManager extends FontManager {
|
||||
static const Duration _fontLoadTimeout = Duration(seconds: 2);
|
||||
static const Duration _fontLoadRetryDuration = Duration(milliseconds: 50);
|
||||
|
||||
final List<Future<void>> _completerFutures = <Future<void>>[];
|
||||
|
||||
@override
|
||||
void registerAsset(
|
||||
Future<void> downloadAllFonts() async {
|
||||
await Future.wait(_completerFutures);
|
||||
}
|
||||
|
||||
@override
|
||||
void registerDownloadedFonts() {}
|
||||
|
||||
@override
|
||||
void downloadAsset(
|
||||
String family,
|
||||
String asset,
|
||||
Map<String, String> descriptors,
|
||||
@@ -314,6 +341,6 @@ class _PolyfillFontManager extends FontManager {
|
||||
fontLoadStart = DateTime.now();
|
||||
watchWidth();
|
||||
|
||||
_fontLoadingFutures.add(completer.future);
|
||||
_completerFutures.add(completer.future);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1465,8 +1465,8 @@ void _textStyleTests() {
|
||||
|
||||
void _paragraphTests() {
|
||||
setUpAll(() async {
|
||||
CanvasKitRenderer.instance.fontCollection.debugRegisterTestFonts();
|
||||
await CanvasKitRenderer.instance.fontCollection.ensureFontsLoaded();
|
||||
await CanvasKitRenderer.instance.fontCollection.debugDownloadTestFonts();
|
||||
CanvasKitRenderer.instance.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
// This test is just a kitchen sink that blasts CanvasKit with all paragraph
|
||||
|
||||
@@ -35,12 +35,13 @@ void testMain() {
|
||||
warnings.clear();
|
||||
});
|
||||
|
||||
test('logs no warnings with the default mock asset manager', () {
|
||||
test('logs no warnings with the default mock asset manager', () async {
|
||||
final SkiaFontCollection fontCollection = SkiaFontCollection();
|
||||
final WebOnlyMockAssetManager mockAssetManager =
|
||||
WebOnlyMockAssetManager();
|
||||
expect(fontCollection.registerFonts(mockAssetManager), completes);
|
||||
expect(fontCollection.ensureFontsLoaded(), completes);
|
||||
await fontCollection.downloadAssetFonts(mockAssetManager);
|
||||
fontCollection.registerDownloadedFonts();
|
||||
|
||||
expect(warnings, isEmpty);
|
||||
});
|
||||
|
||||
@@ -61,8 +62,8 @@ void testMain() {
|
||||
]
|
||||
''';
|
||||
// It should complete without error, but emit a warning about BrokenFont.
|
||||
await fontCollection.registerFonts(mockAssetManager);
|
||||
await fontCollection.ensureFontsLoaded();
|
||||
await fontCollection.downloadAssetFonts(mockAssetManager);
|
||||
fontCollection.registerDownloadedFonts();
|
||||
expect(
|
||||
warnings,
|
||||
containsAllInOrder(
|
||||
@@ -89,13 +90,13 @@ void testMain() {
|
||||
|
||||
final ByteBuffer robotoData = (await (await httpFetch('/assets/fonts/Roboto-Regular.ttf')).arrayBuffer())! as ByteBuffer;
|
||||
|
||||
await fontCollection.registerFonts(mockAssetManager);
|
||||
fontCollection.debugRegisterTestFonts();
|
||||
await fontCollection.ensureFontsLoaded();
|
||||
await fontCollection.downloadAssetFonts(mockAssetManager);
|
||||
await fontCollection.debugDownloadTestFonts();
|
||||
fontCollection.registerDownloadedFonts();
|
||||
expect(warnings, isEmpty);
|
||||
|
||||
// Use `singleWhere` to make sure only one version of 'Ahem' is loaded.
|
||||
final RegisteredFont ahem = fontCollection.debugDownloadedFonts!
|
||||
final RegisteredFont ahem = fontCollection.debugRegisteredFonts!
|
||||
.singleWhere((RegisteredFont font) => font.family == 'Ahem');
|
||||
|
||||
// Check that the contents of 'Ahem' is actually Roboto, because that's
|
||||
@@ -111,18 +112,31 @@ void testMain() {
|
||||
|
||||
final ByteBuffer ahemData = (await (await httpFetch('/assets/fonts/ahem.ttf')).arrayBuffer())! as ByteBuffer;
|
||||
|
||||
await fontCollection.registerFonts(mockAssetManager);
|
||||
fontCollection.debugRegisterTestFonts();
|
||||
await fontCollection.ensureFontsLoaded();
|
||||
await fontCollection.downloadAssetFonts(mockAssetManager);
|
||||
await fontCollection.debugDownloadTestFonts();
|
||||
fontCollection.registerDownloadedFonts();
|
||||
expect(warnings, isEmpty);
|
||||
|
||||
// Use `singleWhere` to make sure only one version of 'Ahem' is loaded.
|
||||
final RegisteredFont ahem = fontCollection.debugDownloadedFonts!
|
||||
final RegisteredFont ahem = fontCollection.debugRegisteredFonts!
|
||||
.singleWhere((RegisteredFont font) => font.family == 'Ahem');
|
||||
|
||||
// Check that the contents of 'Ahem' is actually Roboto, because that's
|
||||
// what's specified in the manifest, and the manifest takes precedence.
|
||||
expect(ahem.bytes.length, ahemData.lengthInBytes);
|
||||
});
|
||||
|
||||
test('download fonts separately from registering', () async {
|
||||
final SkiaFontCollection fontCollection = SkiaFontCollection();
|
||||
|
||||
await fontCollection.debugDownloadTestFonts();
|
||||
/// Fonts should have been downloaded, but not yet registered
|
||||
expect(fontCollection.debugRegisteredFonts, isEmpty);
|
||||
|
||||
fontCollection.registerDownloadedFonts();
|
||||
/// Fonts should now be registered and _registeredFonts should be filled
|
||||
expect(fontCollection.debugRegisteredFonts, isNotEmpty);
|
||||
expect(warnings, isEmpty);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ void main() {
|
||||
Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
Future<Image> createTestImageByColor(Color color) async {
|
||||
|
||||
@@ -19,8 +19,8 @@ Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
debugEmulateFlutterTesterEnvironment = true;
|
||||
await webOnlyInitializePlatform();
|
||||
engine.renderer.fontCollection.debugRegisterTestFonts();
|
||||
await engine.renderer.fontCollection.ensureFontsLoaded();
|
||||
await engine.renderer.fontCollection.debugDownloadTestFonts();
|
||||
engine.renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/48683
|
||||
|
||||
@@ -22,8 +22,8 @@ Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
debugEmulateFlutterTesterEnvironment = true;
|
||||
await webOnlyInitializePlatform();
|
||||
engine.renderer.fontCollection.debugRegisterTestFonts();
|
||||
await engine.renderer.fontCollection.ensureFontsLoaded();
|
||||
await engine.renderer.fontCollection.debugDownloadTestFonts();
|
||||
engine.renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/49429
|
||||
|
||||
@@ -25,8 +25,8 @@ Future<void> testMain() async {
|
||||
setUp(() async {
|
||||
debugEmulateFlutterTesterEnvironment = true;
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/51514
|
||||
|
||||
@@ -16,8 +16,8 @@ void main() {
|
||||
Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
setUp(() async {
|
||||
|
||||
@@ -20,8 +20,8 @@ Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
debugEmulateFlutterTesterEnvironment = true;
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
test('Blend circles with difference and color', () async {
|
||||
|
||||
@@ -20,8 +20,8 @@ Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
debugEmulateFlutterTesterEnvironment = true;
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
const Color red = Color(0xFFFF0000);
|
||||
|
||||
@@ -20,8 +20,8 @@ Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
ui.debugEmulateFlutterTesterEnvironment = true;
|
||||
await ui.webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
|
||||
@@ -20,8 +20,8 @@ void main() {
|
||||
Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
setUp(() async {
|
||||
|
||||
@@ -21,8 +21,8 @@ void main() {
|
||||
Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
await ui.webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
setUp(() async {
|
||||
|
||||
@@ -16,8 +16,8 @@ Future<void> testMain() async {
|
||||
setUp(() async {
|
||||
debugEmulateFlutterTesterEnvironment = true;
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
test('Should blur rectangles based on sigma.', () async {
|
||||
|
||||
@@ -18,8 +18,8 @@ Future<void> testMain() async {
|
||||
debugShowClipLayers = true;
|
||||
SurfaceSceneBuilder.debugForgetFrameScene();
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
|
||||
@@ -21,8 +21,8 @@ Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
debugShowClipLayers = true;
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
setUp(() async {
|
||||
|
||||
@@ -25,8 +25,8 @@ Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
debugEmulateFlutterTesterEnvironment = true;
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
setUp(() {
|
||||
|
||||
@@ -25,8 +25,8 @@ Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
debugEmulateFlutterTesterEnvironment = true;
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
test('Should calculate tangent on line', () async {
|
||||
|
||||
@@ -23,8 +23,8 @@ Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
debugEmulateFlutterTesterEnvironment = true;
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
test('Should draw transformed line.', () async {
|
||||
|
||||
@@ -77,7 +77,7 @@ Future<void> sceneScreenshot(SurfaceSceneBuilder sceneBuilder, String fileName,
|
||||
void setUpStableTestFonts() {
|
||||
setUpAll(() async {
|
||||
await ui.webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
debugEmulateFlutterTesterEnvironment = true;
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
void drawShapes(RecordingCanvas rc, SurfacePaint paint, Rect shaderRect) {
|
||||
|
||||
@@ -21,8 +21,8 @@ Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
debugEmulateFlutterTesterEnvironment = true;
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
test('Should draw linear gradient using rectangle.', () async {
|
||||
|
||||
@@ -17,8 +17,8 @@ Future<void> testMain() async {
|
||||
setUpAll(() async {
|
||||
debugEmulateFlutterTesterEnvironment = true;
|
||||
await webOnlyInitializePlatform();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
Future<void> testGradient(String fileName, Shader shader,
|
||||
|
||||
@@ -41,8 +41,8 @@ Future<void> testMain() async {
|
||||
scene.remove();
|
||||
}
|
||||
initWebGl();
|
||||
renderer.fontCollection.debugRegisterTestFonts();
|
||||
await renderer.fontCollection.ensureFontsLoaded();
|
||||
await renderer.fontCollection.debugDownloadTestFonts();
|
||||
renderer.fontCollection.registerDownloadedFonts();
|
||||
});
|
||||
|
||||
/// Should render the picture unmodified.
|
||||
|
||||
@@ -29,9 +29,10 @@ void testMain() {
|
||||
const String testFontFamily = 'Ahem';
|
||||
final List<String> fontFamilyList = <String>[];
|
||||
|
||||
fontManager.registerAsset(
|
||||
fontManager.downloadAsset(
|
||||
testFontFamily, 'url($testFontUrl)', const <String, String>{});
|
||||
await fontManager.ensureFontsLoaded();
|
||||
await fontManager.downloadAllFonts();
|
||||
fontManager.registerDownloadedFonts();
|
||||
domDocument.fonts!
|
||||
.forEach(allowInterop((DomFontFace f, DomFontFace f2, DomFontFaceSet s) {
|
||||
fontFamilyList.add(f.family!);
|
||||
@@ -45,9 +46,10 @@ void testMain() {
|
||||
const String testFontFamily = 'Ahem ahem ahem';
|
||||
final List<String> fontFamilyList = <String>[];
|
||||
|
||||
fontManager.registerAsset(
|
||||
fontManager.downloadAsset(
|
||||
testFontFamily, 'url($testFontUrl)', const <String, String>{});
|
||||
await fontManager.ensureFontsLoaded();
|
||||
await fontManager.downloadAllFonts();
|
||||
fontManager.registerDownloadedFonts();
|
||||
domDocument.fonts!
|
||||
.forEach(allowInterop((DomFontFace f, DomFontFace f2, DomFontFaceSet s) {
|
||||
fontFamilyList.add(f.family!);
|
||||
@@ -63,9 +65,10 @@ void testMain() {
|
||||
const String testFontFamily = 'AhEm';
|
||||
final List<String> fontFamilyList = <String>[];
|
||||
|
||||
fontManager.registerAsset(
|
||||
fontManager.downloadAsset(
|
||||
testFontFamily, 'url($testFontUrl)', const <String, String>{});
|
||||
await fontManager.ensureFontsLoaded();
|
||||
await fontManager.downloadAllFonts();
|
||||
fontManager.registerDownloadedFonts();
|
||||
domDocument.fonts!
|
||||
.forEach(allowInterop((DomFontFace f, DomFontFace f2, DomFontFaceSet s) {
|
||||
fontFamilyList.add(f.family!);
|
||||
@@ -81,9 +84,10 @@ void testMain() {
|
||||
const String testFontFamily = '/Ahem';
|
||||
final List<String> fontFamilyList = <String>[];
|
||||
|
||||
fontManager.registerAsset(
|
||||
fontManager.downloadAsset(
|
||||
testFontFamily, 'url($testFontUrl)', const <String, String>{});
|
||||
await fontManager.ensureFontsLoaded();
|
||||
await fontManager.downloadAllFonts();
|
||||
fontManager.registerDownloadedFonts();
|
||||
domDocument.fonts!
|
||||
.forEach(allowInterop((DomFontFace f, DomFontFace f2, DomFontFaceSet s) {
|
||||
fontFamilyList.add(f.family!);
|
||||
@@ -105,9 +109,10 @@ void testMain() {
|
||||
const String testFontFamily = 'Ahem!!ahem';
|
||||
final List<String> fontFamilyList = <String>[];
|
||||
|
||||
fontManager.registerAsset(
|
||||
fontManager.downloadAsset(
|
||||
testFontFamily, 'url($testFontUrl)', const <String, String>{});
|
||||
await fontManager.ensureFontsLoaded();
|
||||
await fontManager.downloadAllFonts();
|
||||
fontManager.registerDownloadedFonts();
|
||||
domDocument.fonts!
|
||||
.forEach(allowInterop((DomFontFace f, DomFontFace f2, DomFontFaceSet s) {
|
||||
fontFamilyList.add(f.family!);
|
||||
@@ -129,9 +134,10 @@ void testMain() {
|
||||
const String testFontFamily = 'Ahem ,ahem';
|
||||
final List<String> fontFamilyList = <String>[];
|
||||
|
||||
fontManager.registerAsset(
|
||||
fontManager.downloadAsset(
|
||||
testFontFamily, 'url($testFontUrl)', const <String, String>{});
|
||||
await fontManager.ensureFontsLoaded();
|
||||
await fontManager.downloadAllFonts();
|
||||
fontManager.registerDownloadedFonts();
|
||||
domDocument.fonts!
|
||||
.forEach(allowInterop((DomFontFace f, DomFontFace f2, DomFontFaceSet s) {
|
||||
fontFamilyList.add(f.family!);
|
||||
@@ -154,9 +160,10 @@ void testMain() {
|
||||
const String testFontFamily = 'Ahem 1998';
|
||||
final List<String> fontFamilyList = <String>[];
|
||||
|
||||
fontManager.registerAsset(
|
||||
fontManager.downloadAsset(
|
||||
testFontFamily, 'url($testFontUrl)', const <String, String>{});
|
||||
await fontManager.ensureFontsLoaded();
|
||||
await fontManager.downloadAllFonts();
|
||||
fontManager.registerDownloadedFonts();
|
||||
domDocument.fonts!
|
||||
.forEach(allowInterop((DomFontFace f, DomFontFace f2, DomFontFaceSet s) {
|
||||
fontFamilyList.add(f.family!);
|
||||
|
||||
Reference in New Issue
Block a user