font-kit

repository·main·Indexed 21 days ago

https://github.com/servo/font-kit

A cross-platform Rust library for font management, providing a unified interface for system font discovery, font matching according to CSS Fonts Module Level 3, and glyph rasterization. It decouples font sources (such as SystemSource, Fontconfig, and Filesystem) from font loaders (such as Core Text, DirectWrite, and FreeType), allowing developers to look up fonts via one backend and render them using another.

Tokens
9.4K
Snippets
34
Records
50
Agent score
71%

What's inside font-kit

  1. Overview of font-kit

    main
    font-kit provides a common interface to various system font libraries. It enables developers to perform tasks such as finding fonts on a system, performing nearest-font matching according to the CSS Fonts Module Level 3 specification, and rasterizing glyphs.
  2. How font-kit sources and loaders work together

    main

    font-kit uses two distinct types of backends that can be intermixed at runtime:

    1. Sources: These are platform font databases used to look up installed fonts by name or attributes (e.g., SystemSource, Filesystem, Memory).
    2. Loaders: These are font loading libraries used to load font files (TTF, OTF, etc.) from disk or memory (e.g., Core Text, DirectWrite, FreeType).

    Because they are decoupled, you can perform a lookup via one backend (like DirectWrite on Windows) and then render the resulting font using another (like FreeType).

  3. Represent glyph outlines with Outline and Contour

    main

    An Outline represents a complete glyph vector outline and is composed of one or more Contour objects.

    • Outline: Contains a Vec<Contour> representing the individual subpaths.
    • Contour: Represents a single subpath. It consists of two parallel vectors of equal length:
      • positions: A Vec<Vector2F> containing the coordinates of each point.
      • flags: A Vec<PointFlags> specifying the type of each point (e.g., whether it is a control point for a Bézier curve).

    You can iterate through an Outline and send its contents to any OutlineSink using the copy_to method.

    use font_kit::outline::Outline;
    
    // Assuming 'sink' implements OutlineSink
    outline.copy_to(&mut sink);
  4. How font-kit backends (Sources and Loaders) work

    main

    font-kit uses two types of backends that can be intermixed at runtime:

    • Sources: These are platform font databases used to look up installed fonts by name or attributes (e.g., finding 'Sans Serif' on a system).
    • Loaders: These are libraries that allow loading specific font files (TTF, OTF, etc.) from disk or memory into a usable font object.

    For example, you can use a macOS Source (Core Text) to find a font, but use a cross-platform Loader (FreeType) to render it.

  5. Configure font-kit backends via Cargo features

    main

    By default, font-kit uses native system backends. To use cross-platform backends on Windows or macOS, you must enable specific Cargo features:

    • FreeType Loader: Enable loader-freetype to use FreeType. Use loader-freetype-default to make it the default loader.
    • Fontconfig Source: Enable source-fontconfig to use Fontconfig. Use source-fontconfig-default to make it the default source (use with caution on Windows/macOS).

    If your application provides its own fonts and does not need to search the system, you can omit the default source feature to reduce binary size.

  6. Aggregate multiple font sources with MultiSource

    main

    Use MultiSource to encapsulate multiple Source implementations into a single searchable group. This is useful for combining system fonts with application-specific font directories. When querying a MultiSource, it iterates through its sub-sources and returns the first successful match it finds (e.g., for family name or PostScript name lookups) or aggregates results (e.g., for all_fonts or all_families).

    // Example of creating a MultiSource from multiple sources
    let multi_source = MultiSource::from_sources(vec![
        Box::new(system_source),
        Box::new(app_specific_source),
    ]);
  7. The Handle enum for locating and opening fonts

    main

    The Handle enum encapsulates the information required to locate and open a font. It serves as a reference that can be passed to a loader to produce a Font. A Handle can represent either a file on disk or raw data already loaded into memory.

    There are two variants:

    1. Path: Contains a PathBuf to the font file and a font_index. If the path points to a font collection, font_index specifies which font to use; otherwise, use 0.
    2. Memory: Contains an Arc<Vec<u8>> of the raw font data and a font_index. Similar to the path variant, use 0 if the memory contains a single font rather than a collection.
    use std::path::PathBuf;
    use std::sync::Arc;
    use font_kit::Handle;
    
    // Example: Creating a handle from a path
    let handle = Handle::from_path(PathBuf::from("fonts/myfont.ttf"), 0);
    
    // Example: Creating a handle from memory
    let font_data = Arc::new(vec![0u8; 1024]); // dummy data
    let handle = Handle::from_memory(font_data, 0);
  8. Quickstart: Find, load, and rasterize a font

    main

    To use font-kit, you typically follow a workflow of selecting a font from a Source, loading it into a Font object, and then using a Canvas to rasterize specific glyphs.

    Note that font-kit handles glyph-to-character mapping for simple use cases, but for complex text shaping (like ligatures or bidirectional text), you should use a dedicated shaper alongside font-kit.

    use font_kit::canvas::{Canvas, Format, RasterizationOptions};
    use font_kit::family_name::FamilyName;
    use font_kit::hinting::HintingOptions;
    use font_kit::properties::Properties;
    use font_kit::source::SystemSource;
    use pathfinder_geometry::transform2d::Transform2F;
    use pathfinder_geometry::vector::{Vector2F, Vector2I};
    
    // 1. Select the best matching font from the system
    let font = SystemSource::new()
        .select_best_match(&[FamilyName::SansSerif], &Properties::new())
        .unwrap()
        .load()
        .unwrap();
    
    // 2. Get a glyph ID for a character
    let glyph_id = font.glyph_for_char('A').unwrap();
    
    // 3. Prepare a canvas for rasterization
    let mut canvas = Canvas::new(Vector2I::splat(32), Format::A8);
    
    // 4. Rasterize the glyph
    font.rasterize_glyph(
        &mut canvas,
        glyph_id,
        32.0,
        Transform2F::from_translation(Vector2F::new(0.0, 32.0)),
        HintingOptions::None,
        RasterizationOptions::GrayscaleAa
    ).unwrap();
  9. Configure Cargo features for FreeType and Fontconfig

    main

    On Windows and macOS, the FreeType loader and Fontconfig source are not built by default. To enable them, use the following Cargo features:

    • FreeType Loader: loader-freetype (or loader-freetype-default to make it the default).
    • Fontconfig Source: source-fontconfig (or source-fontconfig-default to make it the default).

    Warning: Using source-fontconfig-default on Windows or macOS is rarely recommended.

  10. Rasterize a glyph with font-kit

    main

    To render a character, you first select a font from a source, load it, find the specific glyph_id for a character, and then use the rasterize_glyph method on a Canvas.

    let font = SystemSource::new()
        .select_by_postscript_name("ArialMT")
        .unwrap()
        .load()
        .unwrap();
    
    let glyph_id = font.glyph_for_char('A').unwrap();
    let mut canvas = Canvas::new(&Size2D::new(32, 32), Format::A8);
    
    font.rasterize_glyph(
        &mut canvas,
        glyph_id,
        32.0,
        &Point2D::new(0.0, 32.0),
        HintingOptions::None,
        RasterizationOptions::GrayscaleAa,
    )
    .unwrap();
  11. Reference of available font-kit backends

    main

    Available Loaders

    • Core Text (macOS): System font loader. Does not do hinting except in bilevel rendering.
    • DirectWrite (Windows): System framework for text rendering. Supports vertical hinting but not full hinting.
    • FreeType (cross-platform): Full-featured font rendering framework.

    Available Sources

    • Core Text (macOS): System font database.
    • DirectWrite (Windows): API to query the system font database.
    • Fontconfig (cross-platform): Unix-specific API to query and match fonts.
    • Filesystem (cross-platform): Reads fonts from a path on disk (default on Android).
    • Memory (cross-platform): Reads from a fixed set of fonts in memory.
    • Multi (cross-platform): Allows querying multiple sources at once.