Unverified Commit 88246030 authored by Jason Simmons's avatar Jason Simmons Committed by GitHub

Add variable font axes to TextStyle (#100978)

parent 17be6d73
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui show ParagraphStyle, TextStyle, StrutStyle, lerpDouble, Shadow, FontFeature, TextHeightBehavior, TextLeadingDistribution; import 'dart:ui' as ui show ParagraphStyle, TextStyle, StrutStyle, lerpDouble, Shadow, FontFeature, FontVariation, TextHeightBehavior, TextLeadingDistribution;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
...@@ -482,6 +482,7 @@ class TextStyle with Diagnosticable { ...@@ -482,6 +482,7 @@ class TextStyle with Diagnosticable {
this.background, this.background,
this.shadows, this.shadows,
this.fontFeatures, this.fontFeatures,
this.fontVariations,
this.decoration, this.decoration,
this.decorationColor, this.decorationColor,
this.decorationStyle, this.decorationStyle,
...@@ -769,6 +770,23 @@ class TextStyle with Diagnosticable { ...@@ -769,6 +770,23 @@ class TextStyle with Diagnosticable {
/// these variants will be used for rendering. /// these variants will be used for rendering.
final List<ui.FontFeature>? fontFeatures; final List<ui.FontFeature>? fontFeatures;
/// A list of [FontVariation]s that affect how a variable font is rendered.
///
/// Some fonts are variable fonts that can generate multiple font faces based
/// on the values of customizable attributes. For example, a variable font
/// may have a weight axis that can be set to a value between 1 and 1000.
/// [FontVariation]s can be used to select the values of these design axes.
///
/// For example, to control the weight axis of the Roboto Slab variable font
/// (https://fonts.google.com/specimen/Roboto+Slab):
/// ```dart
/// TextStyle(
/// fontFamily: 'RobotoSlab',
/// fontVariations: <FontVariation>[FontVariation('wght', 900.0)]
/// )
/// ```
final List<ui.FontVariation>? fontVariations;
/// How visual text overflow should be handled. /// How visual text overflow should be handled.
final TextOverflow? overflow; final TextOverflow? overflow;
...@@ -809,6 +827,7 @@ class TextStyle with Diagnosticable { ...@@ -809,6 +827,7 @@ class TextStyle with Diagnosticable {
Paint? background, Paint? background,
List<ui.Shadow>? shadows, List<ui.Shadow>? shadows,
List<ui.FontFeature>? fontFeatures, List<ui.FontFeature>? fontFeatures,
List<ui.FontVariation>? fontVariations,
TextDecoration? decoration, TextDecoration? decoration,
Color? decorationColor, Color? decorationColor,
TextDecorationStyle? decorationStyle, TextDecorationStyle? decorationStyle,
...@@ -845,6 +864,7 @@ class TextStyle with Diagnosticable { ...@@ -845,6 +864,7 @@ class TextStyle with Diagnosticable {
background: background ?? this.background, background: background ?? this.background,
shadows: shadows ?? this.shadows, shadows: shadows ?? this.shadows,
fontFeatures: fontFeatures ?? this.fontFeatures, fontFeatures: fontFeatures ?? this.fontFeatures,
fontVariations: fontVariations ?? this.fontVariations,
decoration: decoration ?? this.decoration, decoration: decoration ?? this.decoration,
decorationColor: decorationColor ?? this.decorationColor, decorationColor: decorationColor ?? this.decorationColor,
decorationStyle: decorationStyle ?? this.decorationStyle, decorationStyle: decorationStyle ?? this.decorationStyle,
...@@ -911,6 +931,7 @@ class TextStyle with Diagnosticable { ...@@ -911,6 +931,7 @@ class TextStyle with Diagnosticable {
Locale? locale, Locale? locale,
List<ui.Shadow>? shadows, List<ui.Shadow>? shadows,
List<ui.FontFeature>? fontFeatures, List<ui.FontFeature>? fontFeatures,
List<ui.FontVariation>? fontVariations,
String? package, String? package,
TextOverflow? overflow, TextOverflow? overflow,
}) { }) {
...@@ -957,6 +978,7 @@ class TextStyle with Diagnosticable { ...@@ -957,6 +978,7 @@ class TextStyle with Diagnosticable {
background: background, background: background,
shadows: shadows ?? this.shadows, shadows: shadows ?? this.shadows,
fontFeatures: fontFeatures ?? this.fontFeatures, fontFeatures: fontFeatures ?? this.fontFeatures,
fontVariations: fontVariations ?? this.fontVariations,
decoration: decoration ?? this.decoration, decoration: decoration ?? this.decoration,
decorationColor: decorationColor ?? this.decorationColor, decorationColor: decorationColor ?? this.decorationColor,
decorationStyle: decorationStyle ?? this.decorationStyle, decorationStyle: decorationStyle ?? this.decorationStyle,
...@@ -1017,6 +1039,7 @@ class TextStyle with Diagnosticable { ...@@ -1017,6 +1039,7 @@ class TextStyle with Diagnosticable {
background: other.background, background: other.background,
shadows: other.shadows, shadows: other.shadows,
fontFeatures: other.fontFeatures, fontFeatures: other.fontFeatures,
fontVariations: other.fontVariations,
decoration: other.decoration, decoration: other.decoration,
decorationColor: other.decorationColor, decorationColor: other.decorationColor,
decorationStyle: other.decorationStyle, decorationStyle: other.decorationStyle,
...@@ -1073,6 +1096,7 @@ class TextStyle with Diagnosticable { ...@@ -1073,6 +1096,7 @@ class TextStyle with Diagnosticable {
background: t < 0.5 ? null : b.background, background: t < 0.5 ? null : b.background,
shadows: t < 0.5 ? null : b.shadows, shadows: t < 0.5 ? null : b.shadows,
fontFeatures: t < 0.5 ? null : b.fontFeatures, fontFeatures: t < 0.5 ? null : b.fontFeatures,
fontVariations: t < 0.5 ? null : b.fontVariations,
decoration: t < 0.5 ? null : b.decoration, decoration: t < 0.5 ? null : b.decoration,
decorationColor: Color.lerp(null, b.decorationColor, t), decorationColor: Color.lerp(null, b.decorationColor, t),
decorationStyle: t < 0.5 ? null : b.decorationStyle, decorationStyle: t < 0.5 ? null : b.decorationStyle,
...@@ -1103,6 +1127,7 @@ class TextStyle with Diagnosticable { ...@@ -1103,6 +1127,7 @@ class TextStyle with Diagnosticable {
background: t < 0.5 ? a.background : null, background: t < 0.5 ? a.background : null,
shadows: t < 0.5 ? a.shadows : null, shadows: t < 0.5 ? a.shadows : null,
fontFeatures: t < 0.5 ? a.fontFeatures : null, fontFeatures: t < 0.5 ? a.fontFeatures : null,
fontVariations: t < 0.5 ? a.fontVariations : null,
decoration: t < 0.5 ? a.decoration : null, decoration: t < 0.5 ? a.decoration : null,
decorationColor: Color.lerp(a.decorationColor, null, t), decorationColor: Color.lerp(a.decorationColor, null, t),
decorationStyle: t < 0.5 ? a.decorationStyle : null, decorationStyle: t < 0.5 ? a.decorationStyle : null,
...@@ -1140,6 +1165,7 @@ class TextStyle with Diagnosticable { ...@@ -1140,6 +1165,7 @@ class TextStyle with Diagnosticable {
: null, : null,
shadows: t < 0.5 ? a.shadows : b.shadows, shadows: t < 0.5 ? a.shadows : b.shadows,
fontFeatures: t < 0.5 ? a.fontFeatures : b.fontFeatures, fontFeatures: t < 0.5 ? a.fontFeatures : b.fontFeatures,
fontVariations: t < 0.5 ? a.fontVariations : b.fontVariations,
decoration: t < 0.5 ? a.decoration : b.decoration, decoration: t < 0.5 ? a.decoration : b.decoration,
decorationColor: Color.lerp(a.decorationColor, b.decorationColor, t), decorationColor: Color.lerp(a.decorationColor, b.decorationColor, t),
decorationStyle: t < 0.5 ? a.decorationStyle : b.decorationStyle, decorationStyle: t < 0.5 ? a.decorationStyle : b.decorationStyle,
...@@ -1178,6 +1204,7 @@ class TextStyle with Diagnosticable { ...@@ -1178,6 +1204,7 @@ class TextStyle with Diagnosticable {
), ),
shadows: shadows, shadows: shadows,
fontFeatures: fontFeatures, fontFeatures: fontFeatures,
fontVariations: fontVariations,
); );
} }
...@@ -1260,6 +1287,7 @@ class TextStyle with Diagnosticable { ...@@ -1260,6 +1287,7 @@ class TextStyle with Diagnosticable {
background != other.background || background != other.background ||
!listEquals(shadows, other.shadows) || !listEquals(shadows, other.shadows) ||
!listEquals(fontFeatures, other.fontFeatures) || !listEquals(fontFeatures, other.fontFeatures) ||
!listEquals(fontVariations, other.fontVariations) ||
!listEquals(fontFamilyFallback, other.fontFamilyFallback) || !listEquals(fontFamilyFallback, other.fontFamilyFallback) ||
overflow != other.overflow) overflow != other.overflow)
return RenderComparison.layout; return RenderComparison.layout;
...@@ -1296,6 +1324,7 @@ class TextStyle with Diagnosticable { ...@@ -1296,6 +1324,7 @@ class TextStyle with Diagnosticable {
&& other.background == background && other.background == background
&& listEquals(other.shadows, shadows) && listEquals(other.shadows, shadows)
&& listEquals(other.fontFeatures, fontFeatures) && listEquals(other.fontFeatures, fontFeatures)
&& listEquals(other.fontVariations, fontVariations)
&& other.decoration == decoration && other.decoration == decoration
&& other.decorationColor == decorationColor && other.decorationColor == decorationColor
&& other.decorationStyle == decorationStyle && other.decorationStyle == decorationStyle
...@@ -1324,10 +1353,11 @@ class TextStyle with Diagnosticable { ...@@ -1324,10 +1353,11 @@ class TextStyle with Diagnosticable {
background, background,
shadows == null ? null : Object.hashAll(shadows!), shadows == null ? null : Object.hashAll(shadows!),
fontFeatures == null ? null : Object.hashAll(fontFeatures!), fontFeatures == null ? null : Object.hashAll(fontFeatures!),
fontVariations == null ? null : Object.hashAll(fontVariations!),
decoration, decoration,
decorationColor, decorationColor,
decorationStyle,
Object.hash( Object.hash(
decorationStyle,
decorationThickness, decorationThickness,
fontFamily, fontFamily,
fontFamilyFallback == null ? null : Object.hashAll(fontFamilyFallback!), fontFamilyFallback == null ? null : Object.hashAll(fontFamilyFallback!),
......
...@@ -755,6 +755,8 @@ class _TextStyleProxy implements TextStyle { ...@@ -755,6 +755,8 @@ class _TextStyleProxy implements TextStyle {
@override @override
List<ui.FontFeature>? get fontFeatures => _delegate.fontFeatures; List<ui.FontFeature>? get fontFeatures => _delegate.fontFeatures;
@override @override
List<ui.FontVariation>? get fontVariations => _delegate.fontVariations;
@override
TextOverflow? get overflow => _delegate.overflow; TextOverflow? get overflow => _delegate.overflow;
@override @override
...@@ -797,6 +799,7 @@ class _TextStyleProxy implements TextStyle { ...@@ -797,6 +799,7 @@ class _TextStyleProxy implements TextStyle {
Locale? locale, Locale? locale,
List<ui.Shadow>? shadows, List<ui.Shadow>? shadows,
List<ui.FontFeature>? fontFeatures, List<ui.FontFeature>? fontFeatures,
List<ui.FontVariation>? fontVariations,
TextOverflow? overflow, TextOverflow? overflow,
String? package, String? package,
}) { }) {
...@@ -828,6 +831,7 @@ class _TextStyleProxy implements TextStyle { ...@@ -828,6 +831,7 @@ class _TextStyleProxy implements TextStyle {
ui.Paint? background, ui.Paint? background,
List<Shadow>? shadows, List<Shadow>? shadows,
List<ui.FontFeature>? fontFeatures, List<ui.FontFeature>? fontFeatures,
List<ui.FontVariation>? fontVariations,
TextDecoration? decoration, TextDecoration? decoration,
Color? decorationColor, Color? decorationColor,
TextDecorationStyle? decorationStyle, TextDecorationStyle? decorationStyle,
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' as ui show TextStyle, ParagraphStyle, FontFeature, Shadow; import 'dart:ui' as ui show TextStyle, ParagraphStyle, FontFeature, FontVariation, Shadow;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
...@@ -38,6 +38,7 @@ class _DartUiTextStyleToStringMatcher extends Matcher { ...@@ -38,6 +38,7 @@ class _DartUiTextStyleToStringMatcher extends Matcher {
_propertyToString('foreground', textStyle.foreground), _propertyToString('foreground', textStyle.foreground),
_propertyToString('shadows', textStyle.shadows), _propertyToString('shadows', textStyle.shadows),
_propertyToString('fontFeatures', textStyle.fontFeatures), _propertyToString('fontFeatures', textStyle.fontFeatures),
_propertyToString('fontVariations', textStyle.fontVariations),
]; ];
static String _propertyToString(String name, Object? property) => '$name: ${property ?? 'unspecified'}'; static String _propertyToString(String name, Object? property) => '$name: ${property ?? 'unspecified'}';
...@@ -354,8 +355,18 @@ void main() { ...@@ -354,8 +355,18 @@ void main() {
}); });
test('TextStyle.hashCode', () { test('TextStyle.hashCode', () {
const TextStyle a = TextStyle(fontFamilyFallback: <String>['Roboto'], shadows: <ui.Shadow>[ui.Shadow()], fontFeatures: <ui.FontFeature>[ui.FontFeature('abcd')]); const TextStyle a = TextStyle(
const TextStyle b = TextStyle(fontFamilyFallback: <String>['Noto'], shadows: <ui.Shadow>[ui.Shadow()], fontFeatures: <ui.FontFeature>[ui.FontFeature('abcd')]); fontFamilyFallback: <String>['Roboto'],
shadows: <ui.Shadow>[ui.Shadow()],
fontFeatures: <ui.FontFeature>[ui.FontFeature('abcd')],
fontVariations: <ui.FontVariation>[ui.FontVariation('wght', 123.0)],
);
const TextStyle b = TextStyle(
fontFamilyFallback: <String>['Noto'],
shadows: <ui.Shadow>[ui.Shadow()],
fontFeatures: <ui.FontFeature>[ui.FontFeature('abcd')],
fontVariations: <ui.FontVariation>[ui.FontVariation('wght', 123.0)],
);
expect(a.hashCode, a.hashCode); expect(a.hashCode, a.hashCode);
expect(a.hashCode, isNot(equals(b.hashCode))); expect(a.hashCode, isNot(equals(b.hashCode)));
...@@ -476,6 +487,7 @@ void main() { ...@@ -476,6 +487,7 @@ void main() {
shadows: <ui.Shadow>[], shadows: <ui.Shadow>[],
fontStyle: FontStyle.normal, fontStyle: FontStyle.normal,
fontFeatures: <ui.FontFeature>[], fontFeatures: <ui.FontFeature>[],
fontVariations: <ui.FontVariation>[],
textBaseline: TextBaseline.alphabetic, textBaseline: TextBaseline.alphabetic,
leadingDistribution: TextLeadingDistribution.even, leadingDistribution: TextLeadingDistribution.even,
); );
...@@ -487,6 +499,8 @@ void main() { ...@@ -487,6 +499,8 @@ void main() {
expect(style.apply(locale: const Locale.fromSubtags(languageCode: 'es')).locale, const Locale.fromSubtags(languageCode: 'es')); expect(style.apply(locale: const Locale.fromSubtags(languageCode: 'es')).locale, const Locale.fromSubtags(languageCode: 'es'));
expect(style.apply().fontFeatures, const <ui.FontFeature>[]); expect(style.apply().fontFeatures, const <ui.FontFeature>[]);
expect(style.apply(fontFeatures: const <ui.FontFeature>[ui.FontFeature.enable('test')]).fontFeatures, const <ui.FontFeature>[ui.FontFeature.enable('test')]); expect(style.apply(fontFeatures: const <ui.FontFeature>[ui.FontFeature.enable('test')]).fontFeatures, const <ui.FontFeature>[ui.FontFeature.enable('test')]);
expect(style.apply().fontVariations, const <ui.FontVariation>[]);
expect(style.apply(fontVariations: const <ui.FontVariation>[ui.FontVariation('test', 100.0)]).fontVariations, const <ui.FontVariation>[ui.FontVariation('test', 100.0)]);
expect(style.apply().textBaseline, TextBaseline.alphabetic); expect(style.apply().textBaseline, TextBaseline.alphabetic);
expect(style.apply(textBaseline: TextBaseline.ideographic).textBaseline, TextBaseline.ideographic); expect(style.apply(textBaseline: TextBaseline.ideographic).textBaseline, TextBaseline.ideographic);
expect(style.apply().leadingDistribution, TextLeadingDistribution.even); expect(style.apply().leadingDistribution, TextLeadingDistribution.even);
......
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