forked from 1b-agent/opencadstudio-upstream
feat(web): lazy per-script font loading for international CAD text
The web build has no system-font access, so CAD text in non-Latin scripts (Cyrillic, Greek, CJK, …) rendered as nothing — build_fallback was a hard None on wasm (#141). Instead, ship per-script Noto subsets under web/fonts (one alphabet per file, SIL OFL 1.1) and fetch them lazily over HTTP the first time a drawing uses that script, then outline glyphs with ttf-parser. - web_font: Script enum + script_of (char → script font), a per-script store with lazy fetch, and a pending queue drained by the app loop. - CJK is split by language (chinese/japanese/korean). Han ideographs share code points but differ by language, so the shared block is routed by the document's $DWGCODEPAGE (932→JP, 949→KR, GB/936→CN); kana is always Japanese, Hangul always Korean. Re-tessellates when the language changes. - build_fallback (wasm) outlines from the fetched subset; clear_fallback_cache lets glyphs that missed while a font was in flight reappear on load. - PollWebFonts subscription (web only) + WebFontLoaded message drive fetches. - Trunk copy-dir serves web/fonts; nothing is bundled into the native binary (desktop keeps using system fonts). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
d36cc9786f
commit
54106ca9b0
21 files changed
+453
-5
No files matched your search
@@ -263,11 +263,35 @@ pub fn fallback_glyph(ch: char) -> Option<Arc<Glyph>> {
|
||||
built
|
||||
}
|
||||
|
||||
/// Web: no system fonts → no cosmic-text fallback (LFF-missing glyphs simply
|
||||
/// do not render).
|
||||
/// Drop the cached fallback glyphs so the next lookup re-resolves. The web
|
||||
/// build calls this when a per-script font finishes loading: glyphs that
|
||||
/// resolved to `None` while the font was still in flight then get a real
|
||||
/// outline. (#141)
|
||||
pub fn clear_fallback_cache() {
|
||||
fallback_cache().lock().unwrap().clear();
|
||||
}
|
||||
|
||||
/// Web: outline the glyph from the lazily-fetched per-script Noto subset that
|
||||
/// covers it. Returns `None` while that font is still loading (the char renders
|
||||
/// once it arrives and the fallback cache is cleared). (#141)
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn build_fallback(_ch: char) -> Option<Arc<Glyph>> {
|
||||
None
|
||||
fn build_fallback(ch: char) -> Option<Arc<Glyph>> {
|
||||
let script = crate::scene::text::web_font::script_of(ch)?;
|
||||
let bytes = crate::scene::text::web_font::request(script)?;
|
||||
let face = ttf_parser::Face::parse(&bytes, 0).ok()?;
|
||||
let gid = face.glyph_index(ch)?;
|
||||
let k = cap_scale(&face);
|
||||
let advance = face.glyph_hor_advance(gid).unwrap_or(0) as f32 * k;
|
||||
let mut fl = OutlineFlattener::new(k);
|
||||
face.outline_glyph(gid, &mut fl);
|
||||
fl.flush();
|
||||
if fl.contours.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(Arc::new(Glyph {
|
||||
strokes: fl.contours,
|
||||
advance,
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
|
||||
Reference in new issue
Block a user