Skip to content

Commit

Permalink
[write-fonts] Improve root crate docs
Browse files Browse the repository at this point in the history
These are the docs that appear on docs.rs.
  • Loading branch information
cmyr committed Aug 1, 2023
1 parent 4982917 commit b854558
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 1 deletion.
98 changes: 97 additions & 1 deletion write-fonts/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,100 @@
//! Raw types for compiling opentype tables
//! Writing and modifying OpenType tables
//!
//! This crate provides a collection of types correlating to what is described
//! in the [OpenType spec][spec], along with the logic to serialize these types
//! into binary font tables. It is a companion to [`read-fonts`], which provides
//! efficient zero-allocation parsing of these types. It is intended to be used
//! as the basis for font engineering tools such as compilers.
//!
//! ## 'write' versus 'read' types
//!
//! Both `write-fonts` and [`read-fonts`] make heavy use of code generation, and
//! they have a similar structure, where a `tables` module contains a submodule for
//! each supported [table][table-directory], and that module contains items for
//! each table, record, flagset or enum described in the spec. This means that
//! there are (for instance) two distinct `ValueRecord` types, one defined in
//! `read_fonts::tables::gpos`, and one defined in `write_fonts::tables::gpos`.
//!
//! The reason for the distinct types is that it allows us to dramatically
//! simplify the scope of `read-fonts`; the types in that crate are generally
//! just typed views into raw slices of bytes and cannot be modified, whereas
//! the types in `write-fonts` are generally familiar Rust structs and enums.
//!
//! ## Loading and modifying fonts
//!
//! Although `write-fonts` does not contain any parsing logic, it does offer the
//! [`FromTableRef`] and [`ToOwnedTable`] traits (similar to `std`'s `From` & `Into`)
//! for converting from a `read_fonts` type to its `write-fonts` equivalent.
//! This means that you can read an existing font table into `write-fonts`;
//! under the hood we will use `read-fonts` to parse the font, and then convert
//! that to the `write-fonts` version. In general you do not need to think about
//! this conversion yourself; tables implement the [`FontRead`] trait from
//! `read-fonts`, which handles the reading + conversion logic for you.
//!
//! ## Writing subtables
//!
//! A font table commonly contains some set of subtables, which are referenced
//! in the font binary as offsets relative to the position (within the file) of
//! the parent table; and these subtables can themselves contain subtables, and
//! so on. We refer to the entire structure of tables the 'table graph'.
//! A consequence of this structure is that compiling
//! a table is not as simple as just sequentially writing out the bytes of each
//! field; it also involves determining an ordering for the subtables, determining
//! their position in the final binary, and correctly writing that position in
//! the appropriate location in any tables that reference that subtable.
//!
//! As most subtable positions (offsets) are stored as 16-bit integers,
//! it is possible in certain cases that offsets overflow. The task of finding
//! a suitable ordering for each table in the table graph is called "table packing".
//! `write-fonts` handles the packing of tables at serialization time, based
//! on the [hb-repacker] implementation from [HarfBuzz].
//!
//! # Examples
//!
//! Create an 'hhea' table
//! ```no_run
//! use write_fonts::{tables::hhea::Hhea, types::{FWord, UfWord}};
//!
//! let my_table = Hhea {
//! ascender: FWord::new(700),
//! descender: FWord::new(-195),
//! line_gap: FWord::new(0),
//! advance_width_max: UfWord::new(1200),
//! min_left_side_bearing: FWord::new(-80),
//! min_right_side_bearing: FWord::new(-420),
//! x_max_extent: FWord::new(1122),
//! caret_slope_rise: 1,
//! caret_slope_run: 0,
//! caret_offset: 0,
//! number_of_long_metrics: 301,
//! };
//!
//! let _bytes = write_fonts::dump_table(&my_table).expect("failed to write bytes");
//! ```
//!
//! Read and modify an existing 'head' table
//! ```no_run
//! # let path_to_my_font_file = std::path::Path::new("");
//! # fn seconds_since_font_epoch() -> LongDateTime { todo!() }
//! use read_fonts::{FontRef, TableProvider};
//! use write_fonts::{from_obj::ToOwnedTable, tables::head::Head, types::LongDateTime};
//!
//! let font_bytes = std::fs::read(path_to_my_font_file).unwrap();
//! let font = FontRef::new(&font_bytes).expect("failed to read font data");
//! let mut head: Head = font.head().expect("missing 'head' table").to_owned_table();
//! head.modified = seconds_since_font_epoch();
//! // to save the font you need to use `FontBuilder`, adding all the unchanged
//! // tables from the original font, and then the new head table
//! ```
//!
//! [`read-fonts`]: https://docs.rs/read-fonts/
//! [spec]: https://learn.microsoft.com/en-us/typography/opentype/spec/
//! [table-directory]: https://learn.microsoft.com/en-us/typography/opentype/spec/otff#table-directory
//! [`FontRead`]: read_fonts::FontRead
//! [hb-repacker]: https://github.com/harfbuzz/harfbuzz/blob/main/docs/repacker.md
//! [HarfBuzz]: https://harfbuzz.github.io
//! [`FromTableRef`]: from_obj::FromTableRef
//! [`ToOwnedTable`]: from_obj::ToOwnedTable

mod collections;
pub mod error;
Expand Down
10 changes: 10 additions & 0 deletions write-fonts/src/tables/value_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ use crate::{
write::{FontWrite, TableWriter},
};

/// A [ValueRecord](https://learn.microsoft.com/en-us/typography/opentype/spec/gpos#valueRecord)
///
/// GPOS subtables use ValueRecords to describe all the variables and values
/// used to adjust the position of a glyph or set of glyphs. A ValueRecord may
/// define any combination of X and Y values (in design units) to add to
/// (positive values) or subtract from (negative values) the placement and
/// advance values provided in the font. In non-variable fonts, a ValueRecord
/// may also contain an offset to a Device table for each of the specified
/// values. In a variable font, it may also contain an offset to a
/// VariationIndex table for each of the specified values.
#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub struct ValueRecord {
Expand Down

0 comments on commit b854558

Please sign in to comment.