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 by combining a content-aware preprocessing step and improved entropy coding, 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/.
Supporting material, including results of compression measurements, may be found in the companion WOFF 2.0 Evaluation Report.
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 an Editors 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.
1. Introduction
1.1. Notational Conventions
2. General Requirements
3. Overall file structure and basic data types
3.1. Data types
3.2. WOFF2 Header
4. Table directory format
5. Collection directory format
TODO: update numbering
5. Compressed data format
5.1. Transformed glyf table format
5.2. Decoding of variable-length X and Y coordinates
5.3. Transformed loca table format
5.4. Table order constraints
6. Extended Metadata Block
7. Private Data Block
Appendix A: Internet Media Type Registration
This document specifies the WOFF2 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 improvement in compression rates, compared to previously developed WOFF 1.0 format [WOFF1] are realized due to improved entropy coding and font data preprocessing and optimization step that reduces built-in redundancy of various font data structures. The details about WOFF 2.0 development history can be found in [ WOFF2ER].
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 [RFC2119]. 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 primary purpose of the WOFF2 format is to efficiently package fonts linked to Web documents by means of CSS @font-face rules. User agents supporting the WOFF2 file format for linked fonts must respect the requirements of the CSS3 Fonts specification ([CSS3-Fonts] Section 4.1: The @font-face rule). In particular, such linked fonts are only available to the documents that reference them; they MUST NOT be made available to other applications or documents on the user's system.
The input font file may have contain a number of various font data tables described in the clause 5 of the [OFF] specification. The order of the tables in a font file may differ and, while the entries in the table directory are required to be sorted in ascending order by tags, the actual tables can be presented in a font file in arbitrary order. When WOFF2 file is decompressed, the decoder MUST sort the tags in the table directory in ascending alphabetical order and SHOULD arrange the table order in a font file according to the Recommendations (section 8.1 "Optimized table ordering") of the [OFF].
The structure of WOFF2 files is similar to that of SFNT and WOFF 1.0 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 ISO "Open Font Format" [OFF] specifications. However, it differs in some important respects from SFNT. Most notably, the data for the font tables is compressed in a single stream comprising all the tables. Similar to WOFF 1.0 format, the optional extended metadata and private data blocks are each presented as separate blocks of data, and are concatenated together into the WOFF 2.0 file. The compression algorithm used for both the compressed font data stream and extended metadata block is Brotli [Brotli].
A complete WOFF2 file consists of several blocks of data: a 48-byte header, immediately followed (in this order) by a variable-size table directory, a compressed font data block, an optional block of extended metadata, and an optional block of private data. Except for padding with a maximum of three null bytes in places where 4-byte alignment of a table length or block offset is specified, there MUST NOT be any extraneous data between the data blocks or WOFF header and table directory, or beyond the last such block or table. If such extraneous data is present a conforming user agent MUST reject the file as invalid. The file MUST also be rejected as invalid if the offsets and lengths of any data blocks or font tables indicate overlapping byte ranges of the file, or ranges that would extend beyond the end of the file.
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 WOFF2 file. |
ExtendedMetadata | An optional block of extended metadata, represented in XML format and compressed for storage in the WOFF2 file. |
PrivateData | An optional block of private data for the font designer, foundry, or vendor to use. |
Editor's note: Do we want to require 4-byte alignment between data blocks?
Data Types | |
---|---|
UInt8 | 8-bit unsigned integer. |
Int16 | 16-bit signed integer in 2's complement format, stored big-endian. |
UInt16 | 16-bit unsigned integer, stored big-endian. |
255UInt16 | Variable-length encoding of a 16-bit unsigned integer for optimized intermediate font data storage. |
UIntBase128 | Variable-length encoding of 32-bit unsigned integers. |
255UInt16 is a variable-length encoding of an unsigned integer in the range 0 to 65535 inclusive. This data type is intended to be used as intermediate representation of various font values, which are typically expressed as UInt16 but represent relatively small values. Depending on the encoded value, the length of the data field may be one to three bytes, as described in the following table:
Data Type | Syntax | Description and Comments |
---|---|---|
UInt8 | Code | if (Code < 253) Value = Code; /* [0..252] */ |
if ((Code == 254) || (Code == 255)) | ||
UInt8 | Value1 | if (Code == 255) Value = 253 + Value1; /* [253..508] */ if (Code == 254) Value = 506 + Value1; /* [506..761] */ |
else if (Code == 253) | ||
UInt16 | Value | Value; /* [0..65535] */ |
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. An encoder SHOULD choose shorter encodings, and MUST be consistent in choice of encoding for the same value, as this will tend to compress better.
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.
UIntBase128 encoding format allows a possibility of sub-optimal encoding, where e.g. the same numerical value can be represented with variable number of bytes (utilizing leading 'zeros'). For example, the value 63 could be encoded as either one byte 0x3F or two (or more) bytes: [0x80, 0x3f]. An encoder must not allow this to happen and MUST produce shortest possible encoding. A decoder MUST reject the font file if it encounters a UintBase128-encoded value with leading zeros (a value that starts with the byte 0x80), if UintBase128-encoded sequence is longer than 5 bytes, or if a UintBase128-encoded value exceeds 232-1.
Editor's note: We need to figure out how these conditions can be tested. Otherwise, we may need to edit statements that cannot be covered by the conformance tests and make them plain English descriptions instead.
The WOFF 2.0 header includes an identifying signature and provides the information about the compressed and uncompressed sizes of encapsulated font data. It also indicates the specific kind of font data included in the WOFF 2.0 file, font version number and provides offsets to additional data blocks included in the file.
WOFF2 Header | ||
---|---|---|
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 0. |
UInt32 | totalSfntSize | Total size needed for the
uncompressed font data, including the sfnt header, directory, and font tables (including padding). |
UInt32 | totalCompressedSize | Total length of the compressed data block. |
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 WOFF2 Header is the same as the WOFF Header in [WOFF1]. The signature has the value of 0x774F4632 ('wOF2'), which distinguishes it from WOFF 1.0 files. A valid WOFF 2.0 file MUST have the reserved field to 'zero', a decoder MUST NOT reject a downloaded font file if the reserved header value is not zero.
Editor's note (To Do):
- Clarify the exact meaning of the "totalSfntSize" field. It may represent the size of
the original uncompressed font data, but if the transformed 'glyf' and 'loca' tables are
present the uncompressed size of the reconstructed font may differ from the original size
specified in the WOFF2 Header table
The table directory is an array of WOFF2 table directory entries, as defined below. The directory follows immediately after the WOFF2 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 original size of a single font data table and, for those tables where an additional transform has been applied, the size of the transformed table. Transformed tables can be identified either by the known table tag as part of the flags field or by the 4-byte table tag, if present.
Contrary to the way how table directory entries are specified in the original input font file (where table directory entires are sorted in ascending alphabetical order), the WOFF2 table directory entires define the physical order of tables in which they have been processed and encoded as part of the compressed font data stream. It is a decoder responsibility to sort and reorder the table directory when the font file is decompressed.
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) |
The interpretation of the flags field is as follows. Bits [0..5] 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 63. Bits 6 and 7 are reserved for future extensions.
Whether a table tag is encoded with a known table tag or explicitly including the four-byte tag has no semantic significance; it is simply a choice of encoding intended to improve compression efficiency. Similarly, whether a particular four-byte tag is present or not in the known table is not a normative statement about whether such tags should be included in web fonts.
There is a predefined extension mechanism for any custom table tag that is not included in the known tag list (or for any new standard tags that may be defined in the future). If bits [0..5] of the flags byte have the value 63 (0x3f), then following the flag byte is a 4-byte arbitrary tag value. Otherwise, the tag field is omitted in the TableDirectoryEntry structure, and is derived from bits [0..5] of the flag byte from the fixed Known Table Tags table, given below.
Known Table Tags | |||||||
---|---|---|---|---|---|---|---|
Flag | Tag | Flag | Tag | Flag | Tag | Flag | Tag |
0 | cmap | 16 | EBLC | 32 | CBDT | 48 | gvar |
1 | head | 17 | gasp | 33 | CBLC | 49 | hsty |
2 | hhea | 18 | hdmx | 34 | COLR | 50 | just |
3 | hmtx | 19 | kern | 35 | CPAL | 51 | lcar |
4 | maxp | 20 | LTSH | 36 | SVG | 52 | mort |
5 | name | 21 | PCLT | 37 | sbix | 53 | morx |
6 | OS/2 | 22 | VDMX | 38 | acnt | 54 | opbd |
7 | post | 23 | vhea | 39 | avar | 55 | prop |
8 | cvt | 24 | vmtx | 40 | bdat | 56 | trak |
9 | fpgm | 25 | BASE | 01 | bloc | 57 | Zapf |
10 | glyf | 26 | GDEF | 42 | bsln | 58 | Silf |
11 | loca | 27 | GPOS | 43 | cvar | 59 | Glat |
12 | prep | 28 | GSUB | 44 | fdsc | 60 | Gloc |
13 | CFF | 29 | EBSC | 45 | feat | 61 | Feat |
14 | VORG | 30 | JSTF | 46 | fmtx | 62 | Sill |
15 | EBDT | 31 | MATH | 47 | fvar | 63 | arbitrary tag follows |
Please note that according to the SFNT-based font format specifications all table tags should consist of four characters. Table tags with less then four letters, such as e.g. 'cvt ' (tag value 0x63767420) are padded with trailing spaces.
Following the flags are one to two length values, each in UIntBase128 unsigned integer encoding. The origLength field specifies the length of the table in an uncompressed version of the font. Optionally, for those table that are subjected to additional transformations, the transformLength specifies the length of the transformed version of the table.
The field containing the transformed length provides information about the transformed table size prior to it being compressed by [Brotli]. This field is optional and is present only for certain tables (see below the description of the "Compressed data format"). Please note that while the transformed length can be relied upon to determined the decompressed table size, the original table length of the transformed font table should be treated with caution.
The reconstruction process of transformed tables guarantees preserving the functionality of the tables but may produce binary results that are different from the original data. For example, 'glyf' table records may have outline point coordinates encoded using one- or two-byte format, and the repetitive values can either be explicitly duplicated in the coordinate stream or omitted (which would be indicated by the flags byte of the control point). Therefore, various representations of glyph oulines point are possible that would produce identical rendering results; however, the binary data of reconstructed glyph records may differ significantly from the original data. See subclause 5.3.3 of the ISO "Open Font Format" [OFF] specification for details.
For this reason, the value of the origLength field of transformed table should be treated only as a reference and should not be relied upon in making memory allocation decisions when the WOFF2 data is decoded.
The collection directory is present only if the input font is a collection. That is, if the WOFF2 file header "flavor" field value has the value 0x74746366 ('ttcf').
If input font is a collection, the table directory contains one entry for each unique table in the entire collection. That is, the table director for the collection compressed with WOFF2 comprises all tables from all fonts contained in the collection.
The collection directory, if present, follows immediately after the table directory. The collection directory consists of a CollectionHeader and one or more CollectionFontEntry records.
CollectionHeader | ||
---|---|---|
UInt32 | version | The Version of the TTC Header in the original font. |
UInt32 | numFonts | The number of fonts in the collection. |
Immediately after the CollectionHeader follows one CollectionFontEntry per font in the collection (CollectionHeader "numFonts")
CollectionFontEntry | ||
---|---|---|
UInt16 | numTables | The number of tables in this font |
UInt32 | flavor | The "sfnt version" of the font |
255UInt16 | index[numTables] | The Table Directory index of each table in this font (a stream of numTables 255UInt16 values) |
An encoder MUST emit one TableDirectoryEntry for each unique table offset. Thus, for a collection that contains multiple fonts that have Table Records with the same offset, an encoder MUST emit only one TableDirectoryEntry for that offset. An encoder MUST put the index of the matching TableDirectoryEntry into the TTC Font Entry for each font. A decoder MUST restore the collection with the same number of Offset Tables. The Offset Tables within the output collection MUST have either the same numTables as the input collection or one less if DSIG is present in the original Offset Table.
A decoder, when processing a collection, MUST emit a collection containing the same number of fonts with the same number of tables in each font (Offset Table, numTables) as were in the original font. The nested fonts MUST be in the same order as they were in the input collection. The tables within each nested font can be reordered. If the CollectionHeader "version" is 0x00020000 a decoder MUST set the TTC Header fields {ulDsigTag, ulDsigLength, ulDsigOffset} in the output collection to 0.
Retention of font order in collection is required for CSS fragment identifiers to ever work.
The calculation of the head table "checkSumAdjustment" for fonts within a collection is not well defined. The definition of the "whole font" and how to handle multiple head tables is unclear.
If a collection contains multiple unique glyf and loca tables, the transformations described for the Compressed data format MUST be applied to each. A table whose offset is referred to by multiple Offset Tables in the original collection may be considered "shared". An encoder MUST reject a collection containing fonts that share exactly one of glyf and loca. Sharing neither nor glyf nor loca or sharing both is acceptable.
TTC TODO How does extended metadata and private data block work w/TTC? write tests and link appropriately (Put the little AT/FF highlight & links in for normative statements) Update section numbering (prev sections 5 and higher ++) Update anything that refers to table ordering, etc to address multiple copies of table (updated a few but doubtless not all)
The CompressedFontData field in a WOFF2 file contains the concatenation of data for each table in the font, in the order that entries appear in the table directory. The CompressedFontData stream MUST be compressed using the Brotli compression algorithm [Brotli]. If the decompression of the data block fails for any reason, the WOFF2 file is invalid and MUST NOT be loaded.
The process of decoding the table data in a WOFF2 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. 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.
Certain tables (such as glyf and loca tables, identified by their corresponding tags), are subject to additional transforms. If a font 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 decompressed and reconstructed table data MUST be stored in the format specified by the [OFF] specification. Each reconstructed table directory entry MUST contain a valid 'checkSum' value, the decoder MUST recalculate the checkSum value for each decoded table. Also, due to modifying transofrms applied to glyf and loca tables, the decoder MUST recalculate the checkSumAdjustment value of the entire font and MUST store the updated value in the head table. Note that checkSumAdjustment calculation for collections is not well defined; see note.
The known table flag values should not be relied upon in determining the presense of the transformed tables, it is feasible that e.g. the glyf table can be represented in the table directory with either flag = 10 and no tag, or with flag = 63 and 'glyf' tag that follows.
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.If the size of the decompressed font data block doesn't match the sum of lengths defined in the table directory as descripbed above, the WOFF2 file MUST NOT be loaded.
Editor's note (To Do):
- Clarify the exact meaning and the source of "the size of the uncompressed table data block"
A transform MUST be applied to two types of tables: glyf, representing outline data, and loca, representing the offsets of the individual glyphs within a glyf table, if these tables are present. An authoring tool must transform all glyf and loca tables. Additional constraints apply, as specified in section 5.4. The glyf table transformation is specified in section 5.1, and the loca table transformation is specified in section 5.3.
A collection can contain multiple glyf and loca tables. They MUST all be transformed.
Editor's note: Do we need to add the conformance requirement for UA regarding table transforms?
The WOFF 2.0 transformations applied to certain tables are desinged to reduce and/or eliminate the built-in redundancies of the SFNT format and restructure the font data stream for more efficient entropy encoding. As a result, the reconstructed font data will retain the exact functionality of the input font file, but due to certain possible encoding variations (such as e.g. various levels of optimization of outline point coordinates in the 'glyf' table, or difference in offset calculations of the 'loca' table) different WOFF2 decoders may produce an output file that will not be a bitwise match to the input font file. These differences will invalidate the 'DSIG' table, if one is present and, therefore, the compliant WOFF2 encoder MUST remove the DSIG table(s) from an input font data, prior to applying transformations and entropy coding steps.
A collection can contain multiple DSIG tables. They MUST all be removed
The WOFF 2.0 encoders MUST also set bit 11 of the 'flags' field of all head tables (see [OFF] specification) to indicate that a recreated font file was subjected to lossless modifying transform.
A collection can contain multiple head tables. They MUST all be marked subject to lossless modifying transform.
The glyf table transformation is intended to reduce redundant information and provide a more efficient encoding of the actual TrueType outlines of glyphs. The modified transformation is specified below and is based on a similar transformation described in MicroType Express [MTX] specification. The reference to MTX is informative; the details of the modified 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 number of fields speciffying the size of each of the substreams, followed by the substreams in sequence. During the decoding process the reverse transformation takes place, where data from various separate substreams are recombined to create a complete glyph record for each entry of the original glyf table.
Transformed glyf Table | ||
---|---|---|
Data Type | Semantic | Description and value type (if applicable) |
Fixed | version | = 0x00000000 |
UInt16 | numGlyphs | Number of glyphs |
UInt16 | indexFormat | Offset format for loca table, should be consistent with indexToLocFormat of the original head table (see [OFF] specification) |
UInt32 | nContourStreamSize | Size of nContour stream in bytes |
UInt32 | nPointsStreamSize | Size of nPoints stream in bytes |
UInt32 | flagStreamSize | Size of flag stream in bytes |
UInt32 | glyphStreamSize | Size of glyph stream in bytes (a stream of variable-length encoded values, see description below) |
UInt32 | compositeStreamSize | Size of composite stream in bytes (a stream of variable-length encoded values, see description below) |
UInt32 | bboxStreamSize | Size of bbox data in bytes representing combined length of bboxBitmap (a packed bit array) and bboxStream (a stream of Int16 values) |
UInt32 | instructionStreamSize | Size of instruction stream (a stream of UInt8 values) |
Int16 | nContourStream | Stream of Int16 values representing number of contours for each glyph record |
255UInt16 | nPointsStream | Stream of values representing number of outline points for each contour in glyph records |
UInt8 | flagStream | Stream of UInt8 values representing flag values for each outline point. |
Vary | glyphStream | Stream of bytes representing point coordinate values using variable length encoding format (defined in section 5.2) |
Vary | compositeStream | Stream of bytes representing component flag values and associated composite glyph data |
UInt8 | bboxBitmap[n] | Bitmap (a numGlyphs-long bit array) indicating explicit bounding boxes |
Int16 | bboxStream | Stream of Int16 values representing glyph bounding box data |
UInt8 | instructionStream | Stream of UInt8 values representing a set of instructions for each corresponding glyph |
The format is best characterized by describing the decoding process, especially indications of what are valid and invalid data. An encoder MUST produce transformed data that is valid, it is up to the encoder to produce transformed data that decodes to the desired font data. Note also that this format specifies the decoded result at the semantic level, not specific byte streams.
Included in the Transformed glyf Table is a bboxBitmap indicating for each glyph whether it contains an explicitly encoded bounding box, or whether the bounding box is to be inferred from the coordinate values. The relevant computations to determine the bounding box status must be performed by both an encoder and a decoder. For each simple glyph, an encoder MUST calculate the the xMin, yMin, xMax and yMax coordinate values using all outline points (both on- and off-curve points) and compare the calculated values with the encoded bounding box info for the glyph. If the glyph bounding box info matches the calculated values, an encoder MUST omit the bounding box info. Otherwise, if the calculated bounding box values do not equal the glyph values encoded in a font, an encoder MUST set the corresponding bboxBitmap flag and record the original bounding box values in the bboxStream. For a composite glyph, an encoder MUST always set the corresponding bboxBitmap flag and record the original bounding box values in the bboxStream.
A decoder MUST perform similar calculations if the bounding box is to be inferred. For a given glyph, when a corresponding bit in bboxBitmap is not set, the xMin, yMin, xMax and yMax values MUST be calculated at the time of decoding using all outline point coordinates. The total number of bytes in bboxBitmap 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 bit=1 value indicates an explicitly set bounding box.
Upon reading the Transformed glyf Table , 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 Transformed glyf Table . Also, at the point of reconstructing a glyph, a decoder MUST store for each glyph the corresponding offset in the reconstructed glyph table, and this data will collectively become the contents of the reconstructed loca table (see section 5.3 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 Int16 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 simple and the value represents the number of contours in the outline. If the nContour value is equal to -1 (0xffff), then the glyph is composite.
For a simple glyph, the process continues as follows:
2. Read numberOfContours 255UInt16 values from the nPoints stream. Each of these is the number of points 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 UInt8 values from the flags stream. Each corresponds to one point in the reconstructed glyph outline. The interpretation of the flag byte is described in details in section 5.2.
4. For each point (i.e. nPoints times), read a number of point coordinate bytes from the glyph stream. The number of point coordinate 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 bytes according to the procedure specificed in the section 5.2 to reconstruct delta-x and delta-y values of the glyph point coordinates. Store these delta-x and delta-y values in the reconstructed glyph using the standard TrueType glyph encoding [OFF] section 5.3.3.
5. Read one 255UInt16 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 UInt16 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 Int16 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 would require resolving references to component glyphs taking into account composite glyph instructions and the specified scales of individual components, which would conflict with a purely streaming implementation of font decoding. A decoder MUST check for presense of the bonding box info as part of the composite glyph record and MUST NOT load a font file with the composite bounding box data missing.
Simple glyph data structure defines all contours that comprise a glyph outline, which are presented by a sequence of on- and off-curve coordinate points. These point coordinates are encoded as delta values representing the incremental values between the previous and current corresponding X and Y coordinates of a point, the first point of each outline is relative to (0,0) point. To minimize the size of the dataset of point coordinate values, each point is presented as a (flag, xCoordinate, yCoordinate) triplet. The flag value is stored in a separate data stream and the coordinate values are stored as part of the glyph data stream using a variable-length encoding format consuming a total of 2-5 bytes per point.
The most significant bit of a flag indicates whether the point is on- or off-curve point, the remaining seven bits of the flag determine the format of X and Y coordinate values and specify 128 possible combinations of indices that have been assigned taking into consideration typical statistical distribution of data found in TrueType fonts. When X and Y coordinate values are recorded using nibbles (either 4 bits per coordinate or 12 bits per coordinate) the bits are packed in the byte stream with most significant bit of X coordinate first, followed by the value for Y coordinate (most significant bit first). As a result, the size of the glyph dataset is significantly reduced, and the grouping of the similar values (flags, coordinates) in separate and contiguous data streams allows more efficient application of the entropy coding applied as the second stage of encoding process.
Each of the 128 index values define the following properties and specified in details in the table below:
Please note that “Byte Count” field reflects total size of the triplet (flag, xCoordinate, yCoordinate), including ‘flag’ value that is encoded in a separate stream.
Triplet Encoding | |||||||
---|---|---|---|---|---|---|---|
Index | Byte Count | X bits | Y bits | Delta X | Delta Y | X sign | Y sign |
0 | 2 | 0 | 8 | N/A | 0 | N/A | - |
1 | 0 | + | |||||
2 | 256 | - | |||||
3 | 256 | + | |||||
4 | 512 | - | |||||
5 | 512 | + | |||||
6 | 768 | - | |||||
7 | 768 | + | |||||
8 | 1024 | - | |||||
9 | 1024 | + | |||||
10 | 2 | 8 | 0 | 0 | N/A | - | N/A |
11 | 0 | + | |||||
12 | 256 | - | |||||
13 | 256 | + | |||||
14 | 512 | - | |||||
15 | 512 | + | |||||
16 | 768 | - | |||||
17 | 768 | + | |||||
18 | 1024 | - | |||||
19 | 1024 | + | |||||
20 | 2 | 4 | 4 | 1 | 1 | - | - |
21 | 1 | + | - | ||||
22 | 1 | - | + | ||||
23 | 1 | + | + | ||||
24 | 17 | - | - | ||||
25 | 17 | + | - | ||||
26 | 17 | - | + | ||||
27 | 17 | + | + | ||||
28 | 33 | - | - | ||||
29 | 33 | + | - | ||||
30 | 33 | - | + | ||||
31 | 33 | + | + | ||||
32 | 49 | - | - | ||||
33 | 49 | + | - | ||||
34 | 49 | - | + | ||||
35 | 49 | + | + | ||||
36 | 2 | 4 | 4 | 17 | 1 | - | - |
37 | 1 | + | - | ||||
38 | 1 | - | + | ||||
39 | 1 | + | + | ||||
40 | 17 | - | - | ||||
41 | 17 | + | - | ||||
42 | 17 | - | + | ||||
43 | 17 | + | + | ||||
44 | 33 | - | - | ||||
45 | 33 | + | - | ||||
46 | 33 | - | + | ||||
47 | 33 | + | + | ||||
48 | 49 | - | - | ||||
49 | 49 | + | - | ||||
50 | 49 | - | + | ||||
51 | 49 | + | + | ||||
52 | 2 | 4 | 4 | 33 | 1 | - | - |
53 | 1 | + | - | ||||
54 | 1 | - | + | ||||
55 | 1 | + | + | ||||
56 | 17 | - | - | ||||
57 | 17 | + | - | ||||
58 | 17 | - | + | ||||
59 | 17 | + | + | ||||
60 | 33 | - | - | ||||
61 | 33 | + | - | ||||
62 | 33 | - | + | ||||
63 | 33 | + | + | ||||
64 | 49 | - | - | ||||
65 | 49 | + | - | ||||
66 | 49 | - | + | ||||
67 | 49 | + | + | ||||
68 | 2 | 4 | 4 | 49 | 1 | - | - |
69 | 1 | + | - | ||||
70 | 1 | - | + | ||||
71 | 1 | + | + | ||||
72 | 17 | - | - | ||||
73 | 17 | + | - | ||||
74 | 17 | - | + | ||||
75 | 17 | + | + | ||||
76 | 33 | - | - | ||||
77 | 33 | + | - | ||||
78 | 33 | - | + | ||||
79 | 33 | + | + | ||||
80 | 49 | - | - | ||||
81 | 49 | + | - | ||||
82 | 49 | - | + | ||||
83 | 49 | + | + | ||||
84 | 3 | 8 | 8 | 1 | 1 | - | - |
85 | 1 | + | - | ||||
86 | 1 | - | + | ||||
87 | 1 | + | + | ||||
88 | 257 | - | - | ||||
89 | 257 | + | - | ||||
90 | 257 | - | + | ||||
91 | 257 | + | + | ||||
92 | 513 | - | - | ||||
93 | 513 | + | - | ||||
94 | 513 | - | + | ||||
95 | 513 | + | + | ||||
96 | 3 | 8 | 8 | 257 | 1 | - | - |
97 | 1 | + | - | ||||
98 | 1 | - | + | ||||
99 | 1 | + | + | ||||
100 | 257 | - | - | ||||
101 | 257 | + | - | ||||
102 | 257 | - | + | ||||
103 | 257 | + | + | ||||
104 | 513 | - | - | ||||
105 | 513 | + | - | ||||
106 | 513 | - | + | ||||
107 | 513 | + | + | ||||
108 | 3 | 8 | 8 | 513 | 1 | - | - |
109 | 1 | + | - | ||||
110 | 1 | - | + | ||||
111 | 1 | + | + | ||||
112 | 257 | - | - | ||||
113 | 257 | + | - | ||||
114 | 257 | - | + | ||||
115 | 257 | + | + | ||||
116 | 513 | - | - | ||||
117 | 513 | + | - | ||||
118 | 513 | - | + | ||||
119 | 513 | + | + | ||||
120 | 4 | 12 | 12 | 0 | 0 | - | - |
121 | + | - | |||||
122 | - | + | |||||
123 | + | + | |||||
124 | 5 | 16 | 16 | 0 | 0 | - | - |
125 | + | - | |||||
126 | - | + | |||||
127 | + | + |
For additional information and background on the triplet encoding pleasee see section 5.11 of the MTX proposal [MTX].
The transformLength of the transformed loca table MUST always be zero. The origLength MUST be the appropriate size (determined by numGlyphs+1, times the size per glyph, where that size per glyph is two bytes when indexFormat (defined in section 5.1. Transformed glyf table format) is zero, otherwise four bytes).
The loca table MUST be reconstructed when the glyf table is decoded. The process for reconstructing the loca table is specified in section 5.1 as part of the transformed glyf table decoding process. For reconstructed glyph records, a decoder MUST store the corresponding offsets for individual glyphs using a format that is indicated by the indexFormat field of the Transformed glyf Table.
The following constraints on valid WOFF2 files are intended to facilitate a memory-efficient WOFF 2.0 file transfer and decoding process. For a font with TrueType outlines, the glyf table MUST be encoded with the transform, which results in significantly smaller file size.
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 5.3.
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.
Editor's note: Is this really a testable assertion? How one can test for an "adequate amount of space"
if the decoding process allows multiple permutations and all of them are equally valid,
as far as UA and font rendering engines are concerned.
To Do:
- Either nail the concept of "nominal size" or remove it from the spec (replacing it
with e.g. the original size) and pointing out possible size variability due to
various options for encoding glyph coordinates
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 of 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 WOFF2 font files SHOULD check this constraint.
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.
Editor's note: Should we really be prescriptive on validation behavior?
Do we really need formal SHOULD for WOFF2 validation here?
The WOFF2 file MAY contain a block of extended metadata. The interpretation of this block is exactly the same as [WOFF 1].
However, while in a WOFF 1 file the extended metadata block is stored with zlib compression, in a WOFF2 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 WOFF2, and also because Brotli is expected to achieve better compression ratios than zlib in most cases.
If present, the metadata MUST be compressed, in a separate Brotli stream from the main font data; it is never stored in uncompressed form.
The presence (or absence) and content of the metadata block MUST NOT affect font loading or rendering behavior of user agents; it is intended to be purely informative.
The extended metadata MUST be well-formed XML, encoded in UTF-8.
The metadata block MUST follow immediately after the last font table. As all font data tables are padded with up to three null bytes if needed to reach a 4-byte boundary, the beginning of the metadata block will always be 4-byte aligned. If the metadata block is the last block in the WOFF file, there SHOULD be no additional padding after the end of the block.
The WOFF file MAY include a block of arbitrary data, allowing font creators to include whatever information they wish. The content of this data MUST NOT affect font usage or load behavior of user agents. User agents should make no assumptions about the content of a private block; it may (for example) contain ASCII or Unicode text, or some vendor-defined binary data, and it may be compressed or encrypted, but it has no publicly defined format. Conformant user agents will not assume anything about the structure of this data. Only the font developer or vendor responsible for the private block is expected to understand its contents.
The private data block, if present, MUST be the last block in the WOFF file, following the compressed font data stream and the extended metadata block, if one is present. The private data block MUST begin on a 4-byte boundary in the WOFF file, with up to three null bytes inserted as padding after any preceding metadata block if needed to ensure this. The end of the private data block MUST correspond to the end of the WOFF file.
This appendix registers a new MIME media type, in conformance with BCP 13 and W3CRegMedia.
application
font-woff2
None.
None.
binary.
Fonts are interpreted data structures that represent collections of glyph outlines, metrics and layout information for various languages and writing systems. Currently, there are many standardized font data tables that allow an unspecified number of entries, and where existing, predefined data fields allow storage of binary data with variable length. There is a significant risk that the flexibility of font data structures may be exploited to hide malicious binary content disguised as a font data component.
WOFF 2.0 is based on the table-based SFNT (scalable font) format which is highly extensible and offers an opportunity to introduce additional data structures when needed. However, this same extensibility may present specific security concerns – the flexibility and ease of defining new data structures makes it easy for any arbitrary data to be added and hidden inside a font file.
WOFF 2.0 fonts may contain 'hints' for the alignment of graphical elements of the glyphs with the target display pixel grid, and depending on the font technology utilized in the creation of a font these hints may represent active code interpreted and executed by the font rasterizer. Even though they operate within the confines of the glyph outline conversion system and have no access outside the font rendering machinery, hint instructions can be, however, quite complex, and a maliciously designed complex font could cause undue resource consumption (e.g. memory or CPU cycles) on a machine interpreting it. Indeed, fonts are sufficiently complex that most if not all interpreters cannot be completely protected from malicious fonts without undue performance penalties.
Widespread use of fonts as necessary component of visual content presentation warrants that a careful attention should be given to security considerations whenever a font is either embedded into an electronic document or transmitted alongside media content as a linked resource.
WOFF 2.0 uses Brotli compression. The WOFF2 header contains the length of the uncompressed font data including the sfnt header, directory, and font tables (including padding). Applications may therefore constrain the size of memory buffer allocated for decompression and may stop writing if a maliciously crafted WOFF file in fact contains more data than is indicated.
WOFF 2.0 does not provide privacy protections internally; if needed, these should be provided externally.
WOFF 2.0 has a private data block facility, which may contain arbitrary binary data. WOFF 2.0 does not provide a means to access this, or to execute any code contained therein. As with WOFF 1.0, it is required that the content of this block not affect font rendering in any way.
WOFF 2.0 is an improvement on WOFF 1.0. The two formats have different Internet Media Types and may be used in parallel.
This media type registration is extracted from the WOFF 2.0 specification at W3C.
WOFF 2.0 is used by Web browsers, often in conjunction with HTML and CSS.
Chris Lilley (www-font@w3.org).
COMMON
None
The WOFF2 specification is a work product of the World Wide Web Consortium's WebFonts Working Group.
The W3C has change control over this specification.