GSUB — Glyph Substitution Table (OpenType 1.8.3)
The Glyph Substitution (GSUB) table provides data for substition of glyphs for appropriate rendering of scripts, such as cursively-connecting forms in Arabic script, or for advanced typographic effects, such as ligatures.
Overview
The Glyph Substitution table (GSUB) contains information for substituting glyphs to render the scripts and language systems supported in a font. Many language systems require glyph substitutes. For example, in the Arabic script, the glyph shape that depicts a particular character varies according to its position in a word or text string (see figure 1). In other language systems, glyph substitutes are aesthetic options for the user, such as the use of ligature glyphs in the English language (see Figure 2).
OpenType fonts use character encoding standards, such as the Unicode Standard, that assumes a distinction between characters and glyphs: text is encoded as sequences of characters, and the 'cmap' table provides a mapping from that character to a single default glyph. Multiple characters are not directly mapped to a single glyph, as needed for ligatures; and a single character is not mapped directly to multiple glyphs, as may be needed for some complex-script scenarios. The GSUB table provides a way to describe such substititions, enabling applications to apply such substitions during text layout and rendering to achieve desired results.
To access substitute glyphs, GSUB maps from the glyph index or indices defined in a 'cmap' subtable to the glyph index or indices of the substitute glyphs. For example, if a font has three alternative forms of an ampersand glyph, the 'cmap' table associates the ampersand’s character code with only one of these glyphs. In GSUB, the indices of the other ampersand glyphs are then referenced from this one default index.
The text-processing client uses the GSUB data to manage glyph substitution actions. GSUB identifies the glyphs that are input to and output from each glyph substitution action, specifies how and where the client uses glyph substitutes, and regulates the order of glyph substitution operations. Any number of substitutions can be defined for each script or language system represented in a font.
The GSUB table supports seven types of glyph substitutions that are widely used in international typography:
A single substitution replaces a single glyph with another single glyph. This is used to render positional glyph variants in Arabic and vertical text in the Far East (see Figure 3).
A multiple substitution replaces a single glyph with more than one glyph. This is used to specify actions such as ligature decomposition (see Figure 4).
An alternate substitution identifies functionally equivalent but different looking forms of a glyph. These glyphs are often referred to as aesthetic alternatives. For example, a font might have five different glyphs for the ampersand symbol, but one would have a default glyph index in the 'cmap' table. The client could use the default glyph or substitute any of the four alternatives (see Figure 5).
A ligature substitution replaces several glyph indices with a single glyph index, as when an Arabic ligature glyph replaces a string of separate glyphs (see Figure 6). When a string of glyphs can be replaced with a single ligature glyph, the first glyph is substituted with the ligature. The remaining glyphs in the string are deleted, this does not include those glyphs that are skipped as a result of lookup flags.
Contextual substitution is a powerful extension of the above lookup types, describing glyph substitutions in context — that is, a substitution of one or more glyphs within a certain pattern of glyphs. Each substitution describes one or more input glyph sequences and one or more substitutions to be performed on that sequence. Contextual substitutions can be applied to specific glyph sequences, glyph classes, or sets of glyphs.
Chaining contextual substitution, extends the capabilities of contextual substitution. With this, one or more substitutions can be performed on one or more glyphs within a pattern of glyphs (input sequence), by chaining the input sequence to a backtrack and/or lookahead sequence. Each such substitution can be applied in three formats to handle glyphs, glyph classes or glyph sets in the input sequence. Each of these formats can describe one or more of the backtrack, input and lookahead sequences.
Reverse Chaining contextual single substitution, allows one glyph to be substituted with another by chaining input glyph to a backtrack and/or lookahead sequence. The difference between this and other lookup types is that processing of input glyph sequence goes from end to start.
GSUB Table and OpenType Font Variations
OpenType Font Variations allow a single font to support many design variations along one or more axes of design variation. For example, a font with weight and width variations might support weights from thin to black, and widths from ultra-condensed to ultra-expanded. For general information on OpenType Font Variations, see the chapter, OpenType Font Variations Overview.
In a variable font, it may be desirable to have different glyph-substitution actions used for different regions within the font’s variation space. For example, for narrow or heavy instances in which counters become small, it may be desirable to make certain glyph substitutions to use alternate glyphs with certain strokes removed or outlines simplified to allow for larger counters. Such effects can be achieved using a FeatureVariations table within the GSUB table. The FeatureVariations table is described in the chapter, OpenType Layout Common Table Formats. See also the Required Variation Alternates ('rvrn') feature in the OpenType Layout tag registry.
Table Organization
The GSUB table begins with a header that defines offsets to a ScriptList, a FeatureList, a LookupList, and an optional FeatureVariations table (see Figure 3g):
- The ScriptList identifies all the scripts and language systems in the font that use glyph substitutes.
- The FeatureList defines all the glyph substitution features required to render these scripts and language systems.
- The LookupList contains all the lookup data needed to implement each glyph substitution feature.
- The FeatureVariations table can be used to substitute alternate sets of lookup tables to use for any given feature under specified conditions. This is currently used only in variable fonts.
For a detailed discussion of ScriptLists, FeatureLists, LookupLists, and FeatureVariation tables, see the chapter, OpenType Layout Common Table Formats.
This organization helps text-processing clients to easily locate the features and lookups that apply to a particular script or language system. To access GSUB information, clients should use the following procedure:
- Locate the current script in the GSUB ScriptList table.
- If the language system is known, search the script for the correct LangSys table; otherwise, use the script’s default LangSys table.
- The LangSys table provides index numbers into the GSUB FeatureList table to access a required feature and a number of additional features.
- Inspect the featureTag of each Feature table, and select the feature tables to apply to an input glyph string.
- If a Feature Variations table is present, evaluate conditions in the Feature Variation table to determine if any of the initially-selected feature tables should be substituted by an alternate feature table.
- Each Feature table provides an array of index numbers into the GSUB LookupList table. Assemble all lookups from the set of chosen features, and apply the lookups in the order given in the LookupList table.
For a detailed description of the Feature Variations table and how it is processed, see the FeatureVariations Table section in the OpenType Layout Common Table Formats chapter.
Lookup data is defined in Lookup tables, which are defined in the OpenType Layout Common Table Formats chapter. A Lookup table contains one or more Lookup Subtables that define the specific conditions, type, and results of a substitution action used to implement a feature. Specific Lookup subtable types are used for glyph substitution actions, and are defined in this chapter. All subtables within a Lookup table must be of the same lookup type, as listed in the following table for the GSUB LookupType Enumeration:
GSUB LookupType Enumeration
Value | Type | Description |
---|---|---|
1 | Single (format 1.1 1.2) | Replace one glyph with one glyph |
2 | Multiple (format 2.1) | Replace one glyph with more than one glyph |
3 | Alternate (format 3.1) | Replace one glyph with one of many glyphs |
4 | Ligature (format 4.1) | Replace multiple glyphs with one glyph |
5 | Context (format 5.1 5.2 5.3) | Replace one or more glyphs in context |
6 | Chaining Context (format 6.1 6.2 6.3) | Replace one or more glyphs in chained context |
7 | Extension Substitution (format 7.1) | Extension mechanism for other substitutions (i.e. this excludes the Extension type substitution itself) |
8 | Reverse chaining context single (format 8.1) | Applied in reverse order, replace single glyph in chaining context |
9+ | Reserved | For future use (set to zero) |
Each LookupType has one or more subtable formats. The “best” format depends on the type of substitution and the resulting storage efficiency. When glyph information is best presented in more than one format, a single lookup may define more than one subtable, as long as all the subtables are for the same LookupType. For example, within a given lookup, a glyph index array format may best represent one set of target glyphs, whereas a glyph index range format may be better for another set.
A series of substitution operations on the same glyph or string requires multiple lookups, one for each separate action. Each lookup has a different array index in the LookupList table and is applied in the LookupList order.
During text processing, a client applies a lookup to each glyph in the string before moving to the next lookup. A lookup is finished for a glyph after the client locates the target glyph or glyph context and performs a substitution, if specified. To move to the “next” glyph, the client will typically skip all the glyphs that participated in the lookup operation: glyphs that were substituted as well as any other glyphs that formed a context for the operation.
In the case of chaining contextual lookups (LookupType 6), glyphs comprising backtrack and lookahead sequences may participate in more than one context.
The rest of this chapter describes the GSUB header and the subtables defined for each GSUB LookupType. Examples at the end of this chapter illustrate the GSUB header and six of the eight LookupTypes, including the three formats available for contextual substitutions (LookupType 5).
GSUB Header
The GSUB table begins with a header that contains a version number for the table and offsets to three tables: ScriptList, FeatureList, and LookupList. For descriptions of each of these tables, see the chapter, OpenType Layout Common Table Formats. Example 1 at the end of this chapter shows a GSUB Header table definition.
GSUB Header, Version 1.0
Type | Name | Description |
---|---|---|
uint16 | majorVersion | Major version of the GSUB table, = 1 |
uint16 | minorVersion | Minor version of the GSUB table, = 0 |
Offset16 | scriptListOffset | Offset to ScriptList table, from beginning of GSUB table |
Offset16 | featureListOffset | Offset to FeatureList table, from beginning of GSUB table |
Offset16 | lookupListOffset | Offset to LookupList table, from beginning of GSUB table |
GSUB Header, Version 1.1
Type | Name | Description |
---|---|---|
uint16 | majorVersion | Major version of the GSUB table, = 1 |
uint16 | minorVersion | Minor version of the GSUB table, = 1 |
Offset16 | scriptListOffset | Offset to ScriptList table, from beginning of GSUB table |
Offset16 | featureListOffset | Offset to FeatureList table, from beginning of GSUB table |
Offset16 | lookupListOffset | Offset to LookupList table, from beginning of GSUB table |
Offset32 | featureVariationsOffset | Offset to FeatureVariations table, from beginning of the GSUB table (may be NULL) |
LookupType 1: Single Substitution Subtable
Single substitution (SingleSubst) subtables tell a client to replace a single glyph with another glyph. The subtables can be either of two formats. Both formats require two distinct sets of glyph indices: one that defines input glyphs (specified in the Coverage table), and one that defines the output glyphs. Format 1 requires less space than Format 2, but it is less flexible.
1.1 Single Substitution Format 1
Format 1 calculates the indices of the output glyphs, which are not explicitly defined in the subtable. To calculate an output glyph index, Format 1 adds a constant delta value to the input glyph index. For the substitutions to occur properly, the glyph indices in the input and output ranges must be in the same order. This format does not use the Coverage index that is returned from the Coverage table.
The SingleSubstFormat1 subtable begins with a format identifier (substFormat) of 1. An offset references a Coverage table that specifies the indices of the input glyphs. The deltaGlyphID is a constant value added to each input glyph index to calculate the index of the corresponding output glyph. Addition of deltaGlyphID is modulo 65536.
Example 2 at the end of this chapter uses Format 1 to replace standard numerals with lining numerals.
SingleSubstFormat1 subtable: Calculated output glyph indices
Type | Name | Description |
---|---|---|
uint16 | substFormat | Format identifier: format = 1 |
Offset16 | coverageOffset | Offset to Coverage table, from beginning of substitution subtable |
int16 | deltaGlyphID | Add to original glyph ID to get substitute glyph ID |
1.2 Single Substitution Format 2
Format 2 is more flexible than Format 1, but requires more space. It provides an array of output glyph indices (substituteGlyphIDs) explicitly matched to the input glyph indices specified in the Coverage table.
The SingleSubstFormat2 subtable specifies a format identifier (substFormat), an offset to a Coverage table that defines the input glyph indices, a count of output glyph indices in the substituteGlyphIDs array (glyphCount), as well as the list of the output glyph indices in the substitute array (substituteGlyphIDs).
The substituteGlyphIDs array must contain the same number of glyph indices as the Coverage table. To locate the corresponding output glyph index in the substituteGlyphIDs array, this format uses the Coverage index returned from the Coverage table.
Example 3 at the end of this chapter uses Format 2 to substitute vertically oriented glyphs for horizontally oriented glyphs.
SingleSubstFormat2 subtable: Specified output glyph indices
Type | Name | Description |
---|---|---|
uint16 | substFormat | Format identifier: format = 2 |
Offset16 | coverageOffset | Offset to Coverage table, from beginning of substitution subtable |
uint16 | glyphCount | Number of glyph IDs in the substituteGlyphIDs array |
uint16 | substituteGlyphIDs[glyphCount] | Array of substitute glyph IDs — ordered by Coverage index |
LookupType 2: Multiple Substitution Subtable
A Multiple Substitution (MultipleSubst) subtable replaces a single glyph with more than one glyph, as when multiple glyphs replace a single ligature. The subtable has a single format: MultipleSubstFormat1.
2.1 Multiple Substitution Format 1
The Multiple Substitution Format 1 subtable specifies a format identifier (substFormat), an offset to a Coverage table that defines the input glyph indices, a count of offsets in the sequenceOffsets array (sequenceCount), and an array of offsets to Sequence tables that define the output glyph indices (sequenceOffsets). The Sequence table offsets are ordered by the Coverage index of the input glyphs.
For each input glyph listed in the Coverage table, a Sequence table defines the output glyphs. Each Sequence table contains a count of the glyphs in the output glyph sequence (glyphCount) and an array of output glyph indices (substituteGlyphIDs).
Note: The order of the output glyph indices depends on the writing direction of the text. For text written left to right, the left-most glyph will be first glyph in the sequence. Conversely, for text written right to left, the right-most glyph will be first.
The use of multiple substitution for deletion of an input glyph is prohibited. The glyphCount value must always be greater than 0.
Example 4 at the end of this chapter shows how to replace a single ligature with three glyphs.
MultipleSubstFormat1 subtable: Multiple output glyphs
Type | Name | Description |
---|---|---|
uint16 | substFormat | Format identifier: format = 1 |
Offset16 | coverageOffset | Offset to Coverage table, from beginning of substitution subtable |
uint16 | sequenceCount | Number of Sequence table offsets in the sequenceOffsets array |
Offset16 | sequenceOffsets[sequenceCount] | Array of offsets to Sequence tables. Offsets are from beginning of substitution subtable, ordered by Coverage index |
Sequence table
Type | Name | Description |
---|---|---|
uint16 | glyphCount | Number of glyph IDs in the substituteGlyphIDs array. This must always be greater than 0. |
uint16 | substituteGlyphIDs[glyphCount] | String of glyph IDs to substitute |
LookupType 3: Alternate Substitution Subtable
An Alternate Substitution (AlternateSubst) subtable identifies any number of aesthetic alternatives from which a user can choose a glyph variant to replace the input glyph. For example, if a font contains four variants of the ampersand symbol, the 'cmap' table will specify the index of one of the four glyphs as the default glyph index, and an AlternateSubst subtable will list the indices of the other three glyphs as alternatives. A text-processing client would then have the option of replacing the default glyph with any of the three alternatives.
The subtable has one format: AlternateSubstFormat1.
3.1 Alternate Substitution Format 1
The Alternate Substitution Format 1 subtable contains a format identifier (substFormat), an offset to a Coverage table containing the indices of glyphs with alternative forms (coverageOffset), a count of offsets to AlternateSet tables (alternateSetCount), and an array of offsets to AlternateSet tables (alternateSetOffsets).
For each glyph, an AlternateSet subtable contains a count of the alternative glyphs (glyphCount) and an array of their glyph indices (alternateGlyphIDs). Because all the glyphs are functionally equivalent, they can be in any order in the array.
Example 5 at the end of this chapter shows how to replace the default ampersand glyph with alternative glyphs.
AlternateSubstFormat1 subtable: Alternative output glyphs
Type | Name | Description |
---|---|---|
uint16 | substFormat | Format identifier: format = 1 |
Offset16 | coverageOffset | Offset to Coverage table, from beginning of substitution subtable |
uint16 | alternateSetCount | Number of AlternateSet tables |
Offset16 | alternateSetOffsets[alternateSetCount] | Array of offsets to AlternateSet tables. Offsets are from beginning of substitution subtable, ordered by Coverage index |
AlternateSet table
Type | Name | Description |
---|---|---|
uint16 | glyphCount | Number of glyph IDs in the alternateGlyphIDs array |
uint16 | alternateGlyphIDs[glyphCount] | Array of alternate glyph IDs, in arbitrary order |
LookupType 4: Ligature Substitution Subtable
A Ligature Substitution (LigatureSubst) subtable identifies ligature substitutions where a single glyph replaces multiple glyphs. One LigatureSubst subtable can specify any number of ligature substitutions. The subtable has one format: LigatureSubstFormat1.
4.1 Ligature Substitution Format 1
It contains a format identifier (substFormat), a Coverage table offset (coverageOffset), a count of the ligature sets defined in this table (ligatureSetCount), and an array of offsets to LigatureSet tables (ligatureSetOffsets). The Coverage table specifies only the index of the first glyph component of each ligature set.
Example 6 at the end of this chapter shows how to replace a string of glyphs with a single ligature.
LigatureSubstFormat1 subtable: All ligature substitutions in a script
Type | Name | Description |
---|---|---|
uint16 | substFormat | Format identifier: format = 1 |
Offset16 | coverageOffset | Offset to Coverage table, from beginning of substitution subtable |
uint16 | ligatureSetCount | Number of LigatureSet tables |
Offset16 | ligatureSetOffsets[ligatureSetCount] | Array of offsets to LigatureSet tables. Offsets are from beginning of substitution subtable, ordered by Coverage index |
A LigatureSet table, one for each covered glyph, specifies all the ligature strings that begin with the covered glyph. For example, if the Coverage table lists the glyph index for a lowercase “f,” then a LigatureSet table will define the “ffl,” “fl,” “ffi,” “fi,” and “ff” ligatures. If the Coverage table also lists the glyph index for a lowercase “e,” then a different LigatureSet table will define the “etc” ligature.
A LigatureSet table consists of a count of the ligatures that begin with the covered glyph (ligatureCount) and an array of offsets (ligatureSetOffsets) to Ligature tables, which define the glyphs in each ligature. The order in the Ligature offset array defines the preference for using the ligatures. For example, if the “ffl” ligature is preferable to the “ff” ligature, then the Ligature array would list the offset to the “ffl” Ligature table before the offset to the “ff” Ligature table.
LigatureSet table: All ligatures beginning with the same glyph
Type | Name | Description |
---|---|---|
uint16 | ligatureCount | Number of Ligature tables |
Offset16 | ligatureOffsets[LigatureCount] | Array of offsets to Ligature tables. Offsets are from beginning of LigatureSet table, ordered by preference. |
For each ligature in the set, a Ligature table specifies the glyph ID of the output ligature glyph (ligatureGlyph); a count of the total number of component glyphs in the ligature, including the first component (componentCount); and an array of glyph IDs for the components (componentGlyphIDs). The array starts with the second component glyph in the ligature (glyph sequence index = 1, componentGlyphIDs array index = 0) because the first component glyph is specified in the Coverage table.
Note: The componentGlyphIDs array lists glyph IDs according to the writing direction — that is, the logical order — of the text. For text written right to left, the right-most glyph will be first. Conversely, for text written left to right, the left-most glyph will be first.
Ligature table: Glyph components for one ligature
Type | Name | Description |
---|---|---|
uint16 | ligatureGlyph | glyph ID of ligature to substitute |
uint16 | componentCount | Number of components in the ligature |
uint16 | componentGlyphIDs[componentCount - 1] | Array of component glyph IDs — start with the second component, ordered in writing direction |
Substitution Lookup Record
Substitution subtable types 1 to 4 allow for describing glyph substitution actions without providing a way to describe glyph-sequence contexts — that is, contexts in which glyphs must occur in order for substitutions to be applied. Subtable types 5, 6 and 8, on the other hand, allow for describing glyph substitutions that occur in particular contexts. Contextual substitution subtables of types 5 and 6 specify the substitution data in a Substitution Lookup Record (SubstLookupRecord), which identifies which glyphs within a context sequence are to be acted on, and which substitution action (given in a separate Lookup table) is to be applied.
Each record contains a glyphSequenceIndex, which indicates the position within a context glyph sequence where the substitution will occur. In addition, a lookupListIndex identifies the lookup to be applied at the glyph position specified by the glyphSequenceIndex.
The contextual substitution subtables defined in Examples 7, 8, and 9 at the end of this chapter show SubstLookupRecords.
SubstLookupRecord
Type | Name | Description |
---|---|---|
uint16 | glyphSequenceIndex | Index into current glyph sequence — first glyph = 0. |
uint16 | lookupListIndex | Lookup to apply to that position — zero-based index. |
The glyphSequenceIndex in a SubstLookupRecord must take into consideration the order in which lookups are applied to the entire glyph sequence. Because multiple substitutions may occur in a given context, the glyphSequenceIndex refers to the glyph sequence after the text-processing client has applied any previous lookups. In other words, the glyphSequenceIndex identifies the location for the substitution at the time that the lookup is to be applied.
For example, consider an input glyph sequence of four glyphs. The first glyph does not have a substitute, but the middle two glyphs will be replaced with a ligature, and a single glyph will replace the fourth glyph. In this example, the ligature substitution and single substition are both to be expressed as contextual substitutions, with a context that begins at the first glyph.
- The first glyph is in position 0. No lookups will be applied at position 0, so no SubstLookupRecord is defined.
- The SubstLookupRecord defined for the ligature substitution specifies the glyphSequenceIndex as position 1, which is the position of the first glyph component in the ligature string. After the ligature replaces the glyphs in positions 1 and 2, however, the input glyph sequence consists of only three glyphs, not the original four.
- To replace the last glyph in the sequence, the lookup subtable specifies a context that consists of three glyphs, not four; and the SubstLookupRecord defines the glyphSequenceIndex as position 2, not position 3. This position and that context reflect the effect of the ligature substitution applied before this single substitution.
Note: This example assumes that the LookupList specifies the ligature substitution lookup before the single substitution lookup.
LookupType 5: Contextual Substitution Subtable
A Contextual Substitution (ContextSubst) subtable defines a powerful type of glyph substitution lookup: it describes glyph substitutions in context that replace one or more glyphs within a certain pattern of glyphs.
ContextSubst subtables can be any of three formats that define a context in terms of a specific sequence of glyphs, glyph classes, or glyph sets. Each format can describe one or more input glyph sequences and one or more substitutions for each sequence. All three formats specify substitution data in a SubstLookupRecord, described above.
5.1 Context Substitution Format 1: Simple Glyph Contexts
Format 1 defines the context for a glyph substitution as a particular sequence of glyphs. For example, a context could be <xyz>, <holiday>, <!?*#@>, or any other glyph sequence.
Within a context sequence, Format 1 identifies particular glyph positions (not glyph indices) as the targets for specific substitutions. When a text-processing client locates a context in a string of text, it finds the lookup data for a targeted position and makes a substitution by applying the lookup data at that location.
For example, if a client is to replace the glyph string <abc> with its reverse glyph string <cba>, the input context is defined as the glyph sequence, <abc>, and the lookups defined for the context are (1) “a” to “c” and (2) “c” to “a”. When a client encounters the context <abc>, the lookups are performed in the order stored. First, “c” is substituted for “a” resulting in <cbc>. Second, “a” is substituted for the “c” that has not yet been touched, resulting in <cba>.
To specify a context, a Coverage table lists the first glyph in the sequence, and a SubRule table identifies the remaining glyphs. To describe the <abc> context used in the previous example, the Coverage table lists the glyph index of the first component of the sequence — the “a” glyph. A SubRule table defines indices for the “b” and “c” glyphs.
A single ContextSubstFormat1 subtable may define more than one context glyph sequence. If different context sequences begin with the same glyph, then the Coverage table should list the glyph only once because all glyphs in the table must be unique. For example, if three contexts each start with an “s” and two start with a “t,” then the Coverage table will list one “s” and one “t”.
For each context, a SubRule table lists all the glyphs that follow the first glyph. The table also contains an array of SubstLookupRecords that specify the substitution lookup data for each glyph position (including the first glyph position) in the context.
All of the SubRule tables defining contexts that begin with the same first glyph are grouped together and defined in a SubRuleSet table. For example, the SubRule tables that define the three contexts that begin with an “s” are grouped in one SubRuleSet table, and the SubRule tables that define the two contexts that begin with a “t” are grouped in a second SubRuleSet table. Each glyph listed in the Coverage table must have a SubRuleSet table defining all the SubRule tables that apply to a covered glyph.
To locate a context glyph sequence, the text-processing client searches the Coverage table each time it encounters a new text glyph. If the glyph is covered, the client reads the corresponding SubRuleSet table and examines each SubRule table in the set to determine whether the rest of the context matches the subsequent glyphs in the text. If the context and text string match, the client finds the target glyph positions, applies the lookups for those positions, and completes the substitutions.
A ContextSubstFormat1 subtable contains a format identifier (substFormat), an offset to a Coverage table (coverageOffset), a count of defined SubRuleSets (subRuleSetCount), and an array of offsets to the SubRuleSet tables (subRuleSetOffsets). As mentioned, one SubRuleSet table must be defined for each glyph listed in the Coverage table.
In the SubRuleSet array, the SubRuleSet table offsets are ordered in the Coverage index order. The first SubRuleSet in the array applies to the first glyph ID listed in the Coverage table, the second SubRuleSet in the array applies to the second glyph ID listed in the Coverage table, and so on.
Example 7 at the end of the chapter shows how to use the ContextSubstFormat1 subtable to replace a sequence of three glyphs with a sequence preferred for the French language system.
ContextSubstFormat1 Subtable
Type | Name | Description |
---|---|---|
uint16 | substFormat | Format identifier: format = 1 |
Offset16 | coverageOffset | Offset to Coverage table, from beginning of substitution subtable |
uint16 | subRuleSetCount | Number of SubRuleSet tables — must equal glyphCount in Coverage table |
Offset16 | subRuleSetOffsets[subRuleSetCount] | Array of offsets to SubRuleSet tables. Offsets are from beginning of substitution subtable, ordered by Coverage index |
A SubRuleSet table consists of an array of offsets to SubRule tables (subRuleOffsets), ordered by preference, and a count of the SubRule tables defined in the set (subRuleCount). The order in the SubRule array can be critical. Consider two contexts, <abc> and <abcd>. If <abc> is first in the SubRule array, all instances of <abc> in the text — including all instances of <abcd> — will be changed. If <abcd> comes first in the array, however, only <abcd> sequences will be changed, without affecting any instances of <abc>.
SubRuleSet table: All contexts beginning with the same glyph
Type | Name | Description |
---|---|---|
uint16 | subRuleCount | Number of SubRule tables |
Offset16 | subRuleOffsets[subRuleCount] | Array of offsets to SubRule tables. Offsets are from beginning of SubRuleSet table, ordered by preference |
A SubRule table consists of a count of the glyphs to be matched in the input context sequence (glyphCount), including the first glyph in the sequence, and an array of glyph indices that describe the context (inputSequence). The Coverage table specifies the index of the first glyph in the context, and the Input array begins with the second glyph in the context sequence (glyph sequence index = 1, inputSequence array index = 0).
Note: The Input array lists the indices in the order the corresponding glyphs appear in the text. For text written from right to left, the right-most glyph will be first; conversely, for text written from left to right, the left-most glyph will be first.
A SubRule table also contains a count of the substitutions to be performed on the input glyph sequence (substitutionCount) and an array of SubstLookupRecords (substLookupRecords). Each record specifies a position in the input glyph sequence and a LookupList index to the substitution lookup that is applied at that position. The array should list records in design order, or the order the lookups should be applied to the entire glyph sequence.
SubRule table: One simple context definition
Type | Name | Description |
---|---|---|
uint16 | glyphCount | Total number of glyphs in input glyph sequence — includes the first glyph. |
uint16 | substitutionCount | Number of SubstLookupRecords |
uint16 | inputSequence[glyphCount - 1] | Array of input glyph IDs — start with second glyph |
SubstLookupRecord | substLookupRecords[substitutionCount] | Array of SubstLookupRecords, in design order |
5.2 Context Substitution Format 2: Class-based Glyph Contexts
Format 2, a more flexible format than Format 1, describes class-based context substitution. For this format, a specific integer, called a class value, must be assigned to each glyph component in all context glyph sequences. Contexts are then defined as sequences of glyph class values. More than one context may be defined at a time.
For example, suppose that a swash capital glyph should replace each uppercase letter glyph that is preceded by a space glyph and followed by a lowercase letter glyph (a glyph sequence of space - uppercase - lowercase). The set of uppercase glyphs would constitute one glyph class (Class 1), the set of lowercase glyphs would constitute a second class (Class 2), and the space glyph would constitute a third class (Class 3). The input context might be specified with a context rule (called a SubClassRule) that describes “the set of glyph strings that form a sequence of three glyph classes, one glyph from Class 3, followed by one glyph from Class 1, followed by one glyph from Class 2.”
Each ContextSubstFormat2 subtable contains an offset to a class definition table (classDefOffset), which defines the glyph class values of all input contexts. Generally, a unique ClassDef table will be declared in each instance of the ContextSubstFormat2 table that is included in a font, even though several Format 2 tables could share ClassDef tables. Class assignments are fixed (the same for each position in the context), and classes are exclusive (a glyph cannot be in more than one class at a time). The output glyphs that replace the glyphs in the context sequences do not need class values because they are specified elsewhere by glyph ID.
The ContextSubstFormat2 subtable also contains a format identifier (substFormat) and defines an offset to a Coverage table (coverageOffset). For this format, the Coverage table lists indices for the complete set of unique glyphs (not glyph classes) that may appear as the first glyph of any class-based context. In other words, the Coverage table contains the list of glyph indices for all the glyphs in all classes that may be first in any of the context class sequences. For example, if the contexts begin with a Class 1 or Class 2 glyph, then the Coverage table will list the indices of all Class 1 and Class 2 glyphs.
A ContextSubstFormat2 subtable also defines an array of offsets to the SubClassSet tables (subClassSetOffsets) and a count of the SubClassSet tables (subClassSetCount). The array contains one offset for each class (including Class 0) in the ClassDef table. In the array, the class value defines an offset’s index position, and the SubClassSet offsets are ordered by ascending class value (from 0 to subClassSetCount - 1).
For example, the first SubClassSet listed in the array contains all contexts beginning with Class 0 glyphs, the second SubClassSet contains all contexts beginning with Class 1 glyphs, and so on. If no contexts begin with a particular class (that is, if a SubClassSet contains no SubClassRule tables), then the offset to that particular SubClassSet in the SubClassSet array will be set to NULL.
Example 8 at the end of this chapter uses Format 2 to substitute Arabic mark glyphs for base glyphs of different heights.
ContextSubstFormat2 Subtable
Type | Name | Description |
---|---|---|
uint16 | substFormat | Format identifier: format = 2 |
Offset16 | coverageOffset | Offset to Coverage table, from beginning of substitution subtable |
Offset16 | classDefOffset | Offset to glyph ClassDef table, from beginning of substitution subtable |
uint16 | subClassSetCount | Number of SubClassSet tables |
Offset16 | subClassSetOffsets[subClassSetCount] | Array of offsets to SubClassSet tables. Offsets are from beginning of substitution subtable, ordered by class (may be NULL). |
Each context is defined in a SubClassRule table, and all SubClassRules that specify contexts beginning with the same class value are grouped in a SubClassSet table. Consequently, the SubClassSet containing a context identifies a context’s first class component.
Each SubClassSet table consists of a count of the SubClassRule tables defined in the SubClassSet (subClassRuleCount) and an array of offsets to SubClassRule tables (subClassRuleOffsets). The SubClassRule tables are ordered by preference in the SubClassRule array of the SubClassSet.
SubClassSet subtable
Type | Name | Description |
---|---|---|
uint16 | subClassRuleCount | Number of SubClassRule tables |
Offset16 | subClassRuleOffsets[subClassRuleCount] | Array of offsets to SubClassRule tables. Offsets are from beginning of SubClassSet, ordered by preference. |
For each context, a SubClassRule table contains a count of the glyph classes in the context sequence (glyphCount), including the first class. A Class array lists the classes, beginning with the class for the second context position (glyph sequence index = 1, inputSequence array index = 0).
Note: Text order depends on the writing direction of the text. For text written from right to left, the right-most class will be first. Conversely, for text written from left to right, the left-most class will be first.
The values specified in the Class array are the values defined in the ClassDef table. For example, a context consisting of the sequence “Class 2, Class 7, Class 5, Class 0” will produce a Class array of 7,5,0. The first class in the sequence, Class 2, is identified in the ContextSubstFormat2 table by the SubClassSet array index of the corresponding SubClassSet.
A SubClassRule also contains a count of the substitutions to be performed on the context (substitutionCount) and an array of SubstLookupRecords (substLookupRecords) that supply the substitution data. For each position in the context that requires a substitution, a SubstLookupRecord specifies a LookupList index and a position in the input glyph sequence where the lookup is applied. The substLookupRecords array lists SubstLookupRecords in design order — that is, the order in which lookups should be applied to the entire glyph sequence.
SubClassRule table: Context definition for one class
Type | Name | Description |
---|---|---|
uint16 | glyphCount | Total number of classes specified for the context in the rule — includes the first class |
uint16 | substitutionCount | Number of SubstLookupRecords |
uint16 | inputSequence[glyphCount - 1] | Array of classes to be matched to the input glyph sequence, beginning with the second glyph position. |
SubstLookupRecord | substLookupRecords[substitutionCount] | Array of Substitution lookups, in design order. |
5.3 Context Substitution Format 3: Coverage-based Glyph Contexts
Format 3, coverage-based context substitution, defines a context rule as a sequence of coverage tables. Each position in the sequence may define a different Coverage table for the set of glyphs that matches the context pattern. With Format 3, the glyph sets defined in the different Coverage tables may intersect, unlike Format 2 which specifies fixed class assignments (identical for each position in the context sequence) and exclusive classes (a glyph cannot be in more than one class at a time).
For example, consider an input context that contains a lowercase glyph (position 0), followed by an uppercase glyph (position 1), either a lowercase or numeral glyph (position 2), and then either a lowercase or uppercase vowel (position 3). This context requires four Coverage tables, one for each position:
- In position 0, the Coverage table lists the set of lowercase glyphs.
- In position 1, the Coverage table lists the set of uppercase glyphs.
- In position 2, the Coverage table lists the set of lowercase and numeral glyphs, a superset of the glyphs defined in the Coverage table for position 0.
- In position 3, the Coverage table lists the set of lowercase and uppercase vowels, a subset of the glyphs defined in the Coverage tables for both positions 0 and 1.
Unlike Formats 1 and 2, this format defines only one context rule at a time. It consists of a format identifier (substFormat), a count of the glyphs in the sequence to be matched (glyphCount), and an array of Coverage offsets that describe the input context sequence (coverageOffsets).
Note: The order of the Coverage tables listed in the Coverage array must follow the writing direction. For text written from right to left, then the right-most glyph will be first. Conversely, for text written from left to right, the left-most glyph will be first.
The subtable also contains a count of the substitutions to be performed on the input Coverage sequence (substitutionCount) and an array of SubstLookupRecords (substLookupRecords) in design order — that is, the order in which lookups should be applied to the entire glyph sequence.
Example 9 at the end of this chapter uses ContextSubstFormat3 to substitute swash glyphs for two out of three glyphs in a sequence.
ContextSubstFormat3 Subtable
Type | Name | Description |
---|---|---|
uint16 | substFormat | Format identifier: format = 3 |
uint16 | glyphCount | Number of glyphs in the input glyph sequence |
uint16 | substitutionCount | Number of SubstLookupRecords |
Offset16 | coverageOffsets[glyphCount] | Array of offsets to Coverage tables. Offsets are from beginning of substitution subtable, in glyph sequence order. |
SubstLookupRecord | substLookupRecords[substitutionCount] | Array of SubstLookupRecords, in design order. |
LookupType 6: Chaining Contextual Substitution Subtable
A Chaining Contextual Substitution subtable (ChainContextSubst) describes glyph substitutions in context with an ability to look back and/or look ahead in the sequence of glyphs. The design of the Chaining Contextual Substitution subtable is parallel to that of the Contextual Substitution subtable, including the availability of three formats for handling sequences of glyphs, glyph classes, or glyph sets. Each format can describe one or more backtrack, input, and lookahead sequences and one or more substitutions for each sequence.
6.1 Chaining Context Substitution Format 1: Simple Glyph Contexts
Format 1 defines the context for a glyph substitution as a particular sequence of glyphs. For example, a context could be <xyz>, <holiday>, <!?*#@>, or any other glyph sequence.
Within a context sequence, Format 1 identifies particular glyph positions (not glyph indices) as the targets for specific substitutions. When a text-processing client locates a context in a string of text, it finds the lookup data for a targeted position and makes a substitution by applying the lookup data at that location.
To specify the context, the coverage table lists the first glyph in the input sequence, and the ChainSubRule subtable defines the rest. Once a covered glyph is found at position i, the client reads the corresponding ChainSubRuleSet table and examines each table to determine if it matches the surrounding glyphs in the text. In the simplest of cases, there is a match if the string <backtrack sequence>+<input sequence>+<lookahead sequence> matches with the glyphs at position i - backtrackGlyphCount in the text. Note that LookupFlags affect backtrack/lookahead sequences.
To clarify the ordering of glyph arrays for input, backtrack and lookahead sequences, the following illustration is provided. Input sequence match begins at i where the input sequence match begins. The backtrack sequence is ordered beginning at i - 1 and increases in offset value as one moves away from i. The lookahead sequence begins after the input sequence and increases in logical order.
Logical order - | a | b | c | d | e | f | g | h | i | j |
i | ||||||||||
Input sequence - | 0 | 1 | ||||||||
Backtrack sequence - | 3 | 2 | 1 | 0 | ||||||
Lookahead sequence - | 0 | 1 | 2 | 3 |
If there is a match, then the client finds the target glyph positions for substitutions and completes the substitutions. Please note that (just like in the ContextSubstFormat1 subtable) these lookups are required to operate within the range of text from the covered glyph to the end of the input sequence. No substitutions can be defined for the backtrack sequence or the lookahead sequence.
Once the substitutions are complete, the client should move to the glyph position immediately following the matched input sequence and resume the lookup process from there.
A single ChainContextSubstFormat1 subtable may define more than one context glyph sequence. If different context sequences begin with the same glyph, then the Coverage table should list the glyph only once because all glyphs in the table must be unique. For example, if three contexts each start with an “s” and two start with a “t,” then the Coverage table will list one “s” and one “t”.
All of the ChainSubRule tables defining contexts that begin with the same first glyph are grouped together and defined in a ChainSubRuleSet table. For example, the ChainSubRule tables that define the three contexts that begin with an “s” are grouped in one ChainSubRuleSet table, and the ChainSubRule tables that define the two contexts that begin with a “t” are grouped in a second ChainSubRuleSet table. Each glyph listed in the Coverage table must have a ChainSubRuleSet table defining all the ChainSubRule tables that apply to a covered glyph.
A ChainContextSubstFormat1 subtable contains a format identifier (substFormat), an offset to a Coverage table (coverageOffset), a count of defined ChainSubRuleSets (chainSubRuleSetCount), and an array of offsets to the ChainSubRuleSet tables (chainSubRuleSetOffsets). As mentioned, one ChainSubRuleSet table must be defined for each glyph listed in the Coverage table.
In the ChainSubRuleSet array, the ChainSubRuleSet table offsets are ordered in the Coverage index order. The first ChainSubRuleSet in the array applies to the first glyph ID listed in the Coverage table, the second ChainSubRuleSet in the array applies to the second glyph ID listed in the Coverage table, and so on.
ChainContextSubstFormat1 Subtable
Type | Name | Description |
---|---|---|
uint16 | substFormat | Format identifier: format = 1 |
Offset16 | coverageOffset | Offset to Coverage table, from beginning of substitution subtable. |
uint16 | chainSubRuleSetCount | Number of ChainSubRuleSet tables — must equal glyphCount in Coverage table. |
Offset16 | chainSubRuleSetOffsets[chainSubRuleSetCount] | Array of offsets to ChainSubRuleSet tables. Offsets are from beginning of substitution subtable, ordered by Coverage index. |
A ChainSubRuleSet table consists of an array of offsets to ChainSubRule tables (chainSubRuleOffsets), ordered by preference, and a count of the ChainSubRule tables defined in the set (chainSubRuleCount).
The order in the ChainSubRule array can be critical. Consider two contexts, <abc> and <abcd>. If <abc> is first in the ChainSubRule array, all instances of <abc> in the text — including all instances of <abcd> — will be changed. If <abcd> comes first in the array, however, only <abcd> sequences will be changed, without affecting any instances of <abc>.
ChainSubRuleSet table: All contexts beginning with the same glyph
Type | Name | Description |
---|---|---|
uint16 | chainSubRuleCount | Number of ChainSubRule tables |
Offset16 | chainSubRuleOffsets[chainSubRuleCount] | Array of offsets to ChainSubRule tables. Offsets are from beginning of ChainSubRuleSet table, ordered by preference. |
A ChainSubRule table consists of a count of the glyphs to be matched in the backtrack, input, and lookahead context sequences, including the first glyph in each sequence, and an array of glyph indices that describe each portion of the contexts. The Coverage table specifies the index of the first glyph in each context, and each array begins with the second glyph in the context sequence (glyph sequence index = 1, inputSequence array index = 0).
Note: All arrays list the indices in the order the corresponding glyphs appear in the text. For text written from right to left, the right-most glyph will be first; conversely, for text written from left to right, the left-most glyph will be first.
A ChainSubRule table also contains a count of the substitutions to be performed on the input glyph sequence (substitutionCount) and an array of SubstitutionLookupRecords (substLookupRecords). Each record specifies a position in the input glyph sequence and a LookupList index to the substitution lookup that is applied at that position. The array should list records in design order, or the order the lookups should be applied to the entire glyph sequence.
ChainSubRule subtable
Type | Name | Description |
---|---|---|
uint16 | backtrackGlyphCount | Total number of glyphs in the backtrack sequence (number of glyphs to be matched before the first glyph of the input sequence). |
uint16 | backtrackSequence[backtrackGlyphCount] | Array of backtrack glyph IDs — to be matched before the input sequence. |
uint16 | inputGlyphCount | Total number of glyphs in the input sequence — includes the first glyph. |
uint16 | inputSequence[inputGlyphCount - 1] | Array of input glyph IDs — start with second glyph. |
uint16 | lookaheadGlyphCount | Total number of glyphs in the lookahead sequence (number of glyphs to be matched after the input sequence). |
uint16 | lookAheadSequence[lookAheadGlyphCount] | Array of lookahead glyph IDs — to be matched after the input sequence. |
uint16 | substitutionCount | Number of SubstLookupRecords |
SubstLookupRecord | substLookupRecords[SubstCount] | Array of SubstLookupRecords, in design order. |
6.2 Chaining Context Substitution Format 2: Class-based Glyph Contexts
Format 2 describes class-based chaining context substitution. For this format, a specific integer, called a class value, must be assigned to each glyph component in all context glyph sequences. Contexts are then defined as sequences of glyph class values. More than one context may be defined at a time.
To chain contexts, three classes are used in the glyph ClassDef table: backtrack ClassDef, input ClassDef, and lookahead ClassDef.
The ChainContextSubstFormat2 subtable also contains a format identifier (substFormat) and defines an offset to a Coverage table (coverageOffset). For this format, the Coverage table lists indices for the complete set of unique glyphs (not glyph classes) that may appear as the first glyph of any class-based context. In other words, the Coverage table contains the list of glyph indices for all the glyphs in all classes that may be first in any of the context class sequences. For example, if the contexts begin with a Class 1 or Class 2 glyph, then the Coverage table will list the indices of all Class 1 and Class 2 glyphs.
A ChainContextSubstFormat2 subtable also defines an array of offsets to the ChainSubClassSet tables (chainSubClassSetOffsets) and a count of the ChainSubClassSet tables (chainSubClassSetCount). The array contains one offset for each class (including Class 0) in the ClassDef table. In the array, the class value defines an offset’s index position, and the ChainSubClassSet offsets are ordered by ascending class value (from 0 to ChainSubClassSetCount - 1).
If no contexts begin with a particular class (that is, if a ChainSubClassSet contains no ChainSubClassRule tables), then the offset to that particular ChainSubClassSet in the ChainSubClassSet array will be set to NULL.
ChainContextSubstFormat2 Subtable
Type | Name | Description |
---|---|---|
uint16 | substFormat | Format identifier: format = 2 |
Offset16 | coverageOffset | Offset to Coverage table, from beginning of substitution subtable. |
Offset16 | backtrackClassDefOffset | Offset to glyph ClassDef table containing backtrack sequence data, from beginning of substitution subtable. |
Offset16 | inputClassDefOffset | Offset to glyph ClassDef table containing input sequence data, from beginning of substitution subtable. |
Offset16 | lookaheadClassDefOffset | Offset to glyph ClassDef table containing lookahead sequence data, from beginning of substitution subtable. |
uint16 | chainSubClassSetCount | Number of ChainSubClassSet tables |
Offset16 | chainSubClassSetOffsets[chainSubClassSetCount] | Array of offsets to ChainSubClassSet tables. Offsets are from beginning of substitution subtable, ordered by input class (may be NULL) |
Each context is defined in a ChainSubClassRule table, and all ChainSubClassRules that specify contexts beginning with the same class value are grouped in a ChainSubClassSet table. Consequently, the ChainSubClassSet containing a context identifies a context’s first class component.
Each ChainSubClassSet table consists of a count of the ChainSubClassRule tables defined in the ChainSubClassSet (chainSubClassRuleCount) and an array of offsets to ChainSubClassRule tables (chainSubClassRuleOffsets). The ChainSubClassRule tables are ordered by preference in the ChainSubClassRule array of the ChainSubClassSet.
ChainSubClassSet subtable
Type | Name | Description |
---|---|---|
uint16 | chainSubClassRuleCount | Number of ChainSubClassRule tables |
Offset16 | chainSubClassRuleOffsets[chainSubClassRuleCount] | Array of offsets to ChainSubClassRule tables. Offsets are from beginning of ChainSubClassSet, ordered by preference. |
For each context (backtrack, input, lookahead), a ChainSubClassRule table contains a count of the glyph classes for each portion of the context sequence (backtrackGlyphCount, inputGlyphCount, lookaheadGlyphCount), including the first class. A Class array lists the classes, beginning with the class for the second context position (input glyph sequence index = 1, inputSequence array index = 0), that follow the first class in the context.
Note: Text order depends on the writing direction of the text. For text written from right to left, the right-most class will be first. Conversely, for text written from left to right, the left-most class will be first.
The values specified in the Class array are the values defined in the ClassDef table. The first class in the sequence, Class 2, is identified in the ChainContextSubstFormat2 table by the ChainSubClassSet array index of the corresponding ChainSubClassSet.
A ChainSubClassRule also contains a count of the substitutions to be performed on the context (substitutionCount) and an array of SubstLookupRecords (substLookupRecords) that supply the substitution data. For each position in the context that requires a substitution, a SubstLookupRecord specifies a LookupList index and a position in the input glyph sequence where the lookup is applied. The SubstLookupRecord array lists SubstLookupRecords in design order — that is, the order in which lookups should be applied to the entire glyph sequence.
ChainSubClassRule table: Chaining context definition for one class
Type | Name | Description |
---|---|---|
uint16 | backtrackGlyphCount | Total number of glyphs in the backtrack sequence (number of glyphs to be matched before the first glyph of the input sequence). |
uint16 | backtrackSequence[backtrackGlyphCount] | Array of backtrack classes — to be matched with glyph sequence before the input sequence. |
uint16 | inputGlyphCount | Total number of classes in the input sequence — includes the first class. |
uint16 | inputSequence[inputGlyphCount - 1] | Array of classes to be matched with the input glyph sequence, beginning with the second glyph position. |
uint16 | lookaheadGlyphCount | Total number of glyphs in the lookahead sequence (number of glyphs to be matched after the input sequence). |
uint16 | lookAheadSequence[lookAheadGlyphCount] | Array of lookahead classes — to be matched with glyph sequence after the input sequence. |
uint16 | substitutionCount | Number of SubstLookupRecords |
SubstLookupRecord | substLookupRecords[substitutionCount] | Array of SubstLookupRecords, in design order. |
6.3 Chaining Context Substitution Format 3: Coverage-based Glyph Contexts
Format 3 defines a chaining context rule as a sequence of Coverage tables. Each position in the sequence may define a different Coverage table for the set of glyphs that matches the context pattern. With Format 3, the glyph sets defined in the different Coverage tables may intersect, unlike Format 2 which specifies fixed class assignments (identical for each position in the backtrack, input, or lookahead sequence) and exclusive classes (a glyph cannot be in more than one class at a time).
Note: The order of the Coverage tables listed in the Coverage array must follow the writing direction. For text written from right to left, then the right-most glyph will be first. Conversely, for text written from left to right, the left-most glyph will be first.
The subtable also contains a count of the substitutions to be performed on the input Coverage sequence (substitutionCount) and an array of SubstLookupRecords (substLookupRecords) in design order — that is, the order in which lookups should be applied to the entire glyph sequence.
ChainContextSubstFormat3 Subtable
Type | Name | Description |
---|---|---|
uint16 | substFormat | Format identifier: format = 3 |
uint16 | backtrackGlyphCount | Number of glyphs in the backtrack sequence. |
Offset16 | backtrackCoverageOffsets[backtrackGlyphCount] | Array of offsets to coverage tables in backtrack sequence. Offsets are from beginning of substition subtable, in glyph sequence order. |
uint16 | inputGlyphCount | Number of glyphs in input sequence |
Offset16 | inputCoverageOffsets[inputGlyphCount] | Array of offsets to coverage tables in input sequence. Offsets are from beginning of substition subtable, in glyph sequence order. |
uint16 | lookaheadGlyphCount | Number of glyphs in lookahead sequence |
Offset16 | lookaheadCoverageOffsets[lookaheadGlyphCount] | Array of offsets to coverage tables in lookahead sequence. Offsets are from beginning of substitution subtable, in glyph sequence order. |
uint16 | substitutionCount | Number of SubstLookupRecords |
SubstLookupRecord | substLookupRecords[substitutionCount] | Array of SubstLookupRecords, in design order |
LookupType 7: Extension Substitution
This lookup provides a mechanism whereby any other lookup type’s subtables are stored at a 32-bit offset location in the GSUB table. This is needed if the total size of the subtables exceeds the 16-bit limits of the various other offsets in the GSUB table. In this specification, the subtable stored at the 32-bit offset location is termed the “extension” subtable.
This subtable type uses one format: ExtensionSubstFormat1.
7.1 Extension Substitution Subtable Format 1
ExtensionSubstFormat1 subtable
Type | Name | Description |
---|---|---|
uint16 | substFormat | Format identifier. Set to 1. |
uint16 | extensionLookupType | Lookup type of subtable referenced by extensionOffset (that is, the extension subtable). |
Offset32 | extensionOffset | Offset to the extension subtable, of lookup type extensionLookupType, relative to the start of the ExtensionSubstFormat1 subtable. |
The extensionLookupType field must be set to any lookup type other than 7. All subtables in a LookupType 7 lookup must have the same extensionLookupType. All offsets within the extension subtables are set in the usual way, i.e. relative to the extension subtables themselves.
When an OpenType layout engine encounters a LookupType 7 Lookup table, it shall:
- Proceed as though the Lookup table’s lookupType field were set to the extensionLookupType of the subtables.
- Proceed as though each extension subtable referenced by extensionOffset replaced the LookupType 7 subtable that referenced it.
LookupType 8: Reverse Chaining Contextual Single Substitution Subtable
Reverse Chaining Contextual Single Substitution subtable (ReverseChainSingleSubst) describes single-glyph substitutions in context with an ability to look back and/or look ahead in the sequence of glyphs. The major difference between this and other lookup types is that processing of input glyph sequence goes from end to start.
Compared to the Chaining Contextual Sustitution (lookup subtable type 6), this format is restricted to only a coverage-based subtable format, input sequences can contain only a single glyph, and only single substitutions are allowed on this glyph. This constraint is integrated into the subtable format.
This lookup type is designed specifically for the Arabic script writing styles, like nastaliq, where the shape of the glyph is determined by the following glyph, beginning at the last glyph of the “joor”, or set of connected glyphs.
8.1 Reverse Chaining Contextual Single Substitution Format 1: Coverage-based Glyph Contexts
Format 1 defines a chaining context rule as a sequence of Coverage tables. Each position in the sequence may define a different Coverage table for the set of glyphs that matches the context pattern. With Format 1, the glyph sets defined in the different Coverage tables may intersect.
Note: Despite reverse order processing, the order of the Coverage tables listed in the Coverage array must be in logical order (follow the writing direction). The backtrack sequence is as illustrated in the LookupType 6: Chaining Contextual Substitution subtable. The input sequence is one glyph located at i in the logical string. The backtrack begins at i - 1 and increases in offset value as one moves toward the logical beginning of the string. The lookahead sequence begins at i + 1 and increases in offset value as one moves toward the logical end of the string. In processing a reverse chaining substitution, i begins at the logical end of the string and moves to the beginning.
The subtable contains a Coverage table for the input glyph and Coverage table arrays for backtrack and lookahead sequences. It also contains an array of substitute glyph indices (substituteGlyphIDs), which are substititions for glyphs in the Coverage table, and a count of glyphs in the substituteGlyphIDs array. The substituteGlyphIDs array must contain the same number of glyph indices as the Coverage table. To locate the corresponding output glyph index in the substituteGlyphIDs array, this format uses the Coverage index returned from the Coverage table.
Example 10 at the end of this chapter uses ReverseChainSingleSubstFormat1 to substitute Arabic glyphs with a correct stroke thickness on the left (exit) to match the stroke thickness on the right (entry) of the following glyph (in logical order).
ReverseChainSingleSubstFormat1 Subtable
Type | Name | Description |
---|---|---|
uint16 | substFormat | Format identifier: format = 1 |
Offset16 | coverageOffset | Offset to Coverage table, from beginning of substitution subtable. |
uint16 | backtrackGlyphCount | Number of glyphs in the backtrack sequence. |
Offset16 | backtrackCoverageOffsets[backtrackGlyphCount] | Array of offsets to coverage tables in backtrack sequence, in glyph sequence order. |
uint16 | lookaheadGlyphCount | Number of glyphs in lookahead sequence. |
Offset16 | lookaheadCoverageOffsets[lookaheadGlyphCount] | Array of offsets to coverage tables in lookahead sequence, in glyph sequence order. |
uint16 | glyphCount | Number of glyph IDs in the substituteGlyphIDs array. |
uint16 | substituteGlyphIDs[glyphCount] | Array of substitute glyph IDs — ordered by Coverage index. |
GSUB Subtable Examples
The rest of this chapter describes and illustrates examples of all the GSUB subtables, including each of the three formats available for contextual substitutions. All the examples reflect unique parameters described below, but the samples provide a useful reference for building subtables specific to other situations.
All the examples have three columns showing hex data, source, and comments.
Example 1: GSUB Header Table
Example 1 shows a typical GSUB Header table definition.
Example 1
Hex Data | Source | Comments |
---|---|---|
GSUBHeader TheGSUBHeader |
GSUBHeader table definition | |
00010000 | 0x00010000 | major/minor version |
000A | TheScriptList | offset to ScriptList table |
001E | TheFeatureList | offset to FeatureList table |
002C | TheLookupList | offset to LookupList table |
Example 2: SingleSubstFormat1 Subtable
Example 2 illustrates the SingleSubstFormat1 subtable , which uses ranges to replace single input glyphs with their corresponding output glyphs. The indices of the output glyphs are calculated by adding a constant delta value to the indices of the input glyphs. In this example, the Coverage table has a format identifier of 1 to indicate the range format, which is used because the input glyph indices are in consecutive order in the font. The Coverage table specifies one range that contains a startGlyphID for the “0” (zero) glyph and an endGlyphID for the “9” glyph.
Example 2
Hex Data | Source | Comments |
---|---|---|
SingleSubstFormat1 LiningNumeralSubtable |
SingleSubst subtable definition | |
0001 | 1 | substFormat: calculated output glyph indices |
0006 | LiningNumeralCoverage | offset to Coverage table for input glyphs |
00C0 | 192 | deltaGlyphID = 192: add to each input glyph index to produce output glyph index |
CoverageFormat2 LiningNumeralCoverage |
Coverage table definition | |
0002 | 2 | coverageFormat: ranges |
1 | rangeCount | |
rangeRecords[0] | ||
004E | 78 | Start glyph ID for numeral zero glyph |
0058 | 87 | End glyph ID for numeral nine glyph |
0000 | 0 | startCoverageIndex: first CoverageIndex = 0 |
Example 3: SingleSubstFormat2 Subtable
Example 3 uses the SingleSubstFormat2 subtable for lists to substitute punctuation glyphs in Japanese text that is written vertically. Horizontally oriented parentheses and square brackets (the input glyphs) are replaced with vertically oriented parentheses and square brackets (the output glyphs).
The Coverage table, Format 1, identifies each input glyph index. The number of input glyph indices listed in the Coverage table matches the number of output glyph indices listed in the subtable. For correct substitution, the order of the glyph indices in the Coverage table (input glyphs) must match the order in the Substitute array (output glyphs).
Example 3
Hex Data | Source | Comments |
---|---|---|
SingleSubstFormat2 VerticalPunctuationSubtable |
SingleSubst subtable definition | |
0002 | 2 | substFormat: lists |
000E | VerticalPunctuationCoverage | offset to Coverage table |
0004 | 4 | glyphCount — equals glyphCount in Coverage table |
0131 | VerticalOpenBracketGlyph | substituteGlyphIDs[0], ordered by Coverage index |
0135 | VerticalClosedBracketGlyph | substituteGlyphIDs[1] |
013E | VerticalOpenParenthesisGlyph | substituteGlyphIDs[2] |
0143 | VerticalClosedParenthesisGlyph | substituteGlyphIDs[3] |
CoverageFormat1 VerticalPunctuationCoverage |
Coverage table definition | |
0001 | 1 | coverageFormat: lists |
0004 | 4 | glyphCount |
003C | HorizontalOpenBracketGlyph | glyphArray[0], ordered by glyph ID |
0040 | HorizontalClosedBracketGlyph | glyphArray[1] |
004B | HorizontalOpenParenthesisGlyph | glyphArray[2] |
004F | HorizontalClosedParenthesisGlyph | glyphArray[3] |
Example 4: MultipleSubstFormat1 Subtable
Example 4 uses a MultipleSubstFormat1 subtable to replace a single “ffi” ligature with three individual glyphs that form the string <ffi>. The subtable defines a format identifier of 1, an offset to a Coverage table that specifies the glyph index of the “ffi” ligature (the input glyph), an offset to a Sequence table that specifies the sequence of glyph indices for the <ffi> string in its substitute array (the output glyph sequence), and a count of Sequence table offsets.
Example 4
Hex Data | Source | Comments |
---|---|---|
MultipleSubstFormat1 FfiDecompSubtable |
MultipleSubst subtable definition | |
0001 | 1 | substFormat |
0008 | FfiDecompCoverage | offset to Coverage table |
0001 | 1 | sequenceCount — equals glyphCount in Coverage table |
000E | FfiDecompSequence | sequenceOffsets[0] (offset to Sequence table 0) |
CoverageFormat1 FfiDecompCoverage |
Coverage table definition | |
0001 | 1 | coverageFormat: lists |
0001 | 1 | glyphCount |
00F1 | ffiGlyphID | ligature glyph |
Sequence FfiDecompSequence |
Sequence table definition | |
0003 | 3 | glyphCount |
001A | fGlyphID | first glyph in sequence order |
001A | fGlyphID | second glyph |
001D | iGlyphID | third glyph |
Example 5: AlternateSubstFormat 1 Subtable
Example 5 uses the AlternateSubstFormat1 subtable to replace the default ampersand glyph (input glyph) with one of two alternative ampersand glyphs (output glyph).
In this case, the Coverage table specifies the index of a single glyph, the default ampersand, because it is the only glyph covered by this lookup. The AlternateSet table for this covered glyph identifies the alternative glyphs: AltAmpersand1GlyphID and AltAmpersand2GlyphID.
In Example 5, the index position of the AlternateSet table offset in the AlternateSet array is zero (0), which correlates with the index position (also zero) of the default ampersand glyph in the Coverage table.
Example 5
Hex Data | Source | Comments |
---|---|---|
AlternateSubstFormat1 AltAmpersandSubtable |
AlternateSubstFormat1 subtable definition | |
0001 | 1 | substFormat |
0008 | AltAmpersandCoverage | offset to Coverage table |
0001 | 1 | alternateSetCount — equals glyphCount in Coverage table |
000E | AltAmpersandSet | alternateSetOffsets[0] (offset to AlternateSet table 0) |
CoverageFormat1 AltAmpersandCoverage |
Coverage table definition | |
0001 | 1 | coverageFormat: lists |
0001 | 1 | glyphCount |
003A | DefaultAmpersandGlyphID | glyphArray[0] |
AlternateSet AltAmpersandSet |
AlternateSet table definition | |
0002 | 2 | glyphCount |
00C9 | AltAmpersand1GlyphID | alternateGlyphIDs[0] — glyphs in arbitrary order |
00CA | AltAmpersand2GlyphID | alternateGlyphIDs[1] |
Example 6: LigatureSubstFormat1 Subtable
Example 6 shows a LigatureSubstFormat1 subtable that defines data to replace a string of glyphs with a single ligature glyph. Because a LigatureSubstFormat1 subtable can specify glyph substitutions for more than one ligature, this subtable defines three ligatures: “etc,” “ffi,” and “fi.”
The sample subtable contains a format identifier (4) and an offset to a Coverage table. The Coverage table, which lists an index for each first glyph in the ligatures, lists indices for the “e” and “f” glyphs. The Coverage table range format is used here because the “e” and “f” glyph indices are numbered consecutively.
In the LigatureSubst subtable, ligatureSetCount specifies two LigatureSet tables, one for each covered glyph, and the ligatureSetOffsets array stores offsets to them. In this array, the “e” LigatureSet precedes the “f” LigatureSet, matching the order of the corresponding first-glyph components in the Coverage table.
Each LigatureSet table identifies all ligatures that begin with a covered glyph. The sample LigatureSet table defined for the “e” glyph contains only one ligature, “etc.” A LigatureSet table defined for the “f” glyph contains two ligatures, “ffi” and “fi.”
The sample FLigaturesSet table has offsets to two Ligature tables, one for “ffi” and one for “fi.” The ligatureOffsets array lists the “ffi” Ligature table first to indicate that the “ffi” ligature is preferred to the “fi” ligature.
Example 6
Hex Data | Source | Comments |
---|---|---|
LigatureSubstFormat1 LigaturesSubtable |
LigatureSubstFormat1 subtable definition | |
0001 | 1 | substFormat |
000A | LigaturesCoverage | offset to Coverage table |
0002 | 2 | ligatureSetCount |
0014 | ELigaturesSet | ligatureSetOffsets[0] (offset to LigatureSet table 0) — LigatureSet tables in Coverage index order |
0020 | FLigaturesSet | ligatureSetOffsets[1] |
CoverageFormat2 LigaturesCoverage |
Coverage table definition | |
0002 | 2 | coverageFormat: ranges |
0001 | 1 | rangeCount |
rangeRecords[0] | ||
0019 | eGlyphID | Start, first glyph ID |
001A | fGlyphID | End, last glyph ID in range |
0000 | 0 | startCoverageIndex: coverage index of start glyph ID = 0 |
LigatureSet ELigaturesSet |
LigatureSet table definition — all ligatures that start with e | |
0001 | 1 | ligatureCount |
0004 | etcLigature | ligatureOffsets[0] (offset to Ligature table 0) |
Ligature etcLigature |
Ligature table definition | |
015B | etcGlyphID | ligatureGlyph — output glyph ID |
0003 | 3 | componentCount |
0028 | tGlyphID | componentGlyphIDs[0] — second component in ligature |
0017 | cGlyphID | componentGlyphIDs[1] — third component in ligature |
LigatureSet FLigaturesSet |
LigatureSet table definition all ligatures start with f | |
0002 | 2 | ligatureCount |
0006 | ffiLigature | ligatureOffsets[0] — listed first because ffi ligature is preferred to fi ligature |
000E | fiLigature | ligatureOffsets[1] |
Ligature ffiLigature |
Ligature table definition | |
00F1 | ffiGlyphID | ligatureGlyph — output glyph ID |
0003 | 3 | componentCount |
001A | fGlyphID | componentGlyphIDs[0] — second component in ligature |
001D | iGlyphID | componentGlyphIDs[1] — third component in ligature |
Ligature fiLigature |
Ligature table definition | |
00F0 | fiGlyphID | ligatureGlyph — output glyph ID |
0002 | 2 | componentCount |
001D | iGlyphID | componentGlyphIDs[0] — second component in ligature |
Example 7: ContextSubstFormat1 Subtable and SubstLookupRecord
Example 7 uses a ContextSubstFormat1 subtable for glyph sequences to replace a string of three glyphs with another string. For the French language system, the subtable defines a contextual substitution that replaces the input sequence, space-dash-space, with the output sequence, thin space-dash-thin space.
The contextual substitution, called Dash Lookup in this example, contains one ContextSubstFormat1 subtable called the DashSubtable. The subtable specifies two contexts: a SpaceGlyph followed by a DashGlyph, and a DashGlyph followed by a SpaceGlyph. In each sequence, a single substitution replaces the SpaceGlyph with a ThinSpaceGlyph.
The Coverage table, labeled DashCoverage, lists two glyph IDs for the first glyphs in the SpaceGlyph and DashGlyph sequences. One SubRuleSet table is defined for each covered glyph.
SpaceAndDashSubRuleSet lists all the contexts that begin with a SpaceGlyph. It contains an offset to one SubRule table (SpaceAndDashSubRule), which specifies two glyphs in the context sequence, the second of which is a DashGlyph. The SubRule table contains an offset to a SubstLookupRecord that lists the position in the sequence where the glyph substitution should occur (position 0) and the index of the SpaceToThinSpaceLookup applied there to replace the SpaceGlyph with a ThinSpaceGlyph. DashAndSpaceSubRuleSet lists all the contexts that begin with a DashGlyph. An offset to a SubRule table (DashAndSpaceSubRule) specifies two glyphs in the context sequence, and the second one is a SpaceGlyph. The SubRule table contains an offset to a SubstLookupRecord, which lists the position in the sequence where the glyph substitution should occur, and an index to the same lookup used in the SpaceAndDashSubRule. The lookup replaces the SpaceGlyph with a ThinSpaceGlyph.
Example 7
Hex Data | Source | Comments |
---|---|---|
ContextSubstFormat1 DashSubtable |
ContextSubstFormat1 subtable definition for Lookup[0], DashLookup | |
0001 | 1 | substFormat |
000A | DashCoverage | offset to Coverage table |
0002 | 2 | subRuleSetCount |
0012 | SpaceAndDashSubRuleSet | subRuleSetOffsets[0] (offset to SubRuleSet table 0) — SubRuleSets ordered by Coverage index |
0020 | DashAndSpaceSubRuleSet | subRuleSetOffsets[1] |
CoverageFormat1 DashCoverage |
Coverage table definition | |
0001 | 1 | coverageFormat: lists |
0002 | 2 | glyphCount |
0028 | SpaceGlyph | glyphArray[0] — glyphs in numeric order |
005D | DashGlyph | glyphArray[1], dash glyph ID |
SubRuleSet SpaceAndDashSubRuleSet |
SubRuleSet[0] table definition | |
0001 | 1 | subRuleCount |
0004 | SpaceAndDashSubRule | subRuleOffsets[0] (offset to SubRule table 0) — SubRule tables ordered by preference |
SubRule SpaceAndDashSubRule |
SubRule[0] table definition | |
0002 | 2 | glyphCount — number in input sequence |
0001 | 1 | substitutionCount |
005D | DashGlyph | inputSequence[0], starting with second glyph — SpaceGlyph, in Coverage table, is first glyph |
substLookupRecords[0] | ||
0000 | 0 | sequenceIndex — substitution at first glyph position (0) |
0001 | 1 | lookupListIndex — index for SpaceToThinSpaceLookup in LookupList |
SubRuleSet DashAndSpaceSubRuleSet |
SubRuleSet[1] table definition | |
0001 | 1 | subRuleCount |
0004 | DashAndSpaceSubRule | subRuleOffsets[0] (offset to SubRule table 0) — SubRule tables ordered by preference |
SubRule DashAndSpaceSubRule |
SubRule[0] table definition | |
0002 | 2 | glyphCount — number in the input glyph sequence |
0001 | 1 | substitutionCount |
0028 | SpaceGlyph | inputSequence[0] — starting with second glyph |
substLookupRecords[0] | ||
0001 | 1 | sequenceIndex — substitution at second glyph position (glyph sequence index = 1) |
0001 | 1 | lookupListIndex — index for SpaceToThinSpaceLookup |
Example 8: ContextSubstFormat2 Subtable
Example 8 uses a ContextSubstFormat2 subtable with glyph classes to replace default mark glyphs with their alternative forms. Glyph alternatives are selected depending upon the height of the base glyph that they combine with-that is, the mark glyph used above a high base glyph differs from the mark glyph above a very high base glyph.
In the example, SetMarksHighSubtable contains a Class table that defines four glyph classes: medium-height glyphs (Class 0), all default mark glyphs (Class 1), high glyphs (Class 2), and very high glyphs (Class 3). The subtable also contains a Coverage table that lists each base glyph that functions as a first component in a context, ordered by glyph index.
Two SubClassSets are defined, one for substituting high marks and one for very high marks. No SubClassSets are specified for Class 0 and Class 1 glyphs because no contexts begin with glyphs from these classes. The SubClassSet array lists SubClassSets in numerical order, so SubClassSet 2 precedes SubClassSet 3.
Within each SubClassSet, a SubClassRule is defined. In SetMarksHighSubClassSet2, the SubClassRule table specifies two glyphs in the context, the first glyph in Class 2 (a high glyph) and the second in Class 1 (a mark glyph). The SubstLookupRecord specifies applying SubstituteHighMarkLookup at the second position in the sequence-that is, a high mark glyph will replace the default mark glyph.
In SetMarksVeryHighSubClassSet3, the SubClassRule specifies two glyphs in the context, the first in Class 3 (a very high glyph) and the second in Class 1 (a mark glyph). The SubstLookupRecord specifies applying SubstituteVeryHighMarkLookup at the second position in the sequence-that is, a very high mark glyph will replace the default mark glyph.
Example 8
Hex Data | Source | Comments |
---|---|---|
ContextSubstFormat2 SetMarksHighSubtable |
ContextSubstFormat2 subtable definition | |
0002 | 2 | substFormat |
0010 | SetMarksHighCoverage | offset to Coverage table |
001C | SetMarksHighClassDef | offset to Class Def table |
0004 | 4 | subClassSetCount |
0000 | NULL | subClassSetOffsets[0] — NULL: no contexts that begin with Class 0 glyphs are defined |
0000 | NULL | subClassSetOffsets[1] — no contexts that begin with Class 1 glyphs are defined |
0032 | SetMarksHighSubClassSet2 | subClassSetOffsets[2] — offset to SubClassSet table for contexts that begin with Class 2 glyphs (high base glyphs) |
0040 | SetMarksVeryHighSubClassSet3 | subClassSetOffsets[3] — offset to SubClassSet table for contexts that begin with Class 3 glyphs (very high base glyphs) |
CoverageFormat1 SetMarksHighCoverage |
Coverage table definition | |
0001 | 1 | coverageFormat: lists |
0004 | 4 | glyphCount |
0030 | tahGlyphID | glyphArray[0], high base glyph |
0031 | dhahGlyphID | glyphArray[1], high base glyph |
0040 | cafGlyphID | glyphArray[2], very high base glyph |
0041 | gafGlyphID | glyphArray[3], very high base glyph |
ClassDefFormat2 SetMarksHighClassDef |
Class table definition | |
0002 | 2 | classFormat: ranges |
0003 | 3 | classRangeCount |
classRangeRecords[0] | ClassRangeRecords ordered by startGlyphID; record for Class 2, high base glyphs | |
0030 | tahGlyphID | Start, first Glyph ID in range |
0031 | dhahGlyphID | End, last Glyph ID in range |
0002 | 2 | class: 2 |
classRangeRecords[1] | ClassRangeRecord for Class 3, very high base glyphs | |
0040 | cafGlyphID | Start, first Glyph ID in the range |
0041 | gafGlyphID | End, last Glyph ID in the range |
0003 | 3 | class: 3 ClassRange[2] for Class 1, mark gyphs |
classRangeRecords[2] | ClassRangeRecord for Class 1, mark glyphs | |
00D2 | fathatanDefaultGlyphID | Start, first Glyph ID in range default fathatan mark |
00D3 | dammatanDefaultGlyphID | End, last Glyph ID in the range default dammatan mark |
0001 | 1 | class: 1 |
SubClassSet SetMarksHighSubClassSet2 |
SubClassSet[2] table definition all contexts that begin with Class 2 glyphs |
|
0001 | 1 | subClassRuleCount |
0004 | SetMarksHighSubClassRule2 | subClassRuleOffsets[0] (offset to SubClassRule table 0) — SubClassRule tables ordered by preference |
SubClassRule SetMarksHighSubClassRule2 |
SubClassRule[0] table definition, Class 2 glyph (high base) glyph followed by a Class 1 glyph (mark) | |
0002 | 2 | glyphCount |
0001 | 1 | substitutionCount |
0001 | 1 | inputSequence[0] — input sequence beginning with the second Class in the input context sequence; Class 1, mark glyphs |
substLookupRecords[0] | substLookupRecords array in design order | |
0001 | 1 | sequenceIndex — apply substitution to position 2, a mark |
0001 | 1 | lookupListIndex |
SubClassSet SetMarksVeryHighSubClassSet3 |
SubClassSet[3] table definition — all contexts that begin with Class 3 glyphs | |
0001 | 1 | subClassRuleCount |
0004 | SetMarksVeryHighSubClassRule3 | subClassRuleOffsets[0] |
SubClassRule SetMarksVeryHighSubClassRule3 |
SubClassRule[0] table definition — Class 3 glyph (very high base glyph) followed by a Class 1 glyph (mark) | |
0002 | 2 | glyphCount |
0001 | 1 | substitutionCount |
0001 | 1 | inputSequence[0] — input sequence beginning with the second Class in the input context sequence; Class 1, mark glyphs |
substLookupRecords[0] | substLookupRecords array in design order | |
0001 | 1 | sequenceIndex — apply substitution to position 2, second glyph class (mark) |
0002 | 2 | lookupListIndex |
Example 9: ContextualSubstFormat3 Subtable
Example 9 uses the ContextSubstFormat3 subtable with Coverage tables to describe a context sequence of three lowercase glyphs in the pattern: any ascender or descender glyph in position 0 (zero), any x-height glyph in position 1, and any descender glyph in position 2. The overlapping sets of covered glyphs for positions 0 and 2 make Format 3 better for this context than the class-based Format 2.
In positions 0 and 2, swash versions of the glyphs replace the default glyphs. The contextual-substitution lookup is SwashLookup (LookupList index = 0), and its subtable is SwashSubtable. The SwashSubtable defines three Coverage tables: AscenderDescenderCoverage, XheightCoverage, and DescenderCoverage-one for each glyph position in the context sequence, respectively.
The SwashSubtable also defines two SubstLookupRecords: one that applies to position 0, and one for position 2. (No substitutions are applied to position 1.) The record for position 0 uses a single substitution lookup called AscDescSwashLookup to replace the current ascender or descender glyph with a swash ascender or descender glyph. The record for position 2 uses a single substitution lookup called DescSwashLookup to replace the current descender glyph with a swash descender glyph.
Example 9
Hex Data | Source | Comments |
---|---|---|
ContextSubstFormat3 SwashSubtable |
ContextSubstFormat3 subtable definition | |
0003 | 3 | substFormat |
0003 | 3 | glyphCount — number in input glyph sequence |
0002 | 2 | substitutionCount |
0030 | AscenderDescenderCoverage | coverageOffsets[0] — offsets to Coverage tables, in context sequence order |
004C | XheightCoverage | coverageOffsets[1] |
006E | DescenderCoverage | coverageOffsets[2] |
substLookupRecords[0] | SubstLookupRecords in glyph position order | |
0000 | 0 | sequenceIndex |
0001 | 1 | lookupListIndex — single substitution to output ascender or descender swash |
substLookupRecords[1] | ||
0002 | 2 | sequenceIndex |
0002 | 2 | lookupListIndex — single substitution to output descender swash |
CoverageFormat1 AscenderDescenderCoverage |
Coverage table definition | |
0001 | 1 | coverageFormat: lists |
000C | 12 | glyphCount |
0033 | bGlyphID | glyphArray[0] — glyphs in glyph ID order |
0035 | dGlyphID | glyphArray[1] |
0037 | fGlyphID | glyphArray[2] |
0038 | gGlyphID | glyphArray[3] |
0039 | hGlyphID | glyphArray[4] |
003B | jGlyphID | glyphArray[5] |
003C | kGlyphID | glyphArray[6] |
003D | lGlyphID | glyphArray[7] |
0041 | pGlyphID | glyphArray[8] |
0042 | qGlyphID | glyphArray[9] |
0045 | tGlyphID | glyphArray[10] |
004A | yGlyphID | glyphArray[11] |
CoverageFormat1 XheightCoverage |
Coverage table definition | |
0001 | 1 | coverageFormat: lists |
000F | 15 | glyphCount |
0032 | aGlyphID | glyphArray[0] |
0034 | cGlyphID | glyphArray[1] |
0036 | eGlyphID | glyphArray[2] |
003A | iGlyphID | glyphArray[3] |
003E | mGlyphID | glyphArray[4] |
003F | nGlyphID | glyphArray[5] |
0040 | oGlyphID | glyphArray[6] |
0043 | rGlyphID | glyphArray[7] |
0044 | sGlyphID | glyphArray[8] |
0045 | tGlyphID | glyphArray[9] |
0046 | uGlyphID | glyphArray[10] |
0047 | vGlyphID | glyphArray[11] |
0048 | wGlyphID | glyphArray[12] |
0049 | xGlyphID | glyphArray[13] |
004B | zGlyphID | GlyphArray[14] |
CoverageFormat1 DescenderCoverage |
Coverage table definition | |
0001 | 1 | coverageFormat: lists |
0005 | 5 | glyphCount |
0038 | gGlyphID | glyphArray[0] |
003B | jGlyphID | glyphArray[1] |
0041 | pGlyphID | glyphArray[2] |
0042 | qGlyphID | glyphArray[3] |
004A | yGlyphID | glyphArray[4] |
Example 10: ReverseChainSingleSubstFormat1 Subtable and SubstLookupRecord
Example 10 uses a ReverseChainSingleSubstFormat1 subtable for glyph sequences to glyph with the correct form that has a thick connection to the left (thick exit). This allows the glyph to correctly connect to the letter form to the left of it.
The ThickExitCoverage table is the listing of glyphs to be matched for substitution.
The LookaheadCoverage table, labeled ThickEntryCoverage, lists four glyph IDs for the glyph following a substitution coverage glyph. This lookahead coverage attempts to match the context that will cause the substitution to take place.
The Substitute table maps the glyphs to replace those in the ThickConnectCoverage table.
Example 10
Hex Data | Source | Comments |
---|---|---|
ReverseChainSingleSubstFormat1 ThickConnect |
ReverseChainSingleSubstFormat1 subtable definition | |
0001 | 1 | substFormat |
0068 | ThickExitCoverage | offset to Coverage table |
0000 | 0 | backtrackGlyphCount |
0000 | null - not used | backtrackCoverageOffsets[0] |
0001 | 1 | lookaheadGlyphCount |
0026 | ThickEntryCoverage | lookaheadCoverageOffsets[0] |
000C | 12 | glyphCount |
00A7 | BEm2 | substituteGlyphIDs[0] — substitute glyphs ordered by Coverage index |
00B9 | BEi3 | substituteGlyphIDs[1] |
00C5 | JIMm3 | substituteGlyphIDs[2] |
00D4 | JIMi2 | substituteGlyphIDs[3] |
00EA | SINm2 | substituteGlyphIDs[4] |
00F2 | SINi2 | substituteGlyphIDs[5] |
00FD | SADm2 | substituteGlyphIDs[6] |
010D | SADi2 | substituteGlyphIDs[7] |
011B | TOEm3 | substituteGlyphIDs[8] |
012B | TOEi3 | substituteGlyphIDs[9] |
013B | AINm2 | substituteGlyphIDs[10] |
0141 | AINi2 | substituteGlyphIDs[11] |
CoverageFormat1 ThickEntryCoverage |
Coverage table definition | |
0001 | 1 | coverageFormat: lists |
001F | 31 | glyphCount |
00A5 | ALEFf1 | glyphArray[0] — glyphs in glyph ID order |
00A9 | BEm4 | glyphArray[1] |
00AA | BEm5 | glyphArray[2] |
00E2 | DALf1 | glyphArray[3] |
0167 | KAFf1 | glyphArray[4] |
0168 | KAFfs1 | glyphArray[5] |
0169 | KAFm1 | glyphArray[6] |
016D | KAFm5 | glyphArray[7] |
016E | KAFm6 | glyphArray[8] |
0170 | KAFm8 | glyphArray[9] |
0183 | GAFf1 | glyphArray[10] |
0184 | GAFfs1 | glyphArray[11] |
0185 | GAFm1 | glyphArray[12] |
0189 | GAFm5 | glyphArray[13] |
018A | GAFm6 | glyphArray[14] |
018C | GAFm8 | glyphArray[15] |
019F | LAMf1 | glyphArray[16] |
01A0 | LAMm1 | glyphArray[17] |
01A1 | LAMm2 | glyphArray[18] |
01A2 | LAMm3 | glyphArray[19] |
01A3 | LAMm4 | glyphArray[20] |
01A4 | LAMm5 | glyphArray[21] |
01A5 | LAMm6 | glyphArray[22] |
01A6 | LAMm7 | glyphArray[23] |
01A7 | LAMm8 | glyphArray[24] |
01A8 | LAMm9 | glyphArray[25] |
01A9 | LAMm10 | glyphArray[26] |
01AA | LAMm11 | glyphArray[27] |
01AB | LAMm12 | glyphArray[28] |
01AC | LAMm13 | glyphArray[29] |
01EC | HAYf2 | glyphArray[30] |
CoverageFormat1 ThickExitCoverage |
Coverage table definition | |
0001 | 1 | coverageFormat: lists |
000C | 12 | glyphCount |
00A6 | BEm1 | glyphArray[0] |
00B7 | BEi1 | glyphArray[1] |
00C3 | JIMm1 | glyphArray[2] |
00D2 | JIMi1 | glyphArray[3] |
00E9 | SINm1 | glyphArray[4] |
00F1 | SINi1 | glyphArray[5] |
00FC | SADm1 | glyphArray[6] |
010C | SADi1 | glyphArray[7] |
0119 | TOEm1 | glyphArray[8] |
0129 | TOEi1 | glyphArray[9] |
013A | AINm1 | glyphArray[10] |
0140 | AINi1 | glyphArray[11] |