From 5c7deeb8b96f15900ec57a3ae8312a85e9c30e85 Mon Sep 17 00:00:00 2001 From: Keith Simmons Date: Sun, 20 Jun 2021 22:16:26 -0700 Subject: [PATCH] fix rendering when glyph can't be found and add last resort font --- src/renderer/fonts/caching_shaper.rs | 25 ++++++++++--------------- src/renderer/fonts/font_loader.rs | 28 ++++++++++++++++++---------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/renderer/fonts/caching_shaper.rs b/src/renderer/fonts/caching_shaper.rs index 164bc8f..fd1f657 100644 --- a/src/renderer/fonts/caching_shaper.rs +++ b/src/renderer/fonts/caching_shaper.rs @@ -4,7 +4,7 @@ use log::{trace, warn}; use lru::LruCache; use skia_safe::{TextBlob, TextBlobBuilder}; use swash::shape::ShapeContext; -use swash::text::cluster::{CharCluster, Parser, Status, Token}; +use swash::text::cluster::{Char, CharCluster, Parser, Status, Token}; use swash::text::Script; use swash::Metrics; use unicode_segmentation::UnicodeSegmentation; @@ -46,7 +46,7 @@ impl CachingShaper { .unwrap_or(FontKey::Default); self.font_loader - .get_or_load(font_key) + .get_or_load(&font_key) .expect("Could not load font") } @@ -128,6 +128,8 @@ impl CachingShaper { let mut results = Vec::new(); 'cluster: while parser.next(&mut cluster) { + // TODO: Don't redo this work for every cluster. Save it some how + // Create font fallback list let mut font_fallback_keys = Vec::new(); // Add guifont fallback list @@ -145,9 +147,12 @@ impl CachingShaper { // Add skia fallback font_fallback_keys.push(cluster.chars()[0].ch.into()); + // Add last resort + font_fallback_keys.push(FontKey::LastResort); + let mut best = None; // Use the cluster.map function to select a viable font from the fallback list - for fallback_key in font_fallback_keys.into_iter() { + for fallback_key in font_fallback_keys.iter() { if let Some(font_pair) = self.font_loader.get_or_load(fallback_key) { let charmap = font_pair.swash_font.as_ref().charmap(); match cluster.map(|ch| charmap.map(ch)) { @@ -161,19 +166,9 @@ impl CachingShaper { } } - // If we find a font with partial coverage of the cluster, select it if let Some(best) = best { + // Last Resort covers all of the unicode space so we will always have a fallback results.push((cluster.to_owned(), best.clone())); - continue 'cluster; - } else { - warn!("No valid font for {:?}", cluster.chars()); - - // No good match. Just render with the default font. - let default_font = self - .font_loader - .get_or_load(FontKey::Default) - .expect("Could not load default font"); - results.push((cluster.to_owned(), default_font)); } } @@ -188,7 +183,7 @@ impl CachingShaper { current_group.push(cluster); } else { grouped_results.push((current_group, current_font)); - current_group = Vec::new(); + current_group = vec![cluster]; current_font_option = Some(font); } } else { diff --git a/src/renderer/fonts/font_loader.rs b/src/renderer/fonts/font_loader.rs index 2159ca8..7ae0178 100644 --- a/src/renderer/fonts/font_loader.rs +++ b/src/renderer/fonts/font_loader.rs @@ -10,6 +10,7 @@ use super::swash_font::SwashFont; pub struct Asset; const DEFAULT_FONT: &str = "FiraCode-Regular.ttf"; +const LAST_RESORT_FONT: &str = "LastResort-Regular.ttf"; pub struct FontPair { pub skia_font: Font, @@ -46,9 +47,10 @@ pub struct FontLoader { #[derive(Debug, Hash, PartialEq, Eq, Clone)] pub enum FontKey { - Default, Name(String), Character(char), + Default, + LastResort, } impl From<&str> for FontKey { @@ -88,12 +90,6 @@ impl FontLoader { fn load(&mut self, font_key: FontKey) -> Option { match font_key { - FontKey::Default => { - let default_font_data = Asset::get(DEFAULT_FONT).unwrap(); - let data = Data::new_copy(&default_font_data); - let typeface = Typeface::from_data(data, 0).unwrap(); - FontPair::new(Font::from_typeface(typeface, self.font_size)) - } FontKey::Name(name) => { let font_style = FontStyle::normal(); let typeface = self.font_mgr.match_family_style(name, font_style)?; @@ -109,11 +105,23 @@ impl FontLoader { )?; FontPair::new(Font::from_typeface(typeface, self.font_size)) } + FontKey::Default => { + let default_font_data = Asset::get(DEFAULT_FONT).unwrap(); + let data = Data::new_copy(&default_font_data); + let typeface = Typeface::from_data(data, 0).unwrap(); + FontPair::new(Font::from_typeface(typeface, self.font_size)) + } + FontKey::LastResort => { + let default_font_data = Asset::get(LAST_RESORT_FONT).unwrap(); + let data = Data::new_copy(&default_font_data); + let typeface = Typeface::from_data(data, 0).unwrap(); + FontPair::new(Font::from_typeface(typeface, self.font_size)) + } } } - pub fn get_or_load(&mut self, font_key: FontKey) -> Option> { - if let Some(cached) = self.cache.get(&font_key) { + pub fn get_or_load(&mut self, font_key: &FontKey) -> Option> { + if let Some(cached) = self.cache.get(font_key) { return Some(cached.clone()); } @@ -121,7 +129,7 @@ impl FontLoader { let font_arc = Arc::new(loaded_font); - self.cache.put(font_key, font_arc.clone()); + self.cache.put(font_key.clone(), font_arc.clone()); Some(font_arc) }