part of dart._engine; // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. class FontAsset { FontAsset(this.asset, this.descriptors); final String asset; final Map descriptors; } class FontFamily { FontFamily(this.name, this.fontAssets); final String name; final List fontAssets; } class FontManifest { FontManifest(this.families); final List families; } Future fetchFontManifest(ui_web.AssetManager assetManager) async { final HttpFetchResponse response = await assetManager.loadAsset('FontManifest.json') as HttpFetchResponse; if (!response.hasPayload) { printWarning('Font manifest does not exist at `${response.url}` - ignoring.'); return FontManifest([]); } final Converter, Object?> decoder = const Utf8Decoder().fuse(const JsonDecoder()); Object? fontManifestJson; final Sink> inputSink = decoder.startChunkedConversion( ChunkedConversionSink.withCallback((List accumulated) { if (accumulated.length != 1) { throw AssertionError('There was a problem trying to load FontManifest.json'); } fontManifestJson = accumulated.first; }), ); await response.read((JSUint8Array chunk) => inputSink.add(chunk.toDart)); inputSink.close(); if (fontManifestJson == null) { throw AssertionError('There was a problem trying to load FontManifest.json'); } final List families = (fontManifestJson! as List).map((dynamic fontFamilyJson) { final Map fontFamily = fontFamilyJson as Map; final String familyName = fontFamily.readString('family'); final List fontAssets = fontFamily.readList('fonts'); return FontFamily( familyName, fontAssets.map((dynamic fontAssetJson) { String? asset; final Map descriptors = {}; for (final MapEntry descriptor in (fontAssetJson as Map).entries) { if (descriptor.key == 'asset') { asset = descriptor.value as String; } else { // Sometimes these descriptors are strings, and sometimes numbers, so we stringify them here. descriptors[descriptor.key] = '${descriptor.value}'; } } if (asset == null) { throw AssertionError("Invalid Font manifest, missing 'asset' key on font."); } return FontAsset(asset, descriptors); }).toList(), ); }).toList(); return FontManifest(families); } abstract class FontLoadError extends Error { FontLoadError(this.url); String url; String get message; } class FontNotFoundError extends FontLoadError { FontNotFoundError(super.url); @override String get message => 'Font asset not found at url $url.'; } class FontDownloadError extends FontLoadError { FontDownloadError(super.url, this.error); dynamic error; @override String get message => 'Failed to download font asset at url $url with error: $error.'; } class FontInvalidDataError extends FontLoadError { FontInvalidDataError(super.url); @override String get message => 'Invalid data for font asset at url $url.'; } class AssetFontsResult { AssetFontsResult(this.loadedFonts, this.fontFailures); /// A list of asset keys for fonts that were successfully loaded. final List loadedFonts; /// A map of the asset keys to failures for fonts that failed to load. final Map fontFailures; } abstract class FlutterFontCollection { /// Loads a font directly from font data. Future loadFontFromList(Uint8List list, {String? fontFamily}); /// Completes when fonts from FontManifest.json have been loaded. Future loadAssetFonts(FontManifest manifest); // The font fallback manager for this font collection. HTML renderer doesn't // have a font fallback manager and just relies on the browser to fall back // properly. FontFallbackManager? get fontFallbackManager; // Reset the state of font fallbacks. Only to be used in testing. void debugResetFallbackFonts(); // Unregisters all fonts. void clear(); }