STAT — Style Attributes Table (OpenType 1.8)
The style attributes table provides a description of attributes that distinguish a particular style variant from other styles within a font family. Style variants may be implemented as separate fonts, or as dynamic variations in a variable font. A single font may also combine dynamic variation axes using a font variations ('fvar') table along with static attributes. The style attributes table allows software implementations to understand relationships among the various fonts or design-variation instances within a family. It provides strings that can be used to create user interfaces with controls for individual style attributes, or used to compose strings that may be required for use in legacy applications.
A style attributes table is required in all variable fonts. For a general overview of OpenType Font Variations, see the chapter, OpenType Font Variations Overview.
The style attributes table is also recommended for all new, non-variable fonts, especially if fonts have style attributes in axes other than weight, width, or slope.
When used in multi-axis fonts, the style attributes table can accomplish the intended purpose of name IDs 21 and 22, but using a more general and flexible mechanism. For fonts used only in newer applications, strings for name IDs 21 and 22 may not be required if a style attributes table is present. When fonts need to work in older applications as well, however, name IDs 21 and 22 should continue to be used when applicable.
Style Attributes Header
The style attributes table begins with a header comprised of a major/minor version plus arrays of design-axis records and offsets to axis-value tables.
Style attributes header:
Type | Name | Description |
---|---|---|
USHORT | majorVersion | Major version number of the style attributes table — set to 1. |
USHORT | minorVersion | Minor version number of the style attributes table — set to 0. |
USHORT | designAxisSize | The size in bytes of each axis record. |
USHORT | designAxisCount | The number of design axis records. In a font with an 'fvar' table, this value must be greater than or equal to the axisCount value in the 'fvar' table. |
ULONG | offsetToDesignAxes | Offset in bytes from the beginning of the 'STAT' table to the start of the design axes array. |
USHORT | axisValueCount | The number of axis value tables. |
ULONG | offsetToAxisValueOffsets | Offset in bytes from the beginning of the 'STAT' table to the start of the design axes value offsets array. |
The header is followed by the design axes and axis value offsets arrays, the location of which are provided by offset fields.
Type | Name | Description |
---|---|---|
AxisRecord | designAxes[designAxisCount] | The design-axes array. |
USHORT | axisValueOffsets[axisValueCount] | Array of offsets to axis value tables, in bytes from the start of the axis value offsets array. |
The designAxisSize field indicates the size of each axis record. In this version of the 'STAT' table, each record is eight bytes. Future versions may allow for larger records with additional fields. Definition of larger-sized records would entail a minor version number change, with the first eight bytes of each record having the same structure and semantics as in this version. In any 'STAT' table, all axis records must have the same size.
Axis Records
The axis record provides information about a single design axis.
AxisRecord:
Type | Name | Description |
---|---|---|
Tag | axisTag | A tag identifying the axis of design variation. |
USHORT | axisNameID | The name ID for entries in the 'name' table that provide a display string for this axis. |
USHORT | axisOrdering | A value that applications can use to determine primary sorting of face names, or for ordering of descriptors when composing family or face names. |
Each axis record has a tag designating the axis. Take note that tag values must follow the rules for tags described for the font variations ('fvar') table.
The axisNameID field provides a name ID that can be used to obtain strings from the 'name' table that can be used to refer to the axis in application user interfaces. The name ID must be greater than 255 and less than 32768.
In a variable font, there must be an axis record for every axis defined in the font variations table, and it must use the same name ID used in the font variations table. If a variation axis is omitted from the 'STAT' table, or if different name IDs are used, applications may have unexpected behavior in the use of 'STAT' table data.
If a variable font has additional axes that are not implemented as dynamic-variation axes in the font variations table, but that are relevant for the font or the family of which it is a member, axis records should also be included.
A non-variable font should include axis records for any axes that are relevant for the font or the family of which it is a member, especially if axes other than weight, width and slope are used.
Note: For every axis declared using an axis record, the axis should be a variation axis defined in an 'fvar' table, or else it should be reflected in the font’s sub-family name (name ID 17 or name ID 2) except in the case that the font’s value on that axis is a “normal” value that is suppressed from the sub-family name.
The axis ordering field allows the font developer to influence ordering of axes in user interfaces. Lower values are assumed to have an earlier sort order or higher priority than higher values. Otherwise, no specific requirements are specified here regarding how these values are used in applications.
One way in which axisOrdering values might be used is in presenting an enumerated list of face names within a family: rather than listing faces in an arbitrary order, they might be sorted using these values to determine primary, secondary, etc. orderings. For example, if width is given a lower value than weight, then all weights with one particular width would be listed before the different weights with the next width, and so on.
Another way in which axisOrdering might be used is in composing names. A particular scenario for this is generating family and subfamily names that conform to expectations of applications that use GDI or weight/width/slope (WWS) models for font families. In non-variable fonts, the designer can include name ID pairs 1/2 and 21/22 to support these models, but there is no other provision for this in a variable font. The style attributes table provides individual axis value descriptor strings that can be combined in different ways as needed to fit the requirements for name IDs 1/2 or 21/22. But when doing so, there is no independent specification for how the different elements should be ordered in a family name. For example, “Arial Serif Caption” and “Arial Caption Serif” are both possible as a name ID 21 equivalent. The axisOrdering value could be used in applications to choose the ordering when composing such names.
Different fonts belonging to the same family should have matching axis record values. However, if a set of fonts for a family are released, and then at some later time the family is extended with additional fonts using new axes of variation, the previously-shipped fonts do not need to be updated with the additional axis records; the newer fonts will provide the axis details.
Axis Value Tables
Axis value tables provide details regarding a specific style-variant attribute value on some specific axis of design variation.
Different formats for axis value tables are supported. The first field is read to determine the format. Additional formats may be supported in the future, with a minor-version update of the 'STAT' table. If the format is not recognized, then the axis value table can be ignored.
The different formats all include fields with numeric axis values. For any axis with a registered axis tag, the numeric values in the axis value tables will be interpreted in the same manner as they would be interpreted in the font variations table. In particular, they will be interpreted according to the user-coordinate scale and conventions specified for that axis. Similarly, if a variable font has a variation axis defined using a non-registered, custom tag, it is assumed that the values in axis value tables and in the font variations table are interpreted using the same custom scale, even if it is not conventionally defined.
The different formats also include fields for name IDs that provide display strings associated with the numeric value. Name IDs must be greater than 255 and less than 32768.
In a variable font, axis value tables should be provided for each subfamily distinction along each dynamic-variation axis that is reflected in named instances defined using instance records in the font variations table. For example, if a font has named instances for “Bold Extended” and “Light Condensed”, there should be records for at least the two weight-axis values, plus two other records for the two width-axis values. Axis value records can also be added for other values for those axes, even if not referenced in any named instance. For example, if a font has a weight variation axis and has named instances for “Light”, “Regular” and “Bold”, it should have axis value records for those three values, but it can also include other axis value records for other weight values, such as “Semilight” or “Medium”.
A variable font might also have some static, distinguishing, subfamily attributes not implemented as a variation. For example, a weight-variation font may have a paired, italic weight-variation font. Axis value records should also be provided for any such distinctions that are relevant within a family.
Similarly, in a non-variable font, axis value records should be provided for any style variant distinction that is applicable to the font and relevant for the font family to which it belongs.
In some cases, some attribute using a new design axis may be introduced into a family after other fonts have been released, with the new attribute not anticipated in any way in the initial fonts. For example, a font designer might initially create Regular, Bold and Italic variants of a design, and then later add width variants such as Condensed. In that case, the initial fonts might not have identified that they represent the “Normal” attribute on the width scale. The newer fonts should include axis value records that describe the earlier fonts. A flag is defined to designate such axis value records; this is described in detail below.
Three axis value table formats are defined at this time.
AxisValueFormat1:
Type | Name | Description |
---|---|---|
USHORT | format | Format identifier — set to 1. |
USHORT | axisIndex | Index into the axis record array identifying the axis of design variation to which the axis value record applies. |
USHORT | flags | Flags — see below for details. |
USHORT | valueNameID | The name ID for entries in the 'name' table that provide a display string for this attribute value. |
Fixed | value | A numeric value for this attribute value. |
A format 1 table is used simply to associate a specific axis value with a name.
AxisValueFormat2
Type | Name | Description |
---|---|---|
USHORT | format | Format identifier — set to 2. |
USHORT | axisIndex | Index into the axis record array identifying the axis of design variation to which the axis value record applies. |
USHORT | flags | Flags — see below for details. |
USHORT | valueNameID | The name ID for entries in the 'name' table that provide a display string for this attribute value. |
Fixed | nominalValue | A nominal numeric value for this attribute value. |
Fixed | rangeMinValue | The minimum value for a range associated with the specified name ID. |
Fixed | rangeMaxValue | The maximum value for a range associated with the specified name ID. |
A format 2 table can be used if a given name is associated with a particular axis value, but is also associated with a range of values. For example, in a family that supports optical size variations, “Subhead” may be used in relation to a range of sizes. The rangeMinValue and rangeMaxValue fields are used to define that range. In a variable font, a named instance has specific coordinates for each axis. The nominalValue field allows some specific, nominal value to be associated with a name, to align with the named instances defined in the font variations table, while the rangeMinValue and rangeMaxValue fields allow the same name also to be associated with a range of axis values.
AxisValueFormat3
Type | Name | Description |
---|---|---|
USHORT | format | Format identifier — set to 3. |
USHORT | axisIndex | Index into the axis record array identifying the axis of design variation to which the axis value record applies. |
USHORT | flags | Flags — see below for details. |
USHORT | valueNameID | The name ID for entries in the 'name' table that provide a display string for this attribute value. |
Fixed | value | A numeric value for this attribute value. |
Fixed | linkedValue | The numeric value for a style-linked mapping from this value. |
A format 3 table can be used to indicate another value on the same axis that is to be treated as a style-linked counterpart to the current value. This is primarily intended for “bold” style linking on a weight axis. These mappings may be used in applications to determine which style within a family should be selected when a user selects a “bold” formatting option. A mapping is defined from a “non-bold” value to its “bold” counterpart. It is not necessary to provide a “bold” mapping for every weight value; mappings should be provided for lighter weights, but heavier weights (typically, semibold or above) would already be considered “bold” and would not require a “bold” mapping.
Note: Applications are not required to use these style-linked mappings when implementing text formatting user interfaces. This data can be provided in a font for the benefit of applications that choose to do so. If a given application does not apply such style mappings for the given axis, then the linkedValue field is ignored.
The following flags are defined:
Mask | Name | Description |
---|---|---|
0x0001 | OlderSiblingFontAttribute | If set, this axis value table provides axis value information that is applicable to other fonts within the same font family. This is used if the other fonts were released earlier and did not include information about values for some axis. If newer versions of the other fonts include the information themselves and are present, then this record is ignored. |
0x0002 | ElidableAxisValueName | If set, it indicates that the axis value represents the “normal” value for the axis and may be omitted when composing name strings. |
0xFFFC | reservedFlags | Reserved for future use — set to zero. |
When the OlderSiblingFontAttribute flag is used, implementations may use the information provided to determine behaviour associated with a different font in the same family. If a previously-released family is extended with fonts for style variations from a new axis of design variation, then all of them should include a OlderSiblingFontAttribute table for the “normal” value of earlier fonts. The values in the different fonts should match; if they do not, application behavior may be unpredictable.
The ElidableAxisValueName flag can be used to designate a “normal” value for an axis that should not normally appear in a face name. For example, the designer may prefer that face names not include “Normal” width or “Regular” weight. If this flag is set, applications are permitted to omit these descriptors from face names, though they may also include them in certain scenarios.
Note: Fonts should provide axis value tables for “normal” axis values even if they should not normally be reflected in face names.
Note: If a font or a variable-font instance is selected for which all axis values have the ElidableAxisValueName flag set, then applications may keep the name for the weight axis, if present, to use as a constructed subfamily name, with names for all other axis values omitted.
When the OlderSiblingFontAttribute flag is set, this will typically be providing information regarding the “normal” value on some newly-introduced axis. In this case, the ElidableAxisValueName flag may also be set, as desired. When applied to the earlier fonts, those likely would not have included any descriptors for the new axis, and so the effects of the ElidableAxisValueName flag are implicitly assumed.
If multiple axis value tables have the same axis index, then one of the following should be true:
- The font is a variable font, and the axis is defined in the font variations table as a variation.
- The OlderSiblingFontAttribute flag is set in one of the records.
No two tables should provide information for the same axis value.
Two different fonts within a family may share certain style attributes in common. For example, Bold Condensed and Bold Semi Condensed fonts both have the same weight attribute, Bold. Axis value tables for particular values should be implemented consistently across a family. If they are not consistent, applications may exhibit unpredictable behaviors.
Examples
The following examples illustrate data provided by a style attributes table for various font scenarios.
Example 1: Family with different weight variants using non-variable fonts
Suppose a font family has Regular, Bold and Heavy weight variants. These fonts would have matching axis records:
Axis tag | Axis name | Axis ordering |
---|---|---|
'wght' | Weight | 0 |
The three fonts would have axis value data as follows:
Font | Axis tag | Value | Name string | Flag | Other data |
---|---|---|---|---|---|
Font 1 | 'wght' | 400 | Regular | ElidableAxisValueName | linkedValue = 700 |
Font 2 | 'wght' | 700 | Bold | ||
Font 3 | 'wght' | 900 | Heavy |
Example 2: Family using non-variable fonts for different weight values plus italic
Suppose the font family from example 1 also has italic variants. The fonts would have matching axis records reflecting weight and italic axes:
Axis tag | Axis name | Axis ordering |
---|---|---|
'wght' | Weight | 0 |
'ital' | Italic | 1 |
Each of the three non-italic fonts would include an additional axis value record to reflect the non-italic attribute. The six fonts would have data as follows:
Font | Axis tag | Value | Name string | Flag | Other data |
---|---|---|---|---|---|
Font 1 | 'wght' | 400 | Regular | ElidableAxisValueName | linkedValue = 700 |
Font 1 | 'ital' | 0 | Regular | ElidableAxisValueName | linkedValue = 1 |
Font 2 | 'wght' | 700 | Bold | ||
Font 2 | 'ital' | 0 | Regular | ElidableAxisValueName | linkedValue = 1 |
Font 3 | 'wght' | 900 | Heavy | ||
Font 3 | 'ital' | 0 | Regular | ElidableAxisValueName | linkedValue = 1 |
Font 4 | 'wght' | 400 | Regular | ElidableAxisValueName | linkedValue = 700 |
Font 4 | 'ital' | 1 | Italic | ||
Font 5 | 'wght' | 700 | Bold | ||
Font 5 | 'ital' | 1 | Italic | ||
Font 6 | 'wght' | 900 | Heavy | ||
Font 6 | 'ital' | 1 | Italic |
Example 3: Family using non-variable fonts with weight and italic variants, later extended to add width variants
Suppose the font family from example 2 is later extended with different width variants. The new fonts in the family would include matching axis records reflecting three axes:
Axis tag | Axis name | Axis ordering |
---|---|---|
'wght' | Weight | 0 |
'wdth' | Width | 1 |
'ital' | Italic | 2 |
Newer versions of the initially-released fonts would also include the additional axis record. When newer fonts co-exist with the original version of the earlier fonts, the ordering from the more-complete axis records in the newer fonts is used.
To allow for situations in which one of the newer fonts co-exists with the older fonts, which did not reference the width axis, the newer fonts should each include an axis record to describe the “Normal” width, which is inferred onto the earlier fonts.
Axis tag | Value | Name string | Flag | Other data |
---|---|---|---|---|
'wdth' | 100 | Normal | OlderSiblingFontAttribute |
Example 4: A weight/width variable font
Consider a family comprised of a single variable font with weight and width variations. This font would have axis records for the two variation axes:
Axis tag | Axis name | Axis ordering |
---|---|---|
'wght' | Weight | 0 |
'wdth' | Width | 1 |
Suppose the variable font has 6 named instances that correspond to three different weights for each of two widths. The style attributes table should include axis value records for at least those three weights and those two widths, but could also include records for other weight or width values. The font may include the following axis value records:
Axis tag | Value | Name string | Flag | Other data |
---|---|---|---|---|
'wght' | 300 | Light | linkedValue = 600 | |
'wght' | 400 | Regular | ElidableAxisValueName | linkedValue = 700 |
'wght' | 600 | Semibold | ||
'wght' | 700 | Bold | ||
'wght' | 900 | Black | ||
'wdth' | 62.5 | Extra-Condensed | ||
'wdth' | 75 | Condensed | ||
'wdth' | 100 | Normal | ElidableAxisValueName | |
'wdth' | 125 | Expanded | ||
'wdth' | 150 | Extra-Expanded |
Example 5: A family comprised of a non-italic variable font plus an italic variable font
Consider a family comprised of a non-italic, weight/width variable font plus a corresponding italic, weight/width variable font. Each font would have axis records for three axes:
Axis tag | Axis name | Axis ordering |
---|---|---|
'wght' | Weight | 0 |
'wdth' | Width | 1 |
'ital' | Italic | 2 |
In addition to axis value records for various weight or width values, the first font would also include a record to reflect the non-italic attribute:
Axis tag | Value | Name string | Flag | Other data |
---|---|---|---|---|
'ital' | 0 | Normal | ElidableAxisValueName | linkedValue = 1 |
The second font would include a record to reflect the italic attribute, in addition to the records for various weight and width values:
Axis tag | Value | Name string | Flag | Other data |
---|---|---|---|---|
'ital' | 1 | Italic |
The pattern in this example can be applied to other cases involving a family with style variations implemented using a combination of Font Variations mechanisms plus static, non-variation designs. The axis records in each font would span both variation and non-variation axes. Axis value records in a given font would include multiple values for axes implemented using Font Variation mechanisms, plus single records for the relevant attribute values of other axes.