A font file is represented as a collection of tables. The term table is used in two ways when discussing the font file. Generally, a "table" is equivalent to a C struct
, a data structure with a number of fields; specifically, a table is also used in the sense of a database table, a top-level structure potentially containing a number of related sets of information. (For example, "the cname
table".) In this second sense, a table may contain other tables; these contained tables are often referred to as "subtables".
- Data in the font file is stored in big-endian byte order. All types in this specification therefore refer to big-endian types.
typedef byte int8; typedef unsigned short USHORT; typedef short SHORT; typedef unsigned short F2DOT14; typedef unsigned long VERSION; typedef unsigned short NameID; typedef unsigned short Offset16; typedef long LONG; typedef unsigned long ULONG; typedef unsigned long Offset32; typedef byte[] Tag;
- An
F2DOT14
type is a two byte fixed-point number with 14 fractional bits. - Tables within the font file frequently use offset values (often measured from the beginning of the table containing the offset) to denote the location of their subtables. The
Offset16
andOffset32
types refer to two-byte and four-byte offset descriptors respectively. - A
Tag
is a four-byte character string referring to an entry in a tag registry. Tag registries exist for top-level tables, languages, scripts, features, baselines, and variable font axes. - A
VERSION
consists of two bytes, each interpreted as an unsigned integer. The first describes the major version number of a table and the second the minor version number.
A font file may represent glyph data in a number of formats. A font file must have exactly one primary outline representation format, which must be either:
- TrueType outlines, stored in the [=glyf table=].
- CFF version 1 outlines, (sometimes informally called "PostScript outlines") stored in the [=CFF table=].
- CFF version 2 outlines, stored in the [=CFF2 table=].
A font file may also contain data in one or more of secondary outline representation formats. The only secondary outline representation format currently supported is Scalable Vector Graphics, stored in the [=SVG table=].
Additionally, the font file may contain one or more binary representations of the glyph data. The binary glyph representations available are:
- Monochrome bitmaps stored in the [=EBDT table=] and [=EBLC table=].
- Color bitmaps stored in the [=CBDT table=] and [=CBLC table=].
The font file begins with the table directory, which locates the remainder of the tables in the file.
path: idl/TableDirectory.md
- sfntVersion
- File magic number. Must be `0x00010000` if the font file's [=primary outline representation format=] is TrueType outlines, or the four bytes `OTTO` if the primary outline representation format is CFF outlines.
- numTables
- The number of top-level tables in the font file.
- searchRange
- The maximum number of nodes in a binary search tree.
- entrySelector
- The maximum depth of a binary search tree.
- rangeShift
- Nobody really knows what this is.
- tableTag
- The four-character tag name for this table, from the [=table tag registry=].
- checksum
- The table checksum. See below.
- offset
- Byte position of the table, measured from the start of the {{TableDirectory}} table.
-
Tables must aligned to a four byte boundary.
-
Table lengths must be a multiple of four bytes. Zero padding should be added to the end to make up an integral multiple if necessary.
-
Table checksums are computed using the following checksum algorithm (in Python):
def calcChecksum(table): # Zero-pad table to four-byte boundary while len(table) % 4 > 0: table += b"\0" # Calculate the unsigned sum of all four-byte values value = 0 for i in range(0, len(table), 4): long = struct.unpack(">L", table[i:i+4]) value = (value + long) & 0xffffffff return value
-
The [=head table=] is modified after its checksum is computed. Writing the font checksum must be done in the following sequence:
- Fill in the values of all tables. In the
head
table, set thecheckSumAdjustment
to 0. - Calculate the checksum for all tables and fill in the {{TableDirectoryEntry}} structures.
- Calculate the
checkSumAdjustment
as described in the [=head table=] chapter, and insert this into the table.
- Fill in the values of all tables. In the
-
Given a value maxPower, which is defined as being the largest power of two less than or equal to the number of tables, {{TableDirectory/searchRange}} is set to 16 times maxPower, the {{TableDirectory/entrySelector}} is set to the base 2 logarithm of
maxPower
, and the {{TableDirectory/rangeShift}} isnumTables*16
minus thesearchRange
.
This can be implemented with the following Python code:
def maxPowerOfTwo(x): exponent = 0 while x: x = x >> 1 exponent = exponent + 1 return max(exponent - 1, 0) exponent = maxPowerOfTwo(numTables) searchRange = (2 ** exponent) * 16 entrySelector = exponent rangeShift = max(0, numTables * 16 - searchRange)
numTables | 11 | |
---|---|---|
searchRange | 128 | maxPower * 16 |
entrySelector | 3 | log(maxPower)/log(2) |
rangeShift | 483 | 11 * 16 - 128 |
-
When validating table checksums, the [=head table=] must be treated as a special case, and its
checkSumAdjustment
value set to four zero bytes for the purposes of checksumming. Font consumers should not assume that the table length will be a multiple of four, and should use the above checksumming algorithm which adds zero padding to the table data. -
The {{TableDirectory/searchRange}}, {{TableDirectory/entrySelector}}, and {{TableDirectory/rangeShift}} fields should be ignored by font consumers. There is no requirement to use binary tree search to locate the tables, but if a binary tree is used, these values should be recomputed from the {{TableDirectory/numTables}} field.