Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C liability, trademark and document use rules apply.
Based on experience with WOFF 1.0, which is widely deployed, this specification was developed to provide improved compression and thus lower use of network bandwidth, while still allowing fast decompression even on mobile devices. This is achieved firstly by a content-aware preprocessing step, and secondly by an improved entropy coding stage compared to the Flate compression used in WOFF 1.0.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This is a First Public Working Draft of WOFF 2.0.
This is an Editors Draft of WOFF 2.0. It may contain material not reviewed by the Fonts Working Group and is subject to change.
This document was developed by the WebFonts Working Group. The Working Group expects to advance this Working Draft to Recommendation Status.
Please send comments about this document to www-font@w3.org (with public archive).
Publication as a First Public Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document specifies the WOFF 2 font packaging format. This format was designed to provide a reasonably easy-to-implement compression of font data with significantly better compression than previous techniques, suitable for use with CSS @font-face rules.
The all-uppercase key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 [RFC-2119]. If these words occur in lower- or mixed case, they should be interpreted in accordance with their normal English meaning.
This document includes sections of text that are called out as "Notes" and set off from the main text of the specification. These notes are intended as informative explanations or clarifications, to serve as hints or guides to implementers and users, but are not part of the normative text.
The structure of WOFF 2 files is similar to that of sfnt and version 1 WOFF font files, in that there is a header containing a table directory, followed by the data for those tables. The sfnt structure is described fully in the TrueType [TrueType], OpenType [OpenType], and Open Font Format [OFF] specifications. However, it differs in some important respects from sfnt. Most notably, the data for the tables is compressed, in a single stream comprising all the tables. The compression algorithm is Brotli [Brotli].
WOFF2 File | |
---|---|
WOFF2Header | File header with basic font type and version, along with offsets to metadata and private data blocks. |
TableDirectory | Directory of font tables, containing size and other info. |
CompressedFontData | Contents of font tables, compressed for storage in the WOFF 2 file |
ExtendedMetadata | An optional block of extended metadata, represented in XML format and compressed for storage in the WOFF 2 file. |
PrivateData | An optional block of pricate data for the font designer, foundry, or vendor to use. |
SHORT is a 16-bit signed integer in 2's complement format, stored big-endian.
USHORT is a 16-bit unsigned integer, stored big-endian.
255USHORT is a variable-length encoding of an unsigned integer in the range 0 to 65535 inclusive. It will be described as a decoding process. Read an unsigned byte b0. If b0 < 253, the value is b0. If b0 == 255 (0xff), read a second byte b1, and the value is b1 + 203. If b0 == 254 (0xfe), read a second byte b1, and the value is b1 + 506. If b0 == 253 (0xfd), read a USHORT u, and the value is u.
UIntBase128 is a different variable length encoding of unsigned integers, suitable for values up to 232-1. A UIntBase128 encoded number is a sequence of bytes for which the most significant bit is set for all but the last byte, and clear for the last byte. The number itself is base 128 encoded in the lower 7 bits of each byte. Thus, a decoding procedure for a UIntBase128 is: start with value = 0. Consume a byte, setting value = old value times 128 + (byte bitwise-and 127). Repeat last step until the most significant bit of byte is false.
Note that the encoding is not unique. For example, the value 506 can be encoded as [255, 203], [254, 0], and [253, 1, 250]. An encoder may produce any of these, and a decoder must accept them all, although encoders should choose shorter encodings, and should be consistent in choice of encoding for the same value, as this will tend to compress better.
WOFF2Header
WOFFHeader | ||
---|---|---|
UInt32 | signature | 0x774F4632 'wOF2' |
UInt32 | flavor | The "sfnt version" of the input font. |
UInt32 | length | Total size of the WOFF file. |
UInt16 | numTables | Number of entries in directory of font tables. |
UInt16 | reserved | Reserved; set to zero. |
UInt32 | totalSfntSize | Total size needed for the uncompressed font data, including the sfnt header, directory, and font tables (including padding). |
UInt16 | majorVersion | Major version of the WOFF file. |
UInt16 | minorVersion | Minor version of the WOFF file. |
UInt32 | metaOffset | Offset to metadata block, from beginning of WOFF file. |
UInt32 | metaLength | Length of compressed metadata block. |
UInt32 | metaOrigLength | Uncompressed size of metadata block. |
UInt32 | privOffset | Offset to private data block, from beginning of WOFF file. |
UInt32 | privLength | Length of private data block. |
The interpretation of the WOFFHeader is the same as in WOFF 1. (Probable todo: copy and adapt). The signature has the value of 0x774F4632 ('wOF2'), which distinguishes it from WOFF 1 files.
The table directory is an array of WOFF 2 table directory entries, as defined below. The directory follows immediately after the WOFF 2 file header; therefore, there is no explicit offset in the header pointing to this block. Its size is dependent on the exact content; thus, the best strategy for decoding is to process the file as a stream, rather than trying to access it randomly. Each table directory entry specifies the size of a single font data table, as well as information indicating whether to apply an additional transform.
The format of each individual table directory entry is as follows:
TableDirectoryEntry | ||
---|---|---|
UInt8 | flags | table type and flags |
UInt32 | tag | 4-byte tag (optional) |
UIntBase128 | origLength | length of original table |
UIntBase128 | transformLength | transformed length (optional) |
UIntBase128 | compLength | compressed length (optional) |
The interpretation of the flags field is as follows. Bits [0..4] contain an index to the "known tag" table, which represents tags likely to appear in fonts. If the tag is not present in this table, then the value of this bit field is 31. Bit 5 is set if the table is transformed. Bits [6..7] depend on whether the table is the first table in the font; it is 1 for the first table and 3 for subsequent tables.
If bits [0..4] of the flags byte has the value 31, then following the flag byte is a 4-byte tag value. Otherwise, the tag field is omitted in the TableDirectoryEntry structure, and is derived from bits [0..4] of the flag byte from the fixed KnownTableTags table, given below.
KnownTableTags | |
---|---|
0 | cmap |
1 | head |
2 | hhea |
3 | hmtx |
4 | maxp |
5 | name |
6 | OS/2 |
7 | post |
8 | cvt |
9 | fpgm |
10 | glyf |
11 | loca |
12 | prep |
13 | CFF |
14 | VORG |
15 | EBDT |
16 | EBLC |
17 | gasp |
18 | hdmx |
19 | kern |
20 | LTSH |
21 | PCLT |
22 | VDMX |
23 | vhea |
24 | vmtx |
25 | BASE |
26 | GDEF |
27 | GPOS |
28 | GSUB |
29 | [reserved - invalid] |
30 | [reserved - invalid] |
31 | arbitrary tag follows |
Following the flags are one to three length values, each in base 128 unsigned integer encoding. The origLength field specifies the length of the table in an uncompressed version of the font. Optionally, if the transform bit is set in the flags byte, transformLength specifies the length of the transformed version of the table. For the first table in the font only, compLength specifies the size of the compressed data stream. Otherwise, it is omitted.
The CompressedFontData field in a WOFF 2 file contains the concatenation of data for each table in the font, in the order that entries appear in the table directory, then compressed using the Brotli compression algorithm [Brotli]. The process of decoding the table data in a WOFF 2 font file can be specified by decompressing the byte-level compression of the CompressedFontData field, yielding a "table data block", then applying additional decoding steps as described below. Of course, an actual implementation is free to combine these steps or perform some of the steps in an incremental or streaming fashion, but the results must be consistent with the sequential process as specified here.
Each table may be either transformed or not transformed, and this choice is indicated by bit 5 of the flags byte in the corresponding table directory entry. If the table is not transformed, then the table data appears in the compressed stream in literal form, and occupies origLength bytes of the table data block.
If the table is transformed, then the table data must be additionally processed by a transformation specified below. In this case, the transformed table occupies transformLength bytes of the table data block.
The sum of the origLength (for non-transformed tables) and transformLength (for transformed tables) fields in the table directory MUST equal the size of the uncompressed table data block.
A transform may be applied to two types of tables: glyf, representing outline data, and loca, representing the offsets of the individual glyphs within a glyf table. All other table types MUST not have a transform specified. Additional constraints apply, as specified in section 4.3. The glyf table transformation is specified in section 4.1, and the loca table transformation is specified in section 4.2.
The glyf transformation is intended to reduce redundant information and provide a more efficient encoding of the actual TrueType outlines of glyphs. It is based on a similar transformation in MicroType Express [MTX]. That reference is informative; the details of the transformation are stated below and this section is normative.
For greater compression effectiveness, the glyf table is split into seven substreams, to group like data together. The transformed table consists of a header with the size of each of the substreams, followed by the substreams in sequence.
Transformed glyf Header | ||
---|---|---|
Fixed | version | = 0x00000000 |
USHORT | numGlyphs | Number of glyphs |
USHORT | indexFormat | Format for loca |
ULONG | nContourStreamSize | Size of nContour stream |
ULONG | nPointsStreamSize | Size of nPoints stream |
ULONG | flagStreamSize | Size of flag stream |
ULONG | glyphStreamSize | Size of glyph stream |
ULONG | compositeStreamSize | Size of composite stream |
ULONG | bboxStreamSize | Size of bbox stream |
ULONG | instructionStreamSize | Size of instruction stream |
The format is best characterized by describing the decoding process, especially indications of what are valid and invalid data. It is up to the encoder to produce transformed data that is valid and decodes to the desired font data. Note also that this format specifies the decoded result at the semantic level, not specific byte streams.
Immediately following the TransformedglyfHeader is a bitmask indicating whether a glyph contains an explicit bounding box, or whether the bounding box is to be inferred from the coordinate values. The total number of bytes in this bitmask is equal to 4 * ((numGlyphs + 31) / 32). The bits are packed so that glyph number 0 corresponds to the most significant bit of the first byte, glyph number 7 corresponds to the least significant bit of the first byte, glyph number 8 corresponds to the most significant bit of the second byte, and so on. A 1 value indicates an explicity bitmap.
After reading the TransformedGlyphHeader and bounding box bitmask, the decoding process iterates one glyph at a time. For each glyph, it reads zero or more bytes from each of the streams referenced in the TransformedGlyphHeader. Also, at the point of reconstructing a glyph, a decoder should store for each glyph the corresponding offset in the reconstructed glyph table, and this data will collectively become the contents of the reconstructed locatable (see section 4.2 below for more information about the reconstruction of the loca table).
The reconstruction process for a single glyph consists of performing the following steps:
1. Read a SHORT from the nContour stream. Store this in the numberOfContours field in the reconstructed TrueType glyph. The interpretation of the field is the same as the TrueType spec; if it is zero, the glyph is empty. If it is positive, the glyph is simpel and it represents the number of contours in the outline. If it is equal to -1 (0xffff), then the glyph is composite.
For a simple glyph, the process continues as follows:
2. Read numberOfContours 255USHORT values from the nPoints stream. Each of these is the number of popints of that contour. Convert this into the endPtsOfContours[] array by computing the cumulative sum, then subtracting one. For example, if the values in the stream are [2, 4], then the endPtsOfContours array is [1, 5]. Also, the sum of all the values in the array is the total number of points in the glyph, nPoints. In the example given, the value of nPoints is 6.
3. Read nPoints BYTE values from the flags stream. Each corresponds to one point in the reconstructed glyph outline. The interpretation of the flag byte is identical to the MicroType Express triplet encoding, see section 5.11 of [MTX].
4. For each point (i.e. nPoints times), read a number of triplet bytes from the glyph stream. The number of triplet bytes is a function of the flag byte read in the previous step: for (flag < 0x7f) in the range 0 to 83 inclusive, it is one byte. In the range 84 to 119 inclusive, it is two bytes. In the range 120 to 123 inclusive, it is three bytes, and in the range 124 to 127 inclusive, it is four bytes. Decode these triplet bytes, resulting in a delta-x and delta-y value. Store these delta-x and delta-y values in the reconstructed glyph using the standard TrueType glyph encoding [OFF] section 5.3.3.
The decoding of the flag byte and triplet bytes is specified in section 5.11 of the MTX proposal [MTX]. (Editor's note: that should be considered an informative, rather than normative reference, and the normative version should be included here inline.)
5. Read one 255USHORT value from the glyph stream, which is instructionLength, the number of instruction bytes.
6. Read instructionLength bytes from instructionStream, and store these in the reconstituted glyph as instructions.
For a composite glyph (nContour == -1), the following steps take the place of steps 2-6 above:
2a. Read a USHORT from compositeStream. This is interpreted as a component flag word as in the TrueType spec. Based on the flag values, there are between 4 and 14 additional argument bytes, interpreted as glyph index, arg1, arg2, and optional scale or affine matrix.
3a. Read the number of argument bytes as determined in step 2a from the composite stream, and store these in the reconstructed glyph. If the flag word read in step 2a has the FLAG_MORE_COMPONENTS bit (1 << 5) set, go back to step 2a.
4a. If any of the flag words had the FLAG_WE_HAVE_INSTRUCTIONS bit (1 << 8) set, then read the instructions from the glyph and store them in the reconstructed glyph, using the same process as described in steps 5 and 6 above.
Finally, for both simple and composite glyphs, if the corresponding bit in the bounding box bit vector is set, then additionally read 4 SHORT values from the bbox stream, representing xMin, yMin, xMax, and yMax, respectively, and record these into the corresponding fields of the reconstructed glyph. If the corresponding bit in the bounding box bit vector is not set, then derive the bounding box by computing the minimum and maximum x and y coordinates in the outline, and storing that.
A composite glyph MUST have an explicitly supplied bounding box. The motivation is that computing bounding boxes is more complicated, and also may require resolving references to component glyphs, which would conflict with a purely streaming implementation of font decoding.
When the glyf table is present with transform, there MUST be a corresponding loca table, and loca table MUST also have its transform set. The transformLength of the loca table MUST be zero, and the origLength MUST be the appropriate size (generally numGlyphs times a size per glyph, where that size per glyph is two bytes when indexFormat is zero, otherwise four bytes).
The process for reconstructing the loca table is simply to record the offsets for individual glyphs obtained while reconstrucing individual glyphs as specified in section 4.1.
The following constraints on valid WOFF 2 files are intended to facilitate a memory-efficient decode process. For a TrueType-flavor font, the glyf table MAY be encoded either with or without the transform. Usually the file size will be significantly smaller with the transform, but perhaps there are other considerations (such as memory or CPU cost). The decoder MUST be able to handle either case.
When the glyf table is present with transform, the loca table MUST follow the glyf table in the table directory. Additional constraints on the loca table in this case are given in section 4.2.
When the glyf table is present without transform, the corresponding loca table MUST also be present without transform. There are no special constraints regarding sizer or order when not transformed, as it suffices to simply include the table. Further, there are no special constraints when a glyf table is not present (which may be the case for Compact Font Format flavored fonts, or for fonts containing only bitmap glyphs).
In addition to table order, there is an additional constraint for transformed glyf tables: the origLength field must specify an adequate amount of space to represent the reconstructed glyf table. Since there are multiple valid reconstructions of a glyph, according to the encoding rules specified in section 5.3.3 of [OFF], it is necessary to specify a nominal size for a reconstructed glyph. Depending on the context, this nominal size may be greater than, less than, or equal to the actual size of the glyf table in the source font being compressed.
The nominal size of a glyph is the size of encoding a glyph according to section 5.3.3 of [OFF], applying the following rules to resolve choices between multiple valid encodings:
Note that the nominal size is not necessarily minimal. For one, while section 5.3.4 of [OFF] specifies in a note that offsets "should" be multiples of 4, fonts with other alignments are allowed. In addition, a very aggressively optimizing font generation tool may be able to exploit a situation where a coordinate encoding other than the maximally compact may allow a longer run of identical flag values, thus saving bytes. In both these cases, the nominal size may be larger than the size of the glyf table in the source font.
Regardless of the relation between original font table size and nominal size, an encoder MUST supply an origLength value for the transformed glyf table which is greater than or equal to the nominal size. A decoder MAY reject a font not satisfying this constraint. A tool for validating WOFF 2 font files SHOULD check this constraint. Note: the motivation for not requiring decoders to check this strictly is to allow implementation freedom for the decoding process, and not require the performance overhead of computing both nominal and actual sizes.
The WOFF 2 file MAY contain a block of extended metadata. The interpretation of this block is exactly the same as WOFF 1. (possible TODO: copy and adapt). However, while in a WOFF 1 file the extended metadata block is stored with zlib compression, in a WOFF 2 file it MUST be stored compressed with Brotli. The rationale of this change is to minimize the total number of byte-level compression algorithms needed to implement WOFF 2, and also because Brotli is expected to achieve better compression ratios than zlib in most cases.