Skip to main content

shape_with_fallback

Function shape_with_fallback 

Source
pub fn shape_with_fallback(
    primary: Font,
    fallbacks: &[EmbeddedFontId],
    size_pt: f32,
    text: &str,
) -> Vec<WordSubRun>
Expand description

Shape text against primary with per-glyph fallback. Walks each HarfBuzz cluster in the primary’s shaped output; clusters that contain any .notdef (GID 0) glyph are re-shaped against each embedded face in fallbacks in order. The first fallback to produce a glyph stream with no .notdef wins the whole cluster (cluster- granular replacement, never partial: partial replacement would duplicate bases, drop marks, break ligatures).

Returns one WordSubRun per contiguous source span that shares a face. Each sub-run’s glyphs cluster offsets are rebased to the sub-run’s local text, so mos-pdf::plan_embedded reads /ToUnicode clusters with no awareness of the parent word.

Input is normalized through crate::nfc_text before fallback shaping. Each returned WordSubRun::text is therefore a slice of the normalized NFC string; decomposed caller input may not be byte-identical to returned text.

Base14 primary: returns a single sub-run with empty glyphs (Base14 has no glyph stream to inspect for .notdef; fallback isn’t meaningful for that path). The advance comes from the AFM width sum via text_width, same as the legacy shape_text path.

All-fallback-fails behaviour: if no face in fallbacks covers a .notdef cluster, the cluster stays in primary with .notdef glyphs. plan_embedded already skips GID 0 from gid_to_text, so copy-paste extraction is correct (empty for the un-renderable span); the PDF reader renders an empty box.

§Examples

use mos_fonts::{Base14Font, Font, shape_with_fallback};

let subruns = shape_with_fallback(Font::Base14(Base14Font::Helvetica), &[], 10.0, "A");

assert_eq!(subruns.len(), 1);
assert_eq!(subruns[0].text, "A");