pub struct FontCache { /* private fields */ }Expand description
Per-document caches: loaded fonts, and the font-identity counter.
A value the document owns rather than process-wide state, so two documents
loaded on two threads never share a face or a font identity. Send + Sync
and shared by Arc, so every session over one document — every worker of
a parallel render, and a text run and a render run alike — loads each font
once between them rather than once each.
§What is cached, and what is not
The key is the ObjRef that named the /Font resource. A font
dictionary written inline, with no reference of its own, is not cached
and is loaded afresh at every use: two inline copies genuinely are two
fonts, and there is no document-scoped identity to key them on.
The value is an Arc<Font>, so a hit shares the whole loaded font — its
parsed /ToUnicode, its CID tables and its glyph cache — rather than
rebuilding them. Text extraction’s duplicate suppression compares fonts by
that pointer, so sharing is load-bearing for correctness as well as speed.
A dictionary that would not load caches its None too: that is as stable
an answer as a font, and re-deriving it per page is the same wasted work.
§Why the substitution options are not part of the key
Every load under one document must make the same substitution choice — a
substitution that varied between two Tf operators naming the same
resource would give one line of text different metrics from the next — so
a cache is created for one set of options and used with those. The caller
that owns the options owns the cache: pdfrum_page::BuildContext carries
both, in one value, and hands this out by Arc.
Implementations§
Source§impl FontCache
impl FontCache
Sourcepub fn get_or_load<F>(&self, reference: ObjRef, load: F) -> Option<Arc<Font>>
pub fn get_or_load<F>(&self, reference: ObjRef, load: F) -> Option<Arc<Font>>
The font reference names, loading it on the first ask and sharing it
on every later one.
load runs at most once per reference per cache in the uncontended
case, and never under the lock — two threads asking for two different
fonts do not serialize on each other. Two threads racing on the same
reference may both load; whichever inserts first is the shared
instance and both callers get that one Arc, so the loser’s copy is
dropped rather than replacing an instance another page already holds.
That costs one duplicate parse and keeps the loader off the lock.