Skip to content

Commit

Permalink
fonts: synthesize italics for fonts that don't have it
Browse files Browse the repository at this point in the history
This commit adds a slant to *scalable* (not bitmap!) fonts whose
originating font attributes requested italics but for for which
the resolved face is not italic.

refs: #815
  • Loading branch information
wez committed May 22, 2021
1 parent e29fdae commit 2bbe2bd
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 4 deletions.
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ As features stabilize some brief notes about them will accumulate here.
* Fixed: errors loading custom color schemes are now logged to the error log [#794](https://github.com/wez/wezterm/issues/794)
* Fixed: OSC 7 (current working directory) now works with paths that contain spaces and other special characters. Thanks to [@Arvedui](https://github.com/Arvedui)! [#799](https://github.com/wez/wezterm/pull/799)
* Changed: the homebrew tap is now a Cask that installs to the /Applications directory on macOS. Thanks to [@laggardkernel](https://github.com/laggardkernel)!
* New: italics are now synthesized for scalable fonts when the matching font is not actually italic [#815](https://github.com/wez/wezterm/issues/815)

### 20210502-154244-3f7122cb

Expand Down
2 changes: 1 addition & 1 deletion wezterm-font/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl FontDatabase {
continue;
}
if let Some(handle) = self.resolve(attr) {
handles.push(handle.clone());
handles.push(handle.clone().synthesize(attr));
loaded.insert(attr.clone());
}
}
Expand Down
14 changes: 14 additions & 0 deletions wezterm-font/src/ftwrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,20 @@ impl Face {
ft_result(unsafe { FT_Select_Size(self.face, idx as i32) }, ()).context("FT_Select_Size")
}

pub fn set_transform(&mut self, matrix: Option<FT_Matrix>) {
let mut matrix = matrix.clone();
unsafe {
FT_Set_Transform(
self.face,
match &mut matrix {
Some(m) => m as *mut _,
None => std::ptr::null_mut(),
},
std::ptr::null_mut(),
)
}
}

pub fn load_and_render_glyph(
&mut self,
glyph_index: FT_UInt,
Expand Down
15 changes: 14 additions & 1 deletion wezterm-font/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub struct ParsedFont {
cap_height: Option<f64>,
pub handle: FontDataHandle,
coverage: Mutex<RangeSet<u32>>,
pub synthesize_italic: bool,
}

impl std::fmt::Debug for ParsedFont {
Expand All @@ -43,6 +44,7 @@ impl Clone for ParsedFont {
weight: self.weight,
stretch: self.stretch,
italic: self.italic,
synthesize_italic: self.synthesize_italic,
handle: self.handle.clone(),
cap_height: self.cap_height.clone(),
coverage: Mutex::new(self.coverage.lock().unwrap().clone()),
Expand Down Expand Up @@ -130,6 +132,9 @@ impl ParsedFont {

for p in handles {
code.push_str(&format!(" -- {}\n", p.handle.diagnostic_string()));
if p.synthesize_italic {
code.push_str(" -- Will synthesize italics\n");
}

if p.weight == FontWeight::Regular && p.stretch == FontStretch::Normal && !p.italic {
code.push_str(&format!(" \"{}\",\n", p.names.family));
Expand Down Expand Up @@ -164,6 +169,7 @@ impl ParsedFont {
weight,
stretch,
italic,
synthesize_italic: false,
handle,
coverage: Mutex::new(RangeSet::new()),
cap_height,
Expand Down Expand Up @@ -362,7 +368,14 @@ impl ParsedFont {
pub fn best_match(attr: &FontAttributes, mut fonts: Vec<Self>) -> Option<Self> {
let refs: Vec<&Self> = fonts.iter().collect();
let idx = Self::best_matching_index(attr, &refs)?;
fonts.drain(idx..=idx).next()
fonts.drain(idx..=idx).next().map(|p| p.synthesize(attr))
}

/// Update self to reflect whether the rasterizer might need to synthesize
/// italic for this font.
pub fn synthesize(mut self, attr: &FontAttributes) -> Self {
self.synthesize_italic = !self.italic && attr.italic;
self
}
}

Expand Down
14 changes: 12 additions & 2 deletions wezterm-font/src/rasterizer/freetype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::parser::ParsedFont;
use crate::rasterizer::FontRasterizer;
use crate::units::*;
use crate::{ftwrap, RasterizedGlyph};
use ::freetype::FT_GlyphSlotRec_;
use ::freetype::{FT_GlyphSlotRec_, FT_Matrix};
use anyhow::bail;
use std::cell::RefCell;
use std::mem;
Expand Down Expand Up @@ -292,10 +292,20 @@ impl FreeTypeRasterizer {
pub fn from_locator(parsed: &ParsedFont) -> anyhow::Result<Self> {
log::trace!("Rasterizier wants {:?}", parsed);
let lib = ftwrap::Library::new()?;
let face = lib.face_from_locator(&parsed.handle)?;
let mut face = lib.face_from_locator(&parsed.handle)?;
let has_color = unsafe {
(((*face.face).face_flags as u32) & (ftwrap::FT_FACE_FLAG_COLOR as u32)) != 0
};

if parsed.synthesize_italic {
face.set_transform(Some(FT_Matrix {
xx: 1 * 65536, // scale x
yy: 1 * 65536, // scale y
xy: (0.2 * 65536.0) as _, // skew x
yx: 0 * 65536, // skey y
}));
}

Ok(Self {
_lib: lib,
face: RefCell::new(face),
Expand Down

0 comments on commit 2bbe2bd

Please sign in to comment.