Skip to main content

stet_core/
glyph_cache.rs

1// stet - A PostScript Interpreter
2// Copyright (c) 2026 Scott Bowman
3// SPDX-License-Identifier: Apache-2.0 OR MIT
4
5//! Glyph path cache: caches charstring interpretation results per font.
6//!
7//! Stores glyph outlines in charstring coordinates (pre-FontMatrix, pre-CTM).
8//! One cache entry per glyph per font, regardless of size/orientation.
9//! FontMatrix and CTM transforms are still applied per-render.
10
11use crate::display_list::DisplayElement;
12use crate::graphics_state::PathSegment;
13use crate::object::{EntityId, NameId};
14use rustc_hash::FxHashMap;
15use std::sync::Arc;
16
17/// Cached glyph outline + width in charstring coordinates.
18#[derive(Clone)]
19pub struct CachedGlyph {
20    pub segments: Arc<Vec<PathSegment>>,
21    pub width_x: f64,
22    pub width_y: f64,
23}
24
25/// Cached Type 3 glyph: display list elements + origin for translation.
26#[derive(Clone)]
27pub struct CachedType3Glyph {
28    pub elements: Vec<DisplayElement>,
29    pub origin_dev_x: f64,
30    pub origin_dev_y: f64,
31    pub width: (f64, f64),
32}
33
34/// Cache mode set by setcachedevice/setcharwidth during Type 3 BuildChar.
35#[derive(Clone, Copy, PartialEq, Eq)]
36pub enum Type3CacheMode {
37    /// setcachedevice was called — glyph is cacheable.
38    Cache,
39    /// setcharwidth was called — glyph is not cacheable (may use color ops).
40    NoCache,
41}
42
43/// Per-font glyph path cache.
44#[derive(Default)]
45pub struct GlyphCache {
46    /// Type 1 and CFF glyphs keyed by glyph name.
47    pub by_name: FxHashMap<NameId, CachedGlyph>,
48    /// CIDFont glyphs keyed by CID.
49    pub by_cid: FxHashMap<i32, CachedGlyph>,
50    /// TrueType glyphs keyed by glyph ID.
51    pub by_gid: FxHashMap<u16, CachedGlyph>,
52    /// Type 3 glyphs keyed by char code (only setcachedevice glyphs).
53    pub by_charcode: FxHashMap<u8, CachedType3Glyph>,
54    /// Type 3 glyphs keyed by glyph name (only setcachedevice glyphs).
55    ///
56    /// Separate from [`Self::by_charcode`] because `glyphshow` bypasses the
57    /// font's `Encoding` and can therefore name a glyph that no character code
58    /// maps to — such a glyph has no code to key on.
59    pub by_type3_name: FxHashMap<NameId, CachedType3Glyph>,
60}
61
62impl GlyphCache {
63    pub fn new() -> Self {
64        Self {
65            by_name: FxHashMap::default(),
66            by_cid: FxHashMap::default(),
67            by_gid: FxHashMap::default(),
68            by_charcode: FxHashMap::default(),
69            by_type3_name: FxHashMap::default(),
70        }
71    }
72}
73
74/// Get or create the glyph cache for a font entity.
75#[inline]
76pub fn get_or_create_cache(
77    caches: &mut FxHashMap<EntityId, GlyphCache>,
78    font_entity: EntityId,
79) -> &mut GlyphCache {
80    caches.entry(font_entity).or_default()
81}