forked from 1b-agent/opencadstudio-upstream
Move the 30 flat modules under src/scene/ into six folders by role: convert (entity→geometry), text (fonts/shaping), model (render models), pick (hit-test/selection/grips/xclip), view (camera/transform/render), cache (block + property caches). pipeline/ is unchanged. Full path migration — all `scene::X` references become `scene::<group>::X`, no compatibility re-exports. render.rs items that were `pub(super)` (parent was scene) become `pub(in crate::scene)` to keep their original scene-wide visibility. No behavior change; build and tests are green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
64 lines
2.1 KiB
Rust
64 lines
2.1 KiB
Rust
// System TrueType/OpenType font discovery.
|
|
//
|
|
// Wraps a `fontdb` database loaded with the user's installed system fonts so
|
|
// the rest of the app can (a) list available font families for the text-style
|
|
// picker and (b) borrow a face's raw bytes to extract glyph outlines (see the
|
|
// TTF glyph engine). LFF stroke fonts stay separate — this is purely the
|
|
// TrueType side of the renderer.
|
|
|
|
use std::sync::OnceLock;
|
|
|
|
struct SysFonts {
|
|
db: fontdb::Database,
|
|
/// Sorted, de-duplicated family names for the picker.
|
|
families: Vec<String>,
|
|
}
|
|
|
|
static FONTS: OnceLock<SysFonts> = OnceLock::new();
|
|
|
|
fn fonts() -> &'static SysFonts {
|
|
FONTS.get_or_init(|| {
|
|
let mut db = fontdb::Database::new();
|
|
db.load_system_fonts();
|
|
|
|
let mut families: Vec<String> = db
|
|
.faces()
|
|
.filter_map(|face| face.families.first().map(|(name, _)| name.clone()))
|
|
.collect();
|
|
families.sort_by_key(|n| n.to_lowercase());
|
|
families.dedup();
|
|
|
|
SysFonts { db, families }
|
|
})
|
|
}
|
|
|
|
/// All installed system font families, sorted case-insensitively, de-duped.
|
|
pub fn families() -> &'static [String] {
|
|
&fonts().families
|
|
}
|
|
|
|
/// Resolve a family name to a concrete face id (regular weight/style).
|
|
fn face_id(family: &str) -> Option<fontdb::ID> {
|
|
let db = &fonts().db;
|
|
let query = fontdb::Query {
|
|
families: &[fontdb::Family::Name(family)],
|
|
..Default::default()
|
|
};
|
|
db.query(&query)
|
|
}
|
|
|
|
/// Borrow the raw face bytes for `family` and run `f` over them. The byte slice
|
|
/// is only valid inside the closure, so callers extract everything they need
|
|
/// (e.g. flattened glyph outlines) before returning. `index` is the face index
|
|
/// within a TrueType collection. Returns `None` if the family is unknown.
|
|
pub fn with_face_data<T>(family: &str, f: impl FnOnce(&[u8], u32) -> T) -> Option<T> {
|
|
let id = face_id(family)?;
|
|
fonts().db.with_face_data(id, f)
|
|
}
|
|
|
|
/// Whether `family` matches an installed system font (case-insensitive via
|
|
/// fontdb's own matching).
|
|
pub fn has_family(family: &str) -> bool {
|
|
face_id(family).is_some()
|
|
}
|