use crate::font_scan;
pub(crate) enum ScannedFont {
Fallback(Vec<u8>),
BoldChain(Vec<Vec<u8>>),
}
pub(crate) fn install_label_fonts(render_state: &eframe::egui_wgpu::RenderState) -> bool {
let installed = oxigis_ui::map_gpu::set_label_fonts(
render_state,
oxifont_bundled::NOTO_SANS_REGULAR.to_vec(),
Vec::new(),
);
if installed {
tracing::info!("OxiGIS desktop: label font installed (Noto Sans, Latin)");
}
installed
}
static CJK_REGULAR_PATHS: std::sync::OnceLock<std::sync::Arc<[std::path::PathBuf]>> =
std::sync::OnceLock::new();
static CJK_BOLD_PATHS: std::sync::OnceLock<std::sync::Arc<[std::path::PathBuf]>> =
std::sync::OnceLock::new();
pub(crate) fn cjk_regular_paths() -> std::sync::Arc<[std::path::PathBuf]> {
std::sync::Arc::clone(CJK_REGULAR_PATHS.get_or_init(|| font_scan::find_cjk_font_paths().into()))
}
pub(crate) fn cjk_bold_paths() -> std::sync::Arc<[std::path::PathBuf]> {
std::sync::Arc::clone(
CJK_BOLD_PATHS.get_or_init(|| font_scan::find_cjk_bold_font_paths().into()),
)
}
pub(crate) fn start_cjk_font_scan(
ctx: &egui::Context,
) -> Option<std::sync::mpsc::Receiver<ScannedFont>> {
let (tx, rx) = std::sync::mpsc::channel();
let ctx = ctx.clone();
match std::thread::Builder::new()
.name("oxigis-font-scan".to_owned())
.spawn(move || {
for path in cjk_regular_paths().iter() {
let Some(bytes) = font_scan::read_cjk_font(path) else {
continue;
};
tracing::debug!(
path = %path.display(),
"OxiGIS desktop: CJK fallback queued for install",
);
if tx.send(ScannedFont::Fallback(bytes)).is_err() {
return;
}
ctx.request_repaint();
}
let bold: Vec<Vec<u8>> = cjk_bold_paths()
.iter()
.filter_map(|path| font_scan::read_cjk_font(path))
.collect();
if !bold.is_empty() && tx.send(ScannedFont::BoldChain(bold)).is_ok() {
ctx.request_repaint();
}
}) {
Ok(_handle) => Some(rx),
Err(error) => {
tracing::warn!(%error, "OxiGIS desktop: could not start the CJK font scan");
None
}
}
}
pub(crate) fn drain_cjk_font(
render_state: &eframe::egui_wgpu::RenderState,
rx: &std::sync::mpsc::Receiver<ScannedFont>,
ctx: &egui::Context,
) -> bool {
use std::sync::mpsc::TryRecvError;
let mut batch = Vec::new();
let mut bold: Option<Vec<Vec<u8>>> = None;
let spent = loop {
match rx.try_recv() {
Ok(ScannedFont::Fallback(bytes)) => batch.push(bytes),
Ok(ScannedFont::BoldChain(chain)) => bold = Some(chain),
Err(TryRecvError::Disconnected) => break true,
Err(TryRecvError::Empty) => break false,
}
};
if !batch.is_empty() {
let fonts = batch.len();
let bytes: usize = batch.iter().map(Vec::len).sum();
if oxigis_ui::map_gpu::add_label_fallback_fonts(render_state, batch) {
tracing::info!(
fonts,
bytes,
"OxiGIS desktop: CJK label fallbacks installed; labels will re-shape",
);
ctx.request_repaint();
} else {
tracing::warn!(
fonts,
"OxiGIS desktop: CJK fonts arrived before the map; discarded",
);
}
}
if let Some(chain) = bold {
let fonts = chain.len();
if oxigis_ui::map_gpu::set_label_bold_fonts(render_state, chain) {
tracing::info!(
fonts,
"OxiGIS desktop: bold label chain installed; Bold labels draw bold",
);
ctx.request_repaint();
} else {
tracing::warn!(
fonts,
"OxiGIS desktop: bold fonts arrived before the map; discarded",
);
}
}
spent
}