From 3c787b3f6225a6542aa247ef8f85d25d474392af Mon Sep 17 00:00:00 2001 From: Mohammad AlSaleh Date: Wed, 31 Jan 2024 13:45:19 +0300 Subject: [PATCH] Use weight absolute difference in monospace fallback matching When matching on weights smaller than normal, "equal or smaller" weight restriction may cause monospace fallback to fail, depending on font support at such weights for the text to be shaped. So remove that restriction, and calculate weight differences instead of offsets. In case of no exact weight match, and with all other factors being equal, smaller weights will be picked before bigger ones. So, this should generally not cause any behavioral changes when matching on normal weight or bigger. Should fix pop-os/cosmic-term#104. Signed-off-by: Mohammad AlSaleh --- src/attrs.rs | 5 +---- src/font/fallback/mod.rs | 15 +++++++++------ src/font/system.rs | 6 ++++-- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/attrs.rs b/src/attrs.rs index 1be3c46a6a..a7886d072e 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -176,10 +176,7 @@ impl<'a> Attrs<'a> { pub fn matches(&self, face: &fontdb::FaceInfo) -> bool { //TODO: smarter way of including emoji face.post_script_name.contains("Emoji") - || (face.style == self.style - // Relax exact weight matching for the Monospace fallback use-case - && face.weight <= self.weight - && face.stretch == self.stretch) + || (face.style == self.style && face.stretch == self.stretch) } /// Check if this set of attributes can be shaped with another diff --git a/src/font/fallback/mod.rs b/src/font/fallback/mod.rs index 528cdf816d..9dd1d7f6ff 100644 --- a/src/font/fallback/mod.rs +++ b/src/font/fallback/mod.rs @@ -32,13 +32,14 @@ use log::debug as missing_warn; #[cfg(feature = "warn_on_missing_glyphs")] use log::warn as missing_warn; -// Match on lowest weight_offset, then script_non_matches +// Match on lowest font_weight_diff, then script_non_matches, then font_weight // Default font gets None for both `weight_offset` and `script_non_matches`, and thus, it is // always the first to be popped from the set. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] struct MonospaceFallbackInfo { - weight_offset: Option, + font_weight_diff: Option, codepoint_non_matches: Option, + font_weight: u16, id: fontdb::ID, } @@ -144,7 +145,7 @@ impl<'a> Iterator for FontFallbackIter<'a> { let font_match_keys_iter = |is_mono| { self.font_match_keys .iter() - .filter(move |m_key| m_key.weight_offset == Some(0) || is_mono) + .filter(move |m_key| m_key.font_weight_diff == 0 || is_mono) }; while self.default_i < self.default_families.len() { @@ -160,11 +161,12 @@ impl<'a> Iterator for FontFallbackIter<'a> { if let Some(font) = self.font_system.get_font(m_key.id) { if !is_mono { return Some(font); - } else if m_key.weight_offset == Some(0) { + } else if m_key.font_weight_diff == 0 { // Default font let fallback_info = MonospaceFallbackInfo { - weight_offset: None, + font_weight_diff: None, codepoint_non_matches: None, + font_weight: m_key.font_weight, id: m_key.id, }; assert!(self.monospace_fallbacks.insert(fallback_info)); @@ -187,8 +189,9 @@ impl<'a> Iterator for FontFallbackIter<'a> { .count(); let fallback_info = MonospaceFallbackInfo { - weight_offset: m_key.weight_offset, + font_weight_diff: Some(m_key.font_weight_diff), codepoint_non_matches: Some(codepoint_non_matches), + font_weight: m_key.font_weight, id: m_key.id, }; assert!(self.monospace_fallbacks.insert(fallback_info)); diff --git a/src/font/system.rs b/src/font/system.rs index 82f6fd8a22..be801a60b3 100644 --- a/src/font/system.rs +++ b/src/font/system.rs @@ -11,7 +11,8 @@ pub use rustybuzz; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct FontMatchKey { - pub(crate) weight_offset: Option, + pub(crate) font_weight_diff: u16, + pub(crate) font_weight: u16, pub(crate) id: fontdb::ID, } @@ -151,7 +152,8 @@ impl FontSystem { .faces() .filter(|face| attrs.matches(face)) .map(|face| FontMatchKey { - weight_offset: attrs.weight.0.checked_sub(face.weight.0), + font_weight_diff: attrs.weight.0.abs_diff(face.weight.0), + font_weight: face.weight.0, id: face.id, }) .collect::>();