1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 21:32:13 +03:00

fonts: defer best match until we have font_dirs + locator + builtin

A user reported an issue where having just Roboto Thin installed
caused the title font to use that one, rather than the desired
Roboto Bold.

This commit adjusts the font matching code to accumulate candidates
from each of the font_dirs, locator and built-in font locations,
and then find the best match.
This commit is contained in:
Wez Furlong 2022-01-01 11:34:39 -07:00
parent e148cfe8e3
commit 58ece29f00
2 changed files with 69 additions and 40 deletions

View File

@ -75,9 +75,6 @@ impl FontDatabase {
pixel_size: u16, pixel_size: u16,
) { ) {
for attr in fonts { for attr in fonts {
if loaded.contains(attr) {
continue;
}
if let Some(handle) = self.resolve(attr, pixel_size) { if let Some(handle) = self.resolve(attr, pixel_size) {
handles.push(handle.clone().synthesize(attr)); handles.push(handle.clone().synthesize(attr));
loaded.insert(attr.clone()); loaded.insert(attr.clone());
@ -112,6 +109,19 @@ impl FontDatabase {
Ok(matches) Ok(matches)
} }
pub fn candidates(&self, font_attr: &FontAttributes) -> Vec<&ParsedFont> {
self.by_full_name
.values()
.filter_map(|parsed| {
if parsed.matches_name(font_attr) {
Some(parsed)
} else {
None
}
})
.collect()
}
pub fn resolve(&self, font_attr: &FontAttributes, pixel_size: u16) -> Option<&ParsedFont> { pub fn resolve(&self, font_attr: &FontAttributes, pixel_size: u16) -> Option<&ParsedFont> {
let candidates: Vec<&ParsedFont> = self let candidates: Vec<&ParsedFont> = self
.by_full_name .by_full_name

View File

@ -531,8 +531,6 @@ impl FontConfigInner {
let (sys_font, sys_size) = self.compute_title_font(&config); let (sys_font, sys_size) = self.compute_title_font(&config);
let mut handles = vec![];
let font_size = config.window_frame.font_size.unwrap_or(sys_size); let font_size = config.window_frame.font_size.unwrap_or(sys_size);
let text_style = config let text_style = config
@ -545,27 +543,7 @@ impl FontConfigInner {
let pixel_size = (font_size * dpi as f64 / 72.0) as u16; let pixel_size = (font_size * dpi as f64 / 72.0) as u16;
let attributes = text_style.font_with_fallback(); let attributes = text_style.font_with_fallback();
let preferred_attributes = attributes let (handles, _loaded) = self.resolve_font_helper_impl(&attributes, pixel_size)?;
.iter()
.filter(|a| !a.is_fallback)
.map(|a| a.clone())
.collect::<Vec<_>>();
let fallback_attributes = attributes
.iter()
.filter(|a| a.is_fallback)
.map(|a| a.clone())
.collect::<Vec<_>>();
let mut loaded = HashSet::new();
for attrs in &[&preferred_attributes, &fallback_attributes] {
self.font_dirs
.borrow()
.resolve_multiple(attrs, &mut handles, &mut loaded, pixel_size);
handles.append(&mut self.locator.load_fonts(attrs, &mut loaded, pixel_size)?);
self.built_in
.borrow()
.resolve_multiple(attrs, &mut handles, &mut loaded, pixel_size);
}
let shaper = new_shaper(&*config, &handles)?; let shaper = new_shaper(&*config, &handles)?;
@ -594,13 +572,11 @@ impl FontConfigInner {
Ok(loaded) Ok(loaded)
} }
fn resolve_font_helper( fn resolve_font_helper_impl(
&self, &self,
style: &TextStyle, attributes: &[FontAttributes],
config: &ConfigHandle,
pixel_size: u16, pixel_size: u16,
) -> anyhow::Result<(Box<dyn FontShaper>, Vec<ParsedFont>)> { ) -> anyhow::Result<(Vec<ParsedFont>, HashSet<FontAttributes>)> {
let attributes = style.font_with_fallback();
let preferred_attributes = attributes let preferred_attributes = attributes
.iter() .iter()
.filter(|a| !a.is_fallback) .filter(|a| !a.is_fallback)
@ -612,18 +588,61 @@ impl FontConfigInner {
.map(|a| a.clone()) .map(|a| a.clone())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut loaded = HashSet::new(); let mut loaded = HashSet::new();
let mut handles = vec![]; let mut handles = vec![];
for attrs in &[&preferred_attributes, &fallback_attributes] {
self.font_dirs for &attrs in &[&preferred_attributes, &fallback_attributes] {
.borrow() let mut candidates = vec![];
.resolve_multiple(attrs, &mut handles, &mut loaded, pixel_size);
handles.append(&mut self.locator.load_fonts(attrs, &mut loaded, pixel_size)?); let font_dirs = self.font_dirs.borrow();
self.built_in for attr in attrs {
.borrow() candidates.append(&mut font_dirs.candidates(attr));
.resolve_multiple(attrs, &mut handles, &mut loaded, pixel_size); }
let mut loaded_ignored = HashSet::new();
let located = self
.locator
.load_fonts(attrs, &mut loaded_ignored, pixel_size)?;
for font in &located {
candidates.push(font);
}
let built_in = self.built_in.borrow();
for attr in attrs {
candidates.append(&mut built_in.candidates(attr));
}
for attr in attrs {
if loaded.contains(attr) {
continue;
}
let named_candidates: Vec<&ParsedFont> = candidates
.iter()
.filter_map(|&p| if p.matches_name(attr) { Some(p) } else { None })
.collect();
if let Some(idx) =
ParsedFont::best_matching_index(attr, &named_candidates, pixel_size)
{
named_candidates.get(idx).map(|&p| {
loaded.insert(attr.clone());
handles.push(p.clone().synthesize(attr))
});
}
}
} }
Ok((handles, loaded))
}
fn resolve_font_helper(
&self,
style: &TextStyle,
config: &ConfigHandle,
pixel_size: u16,
) -> anyhow::Result<(Box<dyn FontShaper>, Vec<ParsedFont>)> {
let attributes = style.font_with_fallback();
let (handles, loaded) = self.resolve_font_helper_impl(&attributes, pixel_size)?;
for attr in &attributes { for attr in &attributes {
if !attr.is_synthetic && !attr.is_fallback && !loaded.contains(attr) { if !attr.is_synthetic && !attr.is_fallback && !loaded.contains(attr) {
let styled_extra = if attr.weight != FontWeight::default() let styled_extra = if attr.weight != FontWeight::default()