33// found in the LICENSE file.
44part of dart.ui;
55
6- /// Whether to slant the glyphs in the font
6+ /// Whether to use the italic type variation of glyphs in the font.
7+ ///
8+ /// Some modern fonts allow this to be selected in a more fine-grained manner.
9+ /// See [FontVariation.italic] for details.
10+ ///
11+ /// Italic type is distinct from slanted glyphs. To control the slant of a
12+ /// glyph, consider the [FontVariation.slant] font feature.
713enum FontStyle {
8- /// Use the upright glyphs
14+ /// Use the upright ("Roman") glyphs.
915 normal,
1016
11- /// Use glyphs designed for slanting
17+ /// Use glyphs that have a more pronounced angle and typically a cursive style
18+ /// ("italic type").
1219 italic,
1320}
1421
15- /// The thickness of the glyphs used to draw the text
22+ /// The thickness of the glyphs used to draw the text.
23+ ///
24+ /// Fonts are typically weighted on a 9-point scale, which, for historical
25+ /// reasons, uses the names 100 to 900. In Flutter, these are named `w100` to
26+ /// `w900` and have the following conventional meanings:
27+ ///
28+ /// * [w100] : Thin, the thinnest font weight.
29+ ///
30+ /// * [w200] : Extra light.
31+ ///
32+ /// * [w300] : Light.
33+ ///
34+ /// * [w400] : Normal. The constant [FontWeight.normal] is an alias for this value.
35+ ///
36+ /// * [w500] : Medium.
37+ ///
38+ /// * [w600] : Semi-bold.
39+ ///
40+ /// * [w700] : Bold. The constant [FontWeight.bold] is an alias for this value.
41+ ///
42+ /// * [w800] : Extra-bold.
43+ ///
44+ /// * [w900] : Black, the thickest font weight.
45+ ///
46+ /// For example, the font named "Roboto Medium" is typically exposed as a font
47+ /// with the name "Roboto" and the weight [FontWeight.w500] .
48+ ///
49+ /// Some modern fonts allow the weight to be adjusted in arbitrary increments.
50+ /// See [FontVariation.weight] for details.
1651class FontWeight {
1752 const FontWeight ._(this .index, this .value);
1853
@@ -22,31 +57,31 @@ class FontWeight {
2257 /// The thickness value of this font weight.
2358 final int value;
2459
25- /// Thin, the least thick
60+ /// Thin, the least thick.
2661 static const FontWeight w100 = FontWeight ._(0 , 100 );
2762
28- /// Extra-light
63+ /// Extra-light.
2964 static const FontWeight w200 = FontWeight ._(1 , 200 );
3065
31- /// Light
66+ /// Light.
3267 static const FontWeight w300 = FontWeight ._(2 , 300 );
3368
34- /// Normal / regular / plain
69+ /// Normal / regular / plain.
3570 static const FontWeight w400 = FontWeight ._(3 , 400 );
3671
37- /// Medium
72+ /// Medium.
3873 static const FontWeight w500 = FontWeight ._(4 , 500 );
3974
40- /// Semi-bold
75+ /// Semi-bold.
4176 static const FontWeight w600 = FontWeight ._(5 , 600 );
4277
43- /// Bold
78+ /// Bold.
4479 static const FontWeight w700 = FontWeight ._(6 , 700 );
4580
46- /// Extra-bold
81+ /// Extra-bold.
4782 static const FontWeight w800 = FontWeight ._(7 , 800 );
4883
49- /// Black, the most thick
84+ /// Black, the most thick.
5085 static const FontWeight w900 = FontWeight ._(8 , 900 );
5186
5287 /// The default font weight.
@@ -65,6 +100,9 @@ class FontWeight {
65100 /// Rather than using fractional weights, the interpolation rounds to the
66101 /// nearest weight.
67102 ///
103+ /// For a smoother animation of font weight, consider using
104+ /// [FontVariation.weight] if the font in question supports it.
105+ ///
68106 /// If both `a` and `b` are null, then this method will return null. Otherwise,
69107 /// any null values for `a` or `b` are interpreted as equivalent to [normal]
70108 /// (also known as [w400] ).
@@ -118,6 +156,9 @@ class FontWeight {
118156/// ** See code in examples/api/lib/ui/text/font_feature.0.dart **
119157/// {@end-tool}
120158///
159+ /// Some fonts also support continuous font variations; see the [FontVariation]
160+ /// class.
161+ ///
121162/// See also:
122163///
123164/// * <https://en.wikipedia.org/wiki/List_of_typographic_features>,
@@ -938,32 +979,158 @@ class FontFeature {
938979/// Some fonts are variable fonts that can generate a range of different
939980/// font faces by altering the values of the font's design axes.
940981///
941- /// See https://docs.microsoft.com/en-us/typography/opentype/spec/otvaroverview
982+ /// For example:
983+ ///
984+ /// ```dart
985+ /// TextStyle(fontVariations: <ui.FontVariation>[ui.FontVariation('wght', 800.0)])
986+ /// ```
987+ ///
988+ /// Font variations are distinct from font features, as exposed by the
989+ /// [FontFeature] class. Where features can be enabled or disabled in a discrete
990+ /// manner, font variations provide a continuous axis of control.
991+ ///
992+ /// See also:
993+ ///
994+ /// * <https://learn.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg#registered-axis-tags>,
995+ /// which lists registered axis tags.
942996///
943- /// Example:
944- /// `TextStyle(fontVariations: <FontVariation>[FontVariation('wght', 800.0)])`
997+ /// * <https://docs.microsoft.com/en-us/typography/opentype/spec/otvaroverview>,
998+ /// an overview of the font variations technology.
945999class FontVariation {
9461000 /// Creates a [FontVariation] object, which can be added to a [TextStyle] to
9471001 /// change the variable attributes of a font.
9481002 ///
9491003 /// `axis` is the four-character tag that identifies the design axis.
950- /// These tags are specified by font formats such as OpenType.
951- /// See https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg
1004+ /// OpenType lists the [currently registered axis
1005+ /// tags]( https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg).
9521006 ///
9531007 /// `value` is the value that the axis will be set to. The behavior
9541008 /// depends on how the font implements the axis.
9551009 const FontVariation (
9561010 this .axis,
9571011 this .value,
958- ) : assert (axis.length == 4 , 'Axis tag must be exactly four characters long.' );
1012+ ) : assert (axis.length == 4 , 'Axis tag must be exactly four characters long.' ),
1013+ assert (value >= - 32768.0 && value < 32768.0 , 'Value must be representable as a signed 16.16 fixed-point number, i.e. it must be in this range: -32768.0 ≤ value < 32768.0' );
1014+
1015+ // Constructors below should be alphabetic by axis tag. This makes it easier
1016+ // to determine when an axis is missing so that we avoid adding duplicates.
1017+
1018+ // Start of axis tag list.
1019+ // ------------------------------------------------------------------------
1020+
1021+ /// Variable font style. (`ital` )
1022+ ///
1023+ /// Varies the style of glyphs in the font between normal and italic.
1024+ ///
1025+ /// Values must in the range 0.0 (meaning normal, or Roman, as in
1026+ /// [FontStyle.normal] ) to 1.0 (meaning fully italic, as in
1027+ /// [FontStyle.italic] ).
1028+ ///
1029+ /// This is distinct from [FontVariation.slant] , which leans the characters
1030+ /// without changing the font style.
1031+ ///
1032+ /// See also:
1033+ ///
1034+ /// * <https://learn.microsoft.com/en-us/typography/opentype/spec/dvaraxistag_ital>
1035+ const FontVariation .italic (this .value) : assert (value >= 0.0 ), assert (value <= 1.0 ), axis = 'ital' ;
1036+
1037+ /// Optical size optimization. (`opzs` )
1038+ ///
1039+ /// Changes the rendering of the font to be optimized for the given text size.
1040+ /// Normally, the optical size of the font will be derived from the font size.
1041+ ///
1042+ /// This feature could be used when the text represents a particular physical
1043+ /// font size, for example text in the representation of a hardcopy magazine,
1044+ /// which does not correspond to the actual font size being used to render the
1045+ /// text. By setting the optical size explicitly, font variations that might
1046+ /// be applied as the text is zoomed will be fixed at the size being
1047+ /// represented by the text.
1048+ ///
1049+ /// This feature could also be used to smooth animations. If a font varies its
1050+ /// rendering as the font size is adjusted, it may appear to "quiver" (or, one
1051+ /// might even say, "flutter") if the font size is animated. By setting a
1052+ /// fixed optical size, the rendering can be fixed to one particular style as
1053+ /// the text size animates.
1054+ ///
1055+ /// Values must be greater than zero, and are interpreted as points. A point
1056+ /// is 1/72 of an inch, or 1.333 logical pixels (96/72).
1057+ ///
1058+ /// See also:
1059+ ///
1060+ /// * <https://learn.microsoft.com/en-us/typography/opentype/spec/dvaraxistag_opsz>
1061+ const FontVariation .opticalSize (this .value) : assert (value > 0.0 ), axis = 'opsz' ;
9591062
960- /// The tag that identifies the design axis. Must consist of 4 ASCII
961- /// characters.
1063+ /// Variable font width. (`slnt` )
1064+ ///
1065+ /// Varies the slant of glyphs in the font.
1066+ ///
1067+ /// Values must be greater than -90.0 and less than +90.0, and represents the
1068+ /// angle in _counter-clockwise_ degrees relative to "normal", at 0.0.
1069+ ///
1070+ /// For example, to lean the glyphs forward by 45 degrees, one would use
1071+ /// `FontVariation.slant(-45.0)` .
1072+ ///
1073+ /// This is distinct from [FontVariation.italic] , in that slant leans the
1074+ /// characters without changing the font style.
1075+ ///
1076+ /// See also:
1077+ ///
1078+ /// * <https://learn.microsoft.com/en-us/typography/opentype/spec/dvaraxistag_slnt>
1079+ const FontVariation .slant (this .value) : assert (value > - 90.0 ), assert (value < 90.0 ), axis = 'slnt' ;
1080+
1081+ /// Variable font width. (`wdth` )
1082+ ///
1083+ /// Varies the width of glyphs in the font.
1084+ ///
1085+ /// Values must be greater than zero, with no upper limit. 100.0 represents
1086+ /// the "normal" width. Smaller values are "condensed", greater values are
1087+ /// "extended".
1088+ ///
1089+ /// See also:
1090+ ///
1091+ /// * <https://learn.microsoft.com/en-us/typography/opentype/spec/dvaraxistag_wdth>
1092+ const FontVariation .width (this .value) : assert (value >= 0.0 ), axis = 'wdth' ;
1093+
1094+ /// Variable font weight. (`wght` )
1095+ ///
1096+ /// Varies the stroke thickness of the font, similar to [FontWeight] but on a
1097+ /// continuous axis.
1098+ ///
1099+ /// Values must be in the range 1..1000, and are to be interpreted in a manner
1100+ /// consistent with the values of [FontWeight] . For instance, `400` is the
1101+ /// "normal" weight, and `700` is "bold".
1102+ ///
1103+ /// See also:
1104+ ///
1105+ /// * <https://learn.microsoft.com/en-us/typography/opentype/spec/dvaraxistag_wght>
1106+ const FontVariation .weight (this .value) : assert (value >= 1 ), assert (value <= 1000 ), axis = 'wght' ;
1107+
1108+ // ------------------------------------------------------------------------
1109+ // End of axis tags list.
1110+
1111+ /// The tag that identifies the design axis.
1112+ ///
1113+ /// An axis tag must consist of 4 ASCII characters.
9621114 final String axis;
9631115
9641116 /// The value assigned to this design axis.
9651117 ///
9661118 /// The range of usable values depends on the specification of the axis.
1119+ ///
1120+ /// While this property is represented as a [double] in this API
1121+ /// ([binary64] (https://en.wikipedia.org/wiki/Double-precision_floating-point_format)),
1122+ /// fonts use the fixed-point 16.16 format to represent the value of font
1123+ /// variations. This means that the actual range is -32768.0 to approximately
1124+ /// 32767.999985 and in principle the smallest increment between two values is
1125+ /// approximately 0.000015 (1/65536).
1126+ ///
1127+ /// Unfortunately for technical reasons the value is first converted to the
1128+ /// [binary32 floating point
1129+ /// format](https://en.wikipedia.org/wiki/Single-precision_floating-point_format),
1130+ /// which only has 24 bits of precision. This means that for values outside
1131+ /// the range -256.0 to 256.0, the smallest increment is larger than what is
1132+ /// technically supported by OpenType. At the extreme edge of the range, the
1133+ /// smallest increment is only approximately ±0.002.
9671134 final double value;
9681135
9691136 static const int _kEncodedSize = 8 ;
@@ -989,6 +1156,37 @@ class FontVariation {
9891156 @override
9901157 int get hashCode => Object .hash (axis, value);
9911158
1159+ /// Linearly interpolates between two font variations.
1160+ ///
1161+ /// If the two variations have different axis tags, the interpolation switches
1162+ /// abruptly from one to the other at t=0.5. Otherwise, the value is
1163+ /// interpolated (see [lerpDouble] .
1164+ ///
1165+ /// The value is not clamped to the valid values of the axis tag, but it is
1166+ /// clamped to the valid range of font variations values in general (the range
1167+ /// of signed 16.16 fixed point numbers).
1168+ ///
1169+ /// The `t` argument represents position on the timeline, with 0.0 meaning
1170+ /// that the interpolation has not started, returning `a` (or something
1171+ /// equivalent to `a` ), 1.0 meaning that the interpolation has finished,
1172+ /// returning `b` (or something equivalent to `b` ), and values in between
1173+ /// meaning that the interpolation is at the relevant point on the timeline
1174+ /// between `a` and `b` . The interpolation can be extrapolated beyond 0.0 and
1175+ /// 1.0, so negative values and values greater than 1.0 are valid (and can
1176+ /// easily be generated by curves such as [Curves.elasticInOut] ).
1177+ ///
1178+ /// Values for `t` are usually obtained from an [Animation<double>] , such as
1179+ /// an [AnimationController] .
1180+ static FontVariation ? lerp (FontVariation ? a, FontVariation ? b, double t) {
1181+ if (a? .axis != b? .axis || (a == null && b == null )) {
1182+ return t < 0.5 ? a : b;
1183+ }
1184+ return FontVariation (
1185+ a! .axis,
1186+ clampDouble (lerpDouble (a.value, b! .value, t)! , - 32768.0 , 32768.0 - 1.0 / 65536.0 ),
1187+ );
1188+ }
1189+
9921190 @override
9931191 String toString () => "FontVariation('$axis ', $value )" ;
9941192}
0 commit comments