diff --git a/packages/google_fonts/CHANGELOG.md b/packages/google_fonts/CHANGELOG.md index 9dfd4c01370..c9fe22eeae8 100644 --- a/packages/google_fonts/CHANGELOG.md +++ b/packages/google_fonts/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.4.0 + +- Adds support for WOFF2 and WOFF font formats on web platforms for improved performance and smaller bundle sizes. + ## 6.3.3 - Replaces use of the deprecated `FontWeight.index`. diff --git a/packages/google_fonts/lib/src/google_fonts_base.dart b/packages/google_fonts/lib/src/google_fonts_base.dart index c8e956b5fab..9e192d97d82 100755 --- a/packages/google_fonts/lib/src/google_fonts_base.dart +++ b/packages/google_fonts/lib/src/google_fonts_base.dart @@ -6,6 +6,7 @@ // ignore_for_file: avoid_print import 'package:crypto/crypto.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; @@ -145,7 +146,7 @@ Future loadFontIfNecessary(GoogleFontsDescriptor descriptor) async { // Check if this font can be loaded by the pre-bundled assets. assetManifest ??= await AssetManifest.loadFromAssetBundle(rootBundle); - final String? assetPath = _findFamilyWithVariantAssetPath( + final String? assetPath = findFamilyWithVariantAssetPath( descriptor.familyWithVariant, assetManifest?.listAssets(), ); @@ -305,21 +306,23 @@ int _computeMatch(GoogleFontsVariant a, GoogleFontsVariant b) { /// Looks for a matching [familyWithVariant] font, provided the asset manifest. /// Returns the path of the font asset if found, otherwise an empty string. -String? _findFamilyWithVariantAssetPath( +@visibleForTesting +String? findFamilyWithVariantAssetPath( GoogleFontsFamilyWithVariant familyWithVariant, - List? manifestValues, -) { + List? manifestValues, { + bool isWeb = kIsWeb, +}) { if (manifestValues == null) { return null; } final String apiFilenamePrefix = familyWithVariant.toApiFilenamePrefix(); + final fileTypes = isWeb + ? ['.woff2', '.woff', '.ttf', '.otf'] + : ['.ttf', '.otf']; for (final String asset in manifestValues) { - for (final String matchingSuffix in [ - '.ttf', - '.otf', - ].where(asset.endsWith)) { + for (final String matchingSuffix in fileTypes.where(asset.endsWith)) { final String assetWithoutExtension = asset.substring( 0, asset.length - matchingSuffix.length, diff --git a/packages/google_fonts/pubspec.yaml b/packages/google_fonts/pubspec.yaml index 16ceab695dd..565977ed2bf 100644 --- a/packages/google_fonts/pubspec.yaml +++ b/packages/google_fonts/pubspec.yaml @@ -2,7 +2,7 @@ name: google_fonts description: A Flutter package to use fonts from fonts.google.com. Supports HTTP fetching, caching, and asset bundling. repository: https://github.com/flutter/packages/tree/main/packages/google_fonts issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_fonts%22 -version: 6.3.3 +version: 6.4.0 environment: sdk: ^3.9.0 diff --git a/packages/google_fonts/test/find_family_with_variant_asset_path_web_test.dart b/packages/google_fonts/test/find_family_with_variant_asset_path_web_test.dart new file mode 100644 index 00000000000..45bcd21b2ab --- /dev/null +++ b/packages/google_fonts/test/find_family_with_variant_asset_path_web_test.dart @@ -0,0 +1,188 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_fonts/src/google_fonts_base.dart'; +import 'package:google_fonts/src/google_fonts_family_with_variant.dart'; +import 'package:google_fonts/src/google_fonts_variant.dart'; + +void main() { + group('findFamilyWithVariantAssetPath', () { + const familyWithVariant = GoogleFontsFamilyWithVariant( + family: 'Roboto', + googleFontsVariant: GoogleFontsVariant( + fontWeight: FontWeight.w400, + fontStyle: FontStyle.normal, + ), + ); + + group('common behavior', () { + for (final isWeb in [true, false]) { + test('returns null when manifestValues is null (web: $isWeb)', () { + final String? result = findFamilyWithVariantAssetPath( + familyWithVariant, + null, + isWeb: isWeb, + ); + expect(result, isNull); + }); + + test('returns null when manifestValues is empty (web: $isWeb)', () { + final String? result = findFamilyWithVariantAssetPath( + familyWithVariant, + [], + isWeb: isWeb, + ); + expect(result, isNull); + }); + + test('returns null when font family does not match (web: $isWeb)', () { + final String? result = findFamilyWithVariantAssetPath( + familyWithVariant, + [ + 'google_fonts/Lato-Regular.ttf', + 'google_fonts/OpenSans-Regular.ttf', + ], + isWeb: isWeb, + ); + expect(result, isNull); + }); + + test('returns null when variant does not match (web: $isWeb)', () { + final String? result = findFamilyWithVariantAssetPath( + familyWithVariant, + [ + 'google_fonts/Roboto-Bold.ttf', + 'google_fonts/Roboto-Italic.ttf', + ], + isWeb: isWeb, + ); + expect(result, isNull); + }); + + test('matches correct variant with multiple fonts (web: $isWeb)', () { + const boldItalicVariant = GoogleFontsFamilyWithVariant( + family: 'Roboto', + googleFontsVariant: GoogleFontsVariant( + fontWeight: FontWeight.w700, + fontStyle: FontStyle.italic, + ), + ); + final String? result = + findFamilyWithVariantAssetPath(boldItalicVariant, [ + 'google_fonts/Roboto-Regular.ttf', + 'google_fonts/Roboto-Bold.ttf', + 'google_fonts/Roboto-BoldItalic.ttf', + 'google_fonts/Roboto-Italic.ttf', + ], isWeb: isWeb); + expect(result, equals('google_fonts/Roboto-BoldItalic.ttf')); + }); + } + }); + + group('on web', () { + test('supports woff2 format', () { + final String? result = findFamilyWithVariantAssetPath( + familyWithVariant, + ['google_fonts/Roboto-Regular.woff2'], + isWeb: true, + ); + expect(result, equals('google_fonts/Roboto-Regular.woff2')); + }); + + test('supports woff format', () { + final String? result = findFamilyWithVariantAssetPath( + familyWithVariant, + ['google_fonts/Roboto-Regular.woff'], + isWeb: true, + ); + expect(result, equals('google_fonts/Roboto-Regular.woff')); + }); + + test('supports ttf format', () { + final String? result = findFamilyWithVariantAssetPath( + familyWithVariant, + ['google_fonts/Roboto-Regular.ttf'], + isWeb: true, + ); + expect(result, equals('google_fonts/Roboto-Regular.ttf')); + }); + + test('supports otf format', () { + final String? result = findFamilyWithVariantAssetPath( + familyWithVariant, + ['google_fonts/Roboto-Regular.otf'], + isWeb: true, + ); + expect(result, equals('google_fonts/Roboto-Regular.otf')); + }); + + test('returns first matching asset in manifest order', () { + // Returns the first asset that matches, regardless of file type + final String? result = + findFamilyWithVariantAssetPath(familyWithVariant, [ + 'google_fonts/Roboto-Regular.ttf', + 'google_fonts/Roboto-Regular.woff2', + 'google_fonts/Roboto-Regular.woff', + ], isWeb: true); + expect(result, equals('google_fonts/Roboto-Regular.ttf')); + }); + + test('ignores unsupported file extensions', () { + final String? result = + findFamilyWithVariantAssetPath(familyWithVariant, [ + 'google_fonts/Roboto-Regular.eot', + 'google_fonts/Roboto-Regular.svg', + 'google_fonts/Roboto-Regular.woff2', + ], isWeb: true); + expect(result, equals('google_fonts/Roboto-Regular.woff2')); + }); + }); + + group('on non-web', () { + test('supports ttf format', () { + final String? result = findFamilyWithVariantAssetPath( + familyWithVariant, + ['google_fonts/Roboto-Regular.ttf'], + isWeb: false, + ); + expect(result, equals('google_fonts/Roboto-Regular.ttf')); + }); + + test('supports otf format', () { + final String? result = findFamilyWithVariantAssetPath( + familyWithVariant, + ['google_fonts/Roboto-Regular.otf'], + isWeb: false, + ); + expect(result, equals('google_fonts/Roboto-Regular.otf')); + }); + + test('does not select woff2 format', () { + final String? result = findFamilyWithVariantAssetPath( + familyWithVariant, + [ + 'google_fonts/Roboto-Regular.woff2', + 'google_fonts/Roboto-Regular.ttf', + ], + isWeb: false, + ); + expect(result, equals('google_fonts/Roboto-Regular.ttf')); + }); + + test('does not select woff format', () { + final String? result = findFamilyWithVariantAssetPath( + familyWithVariant, + [ + 'google_fonts/Roboto-Regular.woff', + 'google_fonts/Roboto-Regular.otf', + ], + isWeb: false, + ); + expect(result, equals('google_fonts/Roboto-Regular.otf')); + }); + }); + }); +}