Skip to content

Commit 18c3d2a

Browse files
MoSaljackpot51
authored andcommitted
Skip trying monospace fallbacks if default font supports all codepoints
Instead of blindly pushing default font to the start of the monospace fallbacks map. Actually collect codepoint support info for it, and if it supports all codepoints, skip collecting that info from other monospace fonts. If it doesn't, push it to the start of the map as before. This actually provides a big performance boost, while the sophisticated monospace fallback process is still done whenever needed. Signed-off-by: Mohammad AlSaleh <CE.Mohammad.AlSaleh@gmail.com>
1 parent 729dc86 commit 18c3d2a

File tree

1 file changed

+63
-25
lines changed

1 file changed

+63
-25
lines changed

src/font/fallback/mod.rs

+63-25
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,16 @@ impl<'a> FontFallbackIter<'a> {
130130
false
131131
}
132132
}
133+
134+
fn default_font_match_key(&self) -> Option<&FontMatchKey> {
135+
let default_family = self.default_families[self.default_i - 1];
136+
let default_family_name = self.font_system.db().family_name(default_family);
137+
138+
self.font_match_keys
139+
.iter()
140+
.filter(|m_key| m_key.font_weight_diff == 0)
141+
.find(|m_key| self.face_contains_family(m_key.id, default_family_name))
142+
}
133143
}
134144

135145
impl<'a> Iterator for FontFallbackIter<'a> {
@@ -147,9 +157,58 @@ impl<'a> Iterator for FontFallbackIter<'a> {
147157
.filter(move |m_key| m_key.font_weight_diff == 0 || is_mono)
148158
};
149159

150-
while self.default_i < self.default_families.len() {
160+
'DEF_FAM: while self.default_i < self.default_families.len() {
151161
self.default_i += 1;
152162
let is_mono = self.default_families[self.default_i - 1] == &Family::Monospace;
163+
let default_font_match_key = self.default_font_match_key().cloned();
164+
let word_chars_count = self.word.chars().count();
165+
166+
macro_rules! mk_mono_fallback_info {
167+
($m_key:expr) => {{
168+
let supported_cp_count_opt = self
169+
.font_system
170+
.get_font_supported_codepoints_in_word($m_key.id, self.word);
171+
172+
supported_cp_count_opt.map(|supported_cp_count| {
173+
let codepoint_non_matches = word_chars_count - supported_cp_count;
174+
175+
MonospaceFallbackInfo {
176+
font_weight_diff: Some($m_key.font_weight_diff),
177+
codepoint_non_matches: Some(codepoint_non_matches),
178+
font_weight: $m_key.font_weight,
179+
id: $m_key.id,
180+
}
181+
})
182+
}};
183+
}
184+
185+
match (is_mono, default_font_match_key.as_ref()) {
186+
(false, None) => break 'DEF_FAM,
187+
(false, Some(m_key)) => {
188+
if let Some(font) = self.font_system.get_font(m_key.id) {
189+
return Some(font);
190+
} else {
191+
break 'DEF_FAM;
192+
}
193+
}
194+
(true, None) => (),
195+
(true, Some(m_key)) => {
196+
// Default Monospace font
197+
if let Some(mut fallback_info) = mk_mono_fallback_info!(m_key) {
198+
fallback_info.font_weight_diff = None;
199+
200+
// Return early if default Monospace font supports all word codepoints.
201+
// Otherewise, add to fallbacks set
202+
if fallback_info.codepoint_non_matches == Some(0) {
203+
if let Some(font) = self.font_system.get_font(m_key.id) {
204+
return Some(font);
205+
}
206+
} else {
207+
assert!(self.monospace_fallbacks.insert(fallback_info));
208+
}
209+
}
210+
}
211+
};
153212

154213
let mono_ids_for_scripts = if is_mono && !self.scripts.is_empty() {
155214
let scripts = self.scripts.iter().filter_map(|script| {
@@ -162,35 +221,14 @@ impl<'a> Iterator for FontFallbackIter<'a> {
162221
};
163222

164223
for m_key in font_match_keys_iter(is_mono) {
165-
let default_family = self
166-
.font_system
167-
.db()
168-
.family_name(self.default_families[self.default_i - 1]);
169-
if self.face_contains_family(m_key.id, default_family) {
170-
if let Some(font) = self.font_system.get_font(m_key.id) {
171-
if !is_mono {
172-
return Some(font);
173-
} else if m_key.font_weight_diff == 0 {
174-
// Default font
175-
let fallback_info = MonospaceFallbackInfo {
176-
font_weight_diff: None,
177-
codepoint_non_matches: None,
178-
font_weight: m_key.font_weight,
179-
id: m_key.id,
180-
};
181-
assert!(self.monospace_fallbacks.insert(fallback_info));
182-
}
183-
}
184-
}
185-
// Set a monospace fallback if Monospace family is not found
186-
if is_mono {
187-
let include_mono_id = if mono_ids_for_scripts.is_empty() {
224+
if Some(m_key.id) != default_font_match_key.as_ref().map(|m_key| m_key.id) {
225+
let is_mono_id = if mono_ids_for_scripts.is_empty() {
188226
self.font_system.is_monospace(m_key.id)
189227
} else {
190228
mono_ids_for_scripts.binary_search(&m_key.id).is_ok()
191229
};
192230

193-
if include_mono_id {
231+
if is_mono_id {
194232
let supported_cp_count_opt = self
195233
.font_system
196234
.get_font_supported_codepoints_in_word(m_key.id, self.word);

0 commit comments

Comments
 (0)