From 47c7ac62d2bce35c3748866674f098ee34b6f16f Mon Sep 17 00:00:00 2001 From: Frank Koenders <8014077+Frank3K@users.noreply.github.com> Date: Fri, 2 Jan 2026 06:51:38 +0100 Subject: [PATCH 1/2] [google_fonts] Add WOFF and WOFF2 font format support for web Adds support for WOFF and WOFF2 font formats when running on web platforms, in addition to the existing TTF and OTF support. This improves web performance as WOFF2 is a more compressed format optimized for web delivery. Non-web platforms continue to support only .ttf and .otf. --- packages/google_fonts/CHANGELOG.md | 4 + .../lib/src/google_fonts_base.dart | 19 +- packages/google_fonts/pubspec.yaml | 2 +- ...mily_with_variant_asset_path_web_test.dart | 188 ++++++++++++++++++ 4 files changed, 204 insertions(+), 9 deletions(-) create mode 100644 packages/google_fonts/test/find_family_with_variant_asset_path_web_test.dart diff --git a/packages/google_fonts/CHANGELOG.md b/packages/google_fonts/CHANGELOG.md index 9dfd4c013701..c9fe22eeae8a 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 c8e956b5fabc..9e192d97d826 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 16ceab695ddb..565977ed2bf0 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 000000000000..45bcd21b2abe --- /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')); + }); + }); + }); +} From 1bac76886d29d116a8485513e6ee5f48748d3c3f Mon Sep 17 00:00:00 2001 From: Frank Koenders <8014077+Frank3K@users.noreply.github.com> Date: Wed, 14 Jan 2026 20:55:48 +0100 Subject: [PATCH 2/2] [google_fonts] Clarify WOFF2 changelog entry scope --- packages/google_fonts/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google_fonts/CHANGELOG.md b/packages/google_fonts/CHANGELOG.md index 319ce707b5f5..49f8b565b10e 100644 --- a/packages/google_fonts/CHANGELOG.md +++ b/packages/google_fonts/CHANGELOG.md @@ -1,6 +1,6 @@ ## 7.1.0 -- Adds support for WOFF2 and WOFF font formats on web platforms for improved performance and smaller bundle sizes. +- Adds support for WOFF2 and WOFF font formats on web platforms when loading fonts bundled with the app, providing improved performance and smaller bundle sizes. ## 7.0.2