read-fonts 0.38.0

Reading OpenType font files.
Documentation

read-fonts

This crate handles parsing and reading of OpenType fonts. It is intended to be a high performance implementation suitable for tasks such as shaping, while still providing a convenient, high-level API.

Safety

Unsafe code is forbidden by a #![forbid(unsafe_code)] attribute in the root of the library.

codegen

Much of the code in this crate is generated automatically. This generated code lives in the generated directory. Each file in this directory is included in a module in the src directory, using Rust's include! macro. This allows us to separate the generated code from any custom implementation code, while allowing them to exist in the same module.

what we generate

With certain exceptions that require manual handling, we generate code for each table, record, enum, and flags type for each portion of the spec that we cover.

tables

All tables are newtype structs wrapping what is essentially a byte slice. When a table is parsed, we perform minimal validation: that is, we ensure that the provided data is at least long enough to contain all of the required, non-version-dependent fields.

All other validation occurs at runtime. If table data is malformed, and a field cannot be read, we will always return a default value. In the case of a versioned field, this will always be None; for a field that is expected to always be present, it will be the default value for the type in question, usually either 0 or an empty array.

variable length and version-dependent fields

n.b: the design described below has not been benchmarked against the alternatives, and may change

For fields that have variable length, or which only exist in certain table versions, the marker struct has a corresponding field where that length or offset is stored. This means that at runtime there is no need to double check a version or length.

records

Unlike tables, which are essentially a set of methods for reading into a byte slice, records are in general represented as simple packed structs containing scalar types in big-endian encodings. This means that, in general, records are zerocopy types that can be cast from raw bytes.

The exception to this is when a record has variable length; in this case the record is still a simple struct, but cannot be cast from raw bytes, and must be copied.

flags and enums

For flags, we generate a type modeled on those generated by the bitflags! macro. For enums, we generate a raw Rust enum.