daegun

Rust types

33 types, extracted from the source at build time so this list cannot drift from it.

Bidi and segmentation

Unicode text algorithms that do not need a font: bidirectional ordering, script runs, and where a string may be split. All of these are free functions at the crate root: daegun::resolve_bidi and so on.

daegun::BidiParagraph
pub struct BidiParagraph {
    pub base_level: u8,
    pub levels: alloc::vec::Vec<u8>,
    pub visual_order: alloc::vec::Vec<usize>,
}

The result of running the bidirectional algorithm: a level per character, and the visual order.

base_level is the paragraph direction, 0 for left to right and 1 for right to left. levels gives each character its embedding level, and visual_order lists character indices in the order they should appear on screen.

daegun::LineBreak
pub struct LineBreak {
    pub at: usize,
    pub mandatory: bool,
}

One place a line may be broken: at, a byte offset, and mandatory, whether the break must be taken.

Mandatory breaks come from newlines and paragraph separators and must be honoured. The rest are opportunities you take only when the line is full.

daegun::VisualRun
pub struct VisualRun {
    pub chars: alloc::vec::Vec<usize>,
    pub level: u8,
}

One run of a single direction within a line, with the characters it covers and its level.

What line_visual_runs produces, in the order the runs should be drawn.

Drawing

A small front end that picks the CPU or the GPU for you, per glyph, and tells you which it chose.

DrawnGlyph
pub enum DrawnGlyph {
    Nothing,
    Cpu(RasterizedGlyph),
    Gpu(crate::daerizer::daegpu::GlyphSlot),
    GpuColor(Vec<ColorSlot>),
    Scene(crate::daerizer::RenderedScene),
    Reference(RasterizedGlyph),
    BatchFull,
    Refused(Refusal),
}

What happened to one glyph passed to draw_glyph – which path it took, or why it took none.

Cpu and Reference carry a finished bitmap; Gpu carries a slot to instance; GpuColor carries one slot per colored layer; Scene carries finished RGBA for a color glyph; Nothing means the glyph had no ink, which is normal for a space; BatchFull means the batch cannot take more geometry; Refused explains why the request could not be served. is_ok and bitmap cover the common checks.

DrawTarget
pub struct DrawTarget<'a> {
    pub batch: &'a mut GpuBatch,
    pub device: Option<&'a DeviceProfile>,
    pub policy: Policy,
}

Where drawn glyphs go, and the policy deciding whether each takes the CPU or the GPU.

Built with DrawTarget::new when a GPU is available or cpu_only when not. It borrows the GpuBatch it fills, so the batch outlives it and holds the geometry afterwards.

Font and metrics

Opening a font, and the switches that change how a glyph is drawn. Font is the handle every other call hangs off. It is cheap to clone, safe to share between threads, and it caches what it parses, so opening once and keeping it is always the right shape.

BidiRun
pub struct BidiRun {
    pub run: ShapedRun,
    pub level: u8,
    pub chars: Vec<usize>,
}

One run of single-direction text, already shaped, from Font::shape_bidi.

Carries the shaped glyphs, the bidi embedding level – even is left to right, odd is right to left – and chars, the indices of the characters this run covers. Runs come back in the order they should be drawn, so you can lay them out left to right without reordering.

ColorSlot
pub struct ColorSlot {
    pub slot: GlyphSlot,
    pub tint: [f32; 4],
}

One layer of a color glyph on the GPU: the slot to draw, and the tint to draw it in.

tint is straight-alpha RGBA in the 0 to 1 range, ready to pass to GlyphSlot::instance. Draw a glyph's slots in the order they were returned – they paint back to front and the shader does no depth testing.

Font
pub struct Font {
    /* private fields */
}

An open font, and the handle every other call hangs off.

Holds the parsed tables and the caches built from them, all behind private fields – you interact with it entirely through its methods. It is safe to share between threads and cheap to clone, and because it caches outlines, advances and rasterized glyphs, opening a font once and keeping it is always right. Open one with Font::from_bytes, from_vec or from_ttc.

let font = Font::from_bytes(&bytes)?;
let shared = std::sync::Arc::new(font);   // shape from several threads
FontError
pub struct FontError(/* private */);

Why a font could not be opened, or a subset could not be built.

Deliberately opaque: it carries a message for a human rather than a code to branch on, because there is nothing useful a caller can do differently for one kind of malformed font over another. Print it, log it, and reject the file.

GlyphAssembly
pub struct GlyphAssembly {
    pub italics_correction: f64,
    pub parts:              Vec<GlyphPart>,
}

