blinc_text/lib.rs
1//! High-quality text rendering for Blinc UI framework
2//!
3//! This crate provides:
4//! - Font loading and parsing (TTF/OTF via ttf-parser)
5//! - Text shaping (HarfBuzz via rustybuzz)
6//! - Glyph rasterization
7//! - Glyph atlas management
8//! - Text layout engine (line breaking, alignment)
9//!
10//! # Shared Font Registry
11//!
12//! To minimize memory usage (Apple Color Emoji is 180MB!), use the global shared
13//! font registry instead of creating new FontRegistry instances:
14//!
15//! ```ignore
16//! use blinc_text::global_font_registry;
17//!
18//! // All components share this single registry
19//! let registry = global_font_registry();
20//! ```
21
22pub mod atlas;
23pub mod emoji;
24pub mod font;
25pub mod layout;
26pub mod rasterizer;
27pub mod registry;
28pub mod renderer;
29pub mod shaper;
30
31use std::sync::{Arc, Mutex, OnceLock};
32
33pub use atlas::{AtlasRegion, ColorGlyphAtlas, GlyphAtlas, GlyphInfo};
34pub use emoji::{contains_emoji, is_emoji, EmojiRenderer, EmojiSprite};
35pub use font::{Font, FontFace, FontMetrics, FontStyle, FontWeight};
36
37/// Global shared font registry singleton.
38///
39/// This ensures fonts (especially Apple Color Emoji at 180MB) are loaded once
40/// and shared across all text rendering components.
41static GLOBAL_FONT_REGISTRY: OnceLock<Arc<Mutex<registry::FontRegistry>>> = OnceLock::new();
42
43/// Get the global shared font registry.
44///
45/// Returns a reference to the singleton font registry shared across all text
46/// rendering components. Using this instead of creating new FontRegistry instances
47/// saves significant memory (180MB+ for emoji font alone).
48///
49/// # Example
50///
51/// ```ignore
52/// use blinc_text::{global_font_registry, TextRenderer, EmojiRenderer};
53///
54/// // All share the same fonts
55/// let renderer = TextRenderer::with_shared_registry(global_font_registry());
56/// let emoji = EmojiRenderer::with_registry(global_font_registry());
57/// ```
58pub fn global_font_registry() -> Arc<Mutex<registry::FontRegistry>> {
59 Arc::clone(
60 GLOBAL_FONT_REGISTRY.get_or_init(|| Arc::new(Mutex::new(registry::FontRegistry::new()))),
61 )
62}
63
64// Re-export html-escape for entity decoding
65pub use html_escape::decode_html_entities;
66pub use layout::{
67 LayoutOptions, LineBreakMode, PositionedGlyph, TextAlignment, TextAnchor, TextLayout,
68 TextLayoutEngine,
69};
70pub use rasterizer::{GlyphFormat, GlyphRasterizer, RasterizedGlyph};
71pub use registry::{FontRegistry, GenericFont};
72pub use renderer::{ColorSpan, GlyphInstance, PreparedText, TextRenderer};
73pub use shaper::{ShapedGlyph, ShapedText, TextShaper};
74
75use thiserror::Error;
76
77/// Text rendering errors
78#[derive(Error, Debug)]
79pub enum TextError {
80 #[error("Failed to load font: {0}")]
81 FontLoadError(String),
82
83 #[error("Failed to parse font: {0}")]
84 FontParseError(String),
85
86 #[error("Glyph not found for codepoint: {0}")]
87 GlyphNotFound(char),
88
89 #[error("Atlas is full, cannot allocate glyph")]
90 AtlasFull,
91
92 #[error("Invalid font data")]
93 InvalidFontData,
94}
95
96pub type Result<T> = std::result::Result<T, TextError>;