Skip to main content

densa_text/
lib.rs

1//! Real text for densa: fonts, glyph rasterization and a glyph atlas cache.
2//!
3//! Domain-agnostic: any widget that draws text goes through these three pieces.
4//!
5//! - [`Font`] wraps an OpenType/TrueType font (skrifa): character mapping, advances, line
6//!   metrics. [`Font::bundled_mono`] is JetBrains Mono, shipped under the SIL OFL 1.1.
7//! - [`rasterize`] turns a glyph outline into an 8-bit coverage bitmap (zeno), optionally
8//!   shifted by a fraction of a pixel.
9//! - [`GlyphCache`] packs rasterized glyphs into a paged texture atlas (etagere) that grows a
10//!   page at a time and, once at its limit, evicts the least recently used glyphs (never the
11//!   current frame's); it queues the [`AtlasUpdate`]s the GPU texture must follow.
12//!
13//! A warm cache answers lookups without allocating, so per-frame text drawing stays
14//! allocation-free; rasterizing a glyph seen for the first time allocates, once.
15//!
16//! ```
17//! use densa_text::{quantize_x, AtlasConfig, Font, GlyphCache, GlyphMap};
18//!
19//! let mut chars = GlyphMap::new(Font::bundled_mono()?, 14.0);
20//! let mut cache = GlyphCache::new(AtlasConfig::default());
21//!
22//! cache.begin_frame();
23//! let a = chars.get('A').expect("the bundled font has A");
24//! let (_, subpixel) = quantize_x(10.25); // a pen at x = 10.25 px
25//! let placed = cache.get(chars.font(), a.id, chars.px(), subpixel)?;
26//! assert!(placed.size[0] > 0.0, "rasterized into the atlas");
27//! assert_eq!(cache.cached_glyphs(), 1);
28//!
29//! // Asked again (next frame, say): found, not rasterized again.
30//! cache.begin_frame();
31//! cache.get(chars.font(), a.id, chars.px(), subpixel)?;
32//! assert_eq!(cache.cached_glyphs(), 1);
33//! # Ok::<(), Box<dyn std::error::Error>>(())
34//! ```
35
36mod cache;
37mod font;
38mod glyph_map;
39mod raster;
40mod run;
41
42pub use cache::{
43    quantize_x, AtlasConfig, AtlasLimitError, AtlasUpdate, CacheStats, CachedGlyph, GlyphCache,
44    GlyphUnavailable, GlyphUpload, SUBPIXEL_STEPS,
45};
46pub use font::{Font, FontBytes, FontError, FontId, GlyphId, LineMetrics, BUNDLED_MONO};
47pub use glyph_map::{GlyphMap, MappedGlyph, MAX_CACHED_CHARS};
48pub use raster::{rasterize, GlyphBitmap};
49pub use run::{GlyphRun, PositionedGlyph};