diff --git a/eframe/Cargo.toml b/eframe/Cargo.toml index 986e6c39a0c..8687a4dc9e0 100644 --- a/eframe/Cargo.toml +++ b/eframe/Cargo.toml @@ -24,7 +24,7 @@ default = ["default_fonts", "glow"] # detect dark mode system preference dark-light = ["dep:dark-light"] - +system_fonts = ["egui/system_fonts"] # If set, egui will use `include_bytes!` to bundle some fonts. # If you plan on specifying your own fonts you may disable this feature. default_fonts = ["egui/default_fonts"] diff --git a/egui/Cargo.toml b/egui/Cargo.toml index 4d44331689c..1eb814f90c1 100644 --- a/egui/Cargo.toml +++ b/egui/Cargo.toml @@ -36,7 +36,7 @@ deadlock_detection = ["epaint/deadlock_detection"] # If set, egui will use `include_bytes!` to bundle some fonts. # If you plan on specifying your own fonts you may disable this feature. default_fonts = ["epaint/default_fonts"] - +system_fonts = ["epaint/system_fonts"] # Enable additional checks if debug assertions are enabled (debug builds). extra_debug_asserts = ["epaint/extra_debug_asserts"] # Always enable additional checks. diff --git a/epaint/Cargo.toml b/epaint/Cargo.toml index e2c4792af02..1ffa0f654da 100644 --- a/epaint/Cargo.toml +++ b/epaint/Cargo.toml @@ -52,6 +52,9 @@ mint = ["emath/mint"] # implement serde on most types. serde = ["dep:serde", "ahash/serde", "emath/serde"] +# load font from disk automatically according to user input +system_fonts = ["skia-safe"] + [dependencies] emath = { version = "0.18.0", path = "../emath" } @@ -65,6 +68,8 @@ cint = { version = "0.3.1", optional = true } color-hex = { version = "0.2.0", optional = true } serde = { version = "1", optional = true, features = ["derive", "rc"] } +skia-safe = {version = "0.49.1", optional = true, features = ["gl"]} + # native: [target.'cfg(not(target_arch = "wasm32"))'.dependencies] backtrace = { version = "0.3", optional = true } diff --git a/epaint/src/text/font.rs b/epaint/src/text/font.rs index 87c4eb83f66..f7cd0523582 100644 --- a/epaint/src/text/font.rs +++ b/epaint/src/text/font.rs @@ -311,6 +311,18 @@ impl Font { self.glyph_info(c).1.advance_width } + pub fn has_glyph_info_and_cache(&mut self, c: char) -> bool { + if let Some(_font_index_glyph_info) = self.glyph_info_cache.get(&c) { + return true; + } + + self.glyph_info_no_cache_or_fallback(c).is_some() + } + + pub fn push_font_impl(&mut self, new_font_impl: Arc) { + self.fonts.push(new_font_impl); + } + /// `\n` will (intentionally) show up as the replacement character. fn glyph_info(&mut self, c: char) -> (FontIndex, GlyphInfo) { if let Some(font_index_glyph_info) = self.glyph_info_cache.get(&c) { diff --git a/epaint/src/text/fonts.rs b/epaint/src/text/fonts.rs index ff387e0fdb9..9a94f471cbe 100644 --- a/epaint/src/text/fonts.rs +++ b/epaint/src/text/fonts.rs @@ -1,6 +1,3 @@ -use std::collections::BTreeMap; -use std::sync::Arc; - use crate::{ mutex::{Mutex, MutexGuard}, text::{ @@ -10,6 +7,8 @@ use crate::{ TextureAtlas, }; use emath::NumExt as _; +use std::collections::BTreeMap; +use std::sync::Arc; // ---------------------------------------------------------------------------- @@ -243,6 +242,25 @@ pub struct FontDefinitions { pub families: BTreeMap>, } +impl FontDefinitions { + /// query a font which contains the character + #[cfg(feature = "system_fonts")] + pub fn query_font_for_character(c: char) -> Option<(Vec, String)> { + use skia_safe::{FontMgr, FontStyle}; + + let font_mgr = FontMgr::new(); + + if let Some(typeface) = + font_mgr.match_family_style_character("", FontStyle::normal(), &[], c as i32) + { + if let Some((buf, _index)) = typeface.to_font_data() { + return Some((buf, typeface.family_name())); + } + } + None + } +} + impl Default for FontDefinitions { fn default() -> Self { #[allow(unused)] @@ -598,6 +616,50 @@ impl FontsImpl { fn row_height(&mut self, font_id: &FontId) -> f32 { self.font(font_id).row_height() } + + #[cfg(feature = "system_fonts")] + pub fn ensure_correct_fonts_for_text(&mut self, text: &str, main_font_id: &FontId) { + let FontId { size, family: _ } = main_font_id; + let scale_in_pixels = self.font_impl_cache.scale_as_pixels(*size); + + let mut font_impl_manager = self.font(main_font_id); + for c in text.chars() { + if font_impl_manager.has_glyph_info_and_cache(c) { + continue; + } + if let Some((buf, new_font_name)) = FontDefinitions::query_font_for_character(c) { + // update FontData + let font_data = self + .definitions + .font_data + .entry(new_font_name.clone()) + .or_insert_with(|| FontData::from_owned(buf)); + + self.definitions + .families + .entry(FontFamily::Monospace) + .or_default() + .push(new_font_name.clone()); + self.definitions + .families + .entry(FontFamily::Proportional) + .or_default() + .push(new_font_name.clone()); + // update fonts_impl_cache + let ab_glyph = ab_glyph_font_from_font_data(&new_font_name, font_data); + let tweak = font_data.tweak; + self.font_impl_cache + .ab_glyph_fonts + .insert(new_font_name.clone(), (tweak, ab_glyph)); + // update fonts_impl_cache + let new_font_impl = self + .font_impl_cache + .font_impl(scale_in_pixels, &new_font_name); + font_impl_manager = self.font(main_font_id); + font_impl_manager.push_font_impl(new_font_impl); + } + } + } } // ---------------------------------------------------------------------------- diff --git a/epaint/src/text/text_layout.rs b/epaint/src/text/text_layout.rs index c5649dd6d89..e647ccbedbb 100644 --- a/epaint/src/text/text_layout.rs +++ b/epaint/src/text/text_layout.rs @@ -93,6 +93,11 @@ fn layout_section( byte_range, format, } = section; + + // load font from system while we can't recognize with fonts in memory while layout + #[cfg(feature = "system_fonts")] + fonts.ensure_correct_fonts_for_text(&job.text, &format.font_id); + let font = fonts.font(&format.font_id); let font_height = font.row_height();