From 064b591a1bc1521af1e8f805f90e1dabc8fd6ac5 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Thu, 8 Apr 2021 09:12:59 -0700 Subject: [PATCH] fonts: remove ttf_parser, compute coverage from freetype Replaces the last usage of ttf-parser with calling into freetype. This removes a source of inconsistency, as ttf-parser doesn't support all of the things that freetype does. Notably, this prevents a weird error from blowing up codepoint coverage calculations on a system where I have helvetica.bdf in my font dir for long-forgotten reasons. --- Cargo.lock | 9 +-------- wezterm-font/Cargo.toml | 1 - wezterm-font/src/db.rs | 30 +++++++----------------------- wezterm-font/src/ftwrap.rs | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7afe670c7..3d3282b5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2542,7 +2542,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3" dependencies = [ - "ttf-parser 0.6.2", + "ttf-parser", ] [[package]] @@ -3919,12 +3919,6 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" -[[package]] -name = "ttf-parser" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e00391c1f3d171490a3f8bd79999b0002ae38d3da0d6a3a306c754b053d71b" - [[package]] name = "typenum" version = "1.13.0" @@ -4432,7 +4426,6 @@ dependencies = [ "termwiz", "thiserror", "tinyvec", - "ttf-parser 0.12.0", "unicode-general-category 0.3.0", "unicode-segmentation", "walkdir", diff --git a/wezterm-font/Cargo.toml b/wezterm-font/Cargo.toml index 62513f56f..a162b2186 100644 --- a/wezterm-font/Cargo.toml +++ b/wezterm-font/Cargo.toml @@ -22,7 +22,6 @@ rangeset = { path = "../rangeset" } termwiz = { path = "../termwiz" } thiserror = "1.0" tinyvec = "1.1" # Note: constrained by the allsorts crate -ttf-parser = "0.12" unicode-segmentation = "1.7" unicode-general-category = "0.3" walkdir = "2" diff --git a/wezterm-font/src/db.rs b/wezterm-font/src/db.rs index 17a6b67fb..ccad259e3 100644 --- a/wezterm-font/src/db.rs +++ b/wezterm-font/src/db.rs @@ -1,11 +1,11 @@ //! A font-database to keep track of fonts that we've located +use crate::ftwrap::Library; use crate::parser::{load_built_in_fonts, parse_and_collect_font_info, FontMatch, ParsedFont}; use crate::FontDataHandle; -use anyhow::{anyhow, Context}; +use anyhow::Context; use config::{Config, FontAttributes}; use rangeset::RangeSet; -use std::borrow::Cow; use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; use std::sync::{Arc, Mutex}; @@ -20,28 +20,12 @@ impl Entry { /// Parses out the underlying TTF data and produces a RangeSet holding /// the set of codepoints for which the font has coverage. fn compute_coverage(&self) -> anyhow::Result> { - use ttf_parser::Face; - let (data, index) = match &self.handle { - FontDataHandle::Memory { data, index, .. } => (data.clone(), *index), - FontDataHandle::OnDisk { path, index, .. } => { - let data = std::fs::read(path) - .with_context(|| anyhow!("reading font data from {}", path.display()))?; - (Cow::Owned(data), *index) - } - }; + let lib = Library::new()?; + let face = lib + .face_from_locator(&self.handle) + .with_context(|| format!("freetype parsing {:?}", self.handle))?; - let face = Face::from_slice(&data, index) - .with_context(|| format!("ttf_parser parsing {:?}", self.handle))?; - let mut coverage = RangeSet::new(); - - for table in face.character_mapping_subtables() { - if table.is_unicode() { - table.codepoints(|cp| coverage.add(cp)); - break; - } - } - - Ok(coverage) + Ok(face.compute_coverage()) } /// Computes the intersection of the wanted set of codepoints with diff --git a/wezterm-font/src/ftwrap.rs b/wezterm-font/src/ftwrap.rs index 74c5c9a7f..0b513b07d 100644 --- a/wezterm-font/src/ftwrap.rs +++ b/wezterm-font/src/ftwrap.rs @@ -5,6 +5,7 @@ use crate::parser::ParsedFont; use anyhow::{anyhow, Context}; use config::{configuration, FreeTypeLoadTarget}; pub use freetype::*; +use rangeset::RangeSet; use std::borrow::Cow; use std::convert::TryInto; use std::ffi::CStr; @@ -228,6 +229,37 @@ impl Face { unsafe { ((*self.face).style_flags & FT_STYLE_FLAG_ITALIC as FT_Long) != 0 } } + pub fn compute_coverage(&self) -> RangeSet { + let mut coverage = RangeSet::new(); + + for encoding in &[ + FT_Encoding::FT_ENCODING_UNICODE, + FT_Encoding::FT_ENCODING_MS_SYMBOL, + ] { + if unsafe { FT_Select_Charmap(self.face, *encoding) } != 0 { + continue; + } + + let mut glyph = 0; + let mut ucs4 = unsafe { FT_Get_First_Char(self.face, &mut glyph) }; + while glyph != 0 { + coverage.add(ucs4); + ucs4 = unsafe { FT_Get_Next_Char(self.face, ucs4, &mut glyph) }; + } + + if *encoding == FT_Encoding::FT_ENCODING_MS_SYMBOL { + // Fontconfig duplicates F000..F0FF to 0000..00FF + for ucs4 in 0xf00..0xf100 { + if coverage.contains(ucs4) { + coverage.add(ucs4 - 0xf000); + } + } + } + } + + coverage + } + /// This is a wrapper around set_char_size and select_size /// that accounts for some weirdness with eg: color emoji pub fn set_font_size(&mut self, point_size: f64, dpi: u32) -> anyhow::Result<(f64, f64)> {