The recipe for building an arbitrarily large symbol out of repeating pieces.

The parts run in order from one end to the other. Parts marked is_extender may be repeated as many times as needed; the others appear exactly once. Overlap adjacent parts by at least Font::math_min_connector_overlap or the joins will show.

GlyphClass
pub enum GlyphClass {
    Base,
    Ligature,
    Mark,
    Component,
}

What kind of glyph this is, from GDEF: Base, Ligature, Mark or Component.

Chiefly used to tell a combining mark from a spacing glyph, since a mark takes no advance of its own and attaches to the base before it.

GlyphPart
pub struct GlyphPart {
    pub glyph_id:               u16,
    pub start_connector_length: f64,
    pub end_connector_length:   f64,
    pub full_advance:           f64,
    pub is_extender:            bool,
}

One piece of an assembled symbol, with the overlap it allows at each end.

start_connector_length and end_connector_length say how much of each end is flat and may therefore be overlapped with a neighbor. full_advance is the whole piece. is_extender marks a piece that may repeat.

MathConstants
pub struct MathConstants {
    pub script_percent_scale_down: f64,
    pub script_script_percent_scale_down: f64,
    pub delimited_sub_formula_min_height: f64,
    pub display_operator_min_height: f64,
    pub math_leading: f64,
    pub axis_height: f64,
    pub accent_base_height: f64,
    pub flattened_accent_base_height: f64,
    pub subscript_shift_down: f64,
    pub subscript_top_max: f64,
    pub subscript_baseline_drop_min: f64,
    pub superscript_shift_up: f64,
    pub superscript_shift_up_cramped: f64,
    pub superscript_bottom_min: f64,
    pub superscript_baseline_drop_max: f64,
    pub sub_superscript_gap_min: f64,
    pub superscript_bottom_max_with_subscript: f64,
    pub space_after_script: f64,
    pub upper_limit_gap_min: f64,
    pub upper_limit_baseline_rise_min: f64,
    pub lower_limit_gap_min: f64,
    pub lower_limit_baseline_drop_min: f64,
    pub stack_top_shift_up: f64,
    pub stack_top_display_style_shift_up: f64,
    pub stack_bottom_shift_down: f64,
    pub stack_bottom_display_style_shift_down: f64,
    pub stack_gap_min: f64,
    pub stack_display_style_gap_min: f64,
    pub stretch_stack_top_shift_up: f64,
    pub stretch_stack_bottom_shift_down: f64,
    pub stretch_stack_gap_above_min: f64,
    pub stretch_stack_gap_below_min: f64,
    pub fraction_numerator_shift_up: f64,
    pub fraction_numerator_display_style_shift_up: f64,
    pub fraction_denominator_shift_down: f64,
    pub fraction_denominator_display_style_shift_down: f64,
    pub fraction_numerator_gap_min: f64,
    pub fraction_num_display_style_gap_min: f64,
    pub fraction_rule_thickness: f64,
    pub fraction_denominator_gap_min: f64,
    pub fraction_denom_display_style_gap_min: f64,
    pub skewed_fraction_horizontal_gap: f64,
    pub skewed_fraction_vertical_gap: f64,
    pub overbar_vertical_gap: f64,
    pub overbar_rule_thickness: f64,
    pub overbar_extra_ascender: f64,
    pub underbar_vertical_gap: f64,
    pub underbar_rule_thickness: f64,
    pub underbar_extra_descender: f64,
    pub radical_vertical_gap: f64,
    pub radical_display_style_vertical_gap: f64,
    pub radical_rule_thickness: f64,
    pub radical_extra_ascender: f64,
    pub radical_kern_before_degree: f64,
    pub radical_kern_after_degree: f64,
    pub radical_degree_bottom_raise_percent: f64,
}

The MATH table's layout constants – dozens of measurements math typesetting needs.

Superscript and subscript shifts, fraction bar thickness and gaps, radical clearances, the axis height that fraction bars and operators center on, and the scale-down percentages for nested script levels. All on the 1000-unit em, except the percentages, which are percentages.

MathGlyphConstruction
pub struct MathGlyphConstruction {
    pub assembly: Option<GlyphAssembly>,
    pub variants: Vec<MathGlyphVariant>,
}

How a symbol grows: a list of progressively larger glyphs, and optionally a recipe for assembling one from pieces.

A bracket around a tall expression grows in two stages. First the font offers variants, discrete larger glyphs – try those in order and take the first that fits. When none is large enough, assembly stacks pieces instead, repeating the extenders as many times as needed.

