fix(engine): silence usvg font-substitution warn spam
The bundled hayeah card SVGs declare font-family="Arial" for rank/suit text. usvg matches family names exactly, so on systems without Arial installed (every Linux distro by default) every text node bridged a log::warn! into our tracing output — 50+ lines per launch. Two-part fix: - svg_loader now populates a process-wide fontdb with system fonts (lazy via OnceLock) so substitution actually has faces to fall through to. usvg::Options::default() ships an empty fontdb, which meant text glyphs had nothing to fall back on at all. - LogPlugin extends DEFAULT_FILTER with usvg::text=error so the residual "no match" warns drop. The substitution itself works; the message is purely informational because Arial truly isn't installed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
//! loading via `load_with_settings(...)`. The default of 512×768 is a
|
||||
//! safe fallback that fits a typical 2:3 playing card.
|
||||
|
||||
use std::sync::{Arc, OnceLock};
|
||||
|
||||
use bevy::asset::io::Reader;
|
||||
use bevy::asset::{AssetLoader, LoadContext, RenderAssetUsages};
|
||||
use bevy::image::Image;
|
||||
@@ -27,6 +29,7 @@ use bevy::reflect::TypePath;
|
||||
use bevy::render::render_resource::{Extent3d, TextureDimension, TextureFormat};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use usvg::fontdb;
|
||||
|
||||
/// Per-asset settings consumed by [`SvgLoader::load`].
|
||||
///
|
||||
@@ -102,7 +105,10 @@ impl AssetLoader for SvgLoader {
|
||||
/// thumbnail generators) can rasterise without going through the
|
||||
/// asset graph.
|
||||
pub fn rasterize_svg(svg_bytes: &[u8], target: UVec2) -> Result<Image, SvgLoaderError> {
|
||||
let opt = usvg::Options::default();
|
||||
let opt = usvg::Options {
|
||||
fontdb: shared_fontdb(),
|
||||
..Default::default()
|
||||
};
|
||||
let tree = usvg::Tree::from_data(svg_bytes, &opt)?;
|
||||
|
||||
let svg_size = tree.size();
|
||||
@@ -140,6 +146,27 @@ pub fn rasterize_svg(svg_bytes: &[u8], target: UVec2) -> Result<Image, SvgLoader
|
||||
))
|
||||
}
|
||||
|
||||
/// Returns a process-wide font database populated with the OS-installed
|
||||
/// fonts the user has available. Initialised lazily on first SVG that
|
||||
/// references text, then shared (via `Arc`) across every subsequent
|
||||
/// rasterisation. `usvg::Options::default()` ships an empty `fontdb`,
|
||||
/// so without this call any text glyph in an SVG renders with no font
|
||||
/// match — the visible symptom on the bundled hayeah artwork is the
|
||||
/// "No match for Arial font-family" warn spam plus glyphs that fall
|
||||
/// through to whatever shape-only path usvg uses for missing fonts.
|
||||
/// `load_system_fonts` is comparatively expensive (~50–200 ms on a
|
||||
/// typical desktop) so we only pay it once for the lifetime of the
|
||||
/// process, gated by `OnceLock`.
|
||||
fn shared_fontdb() -> Arc<fontdb::Database> {
|
||||
static DB: OnceLock<Arc<fontdb::Database>> = OnceLock::new();
|
||||
DB.get_or_init(|| {
|
||||
let mut db = fontdb::Database::new();
|
||||
db.load_system_fonts();
|
||||
Arc::new(db)
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user