Skip to content

Commit 8824603

Browse files
Add variable font axes to TextStyle (#100978)
1 parent 17be6d7 commit 8824603

File tree

3 files changed

+53
-5
lines changed

3 files changed

+53
-5
lines changed

packages/flutter/lib/src/painting/text_style.dart

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:ui' as ui show ParagraphStyle, TextStyle, StrutStyle, lerpDouble, Shadow, FontFeature, TextHeightBehavior, TextLeadingDistribution;
5+
import 'dart:ui' as ui show ParagraphStyle, TextStyle, StrutStyle, lerpDouble, Shadow, FontFeature, FontVariation, TextHeightBehavior, TextLeadingDistribution;
66

77
import 'package:flutter/foundation.dart';
88

@@ -482,6 +482,7 @@ class TextStyle with Diagnosticable {
482482
this.background,
483483
this.shadows,
484484
this.fontFeatures,
485+
this.fontVariations,
485486
this.decoration,
486487
this.decorationColor,
487488
this.decorationStyle,
@@ -769,6 +770,23 @@ class TextStyle with Diagnosticable {
769770
/// these variants will be used for rendering.
770771
final List<ui.FontFeature>? fontFeatures;
771772

773+
/// A list of [FontVariation]s that affect how a variable font is rendered.
774+
///
775+
/// Some fonts are variable fonts that can generate multiple font faces based
776+
/// on the values of customizable attributes. For example, a variable font
777+
/// may have a weight axis that can be set to a value between 1 and 1000.
778+
/// [FontVariation]s can be used to select the values of these design axes.
779+
///
780+
/// For example, to control the weight axis of the Roboto Slab variable font
781+
/// (https://fonts.google.com/specimen/Roboto+Slab):
782+
/// ```dart
783+
/// TextStyle(
784+
/// fontFamily: 'RobotoSlab',
785+
/// fontVariations: <FontVariation>[FontVariation('wght', 900.0)]
786+
/// )
787+
/// ```
788+
final List<ui.FontVariation>? fontVariations;
789+
772790
/// How visual text overflow should be handled.
773791
final TextOverflow? overflow;
774792

@@ -809,6 +827,7 @@ class TextStyle with Diagnosticable {
809827
Paint? background,
810828
List<ui.Shadow>? shadows,
811829
List<ui.FontFeature>? fontFeatures,
830+
List<ui.FontVariation>? fontVariations,
812831
TextDecoration? decoration,
813832
Color? decorationColor,
814833
TextDecorationStyle? decorationStyle,
@@ -845,6 +864,7 @@ class TextStyle with Diagnosticable {
845864
background: background ?? this.background,
846865
shadows: shadows ?? this.shadows,
847866
fontFeatures: fontFeatures ?? this.fontFeatures,
867+
fontVariations: fontVariations ?? this.fontVariations,
848868
decoration: decoration ?? this.decoration,
849869
decorationColor: decorationColor ?? this.decorationColor,
850870
decorationStyle: decorationStyle ?? this.decorationStyle,
@@ -911,6 +931,7 @@ class TextStyle with Diagnosticable {
911931
Locale? locale,
912932
List<ui.Shadow>? shadows,
913933
List<ui.FontFeature>? fontFeatures,
934+
List<ui.FontVariation>? fontVariations,
914935
String? package,
915936
TextOverflow? overflow,
916937
}) {
@@ -957,6 +978,7 @@ class TextStyle with Diagnosticable {
957978
background: background,
958979
shadows: shadows ?? this.shadows,
959980
fontFeatures: fontFeatures ?? this.fontFeatures,
981+
fontVariations: fontVariations ?? this.fontVariations,
960982
decoration: decoration ?? this.decoration,
961983
decorationColor: decorationColor ?? this.decorationColor,
962984
decorationStyle: decorationStyle ?? this.decorationStyle,
@@ -1017,6 +1039,7 @@ class TextStyle with Diagnosticable {
10171039
background: other.background,
10181040
shadows: other.shadows,
10191041
fontFeatures: other.fontFeatures,
1042+
fontVariations: other.fontVariations,
10201043
decoration: other.decoration,
10211044
decorationColor: other.decorationColor,
10221045
decorationStyle: other.decorationStyle,
@@ -1073,6 +1096,7 @@ class TextStyle with Diagnosticable {
10731096
background: t < 0.5 ? null : b.background,
10741097
shadows: t < 0.5 ? null : b.shadows,
10751098
fontFeatures: t < 0.5 ? null : b.fontFeatures,
1099+
fontVariations: t < 0.5 ? null : b.fontVariations,
10761100
decoration: t < 0.5 ? null : b.decoration,
10771101
decorationColor: Color.lerp(null, b.decorationColor, t),
10781102
decorationStyle: t < 0.5 ? null : b.decorationStyle,
@@ -1103,6 +1127,7 @@ class TextStyle with Diagnosticable {
11031127
background: t < 0.5 ? a.background : null,
11041128
shadows: t < 0.5 ? a.shadows : null,
11051129
fontFeatures: t < 0.5 ? a.fontFeatures : null,
1130+
fontVariations: t < 0.5 ? a.fontVariations : null,
11061131
decoration: t < 0.5 ? a.decoration : null,
11071132
decorationColor: Color.lerp(a.decorationColor, null, t),
11081133
decorationStyle: t < 0.5 ? a.decorationStyle : null,
@@ -1140,6 +1165,7 @@ class TextStyle with Diagnosticable {
11401165
: null,
11411166
shadows: t < 0.5 ? a.shadows : b.shadows,
11421167
fontFeatures: t < 0.5 ? a.fontFeatures : b.fontFeatures,
1168+
fontVariations: t < 0.5 ? a.fontVariations : b.fontVariations,
11431169
decoration: t < 0.5 ? a.decoration : b.decoration,
11441170
decorationColor: Color.lerp(a.decorationColor, b.decorationColor, t),
11451171
decorationStyle: t < 0.5 ? a.decorationStyle : b.decorationStyle,
@@ -1178,6 +1204,7 @@ class TextStyle with Diagnosticable {
11781204
),
11791205
shadows: shadows,
11801206
fontFeatures: fontFeatures,
1207+
fontVariations: fontVariations,
11811208
);
11821209
}
11831210

@@ -1260,6 +1287,7 @@ class TextStyle with Diagnosticable {
12601287
background != other.background ||
12611288
!listEquals(shadows, other.shadows) ||
12621289
!listEquals(fontFeatures, other.fontFeatures) ||
1290+
!listEquals(fontVariations, other.fontVariations) ||
12631291
!listEquals(fontFamilyFallback, other.fontFamilyFallback) ||
12641292
overflow != other.overflow)
12651293
return RenderComparison.layout;
@@ -1296,6 +1324,7 @@ class TextStyle with Diagnosticable {
12961324
&& other.background == background
12971325
&& listEquals(other.shadows, shadows)
12981326
&& listEquals(other.fontFeatures, fontFeatures)
1327+
&& listEquals(other.fontVariations, fontVariations)
12991328
&& other.decoration == decoration
13001329
&& other.decorationColor == decorationColor
13011330
&& other.decorationStyle == decorationStyle
@@ -1324,10 +1353,11 @@ class TextStyle with Diagnosticable {
13241353
background,
13251354
shadows == null ? null : Object.hashAll(shadows!),
13261355
fontFeatures == null ? null : Object.hashAll(fontFeatures!),
1356+
fontVariations == null ? null : Object.hashAll(fontVariations!),
13271357
decoration,
13281358
decorationColor,
1329-
decorationStyle,
13301359
Object.hash(
1360+
decorationStyle,
13311361
decorationThickness,
13321362
fontFamily,
13331363
fontFamilyFallback == null ? null : Object.hashAll(fontFamilyFallback!),

packages/flutter/test/material/theme_test.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,8 @@ class _TextStyleProxy implements TextStyle {
755755
@override
756756
List<ui.FontFeature>? get fontFeatures => _delegate.fontFeatures;
757757
@override
758+
List<ui.FontVariation>? get fontVariations => _delegate.fontVariations;
759+
@override
758760
TextOverflow? get overflow => _delegate.overflow;
759761

760762
@override
@@ -797,6 +799,7 @@ class _TextStyleProxy implements TextStyle {
797799
Locale? locale,
798800
List<ui.Shadow>? shadows,
799801
List<ui.FontFeature>? fontFeatures,
802+
List<ui.FontVariation>? fontVariations,
800803
TextOverflow? overflow,
801804
String? package,
802805
}) {
@@ -828,6 +831,7 @@ class _TextStyleProxy implements TextStyle {
828831
ui.Paint? background,
829832
List<Shadow>? shadows,
830833
List<ui.FontFeature>? fontFeatures,
834+
List<ui.FontVariation>? fontVariations,
831835
TextDecoration? decoration,
832836
Color? decorationColor,
833837
TextDecorationStyle? decorationStyle,

packages/flutter/test/painting/text_style_test.dart

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:ui' as ui show TextStyle, ParagraphStyle, FontFeature, Shadow;
5+
import 'dart:ui' as ui show TextStyle, ParagraphStyle, FontFeature, FontVariation, Shadow;
66

77
import 'package:flutter/foundation.dart';
88
import 'package:flutter/painting.dart';
@@ -38,6 +38,7 @@ class _DartUiTextStyleToStringMatcher extends Matcher {
3838
_propertyToString('foreground', textStyle.foreground),
3939
_propertyToString('shadows', textStyle.shadows),
4040
_propertyToString('fontFeatures', textStyle.fontFeatures),
41+
_propertyToString('fontVariations', textStyle.fontVariations),
4142
];
4243

4344
static String _propertyToString(String name, Object? property) => '$name: ${property ?? 'unspecified'}';
@@ -354,8 +355,18 @@ void main() {
354355
});
355356

356357
test('TextStyle.hashCode', () {
357-
const TextStyle a = TextStyle(fontFamilyFallback: <String>['Roboto'], shadows: <ui.Shadow>[ui.Shadow()], fontFeatures: <ui.FontFeature>[ui.FontFeature('abcd')]);
358-
const TextStyle b = TextStyle(fontFamilyFallback: <String>['Noto'], shadows: <ui.Shadow>[ui.Shadow()], fontFeatures: <ui.FontFeature>[ui.FontFeature('abcd')]);
358+
const TextStyle a = TextStyle(
359+
fontFamilyFallback: <String>['Roboto'],
360+
shadows: <ui.Shadow>[ui.Shadow()],
361+
fontFeatures: <ui.FontFeature>[ui.FontFeature('abcd')],
362+
fontVariations: <ui.FontVariation>[ui.FontVariation('wght', 123.0)],
363+
);
364+
const TextStyle b = TextStyle(
365+
fontFamilyFallback: <String>['Noto'],
366+
shadows: <ui.Shadow>[ui.Shadow()],
367+
fontFeatures: <ui.FontFeature>[ui.FontFeature('abcd')],
368+
fontVariations: <ui.FontVariation>[ui.FontVariation('wght', 123.0)],
369+
);
359370
expect(a.hashCode, a.hashCode);
360371
expect(a.hashCode, isNot(equals(b.hashCode)));
361372

@@ -476,6 +487,7 @@ void main() {
476487
shadows: <ui.Shadow>[],
477488
fontStyle: FontStyle.normal,
478489
fontFeatures: <ui.FontFeature>[],
490+
fontVariations: <ui.FontVariation>[],
479491
textBaseline: TextBaseline.alphabetic,
480492
leadingDistribution: TextLeadingDistribution.even,
481493
);
@@ -487,6 +499,8 @@ void main() {
487499
expect(style.apply(locale: const Locale.fromSubtags(languageCode: 'es')).locale, const Locale.fromSubtags(languageCode: 'es'));
488500
expect(style.apply().fontFeatures, const <ui.FontFeature>[]);
489501
expect(style.apply(fontFeatures: const <ui.FontFeature>[ui.FontFeature.enable('test')]).fontFeatures, const <ui.FontFeature>[ui.FontFeature.enable('test')]);
502+
expect(style.apply().fontVariations, const <ui.FontVariation>[]);
503+
expect(style.apply(fontVariations: const <ui.FontVariation>[ui.FontVariation('test', 100.0)]).fontVariations, const <ui.FontVariation>[ui.FontVariation('test', 100.0)]);
490504
expect(style.apply().textBaseline, TextBaseline.alphabetic);
491505
expect(style.apply(textBaseline: TextBaseline.ideographic).textBaseline, TextBaseline.ideographic);
492506
expect(style.apply().leadingDistribution, TextLeadingDistribution.even);

0 commit comments

Comments
 (0)