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

;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, ranges

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

;RangeRecord[0]

004E

78

;Start GlyphID

; for numeral zero glyph

0058

87

;End GlyphID

; 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

;Substitute[0]

; ordered by Coverage Index

0135

VerticalClosedBracketGlyph

;Substitute[1]

013E

VerticalOpenParenthesisGlyph

;Substitute[2]

0143

VerticalClosedParenthesisGlyph

;Substitute[3]

CoverageFormat1

VerticalPunctuationCoverage

;Coverage table definition

0001

1

;CoverageFormat

; lists

0004

4

;GlyphCount

003C

HorizontalOpenBracketGlyph

;GlyphArray[0]

; ordered by GlyphID

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

;offset to Sequence[0] table

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

;AlternateSetCnt

; equals GlyphCount in

; Coverage table

000E

AltAmpersandSet

;offset to AlternateSet[0]

; table

CoverageFormat1

AltAmpersandCoverage

;Coverage table definition

0001

1

;CoverageFormat

0001

1

;GlyphCount

003A

DefaultAmpersandGlyphID

;GlyphArray[0]

AlternateSet

AltAmpersandSet

;AlternateSet table definition

0002

2

;GlyphCount

00C9

AltAmpersand1GlyphID

;offset to Alternate[0]

; in arbitrary order

00CA

AltAmpersand2GlyphID

;offset to Alternate[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, LigSetCount specifies two LigatureSet tables, one for each covered glyph, and the LigatureSet 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 Ligature 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

;LigSetCount

0014

ELigaturesSet

;offset to LigatureSet[0] table

; in Coverage Index order

0020

FLigaturesSet

;offset to LigatureSet[1] table

CoverageFormat2

LigaturesCoverage

;Coverage table definition

0002

2

;CoverageFormat, ranges

0001

1

;RangeCount

;RangeRecord[0]

0019

eGlyphID

;Start, first GlyphID

001A

fGlyphID

;End, last GlyphID in range

0000

0

;StartCoverageIndex

; coverage index of start

; glyphID

LigatureSet

ELigaturesSet

;LigatureSet table definition

; all ligatures that start

; with e

0001

1

;LigatureCount

0004

etcLigature

;offset to Ligature[0] table

Ligature

etcLigature

;Ligature table definition

015B

etcGlyphID

;LigGlyph

;output GlyphID

0003

3

;CompCount

; number of components

0028

tGlyphID

;Component[1]

; second component in ligature

0017

cGlyphID

;Component[2

; third component in ligature

LigatureSet

FLigaturesSet

;LigatureSet table definition

; all ligatures start with f

0002

2

;LigatureCount

0006

ffiLigature

;offset to Ligature[0] table

; listed first because ffi

; ligature is preferred to

; fi ligature

000E

fiLigature

;offset to Ligature[1] table

Ligature

ffiLigature

;Ligature table definition

00F1

ffiGlyphID

;LigGlyph, output GlyphID

0003

3

;CompCount

001A

fGlyphID

;Component[1]

; second component in ligature

001D

iGlyphID

;Component[2]

; third component in ligature

Ligature

fiLigature

;Ligature table definition

00F0

fiGlyphID

;LigGlyph, output GlyphID

0002

2

;CompCount

001D

iGlyphID

;Component[1]

; 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 GlyphIDs 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

;offset to SubRuleSet[0]

; ordered by Coverage Index

0020

DashAndSpaceSubRuleSet

;offset to SubRuleSet[1]

CoverageFormat1

DashCoverage

;Coverage table definition

0001

1

;CoverageFormat

; lists

0002

2

;GlyphCount

0028

SpaceGlyph

;GlyphArray[0]

; in numeric order

005D

DashGlyph

;GlyphArray[1]

;dash GlyphID

SubRuleSet

SpaceAndDashSubRuleSet

;SubRuleSet[0] table definition

0001

1

;SubRuleCount

0004

SpaceAndDashSubRule

;offset to SubRule[0]

; ordered by preference

SubRule

SpaceAndDashSubRule

;SubRule[0] table definition

0002

2

;GlyphCount

;number in input sequence

0001

1

;SubstCount

005D

DashGlyph

;Input[1]

; starting with second glyph

; SpaceGlyph in Coverage table

; is first glyph

;SubstLookupRecord[0]

0000

0

;SequenceIndex

; substitution at first glyph

; position (0)

0001

1

;LookupListIndex

; index for

; SpaceToThinSpaceLookup in

; LookupList

SubRuleSet

DashAndSpaceSubRuleSet

;SubRuleSet[0] table definition

0001

1

;SubRuleCount

0004

DashAndSpaceSubRule

;offset to SubRule[0]

; ordered by preference

SubRule

DashAndSpaceSubRule

;SubRule[0] table definition

0002

2

;GlyphCount

; number in the input glyph

; sequence

0001

1

;SubstCount

0028

SpaceGlyph

;Input[1]

; starting with second glyph

;SubstLookupRecord definition

0001

1

;SequenceIndex

;substitution at second glyph

; position(1)

0001

1

;LookupListIndex

; 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

;SubClassSetCnt

0000

NULL

;offset to SubClassSet[0] table

; no contexts that begin with

; Class 0 glyphs are defined

0000

NULL

;offset to SubClassSet[1] table

; no contexts that begin with

; Class 1 glyphs are defined

0032

SetMarksHighSubClassSet2

;offset to SubClassSet[2] table

; for contexts that begin with

; Class 2 glyphs (high base

; glyphs)

0040

SetMarksVeryHighSubClassSet3

;offset to SubClassSet[3] 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

;Class Format, ranges

0003

3

;ClassRangeCount

;ClassRange[0]

; ordered by StartGlyphID

;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

;ClassRange[1]

; 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

;ClassRange[2]

; for Class 1, mark gyphs

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

SubClassSet

SetMarksHighSubClassSet2

;SubClassSet[2] table definition

; all contexts that begin with

;Class 2 glyphs

0001

1

;SubClassRuleCnt

0004

SetMarksHighSubClassRule2

;offset to SubClassRule[0] table

; 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

;SubstCount

0001

1

;offset to Class[1]

; beginning with the second

; Class in the context

; sequence (mark = Class 1)

;begin SubstLookupRecord array

; in design order

;SubstLookupRecord[0]

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

;SubClassRuleCnt

0004

SetMarksVeryHighSubClassRule3

;offset to SubClassRule[0] table

; ordered by preference

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

;SubstCount

0001

1

;offset to Class[1]

; beginning with the second

; Class in the context

; sequence = marks, Class 1

;begin SubstLookupRecord array

; in design order

;SubstLookupRecord[0]

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

; in input glyph sequence

0002

2

;SubstCount

0030

AscenderDescenderCoverage

;offset to Coverage[0] table

; in context sequence order

004C

XheightCoverage

;offset to Coverage[1] table

006E

DescenderCoverage

;offset to Coverage[2] table

;SubstLookupRecord[0]

; in glyph position order

0000

0

;SequenceIndex

0001

1

;LookupListIndex

;single substitution to output

; ascender or descender swash

;SubstLookupRecord[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]

; in GlyphID 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]

; in GlyphID order

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]

; in GlyphID order

003B

jGlyphID

;GlyphArray[1]

0041

pGlyphID

;GlyphArray[2]

0042

qGlyphID

;GlyphArray[3]

004A

yGlyphID

;GlyphArray[4]