Skip to content

Latest commit

 

History

History
133 lines (100 loc) · 7.03 KB

01-font_file.md

File metadata and controls

133 lines (100 loc) · 7.03 KB

Font File Structure

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 types

  • 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 and Offset32 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.

Glyph representation formats

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=].

Table Directory

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.
Implementation notes for font producers
  • 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 the checkSumAdjustment 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.
  • 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}} is numTables*16 minus the searchRange.

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)
Here is an example of filling in the header information for a font file with 11 tables according to the formal definition. The largest power of 2 less than 11 is 8, so:
numTables11
searchRange128maxPower * 16
entrySelector3log(maxPower)/log(2)
rangeShift48311 * 16 - 128
Implementation notes for font consumers
  • 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.

Font collection files