Skip to main content

FcFontRegistry

Struct FcFontRegistry 

Source
pub struct FcFontRegistry {
Show 13 fields pub cache: FcFontCache, pub known_paths: RwLock<BTreeMap<String, Vec<PathBuf>>>, pub build_queue: Mutex<Vec<FcBuildJob>>, pub queue_condvar: Condvar, pub processed_paths: Mutex<HashSet<PathBuf>>, pub completed_paths: Mutex<HashSet<PathBuf>>, pub progress: Condvar, pub scan_complete: Atomic<bool>, pub build_complete: Atomic<bool>, pub shutdown: Atomic<bool>, pub cache_loaded: Atomic<bool>, pub lazy_scout: Atomic<bool>, pub os: OperatingSystem,
}
Expand description

Thread-safe, incrementally-populated font registry.

Wraps an FcFontCache behind a RwLock so that background threads can populate it concurrently while the main thread reads from it.

Fields§

§cache: FcFontCache

The underlying font cache, populated incrementally by Builder threads.

As of v4.1, FcFontCache carries its own internal RwLock and Arc, so the registry can hand out handles (via shared_cache) that live-update with builder writes — no outer lock needed, no staleness for snapshot-holders downstream.

§known_paths: RwLock<BTreeMap<String, Vec<PathBuf>>>

Maps guessed lowercase family name → file paths

§build_queue: Mutex<Vec<FcBuildJob>>§queue_condvar: Condvar

Notified when new jobs are added to build_queue or on shutdown. Builder threads wait on this (paired with build_queue).

§processed_paths: Mutex<HashSet<PathBuf>>

Paths claimed for parsing (set BEFORE parsing, for deduplication).

§completed_paths: Mutex<HashSet<PathBuf>>

Paths fully parsed and inserted into cache (set AFTER parsing).

§progress: Condvar

Notified when any progress occurs: font completed, scan done, build done. The main thread waits on this (paired with completed_paths).

§scan_complete: Atomic<bool>§build_complete: Atomic<bool>§shutdown: Atomic<bool>§cache_loaded: Atomic<bool>

Whether a disk cache was successfully loaded (skip blocking in request_fonts)

§lazy_scout: Atomic<bool>

When true, the scout populates known_paths + sets scan_complete but does NOT push every path onto build_queue. Builders therefore idle until a caller runs FcFontRegistry::request_fonts or FcFontRegistry::request_and_resolve_with_scripts, which priority-bumps only the requested families into the queue. Cuts steady-state memory: the ~300 system fonts on macOS each cost ~50 KiB of parsed NAME + OS/2 metadata in the cache’s pattern map — skipping those that the current workload never touches saves ~15 MiB on a short-lived headless render.

Set via FcFontRegistry::set_scout_lazy before FcFontRegistry::spawn_scout_and_builders. Defaults to false to preserve the existing eager-scout behaviour for long-running embedders who want the disk cache to populate in the background.

§os: OperatingSystem

Implementations§

Source§

impl FcFontRegistry

Source

pub fn new() -> Arc<FcFontRegistry>

Create a new empty registry.

Source

pub fn set_scout_lazy(&self, lazy: bool)

Enable/disable lazy scout mode. See FcFontRegistry::lazy_scout for what this changes. Must be called before FcFontRegistry::spawn_scout_and_builders — the scout thread reads the flag once when it starts iterating the build queue.

Source

pub fn register_memory_fonts(&self, fonts: Vec<NamedFont>)

Register in-memory (bundled) fonts. These are available immediately.

Source

pub fn spawn_scout_and_builders(self: &Arc<FcFontRegistry>)

Spawn the Scout thread and Builder pool. Returns immediately.

Source

pub fn request_fonts( &self, family_stacks: &[Vec<String>], ) -> Vec<FontFallbackChain>

Block the calling thread until all requested font families are loaded (or confirmed to not exist on the system).

This is called by the layout engine before the first layout pass. It boosts the priority of any not-yet-loaded fonts to Critical and waits for the Builder to process them.

Hard timeout: 5 seconds.

Source

pub fn get_metadata_by_id(&self, id: &FontId) -> Option<FcPattern>

Get font metadata by ID.

Source

pub fn get_font_bytes(&self, id: &FontId) -> Option<Arc<FontBytes>>

Get font bytes for a given font ID — disk-backed fonts come back as a shared mmap; in-memory fonts as Owned. See FcFontCache::get_font_bytes for the lifetime semantics.

Source

pub fn get_disk_font_path(&self, id: &FontId) -> Option<FcFontPath>

Get the disk font path for a font ID.

Source

pub fn is_memory_font(&self, id: &FontId) -> bool

Check if a font ID is a memory font.

Source

pub fn list(&self) -> Vec<(FcPattern, FontId)>

List all known fonts (pattern + ID pairs).

Source

pub fn query(&self, pattern: &FcPattern) -> Option<FontMatch>

Query the registry for a font matching the given pattern.

Source

pub fn resolve_font_chain( &self, font_families: &[String], weight: FcWeight, italic: PatternMatch, oblique: PatternMatch, ) -> FontFallbackChain

Resolve a complete font fallback chain for a CSS font-family stack.

Source

pub fn request_and_resolve_with_scripts( &self, font_families: &[String], weight: FcWeight, italic: PatternMatch, oblique: PatternMatch, scripts_hint: Option<&[UnicodeRange]>, ) -> FontFallbackChain

On-demand font-chain resolution: triggers the scout + builder to parse the requested families (if not already parsed), waits for them via condvar, then resolves a full fallback chain with the caller-supplied weight / italic / oblique / scripts_hint.

