pub struct FaceSet { /* private fields */ }Expand description
The host’s registered fonts: families for styles to name, plus a global
fallback chain consulted per character. Immutable once built —
register everything, then Arc it for builders and the renderer.
Implementations§
Source§impl FaceSet
impl FaceSet
pub fn new() -> Self
Sourcepub fn register(&mut self, family: &str, bytes: Vec<u8>) -> Option<FontId>
pub fn register(&mut self, family: &str, bytes: Vec<u8>) -> Option<FontId>
Register font bytes under a family name (regular weight/style).
Returns None when the bytes don’t parse as a font.
Examples found in repository?
16fn main() {
17 let dir = concat!(env!("CARGO_MANIFEST_DIR"), "/../../assets/fonts");
18 // A CJK face is 20k+ glyphs and too big to vendor: point VALO_CJK_FONT
19 // at one to get the CJK column, otherwise the bench runs latin only.
20 let cjk_file = std::env::var("VALO_CJK_FONT").unwrap_or_default();
21 let mut fonts = FaceSet::default();
22 let latin = fonts
23 .register(
24 "Latin",
25 std::fs::read(format!("{dir}/fira_sans.ttf")).unwrap(),
26 )
27 .unwrap();
28 let cjk = std::fs::read(cjk_file)
29 .ok()
30 .and_then(|bytes| fonts.register("CJK", bytes));
31
32 let mut sets = vec![("latin", latin, glyphs(&fonts, latin, LATIN))];
33 if let Some(id) = cjk {
34 sets.push(("cjk", id, glyphs(&fonts, id, CJK)));
35 }
36
37 println!(
38 "{:>6} {:>6} {:>12} {:>12} (µs/glyph, n={})",
39 "set",
40 "px",
41 "alpha",
42 "sdf",
43 LATIN.len()
44 );
45 let mut raster = Rasterizer::new();
46 for (label, font, ids) in &sets {
47 for px in SIZES {
48 let alpha = time_per_glyph(ids, |g| {
49 raster.alpha(fonts.get(*font), g, px, 0.0);
50 });
51 let mut raster2 = Rasterizer::new();
52 let sdf = time_per_glyph(ids, |g| {
53 raster2.sdf(fonts.get(*font), g, px);
54 });
55 println!("{label:>6} {px:>6.0} {alpha:>10.1}µs {sdf:>10.1}µs");
56 }
57 }
58}Sourcepub fn register_with(
&mut self,
family: &str,
attrs: FontAttrs,
bytes: Vec<u8>,
) -> Option<FontId>
pub fn register_with( &mut self, family: &str, attrs: FontAttrs, bytes: Vec<u8>, ) -> Option<FontId>
Register one variant of a family — resolve picks the nearest
weight with a matching style (CSS §5.2, simplified: style first,
then minimal weight distance, ties to the first registered).
Sourcepub fn add(&mut self, font: Font) -> FontId
pub fn add(&mut self, font: Font) -> FontId
Add an already-parsed Font under ITS OWN name/attrs — the
SkTypeface → registerTypeface shape.
Sourcepub fn with_font(&self, font: Font) -> (FaceSet, FontId)
pub fn with_font(&self, font: Font) -> (FaceSet, FontId)
A new collection = this one + font. Faces are shared by Arc, so
this is O(faces) pointer clones — no re-parsing, and every existing
holder of the old collection is untouched.
Sourcepub fn with_fallbacks(&self, fallbacks: Vec<FontId>) -> FaceSet
pub fn with_fallbacks(&self, fallbacks: Vec<FontId>) -> FaceSet
A new collection with the fallback chain REPLACED (order matters).
Sourcepub fn add_fallback(&mut self, id: FontId)
pub fn add_fallback(&mut self, id: FontId)
Append to the global fallback chain (consulted after a style’s own families: nearest attrs among the faces covering the character, ties in chain order).
Sourcepub fn grown_by(
&self,
source: &mut dyn FontSource,
demand: &FontDemand,
) -> Option<FaceSet>
pub fn grown_by( &self, source: &mut dyn FontSource, demand: &FontDemand, ) -> Option<FaceSet>
Grow this collection to answer demand from source: demanded
families register under their own names PLUS the demanded name as
an alias (a localized or differently-spelled request must match on
the next layout, or a loop around this call could demand forever);
codepoints still uncovered afterwards extend the fallback chain
with a face matching the demanding span’s attrs. Some(grown)
only when something new was found — the caller’s signal to
re-register the collection and lay out again.
Grow a COPY of this face set to answer demand from source — the
out-of-band path (a host that already knows what it wants). Live
resolution goes through FontCollection, which owns its sources.
Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
True until the first add/register — building paragraphs against
an empty collection is a contract violation (resolve asserts).
Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Faces registered so far. Ids are append-only, so a holder of an older
collection can name the faces added since: old.len()..new.len().
Sourcepub fn get_arc(&self, id: FontId) -> Arc<Font> ⓘ
pub fn get_arc(&self, id: FontId) -> Arc<Font> ⓘ
The shared instance behind id — what glyph runs carry to the
renderer (Skia: blobs hold sk_sp<SkTypeface>).
Sourcepub fn get(&self, id: FontId) -> &Font
pub fn get(&self, id: FontId) -> &Font
Examples found in repository?
16fn main() {
17 let dir = concat!(env!("CARGO_MANIFEST_DIR"), "/../../assets/fonts");
18 // A CJK face is 20k+ glyphs and too big to vendor: point VALO_CJK_FONT
19 // at one to get the CJK column, otherwise the bench runs latin only.
20 let cjk_file = std::env::var("VALO_CJK_FONT").unwrap_or_default();
21 let mut fonts = FaceSet::default();
22 let latin = fonts
23 .register(
24 "Latin",
25 std::fs::read(format!("{dir}/fira_sans.ttf")).unwrap(),
26 )
27 .unwrap();
28 let cjk = std::fs::read(cjk_file)
29 .ok()
30 .and_then(|bytes| fonts.register("CJK", bytes));
31
32 let mut sets = vec![("latin", latin, glyphs(&fonts, latin, LATIN))];
33 if let Some(id) = cjk {
34 sets.push(("cjk", id, glyphs(&fonts, id, CJK)));
35 }
36
37 println!(
38 "{:>6} {:>6} {:>12} {:>12} (µs/glyph, n={})",
39 "set",
40 "px",
41 "alpha",
42 "sdf",
43 LATIN.len()
44 );
45 let mut raster = Rasterizer::new();
46 for (label, font, ids) in &sets {
47 for px in SIZES {
48 let alpha = time_per_glyph(ids, |g| {
49 raster.alpha(fonts.get(*font), g, px, 0.0);
50 });
51 let mut raster2 = Rasterizer::new();
52 let sdf = time_per_glyph(ids, |g| {
53 raster2.sdf(fonts.get(*font), g, px);
54 });
55 println!("{label:>6} {px:>6.0} {alpha:>10.1}µs {sdf:>10.1}µs");
56 }
57 }
58}
59
60fn glyphs(fonts: &FaceSet, id: FontId, text: &str) -> Vec<u32> {
61 let font = fonts.get(id);
62 text.chars().filter_map(|ch| font.glyph_for(ch)).collect()
63}pub fn family(&self, name: &str) -> Option<FontId>
Sourcepub fn faces<'a>(&'a self, name: &'a str) -> impl Iterator<Item = FontId> + 'a
pub fn faces<'a>(&'a self, name: &'a str) -> impl Iterator<Item = FontId> + 'a
Ids of EVERY face answering to name, in registration order. Subset
families (css2/cn-font-split unicode-range chunks) register many
faces under one name with disjoint coverage — a fallback chain built
from Self::family alone reaches only the first-loaded chunk, so
hosts expand fallback names with this.
Sourcepub fn family_variant(&self, name: &str, attrs: FontAttrs) -> Option<FontId>
pub fn family_variant(&self, name: &str, attrs: FontAttrs) -> Option<FontId>
The family variant nearest attrs: matching style wins, then the
smallest weight distance (ties to the first registered).
Sourcepub fn resolve(&self, families: &[String], attrs: FontAttrs, ch: char) -> FontId
pub fn resolve(&self, families: &[String], attrs: FontAttrs, ch: char) -> FontId
The font that renders ch for a style: per requested family, the
nearest variant that COVERS ch — subset families (cn-font-split
chunks) carry one unicode range per face, so coverage must look past
the best-attrs face. Then the fallback chain, else the first
candidate.
Sourcepub fn resolve_covered(
&self,
families: &[String],
attrs: FontAttrs,
ch: char,
) -> (FontId, bool)
pub fn resolve_covered( &self, families: &[String], attrs: FontAttrs, ch: char, ) -> (FontId, bool)
Self::resolve plus whether ANYTHING actually covers ch — false
means the returned face will shape .notdef. The demand signal:
callers report uncovered chars to the host, which
decides where fonts come from — valo only detects.