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::BidiParagraphpub 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_levelis the paragraph direction, 0 for left to right and 1 for right to left.levelsgives each character its embedding level, andvisual_orderlists character indices in the order they should appear on screen.daegun::LineBreakpub struct LineBreak { pub at: usize, pub mandatory: bool, }One place a line may be broken:
at, a byte offset, andmandatory, 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::VisualRunpub 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_runsproduces, 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.
DrawnGlyphpub 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.CpuandReferencecarry a finished bitmap;Gpucarries a slot to instance;GpuColorcarries one slot per colored layer;Scenecarries finished RGBA for a color glyph;Nothingmeans the glyph had no ink, which is normal for a space;BatchFullmeans the batch cannot take more geometry;Refusedexplains why the request could not be served.is_okandbitmapcover the common checks.DrawTargetpub 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::newwhen a GPU is available orcpu_onlywhen not. It borrows theGpuBatchit 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.
BidiRunpub 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 – andchars, 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.ColorSlotpub 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.
tintis straight-alpha RGBA in the 0 to 1 range, ready to pass toGlyphSlot::instance. Draw a glyph's slots in the order they were returned – they paint back to front and the shader does no depth testing.Fontpub 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_vecorfrom_ttc.let font = Font::from_bytes(&bytes)?; let shared = std::sync::Arc::new(font); // shape from several threadsFontErrorpub 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.
GlyphAssemblypub struct GlyphAssembly { pub italics_correction: f64, pub parts: Vec<GlyphPart>, }The recipe for building an arbitrarily large symbol out of repeating pieces.
The
partsrun in order from one end to the other. Parts markedis_extendermay be repeated as many times as needed; the others appear exactly once. Overlap adjacent parts by at leastFont::math_min_connector_overlapor the joins will show.GlyphClasspub enum GlyphClass { Base, Ligature, Mark, Component, }What kind of glyph this is, from
GDEF:Base,Ligature,MarkorComponent.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.
GlyphPartpub 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_lengthandend_connector_lengthsay how much of each end is flat and may therefore be overlapped with a neighbor.full_advanceis the whole piece.is_extendermarks a piece that may repeat.MathConstantspub 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
MATHtable'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.
MathGlyphConstructionpub 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,assemblystacks pieces instead, repeating the extenders as many times as needed.MathGlyphVariantpub 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.
Os2Infopub 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 onFont.win_metricsandtypo_metricsare the two sets of vertical metrics that so often disagree;uses_typo_metricssays which the font wants you to believe, andFont::line_metricsapplies that rule for you.RasterizedGlyphpub struct RasterizedGlyph { pub metrics: Metrics, pub bitmap: Vec<u8>, }One rasterized glyph: its coverage bitmap and where that bitmap goes.
bitmapis coverage, one byte per pixel – or three under a subpixel layout – andmetricssays 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.RasterOptionspub 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);StatInfopub struct StatInfo { pub axes: Vec<StatAxis>, pub values: Vec<StatAxisValue>, pub elided_fallback_name: Option<String>, }The
STATtable: 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_nameis the name to use when every axis is at its default – usually "Regular".SubSuperMetricspub 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.
TypographicMetricspub 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_positionandunderline_thicknessare what the designer chose. All values are on the 1000-unit em.TypoLineMetricspub 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.
descenderis negative, being a coordinate below the baseline, so line height isascender - descender + line_gap.WinMetricspub 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::Justifiedpub 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.
widthis what was actually achieved andbest_effortis set when the target could not be met exactly – a line with nothing stretchable in it cannot always be made to fit.shrinksays whether the line was tightened rather than stretched, andlevelwhich justification level was applied.daegun::JustifyOptionspub struct JustifyOptions<'a> { pub script_tag: &'a str, pub lang_sys_tag: Option<&'a str>, pub target_width: f64, pub tolerance: f64, }What
Font::justifyneeds: the script, the target width, and how much slack to allow.target_widthis on the 1000-unit em.toleranceis how far from the target is acceptable before the result is marked best-effort.script_tagselects the justification rules, since Arabic and Latin justify quite differently, andlang_sys_tagnarrows them further or may beNone. There is noDefault– name all four fields.
Layout
The direction a laid-out line runs.
daegun::Alignpub enum Align { #[default] Start, End, Center, Justify, }How a line is placed within the measure: start, end, center or justified.
StartandEndfollow the paragraph direction rather than naming left and right, soStartis left in English and right in Arabic.daegun::LayoutLinepub 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::LayoutOptionspub 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::layoutneeds: 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_sizeis the measure to wrap within.line_heightofNoneuses 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::PositionedRunpub 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.
runis the shaped glyphs andoffsetis 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.levelcarries the bidi embedding level,charsthe character range it covers, anduprightwhether it stays upright in vertical text. Adding the run's own advances to the offset gives each glyph its pen position.daegun::TextLayoutpub 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. Walklines, then therunswithin each, and draw each run at its offset. All positions are on the 1000-unit em.daegun::TextOrientationpub 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::WritingModepub enum WritingMode { #[default] Horizontal, VerticalRl, VerticalLr, }Which way the text runs:
Horizontal,VerticalRlorVerticalLr.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::BreakStrategypub enum BreakStrategy { #[default] Greedy, Optimal, }How
Font::layoutchooses where to break:GreedyorOptimal.Greedyfills each line as far as it can and breaks at the last opportunity that fits – fast, and what most software does.Optimalconsiders 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.