This is the “scout-on-demand” entry point: callers can skip the eager request_fonts(common_stacks) at init and pay the per-family parse only when a DOM actually needs that family. On excel.html that cuts the init cost from ~150 ms to ~10 ms and peak RSS from ~71 MiB to ~55 MiB because only the ~2 families excel uses get parsed, not the full common-stack set (~35 fonts across Helvetica/Lucida/Menlo/Times/NewYork/ Courier/SFNS).

Re-entrant from layout: holds no locks for the duration of the call, and request_fonts internally handles the scan_complete wait + priority-bump + completed_paths wait.

Source

pub fn shared_cache(&self) -> FcFontCache

Get a shared handle on the cache. The returned FcFontCache shares state with this registry (and with every other holder of the handle): writes by builder threads via [insert_font] are immediately visible to all readers.

Replaces v4.0’s into_fc_font_cache (which took a deep snapshot) — the deep copy was the source of the stale-state bug in lazy-scout mode, since builders kept writing to the registry’s cache while downstream holders were stuck on a frozen copy.

Source

pub fn wait_for_scout(&self)

Block until the background scout + builder threads have populated the in-memory pattern map with every font’s NAME + OS/2 metadata (most importantly unicode_ranges). Returns immediately if a disk cache was loaded, both scan + build already completed, or the 5 s deadline elapses.

Callers that skip [request_fonts] but still need a fully populated FcFontCache snapshot (e.g. headless renderers that do their own font-chain resolution) must invoke this first — otherwise into_fc_font_cache may capture the cache mid-build and every resolve_char call will return None because unicode_ranges is empty for not-yet-parsed fonts.

This waits for build_complete (not just scan_complete) — the scout finishes readdir quickly but the builder threads do the actual header parsing, and it is the builder output that populates unicode_ranges.

Source

pub fn shutdown(&self)

Signal all background threads to shut down.

Source

pub fn is_scan_complete(&self) -> bool

Returns true if the Scout has finished enumerating all font directories.

Source

pub fn is_build_complete(&self) -> bool

Returns true if all fonts in the queue have been processed.

Source

pub fn is_cache_loaded(&self) -> bool

Returns true if a disk cache was successfully loaded at startup.

Source

pub fn request_fonts_fast( &self, requests: &[(Vec<String>, BTreeSet<char>)], weight: FcWeight, italic: PatternMatch, ) -> Vec<FontFallbackChain>

Fast-path font resolution: for each stack + codepoints pair, return a FontFallbackChain built by cmap-probing candidate files until coverage is satisfied.

Semantics (one face per family — CSS-correct):

  • Iterate the expanded family stack in CSS order.
  • For each family, walk candidate file paths from known_paths, and within each file walk faces sorted by style match (best (bold, italic) match to the request first). The first face that covers any currently-uncovered codepoint is added to the chain; we then move to the next family.
  • Stop the whole stack as soon as every requested codepoint is covered.
  • Any codepoints still uncovered after the last family is a miss (e.g. emoji against a sans-serif-only stack); the shaper will display .notdef for them. This matches CSS’s behaviour for fonts that don’t cover the requested chars.

Bypasses the builder-thread dance entirely — no jobs queued, no 5 s deadline, no full allsorts parse. ~100 µs per face touched on warm FS.

Source

pub fn insert_font(&self, pattern: FcPattern, path: FcFontPath)

Insert a parsed font into the cache (called by Builder threads).

Source§

impl FcFontRegistry

Source

pub fn scout_thread(&self)

Scout thread: enumerates font directories and populates the build queue.

  1. Walks all OS font directories recursively, collecting font file paths.
  2. Tokenizes each filename and assigns a priority (High for common OS fonts, Low for everything else).
  3. Populates known_paths (family → file paths) and build_queue.
  4. Signals scan_complete when done.
Source

pub fn builder_thread(&self)

Builder thread loop: pops jobs from the priority queue, parses fonts, and inserts results into the registry.

Exit conditions:

  • shutdown is set (registry is dropping).
  • In eager mode: once the scout finishes the initial directory walk, queue empties, and every queued path is processed. At that point build_complete flips and the thread returns.
  • In lazy-scout mode: the thread keeps waiting on queue_condvar indefinitely, because the scout does not pre-queue anything — all jobs come in later from FcFontRegistry::request_fonts. Exiting on the “queue empty + scan complete” condition (as the eager path does) would race the Critical job push and cause the request to hang forever.
Source§

impl FcFontRegistry

Source

pub fn load_from_disk_cache(&self) -> Option<()>

Load font metadata from the on-disk cache.

Reads and deserializes the bincode font manifest from the platform cache directory, then populates the inner FcFontCache with all cached patterns, font paths, and token indices. Marks all cached file paths as processed/completed so builder threads skip them.

Returns Some(()) on success, None if the cache is missing, unreadable, malformed, or has a version mismatch. On WASM this is a no-op that always returns None.

Source

pub fn save_to_disk_cache(&self) -> Option<()>

Serialize the current registry state to the on-disk font cache.

Collects all discovered font paths and their parsed metadata into a FontManifest, then writes it as bincode to the platform cache directory (e.g. ~/.cache/rfc/fonts/manifest.bin on Linux).

Returns None if the cache path cannot be determined, the parent directory cannot be created, or serialization / writing fails. On WASM this is a no-op that always returns None (no filesystem access).

Trait Implementations§

Source§

impl Debug for FcFontRegistry

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Drop for FcFontRegistry

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.