The 'gvar' table

Apple Advanced Typography style variations allow the font designer to build high quality styles into the typeface itself. This reduces the dependence on algorithmic styling in the graphics system. To include font variations in your font, you must also include the font variations table.

The (tag name: 'gvar' ) allows you to include all of the data required for stylizing the glyphs in your font.

Conceptually, variation fonts define over which font characteristics can vary. Thus, in the figure below, we see the Q glyph from Skia drawn at various points along the 'wght' axis. Since the minimum and maximum values have been defined as +0.7 and +1.3, respectively, the specification of a style coordinate of 1.0 refers to the style of the center 'Q.'

Multiple axes can be combined within a single font. For example, you may want to create a 'wght' axis and a 'wdth' axis. The user can then select any combination of weight and width, such as 75% bold and 50% condensed. The next figure shows an example of a two-axis font variation in which the weight axis has a minimum value of 1.0 and maximum of 1.5 and the width axis has a minimum of 0.6 and a maximum of 1.0.

Data for how these axes are presented to the user is contained in the font variations table. The glyph variations table contains data which is used to determine the outline for a glyph given a combination of settings for the various axes.

This is done by using tuples. The terminology is derived from mathematics, but its meaning there (an n-tuple is defined as an ordered list of n numbers) may not illuminate its use in the 'gvar' table. For a variation font, a tuple is a list of deltas applied to the points in a glyph found in the 'glyf' table. The results determine the actual coordinates of the points on the outline for the glyph as it is to be rendered. Hinting can then be applied to this modified outline. The hints themselves can vary for the glyph; this is controlled by the 'cvar' table.

Each tuple is associated with a set of coordinates, one for each axis. These coordinates determine whether or not the tuple is applied and supply a multiplier applied to the deltas. The glyph's shape can therefore vary smoothly as the user adjusts the settings for the axes.

So that a glyph can vary in its dimensions as well as its shape, tuples have entries for each point in the glyph plus entries for four "phantom points," which represent the glyph's side-bearings. These phantom points are, in order, the left-side phantom point, the right-side phantom point, the top phantom point, and the bottom phantom point.

Structure of the 'gvar' table

Conceptually, the 'gvar' table is very straightforward. Its apparent complexity is the result of the techniques used to compress the data.

For each glyph in the font, the 'gvar' table stores a set of tuples. (This set may be empty.) The tuples have coordinates, one per axis. Optionally, they also have intermediate coordinates; if they do, there is one per axis. The tuple also has a list of points it moves, and the deltas for those points.

Header

The glyph variations table consists of a glyph variations table header, glyph offset array, glyph style coordinate array, and glyph variations array. The overall structure of the glyph variations table is shown in the following figure:

The glyph variations table header format is shown in this table:

The shared coordinates pointed to by the globalCoordCount are a space-saving mechanism. Instead of storing its own coordinates, a tuple can instead have an index into the global coordinate space.

The number of bytes occupied by the global coordinates can be found using the expression offsetToData - offsetToCoord . This size should be equal to globalCoordCount * axisCount * sizeof(shortFrac) . That is, there are globalCoord shortFrac &s for each axis in the font.

If the flag bitfield is set to 1, the offsets to the per-glyph data four bytes in size. If the flag bit-field is set to 0, the offsets are two bytes.

The offset array follows the glyph variation header. The offset array gives the offset from the beginning of the glyphVariationData array. This data specifies where each glyph variation begins. The variation data is the same order as the glyph order. This allows the length of a particular glyph variation to be computed by subtracting the offset of the next variation from the current one. This means that there must be glyphCount + 1 entries in the offset array.

Coordinates

Tuple coordiantes are used by CoreText to determine which tuples apply given the user's settings for the variation axes.

The first step in this process is normalizing the setting for a given axis; that is, mapping the value from the range defined by the 'fvar' table to the range [-1, 1] . (Note that this is exactly the range of values which can be represented by a shortFrac .)

The default mapping is to do this so that the minimum value for the axis maps to -1, the default value to 0, and the maximum value to 1. Values between two of these three key values are mapped linearly to the range [-1, 0) (if less than the default) or the range (0, 1] (if more than the default). This linear mapping can be refined via the 'avar' table.

To use Skia as an example, Skia has two axes, weight and width. The weight axis has the range [0.48, 3.2] defined in the 'fvar' table, with a default value of 1.0. The width axis has the range [0.62, 1.3] and the default value of 1.0.

If the user sets the weight to 0.5, this is normalized to ( 1.0 - 0.5 ) / ( 1.0 - 0.48 ) = -0.96. If the user sets the weight to 1.25, this is normalized to ( 1.25 - 1.0 ) / ( 3.2 - 1.0 ) = 0.11.

If a tuple's coordinate for a given axis is 0, then the normalized setting of that axis is ignored when determining whether or not to apply that tuple.

Otherwise, tuple is applied if and only if the current normalized setting for each axis is between the coordinate for that axis and 0 (inclusive).

For each axis (except the ignored ones), a scalar is calculated linearly. So if the normalized setting is 0.5 and the coordinate 1, the scalar is 0.5. The product of all the scalars for non-ignored axes is the scalar for the tuple. For each point the tuple moves, the deltas are multiplied by the tuple's scalar and then added to the point's position. The end result is the point's actual position for drawing the glyph.

The glyphVariationData structure

The glyphVariationData array follows the glyph variation offset array. The data for each glyph is structured as follows: