mirror of
https://github.com/wez/wezterm.git
synced 2024-11-10 15:04:32 +03:00
wezterm-font: remove font-loader dep on windows
There are a number of cases where font-loader might panic on windows, and the optional font-loader dep causes problems with `cargo vendor` in #337, so this is a step to removing that dep. This commit makes direct GDI calls to enumerate monospace truetype fonts from the system and then applies our normal matching on the result.
This commit is contained in:
parent
9bebc811d0
commit
9ca428c4e1
@ -225,6 +225,8 @@ impl_lua_conversion!(StyleRule);
|
||||
pub enum FontLocatorSelection {
|
||||
/// Use fontconfig APIs to resolve fonts (!macos, posix systems)
|
||||
FontConfig,
|
||||
/// Use the EnumFontFamilies call on win32 systems
|
||||
EnumFontFamilies,
|
||||
/// Use the fontloader crate to use a system specific method of
|
||||
/// resolving fonts
|
||||
FontLoader,
|
||||
@ -238,10 +240,12 @@ lazy_static::lazy_static! {
|
||||
|
||||
impl Default for FontLocatorSelection {
|
||||
fn default() -> Self {
|
||||
if cfg!(all(unix, not(target_os = "macos"))) {
|
||||
FontLocatorSelection::FontConfig
|
||||
} else {
|
||||
if cfg!(windows) {
|
||||
FontLocatorSelection::EnumFontFamilies
|
||||
} else if cfg!(target_os = "macos") {
|
||||
FontLocatorSelection::FontLoader
|
||||
} else {
|
||||
FontLocatorSelection::FontConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,7 +262,12 @@ impl FontLocatorSelection {
|
||||
}
|
||||
|
||||
pub fn variants() -> Vec<&'static str> {
|
||||
vec!["FontConfig", "FontLoader", "ConfigDirsOnly"]
|
||||
vec![
|
||||
"FontConfig",
|
||||
"FontLoader",
|
||||
"ConfigDirsOnly",
|
||||
"EnumFontFamilies",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,6 +278,7 @@ impl std::str::FromStr for FontLocatorSelection {
|
||||
"fontconfig" => Ok(Self::FontConfig),
|
||||
"fontloader" => Ok(Self::FontLoader),
|
||||
"configdirsonly" => Ok(Self::ConfigDirsOnly),
|
||||
"enumfontfamilies" => Ok(Self::EnumFontFamilies),
|
||||
_ => Err(anyhow!(
|
||||
"{} is not a valid FontLocatorSelection variant, possible values are {:?}",
|
||||
s,
|
||||
|
@ -29,11 +29,6 @@ window = { path = "../window" }
|
||||
[target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies]
|
||||
fontconfig = { path = "../deps/fontconfig" }
|
||||
|
||||
# on linux, font-loader pulls in servo-font* crates which conflict with
|
||||
# our newer font related deps, so we avoid it on linux
|
||||
[target.'cfg(any(windows, target_os = "macos"))'.dependencies]
|
||||
font-loader = { version = "0.8" }
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
dwrote = "0.9"
|
||||
winapi = "0.3"
|
||||
@ -41,3 +36,6 @@ 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" }
|
||||
|
133
wezterm-font/src/locator/enum_font_families.rs
Normal file
133
wezterm-font/src/locator/enum_font_families.rs
Normal file
@ -0,0 +1,133 @@
|
||||
#![cfg(windows)]
|
||||
|
||||
use crate::locator::{FontDataHandle, FontLocator};
|
||||
use config::FontAttributes;
|
||||
use std::collections::HashSet;
|
||||
use std::ffi::OsString;
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
use winapi::ctypes::c_int;
|
||||
use winapi::shared::minwindef::{DWORD, LPARAM};
|
||||
use winapi::um::wingdi::{
|
||||
CreateCompatibleDC, CreateFontIndirectW, DeleteDC, EnumFontFamiliesExW, GetFontData,
|
||||
SelectObject, ENUMLOGFONTEXW, FIXED_PITCH, GDI_ERROR, LF_FULLFACESIZE, LOGFONTW,
|
||||
OUT_TT_ONLY_PRECIS, TEXTMETRICW, TRUETYPE_FONTTYPE,
|
||||
};
|
||||
|
||||
/// A FontLocator implemented using the system font loading
|
||||
/// functions provided by the font-loader crate.
|
||||
pub struct EnumFontFamiliesFontLocator {}
|
||||
|
||||
struct Entry {
|
||||
log_font: ENUMLOGFONTEXW,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl Entry {
|
||||
fn locator(&self) -> anyhow::Result<FontDataHandle> {
|
||||
unsafe {
|
||||
let hdc = CreateCompatibleDC(std::ptr::null_mut());
|
||||
let font = CreateFontIndirectW(&self.log_font.elfLogFont);
|
||||
SelectObject(hdc, font as *mut _);
|
||||
let size = GetFontData(hdc, 0, 0, std::ptr::null_mut(), 0);
|
||||
let result = match size {
|
||||
_ if size > 0 && size != GDI_ERROR => {
|
||||
let mut data = vec![0u8; size as usize];
|
||||
GetFontData(hdc, 0, 0, data.as_mut_ptr() as *mut _, size);
|
||||
Ok(FontDataHandle::Memory {
|
||||
data,
|
||||
index: 0,
|
||||
name: self.name.clone(),
|
||||
})
|
||||
}
|
||||
_ => Err(anyhow::anyhow!("Failed to get font data")),
|
||||
};
|
||||
DeleteDC(hdc);
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "system" fn callback(
|
||||
lpelfe: *const LOGFONTW,
|
||||
_: *const TEXTMETRICW,
|
||||
fonttype: DWORD,
|
||||
lparam: LPARAM,
|
||||
) -> c_int {
|
||||
let log_font: &ENUMLOGFONTEXW = &*(lpelfe as *const ENUMLOGFONTEXW);
|
||||
if fonttype == TRUETYPE_FONTTYPE && log_font.elfFullName[0] != b'@' as u16 {
|
||||
let fonts = lparam as *mut Vec<Entry>;
|
||||
|
||||
let len = log_font
|
||||
.elfFullName
|
||||
.iter()
|
||||
.position(|&c| c == 0)
|
||||
.unwrap_or(LF_FULLFACESIZE);
|
||||
if let Ok(name) = OsString::from_wide(&log_font.elfFullName[0..len]).into_string() {
|
||||
(*fonts).push(Entry {
|
||||
log_font: *log_font,
|
||||
name,
|
||||
});
|
||||
}
|
||||
}
|
||||
1 // continue enumeration
|
||||
}
|
||||
|
||||
impl FontLocator for EnumFontFamiliesFontLocator {
|
||||
fn load_fonts(
|
||||
&self,
|
||||
fonts_selection: &[FontAttributes],
|
||||
loaded: &mut HashSet<FontAttributes>,
|
||||
) -> anyhow::Result<Vec<FontDataHandle>> {
|
||||
let mut log_font = LOGFONTW {
|
||||
lfHeight: 0,
|
||||
lfWidth: 0,
|
||||
lfEscapement: 0,
|
||||
lfOrientation: 0,
|
||||
lfWeight: 0,
|
||||
lfItalic: 0,
|
||||
lfUnderline: 0,
|
||||
lfStrikeOut: 0,
|
||||
lfCharSet: 0,
|
||||
lfOutPrecision: OUT_TT_ONLY_PRECIS as u8,
|
||||
lfClipPrecision: 0,
|
||||
lfQuality: 0,
|
||||
lfPitchAndFamily: FIXED_PITCH as u8,
|
||||
lfFaceName: [0u16; 32],
|
||||
};
|
||||
|
||||
let mut sys_fonts: Vec<Entry> = vec![];
|
||||
unsafe {
|
||||
let hdc = CreateCompatibleDC(std::ptr::null_mut());
|
||||
EnumFontFamiliesExW(
|
||||
hdc,
|
||||
&mut log_font,
|
||||
Some(callback),
|
||||
&mut sys_fonts as *mut _ as LPARAM,
|
||||
0,
|
||||
);
|
||||
DeleteDC(hdc);
|
||||
}
|
||||
|
||||
let mut handles = vec![];
|
||||
for font in sys_fonts {
|
||||
if let Ok(handle) = font.locator() {
|
||||
if let Ok(parsed) = crate::parser::ParsedFont::from_locator(&handle) {
|
||||
handles.push((handle, parsed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut fonts = Vec::new();
|
||||
for font_attr in fonts_selection {
|
||||
for (handle, parsed) in &handles {
|
||||
if crate::parser::font_info_matches(font_attr, parsed.names()) {
|
||||
fonts.push(handle.clone());
|
||||
loaded.insert(font_attr.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(fonts)
|
||||
}
|
||||
}
|
@ -2,9 +2,10 @@ use config::FontAttributes;
|
||||
use std::collections::HashSet;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub mod enum_font_families;
|
||||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
pub mod font_config;
|
||||
#[cfg(any(target_os = "macos", windows))]
|
||||
#[cfg(target_os = "macos")]
|
||||
pub mod font_loader;
|
||||
|
||||
/// Represents the data behind a font.
|
||||
@ -64,11 +65,17 @@ pub fn new_locator(locator: FontLocatorSelection) -> Box<dyn FontLocator> {
|
||||
panic!("fontconfig not compiled in");
|
||||
}
|
||||
FontLocatorSelection::FontLoader => {
|
||||
#[cfg(any(target_os = "macos", windows))]
|
||||
#[cfg(target_os = "macos")]
|
||||
return Box::new(font_loader::FontLoaderFontLocator {});
|
||||
#[cfg(not(any(target_os = "macos", windows)))]
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
panic!("fontloader not compiled in");
|
||||
}
|
||||
FontLocatorSelection::EnumFontFamilies => {
|
||||
#[cfg(windows)]
|
||||
return Box::new(enum_font_families::EnumFontFamiliesFontLocator {});
|
||||
#[cfg(not(windows))]
|
||||
panic!("EnumFontFamilies not compiled in");
|
||||
}
|
||||
FontLocatorSelection::ConfigDirsOnly => Box::new(NopSystemSource {}),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user