Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/google_fonts/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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`.
Expand Down
19 changes: 11 additions & 8 deletions packages/google_fonts/lib/src/google_fonts_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -145,7 +146,7 @@ Future<void> 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(),
);
Expand Down Expand Up @@ -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<String>? manifestValues,
) {
List<String>? 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 <String>[
'.ttf',
'.otf',
].where(asset.endsWith)) {
for (final String matchingSuffix in fileTypes.where(asset.endsWith)) {
final String assetWithoutExtension = asset.substring(
0,
asset.length - matchingSuffix.length,
Expand Down
2 changes: 1 addition & 1 deletion packages/google_fonts/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
<String>[],
isWeb: isWeb,
);
expect(result, isNull);
});

test('returns null when font family does not match (web: $isWeb)', () {
final String? result = findFamilyWithVariantAssetPath(
familyWithVariant,
<String>[
'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,
<String>[
'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, <String>[
'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,
<String>['google_fonts/Roboto-Regular.woff2'],
isWeb: true,
);
expect(result, equals('google_fonts/Roboto-Regular.woff2'));
});

test('supports woff format', () {
final String? result = findFamilyWithVariantAssetPath(
familyWithVariant,
<String>['google_fonts/Roboto-Regular.woff'],
isWeb: true,
);
expect(result, equals('google_fonts/Roboto-Regular.woff'));
});

test('supports ttf format', () {
final String? result = findFamilyWithVariantAssetPath(
familyWithVariant,
<String>['google_fonts/Roboto-Regular.ttf'],
isWeb: true,
);
expect(result, equals('google_fonts/Roboto-Regular.ttf'));
});

test('supports otf format', () {
final String? result = findFamilyWithVariantAssetPath(
familyWithVariant,
<String>['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, <String>[
'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, <String>[
'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,
<String>['google_fonts/Roboto-Regular.ttf'],
isWeb: false,
);
expect(result, equals('google_fonts/Roboto-Regular.ttf'));
});

test('supports otf format', () {
final String? result = findFamilyWithVariantAssetPath(
familyWithVariant,
<String>['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,
<String>[
'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,
<String>[
'google_fonts/Roboto-Regular.woff',
'google_fonts/Roboto-Regular.otf',
],
isWeb: false,
);
expect(result, equals('google_fonts/Roboto-Regular.otf'));
});
});
});
}