Unverified Commit 00565c2d authored by Jason Simmons's avatar Jason Simmons Committed by GitHub

An API for dynamically loading fonts (#23595)

See https://github.com/flutter/flutter/issues/17910
parent 3789f478
......@@ -13,6 +13,7 @@ library services;
export 'src/services/asset_bundle.dart';
export 'src/services/binding.dart';
export 'src/services/clipboard.dart';
export 'src/services/font_loader.dart';
export 'src/services/haptic_feedback.dart';
export 'src/services/message_codec.dart';
export 'src/services/message_codecs.dart';
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// 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 'dart:ui';
import 'package:flutter/foundation.dart';
/// A class that enables the dynamic loading of fonts at runtime.
///
/// The [FontLoader] class provides a builder pattern, where the caller builds
/// up the assets that make up a font family, then calls [load] to load the
/// entire font family into a running Flutter application.
class FontLoader {
/// Creates a new [FontLoader] that will load font assets for the specified
/// [family].
///
/// The font family will not be available for use until [load] has been
/// called.
FontLoader(this.family)
: _loaded = false,
_fontFutures = <Future<Uint8List>>[];
/// The font family being loaded.
///
/// The family groups a series of related font assets, each of which defines
/// how to render a specific [FontWeight] and [FontStyle] within the family.
final String family;
/// Registers a font asset to be loaded by this font loader.
///
/// The [bytes] argument specifies the actual font asset bytes. Currently,
/// only TrueType (TTF) fonts are supported.
void addFont(Future<ByteData> bytes) {
if (_loaded)
throw StateError('FontLoader is already loaded');
_fontFutures.add(bytes.then(
(ByteData data) => Uint8List.view(data.buffer, data.offsetInBytes, data.lengthInBytes)
));
}
/// Loads this font loader's font [family] and all of its associated assets
/// into the Flutter engine, making the font available to the current
/// application.
///
/// This method should only be called once per font loader. Attempts to
/// load fonts from the same loader more than once will cause a [StateError]
/// to be thrown.
///
/// The returned future will complete with an error if any of the font asset
/// futures yield an error.
Future<void> load() async {
if (_loaded)
throw StateError('FontLoader is already loaded');
_loaded = true;
final Iterable<Future<void>> loadFutures = _fontFutures.map(
(Future<Uint8List> f) => f.then<void>(
(Uint8List list) => loadFont(list, family)
)
);
return Future.wait(loadFutures.toList());
}
@protected
@visibleForTesting
Future<void> loadFont(Uint8List list, String family) {
return loadFontFromList(list, fontFamily: family);
}
bool _loaded;
final List<Future<Uint8List>> _fontFutures;
}
// Copyright 2018 The Chromium Authors. All rights reserved.
// 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 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
class TestFontLoader extends FontLoader {
TestFontLoader(String family) : super(family);
@override
Future<void> loadFont(Uint8List list, String family) async {
fontAssets.add(list);
}
List<Uint8List> fontAssets = <Uint8List>[];
}
void main() {
test('Font loader test', () async {
final TestFontLoader tfl = TestFontLoader('TestFamily');
final List<Uint8List> expectedAssets = <Uint8List>[
Uint8List.fromList(<int>[100]),
Uint8List.fromList(<int>[10, 20, 30]),
Uint8List.fromList(<int>[200]),
];
for (Uint8List asset in expectedAssets) {
tfl.addFont(Future<ByteData>.value(ByteData.view(asset.buffer)));
}
await tfl.load();
expect(tfl.fontAssets, unorderedEquals(expectedAssets));
});
}
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