1
1
mirror of https://github.com/wez/wezterm.git synced 2024-09-21 03:39:16 +03:00

wezterm: avoid implausible font sizes in shaper metrics

In this scenario:

```lua
local wezterm = require "wezterm"

return {
  font_size = 12.0,
  font_dirs = {"/home/wez/.fonts"},
  font_locator = "ConfigDirsOnly",
  font = wezterm.font_with_fallback({
    -- this is an invalid font
     "does not exist",
    "Noto Color Emoji",
  }),
}
```

we'd take the metrics from the emoji font and the cell size would
be crazy huge.

With this change we filter out "outliers" based on the approximate
pixel size for a font given its size and dpi.  If a fallback position
is significantly larger or smaller than the theoretical size then
we skip it when considering the metrics.

The result of this is that with the above configuration we end up
with `{"Noto Color Emoji", "JetBrains Mono"}` as the font order;
most of the textual glyphs will render from `JetBrains Mono` but
the number glyphs prefer the `Noto Color Emoji` renditions which
are typically double width.  While the terminal looks a bit
cartoonish as a result of that selection, the sizes are much more
reasonable compared to the screenshot in #263.

refs: #263
This commit is contained in:
Wez Furlong 2020-10-11 14:53:36 -07:00
parent b3f51e8ee2
commit bc1d4bba35

View File

@ -267,9 +267,39 @@ impl FontShaper for HarfbuzzShaper {
}
fn metrics(&self, size: f64, dpi: u32) -> anyhow::Result<FontMetrics> {
// Returns the metrics for the selected font... but look out
// for implausible sizes.
// Ideally we wouldn't need this, but in the event that a user
// has a wonky configuration we don't want to pick something
// like a bitmap emoji font for the metrics or well end up
// with crazy huge cells.
// We do a sniff test based on the theoretical pixel height for
// the supplied size+dpi.
// If a given fallback slot deviates from the theoretical size
// by too much we'll skip to the next slot.
let theoretical_height = size * dpi as f64 / 72.0;
let mut metrics_idx = 0;
while let Ok(Some(mut pair)) = self.load_fallback(metrics_idx) {
let (_, cell_height) = pair.face.set_font_size(size, dpi)?;
let diff = (theoretical_height - cell_height).abs();
let factor = diff / theoretical_height;
if factor < 2.0 {
break;
}
log::trace!(
"skip idx {} because diff={} factor={} theoretical_height={} cell_height={}",
metrics_idx,
diff,
factor,
theoretical_height,
cell_height
);
metrics_idx += 1;
}
let mut pair = self
.load_fallback(0)?
.ok_or_else(|| anyhow!("unable to load first font!?"))?;
.load_fallback(metrics_idx)?
.ok_or_else(|| anyhow!("unable to load font idx {}!?", metrics_idx))?;
let (cell_width, cell_height) = pair.face.set_font_size(size, dpi)?;
let y_scale = unsafe { (*(*pair.face.face).size).metrics.y_scale as f64 / 65536.0 };
let metrics = FontMetrics {