diff --git a/Cargo.lock b/Cargo.lock index d6a5fdaea..27f3c7807 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -656,15 +656,6 @@ dependencies = [ "bitflags 1.2.1", ] -[[package]] -name = "cmake" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e56268c17a6248366d66d4a47a3381369d068cce8409bb1716ed77ea32163bb" -dependencies = [ - "cc", -] - [[package]] name = "cocoa" version = "0.20.2" @@ -780,16 +771,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" -[[package]] -name = "core-foundation" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" -dependencies = [ - "core-foundation-sys 0.6.2", - "libc", -] - [[package]] name = "core-foundation" version = "0.7.0" @@ -801,10 +782,14 @@ dependencies = [ ] [[package]] -name = "core-foundation-sys" -version = "0.6.2" +name = "core-foundation" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" +checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +dependencies = [ + "core-foundation-sys 0.8.2", + "libc", +] [[package]] name = "core-foundation-sys" @@ -813,16 +798,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" [[package]] -name = "core-graphics" -version = "0.14.0" +name = "core-foundation-sys" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54c4ab33705fa1fc8af375bb7929d68e1c1546c1ecef408966d8c3e49a1d84a" -dependencies = [ - "bitflags 1.2.1", - "core-foundation 0.6.4", - "foreign-types", - "libc", -] +checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" [[package]] name = "core-graphics" @@ -837,25 +816,38 @@ dependencies = [ ] [[package]] -name = "core-text" -version = "10.0.0" +name = "core-graphics" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f59bff773954e5cd058a3f5983406b52bec7cc65202bef340ba64a0c40ac91" +checksum = "fc239bba52bab96649441699533a68de294a101533b0270b2d65aa402b29a7f9" dependencies = [ - "core-foundation 0.6.4", - "core-graphics 0.14.0", + "bitflags 1.2.1", + "core-foundation 0.9.1", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags 1.2.1", + "core-foundation 0.9.1", "foreign-types", "libc", ] [[package]] name = "core-text" -version = "15.0.0" +version = "19.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131b3fd1f8bd5db9f2b398fa4fdb6008c64afc04d447c306ac2c7e98fba2a61d" +checksum = "d2c7f46e8b820fd5f4b28528104b28b0a91cbe9e9c5bde8017087fb44bc93a60" dependencies = [ - "core-foundation 0.7.0", - "core-graphics 0.19.2", + "core-foundation 0.9.1", + "core-graphics 0.22.1", "foreign-types", "libc", ] @@ -1150,16 +1142,6 @@ dependencies = [ "smallvec 0.6.13", ] -[[package]] -name = "expat-sys" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa" -dependencies = [ - "cmake", - "pkg-config", -] - [[package]] name = "fake-simd" version = "0.1.2" @@ -1239,19 +1221,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "font-loader" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ece0e8a5dd99a65f8de977b4a3f89e3b5a5259e15ae610952cdb894e96f5e2e" -dependencies = [ - "core-foundation 0.6.4", - "core-text 10.0.0", - "libc", - "servo-fontconfig", - "winapi 0.3.9", -] - [[package]] name = "fontconfig" version = "0.1.0" @@ -3332,37 +3301,6 @@ dependencies = [ "serial-core", ] -[[package]] -name = "servo-fontconfig" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a088f8d775a5c5314aae09bd77340bc9c67d72b9a45258be34c83548b4814cd9" -dependencies = [ - "libc", - "servo-fontconfig-sys", -] - -[[package]] -name = "servo-fontconfig-sys" -version = "4.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0aa080856db55f188aaf36f01cae8c03448a6056552adb77d461179e44e1a14" -dependencies = [ - "expat-sys", - "pkg-config", - "servo-freetype-sys", -] - -[[package]] -name = "servo-freetype-sys" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9232032c2e85118c0282c6562c84cab12316e655491ba0a5d1905b2320060d1b" -dependencies = [ - "cmake", - "pkg-config", -] - [[package]] name = "sha-1" version = "0.8.2" @@ -4348,11 +4286,10 @@ dependencies = [ "allsorts", "anyhow", "config", - "core-foundation 0.7.0", - "core-text 15.0.0", + "core-foundation 0.9.1", + "core-text", "dwrote", "euclid 0.20.14", - "font-loader", "fontconfig", "freetype", "harfbuzz", diff --git a/config/src/font.rs b/config/src/font.rs index a6892d9ad..2663a6ca3 100644 --- a/config/src/font.rs +++ b/config/src/font.rs @@ -227,9 +227,8 @@ pub enum FontLocatorSelection { FontConfig, /// Use the EnumFontFamilies call on win32 systems EnumFontFamilies, - /// Use the fontloader crate to use a system specific method of - /// resolving fonts - FontLoader, + /// Use CoreText on macOS + CoreText, /// Use only the font_dirs configuration to locate fonts ConfigDirsOnly, } @@ -243,7 +242,7 @@ impl Default for FontLocatorSelection { if cfg!(windows) { FontLocatorSelection::EnumFontFamilies } else if cfg!(target_os = "macos") { - FontLocatorSelection::FontLoader + FontLocatorSelection::CoreText } else { FontLocatorSelection::FontConfig } @@ -264,7 +263,7 @@ impl FontLocatorSelection { pub fn variants() -> Vec<&'static str> { vec![ "FontConfig", - "FontLoader", + "CoreText", "ConfigDirsOnly", "EnumFontFamilies", ] @@ -276,7 +275,7 @@ impl std::str::FromStr for FontLocatorSelection { fn from_str(s: &str) -> Result { match s.to_lowercase().as_ref() { "fontconfig" => Ok(Self::FontConfig), - "fontloader" => Ok(Self::FontLoader), + "coretext" => Ok(Self::CoreText), "configdirsonly" => Ok(Self::ConfigDirsOnly), "enumfontfamilies" => Ok(Self::EnumFontFamilies), _ => Err(anyhow!( diff --git a/wezterm-font/Cargo.toml b/wezterm-font/Cargo.toml index 80c09ac9e..852c821bf 100644 --- a/wezterm-font/Cargo.toml +++ b/wezterm-font/Cargo.toml @@ -34,8 +34,5 @@ dwrote = "0.9" winapi = "0.3" [target.'cfg(target_os = "macos")'.dependencies] -core-foundation = "0.7" -core-text = "15.0" -# on linux, font-loader pulls in servo-font* crates which conflict with -# our newer font related deps, so we avoid it on linux -font-loader = { version = "0.8" } +core-foundation = "0.9" +core-text = "19.0" diff --git a/wezterm-font/src/locator/core_text.rs b/wezterm-font/src/locator/core_text.rs new file mode 100644 index 000000000..276520204 --- /dev/null +++ b/wezterm-font/src/locator/core_text.rs @@ -0,0 +1,93 @@ +#![cfg(target_os="macos")] + +use crate::locator::{FontDataHandle, FontLocator}; +use config::FontAttributes; +use core_foundation::base::{CFType, TCFType}; +use core_foundation::dictionary::CFDictionary; +use core_foundation::number::CFNumber; +use core_foundation::string::CFString; +use core_foundation::url::CFURL; +use core_text::font_descriptor::*; +use std::collections::HashSet; +use std::path::PathBuf; + +/// A FontLocator implemented using the system font loading +/// functions provided by the font-loader crate. +pub struct CoreTextFontLocator {} + +fn descriptor_from_attr(attr: &FontAttributes) -> anyhow::Result { + let family_name = attr + .family + .parse::() + .map_err(|_| anyhow::anyhow!("failed to parse family name {} as CFString", attr.family))?; + + let symbolic_traits: CTFontSymbolicTraits = kCTFontMonoSpaceTrait + | if attr.bold { kCTFontBoldTrait } else { 0 } + | if attr.italic { kCTFontItalicTrait } else { 0 }; + + let family_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontFamilyNameAttribute) }; + let traits_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontTraitsAttribute) }; + let symbolic_traits_attr: CFString = + unsafe { TCFType::wrap_under_get_rule(kCTFontSymbolicTrait) }; + + let traits = CFDictionary::from_CFType_pairs(&[( + symbolic_traits_attr.as_CFType(), + CFNumber::from(symbolic_traits as i32).as_CFType(), + )]); + + let attributes = CFDictionary::from_CFType_pairs(&[ + (traits_attr, traits.as_CFType()), + (family_attr, family_name.as_CFType()), + ]); + Ok(core_text::font_descriptor::new_from_attributes(&attributes)) +} + +fn font_path_from_descriptor(descriptor: &CTFontDescriptor) -> anyhow::Result { + let url: CFURL; + unsafe { + let value = + CTFontDescriptorCopyAttribute(descriptor.as_concrete_TypeRef(), kCTFontURLAttribute); + + if value.is_null() { + return Err(anyhow::anyhow!("font descriptor has no URL")); + } + + let value: CFType = TCFType::wrap_under_get_rule(value); + if !value.instance_of::() { + return Err(anyhow::anyhow!("font descriptor URL is not a CFURL")); + } + url = TCFType::wrap_under_get_rule(std::mem::transmute(value.as_CFTypeRef())); + } + if let Some(path) = url.to_path() { + Ok(path) + } else { + Err(anyhow::anyhow!("font descriptor URL is not a path")) + } +} + +impl FontLocator for CoreTextFontLocator { + fn load_fonts( + &self, + fonts_selection: &[FontAttributes], + loaded: &mut HashSet, + ) -> anyhow::Result> { + let mut fonts = vec![]; + + for attr in fonts_selection { + if let Ok(descriptor) = descriptor_from_attr(attr) { + if let Ok(path) = font_path_from_descriptor(&descriptor) { + let handle = FontDataHandle::OnDisk { path, index: 0 }; + + if let Ok(parsed) = crate::parser::ParsedFont::from_locator(&handle) { + if crate::parser::font_info_matches(attr, parsed.names()) { + fonts.push(handle); + loaded.insert(attr.clone()); + } + } + } + } + } + + Ok(fonts) + } +} diff --git a/wezterm-font/src/locator/font_config.rs b/wezterm-font/src/locator/font_config.rs index d01739d0e..e0741ce38 100644 --- a/wezterm-font/src/locator/font_config.rs +++ b/wezterm-font/src/locator/font_config.rs @@ -16,7 +16,6 @@ impl FontLocator for FontConfigFontLocator { loaded: &mut HashSet, ) -> anyhow::Result> { let mut fonts = vec![]; - let mut fallback = vec![]; for attr in fonts_selection { let mut pattern = FontPattern::new()?; @@ -55,8 +54,6 @@ impl FontLocator for FontConfigFontLocator { } } - fonts.append(&mut fallback); - Ok(fonts) } } diff --git a/wezterm-font/src/locator/font_loader.rs b/wezterm-font/src/locator/font_loader.rs deleted file mode 100644 index beb1cb382..000000000 --- a/wezterm-font/src/locator/font_loader.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::locator::{FontDataHandle, FontLocator}; -use ::font_loader::system_fonts; -use config::FontAttributes; -use std::collections::HashSet; - -/// A FontLocator implemented using the system font loading -/// functions provided by the font-loader crate. -pub struct FontLoaderFontLocator {} - -impl FontLocator for FontLoaderFontLocator { - fn load_fonts( - &self, - fonts_selection: &[FontAttributes], - loaded: &mut HashSet, - ) -> anyhow::Result> { - let mut fonts = Vec::new(); - for font_attr in fonts_selection { - if cfg!(windows) && font_attr.family.len() > 31 { - // Avoid a super painful panic in the upstream library: - // https://github.com/MSleepyPanda/rust-font-loader/blob/2b264974fe080955d341ce8a163035bdce24ff2f/src/win32.rs#L87 - log::error!( - "font-loader would panic for font family `{}`", - font_attr.family - ); - continue; - } - let mut font_props = system_fonts::FontPropertyBuilder::new() - .family(&font_attr.family) - .monospace(); - font_props = if font_attr.bold { - font_props.bold() - } else { - font_props - }; - font_props = if font_attr.italic { - font_props.italic() - } else { - font_props - }; - let font_props = font_props.build(); - - if let Some((data, index)) = system_fonts::get(&font_props) { - let handle = FontDataHandle::Memory { - data, - index: index as u32, - name: font_attr.family.clone(), - }; - - // The system may just decide to give us its fallback, - // eg: Consolas, so we need to parse the returned font - // here to see if we got what we asked for. - if let Ok(parsed) = crate::parser::ParsedFont::from_locator(&handle) { - if crate::parser::font_info_matches(font_attr, parsed.names()) { - fonts.push(handle); - loaded.insert(font_attr.clone()); - } - } - } - } - Ok(fonts) - } -} diff --git a/wezterm-font/src/locator/mod.rs b/wezterm-font/src/locator/mod.rs index 54d34ad65..95416fec3 100644 --- a/wezterm-font/src/locator/mod.rs +++ b/wezterm-font/src/locator/mod.rs @@ -2,11 +2,10 @@ use config::FontAttributes; use std::collections::HashSet; use std::path::PathBuf; +pub mod core_text; pub mod enum_font_families; #[cfg(all(unix, not(target_os = "macos")))] pub mod font_config; -#[cfg(target_os = "macos")] -pub mod font_loader; /// Represents the data behind a font. /// This may be a font file that we can read off disk, @@ -64,11 +63,11 @@ pub fn new_locator(locator: FontLocatorSelection) -> Box { #[cfg(not(all(unix, not(target_os = "macos"))))] panic!("fontconfig not compiled in"); } - FontLocatorSelection::FontLoader => { + FontLocatorSelection::CoreText => { #[cfg(target_os = "macos")] - return Box::new(font_loader::FontLoaderFontLocator {}); + return Box::new(core_text::CoreTextFontLocator {}); #[cfg(not(target_os = "macos"))] - panic!("fontloader not compiled in"); + panic!("CoreText not compiled in"); } FontLocatorSelection::EnumFontFamilies => { #[cfg(windows)] diff --git a/wezterm-font/src/parser.rs b/wezterm-font/src/parser.rs index 32c94d3ae..336aaa9f0 100644 --- a/wezterm-font/src/parser.rs +++ b/wezterm-font/src/parser.rs @@ -551,7 +551,7 @@ pub fn font_info_matches(attr: &FontAttributes, names: &Names) -> bool { Some("Italic") if attr.italic && !attr.bold => true, Some("Bold") if attr.bold && !attr.italic => true, Some("Bold Italic") if attr.bold && attr.italic => true, - Some("Regular") | None if !attr.italic && !attr.bold => true, + Some("Medium") | Some("Regular") | None if !attr.italic && !attr.bold => true, _ => false, } } else {