MathGlyphVariant
pub struct MathGlyphVariant {
    pub glyph_id: u16,
    pub advance:  f64,
}

One of the fixed larger forms of a growing symbol, with its advance.

The advance is along the growth direction – height for a vertical variant, width for a horizontal one – on the 1000-unit em, so you can pick the smallest that fits.

Os2Info
pub struct Os2Info {
    pub version: u16,
    pub family_class: Option<u16>,
    pub selection: Option<u16>,
    pub win_metrics: Option<WinMetrics>,
    pub typo_metrics: Option<TypoLineMetrics>,
}

The OS/2 table: the font's own claims about its style, its class and its vertical metrics.

The style predicates – is_italic, is_bold, is_regular, is_oblique, uses_typo_metrics – are methods on this type rather than on Font. win_metrics and typo_metrics are the two sets of vertical metrics that so often disagree; uses_typo_metrics says which the font wants you to believe, and Font::line_metrics applies that rule for you.

RasterizedGlyph
pub struct RasterizedGlyph {
    pub metrics: Metrics,
    pub bitmap: Vec<u8>,
}

One rasterized glyph: its coverage bitmap and where that bitmap goes.

bitmap is coverage, one byte per pixel – or three under a subpixel layout – and metrics says how big it is and where it sits relative to the pen. It is a mask, not a color: you supply the color and use the coverage as alpha.

RasterOptions
pub struct RasterOptions {
    pub layout: SubpixelLayout,
    pub gamma: Option<f32>,
    pub transform: Option<[f32; 6]>,
    pub hinting: HintMode,
    pub stroke: Option<StrokeStyle>,
    pub embolden: Option<f32>,
    pub oblique: Option<f32>,
}

The switches that change how a glyph is rasterized: hinting, gamma, transform, stroke, weight and slant.

A builder, so you name only what you change and leave the rest at its default. The fields are public if you would rather construct it directly. Its defaults are grayscale coverage with no hinting, no gamma and no transform.

let opts = RasterOptions::default()
    .with_hinting(HintMode::Auto)
    .with_gamma(1.8);
StatInfo
pub struct StatInfo {
    pub axes:                 Vec<StatAxis>,
    pub values:                Vec<StatAxisValue>,
    pub elided_fallback_name: Option<String>,
}

The STAT table: how this font sits within its wider family.

Names the family's design axes and the value this particular face takes on each, so a font menu can group separate files into one family with a weight slider. elided_fallback_name is the name to use when every axis is at its default – usually "Regular".

SubSuperMetrics
pub struct SubSuperMetrics {
    pub x_size:   i32,
    pub y_size:   i32,
    pub x_offset: i32,
    pub y_offset: i32,
}

The size and offset a font specifies for subscripts or superscripts.

Synthesising a superscript by scaling to 60% and shifting up by a guess is what most software does and it rarely matches the design. These are the font's own numbers, on the 1000-unit em.

TypographicMetrics
pub struct TypographicMetrics {
    pub x_height:            i32,
    pub underline_position:  i32,
    pub underline_thickness: i32,
    pub strikeout_size:      i32,
    pub strikeout_position:  i32,
    pub subscript:           SubSuperMetrics,
    pub superscript:         SubSuperMetrics,
}

The secondary measurements a text renderer needs: x-height, underline, strikeout, and subscript and superscript placement.

Everything needed to decorate text correctly rather than guessing. Drawing an underline at a fixed offset looks wrong across fonts; underline_position and underline_thickness are what the designer chose. All values are on the 1000-unit em.

TypoLineMetrics
pub struct TypoLineMetrics {
    pub ascender:  i32,
    pub descender: i32,
    pub line_gap:  i32,
}

The typographic ascender, descender and line gap from OS/2.

The designer's intended line spacing. descender is negative, being a coordinate below the baseline, so line height is ascender - descender + line_gap.

WinMetrics
pub struct WinMetrics {
    pub ascent:  i32,
    pub descent: i32,
}

The Windows ascent and descent from OS/2, both positive numbers.

These describe the clipping box Windows historically used, so they are usually larger than the typographic metrics. Note that unlike TypoLineMetrics::descender, the descent here is positive – it is a distance, not a coordinate.

Justification

Stretching or shrinking a line to a target width using the font's own rules.

daegun::Justified
pub struct Justified {
    pub run: ShapedRun,
    pub level: Option<usize>,
    pub shrink: bool,
    pub width: f64,
    pub best_effort: bool,
}

The result of justifying a line: the shaped run, the width achieved, and whether it fell short.

width is what was actually achieved and best_effort is set when the target could not be met exactly – a line with nothing stretchable in it cannot always be made to fit. shrink says whether the line was tightened rather than stretched, and level which justification level was applied.

daegun::JustifyOptions
pub struct JustifyOptions<'a> {
    pub script_tag: &'a str,
    pub lang_sys_tag: Option<&'a str>,
    pub target_width: f64,
    pub tolerance: f64,
}

What Font::justify needs: the script, the target width, and how much slack to allow.

target_width is on the 1000-unit em. tolerance is how far from the target is acceptable before the result is marked best-effort. script_tag selects the justification rules, since Arabic and Latin justify quite differently, and lang_sys_tag narrows them further or may be None. There is no Default – name all four fields.

Layout

The direction a laid-out line runs.

daegun::Align
pub enum Align {
    #[default]
    Start,
    End,
    Center,
    Justify,
}

How a line is placed within the measure: start, end, center or justified.

Start and End follow the paragraph direction rather than naming left and right, so Start is left in English and right in Arabic.

daegun::LayoutLine
pub struct LayoutLine {
    pub runs: Vec<PositionedRun>,
    pub chars: (usize, usize),
    pub baseline: f64,
    pub inline_size: f64,
    pub ascent: f64,
    pub descent: f64,
    pub hard_break: bool,
}

One line of a laid-out paragraph, with its runs and its position.

Runs within a line are already in visual order, including across direction changes.

daegun::LayoutOptions
pub struct LayoutOptions<'a> {
    pub max_inline_size: f64,
    pub align: Align,
    pub writing_mode: WritingMode,
    pub text_orientation: TextOrientation,
    pub base_direction: Option<bool>,
    pub language: Option<&'a str>,
    pub line_height: Option<f64>,
    pub strategy: BreakStrategy,
    pub max_lines: Option<usize>,
}

What Font::layout needs: the measure, the line height, the break strategy, the alignment and the writing mode.

Sizes are on the 1000-unit em, so a pixel measure goes in as px_value / (px / 1000.0). max_inline_size is the measure to wrap within. line_height of None uses the font's own metrics. Construct it with ..LayoutOptions::default() so new fields do not break your code.

let scale = 16.0 / 1000.0;
let opts = LayoutOptions {
    max_inline_size: 320.0 / scale,
    line_height: Some(24.0 / scale),
    strategy: BreakStrategy::Optimal,
    ..LayoutOptions::default()
};
daegun::PositionedRun
pub struct PositionedRun {
    pub run: ShapedRun,
    pub offset: (f64, f64),
    pub level: u8,
    pub chars: (usize, usize),
    pub upright: bool,
}

One shaped run within a line, together with where the line places it.

run is the shaped glyphs and offset is a (f64, f64) tuple placing the run within the line, both on the 1000-unit em – destructure it rather than treating it as one number. level carries the bidi embedding level, chars the character range it covers, and upright whether it stays upright in vertical text. Adding the run's own advances to the offset gives each glyph its pen position.

daegun::TextLayout
pub struct TextLayout {
    pub lines: Vec<LayoutLine>,
    pub inline_size: f64,
    pub block_size: f64,
    pub truncated: Option<usize>,
}

A laid-out paragraph: its lines, each with its positioned runs.

The finished product of Font::layout. Walk lines, then the runs within each, and draw each run at its offset. All positions are on the 1000-unit em.

daegun::TextOrientation
pub enum TextOrientation {
    #[default]
    Mixed,
    Upright,
    Sideways,
}

How individual glyphs are turned within vertical text.

In vertical Japanese, Han characters stay upright while Latin words are usually rotated 90 degrees. This selects that behavior, matching the CSS property of the same name.

daegun::WritingMode
pub enum WritingMode {
    #[default]
    Horizontal,
    VerticalRl,
    VerticalLr,
}

Which way the text runs: Horizontal, VerticalRl or VerticalLr.

The two vertical modes both run glyphs downward and differ only in whether successive lines advance to the left – traditional for Japanese and Chinese – or to the right.

Line breaking

Where a paragraph may break, and how a chosen break behaves.

daegun::BreakStrategy
pub enum BreakStrategy {
    #[default]
    Greedy,
    Optimal,
}

How Font::layout chooses where to break: Greedy or Optimal.

Greedy fills each line as far as it can and breaks at the last opportunity that fits – fast, and what most software does. Optimal considers the paragraph as a whole and picks the set of breaks with the least total raggedness, which costs more and looks markedly better, especially in narrow measures.

Type to search.