1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-24 13:52:55 +03:00

fonts: start breaking out the loader/locator concept

This commit is contained in:
Wez Furlong 2019-12-08 22:48:47 -08:00
parent 151a915128
commit 6f867ac3e2
5 changed files with 233 additions and 0 deletions

View File

@ -0,0 +1,59 @@
use crate::config::FontAttributes;
use crate::font::loader::{FontDataHandle, FontLocator};
use failure::Fallible;
/// A FontLocator implemented using the system font loading
/// functions provided by font-config
pub struct FontConfigFontLocator {}
impl FontLocator for FontLoaderFontLocator {
fn load_fonts(&self, fonts_selection: &[FontAttributes]) -> Fallible<Vec<FontDataHandle>> {
let mut fonts = vec![];
let mut fallback = vec![];
for attr in style.font_with_fallback() {
let mut pattern = FontPattern::new()?;
pattern.family(&attr.family)?;
if attr.bold {
pattern.add_integer("weight", 200)?;
}
if attr.italic {
pattern.add_integer("slant", 100)?;
}
/*
pattern.add_double("size", config.font_size * font_scale)?;
pattern.add_double("dpi", config.dpi)?;
*/
pattern.monospace()?;
pattern.config_substitute(fcwrap::MatchKind::Pattern)?;
pattern.default_substitute();
// and obtain the selection with the best preference
// at index 0.
let font_list = pattern.sort(true)?;
for (idx, pat) in font_list.iter().enumerate() {
pattern.render_prepare(&pat)?;
let file = pat.get_file()?;
let handle = FontDataHandle::OnDisk {
path: file.into(),
index: 0, // FIXME: extract this from pat!
};
// When it comes to handling fallback, we prefer our
// user specified set of names so we take those first.
// The additional items in this loop are fallback fonts
// suggested by fontconfig and are lower precedence
if idx == 0 {
self.fonts.push(handle);
} else {
self.fallback.push(handle);
}
}
}
fonts.extend_from_slice(&mut fallback);
Ok(fonts)
}
}

106
src/font/loader/font_kit.rs Normal file
View File

@ -0,0 +1,106 @@
use crate::config::FontAttributes;
use crate::font::loader::{FontDataHandle, FontLocator};
use ::font_kit::error::SelectionError;
use ::font_kit::family_handle::FamilyHandle;
use ::font_kit::family_name::FamilyName;
use ::font_kit::handle::Handle;
use ::font_kit::properties::Properties;
use ::font_kit::source::Source;
use ::font_kit::sources::mem::MemSource;
use failure::Fallible;
use std::path::PathBuf;
/// A FontLocator implemented using the font loading
/// functions provided by Source's from font-kit crate.
impl<S> FontLocator for S
where
S: Source,
{
fn load_fonts(&self, fonts_selection: &[FontAttributes]) -> Fallible<Vec<FontDataHandle>> {
let mut handles = vec![];
for font in fonts_selection {
let mut props = Properties::new();
if font.bold {
props.weight(font_kit::properties::Weight::BOLD);
}
if font.italic {
props.style(font_kit::properties::Style::Italic);
}
let family = FamilyName::Title(font.family.clone());
match self.select_best_match(&[family.clone()], &props) {
Ok(Handle::Path { path, font_index }) => handles.push(FontDataHandle::OnDisk {
path,
index: font_index,
}),
Ok(Handle::Memory { bytes, font_index }) => handles.push(FontDataHandle::Memory {
data: bytes.to_vec(),
index: font_index,
}),
Err(_) => {}
}
}
Ok(handles)
}
}
/// A FontLocator that uses a set of fonts discovered in an arbitrary
/// location on the local filesystem
pub struct FileSystemDirectorySource {
mem_source: MemSource,
}
impl FileSystemDirectorySource {
pub fn new(paths: &[PathBuf]) -> Self {
let mut fonts = vec![];
for path in paths {
for entry in walkdir::WalkDir::new(path).into_iter() {
let entry = match entry {
Ok(entry) => entry,
Err(_) => continue,
};
let path = entry.path();
let mut file = match std::fs::File::open(path) {
Err(_) => continue,
Ok(file) => file,
};
use font_kit::file_type::FileType;
match font_kit::font::Font::analyze_file(&mut file) {
Err(_) => continue,
Ok(FileType::Single) => fonts.push(Handle::from_path(path.to_owned(), 0)),
Ok(FileType::Collection(font_count)) => {
for font_index in 0..font_count {
fonts.push(Handle::from_path(path.to_owned(), font_index))
}
}
}
}
}
Self {
mem_source: MemSource::from_fonts(fonts.into_iter()).unwrap(),
}
}
}
impl Source for FileSystemDirectorySource {
fn all_fonts(&self) -> Result<Vec<Handle>, SelectionError> {
self.mem_source.all_fonts()
}
fn all_families(&self) -> Result<Vec<String>, SelectionError> {
self.mem_source.all_families()
}
fn select_family_by_name(&self, family_name: &str) -> Result<FamilyHandle, SelectionError> {
self.mem_source.select_family_by_name(family_name)
}
fn select_by_postscript_name(&self, postscript_name: &str) -> Result<Handle, SelectionError> {
self.mem_source.select_by_postscript_name(postscript_name)
}
}

View File

@ -0,0 +1,39 @@
use crate::config::FontAttributes;
use crate::font::loader::{FontDataHandle, FontLocator};
use ::font_loader::system_fonts;
use failure::Fallible;
/// 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]) -> Fallible<Vec<FontDataHandle>> {
let mut fonts = Vec::new();
for font_attr in fonts_selection {
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,
};
fonts.push(handle);
}
}
Ok(fonts)
}
}

27
src/font/loader/mod.rs Normal file
View File

@ -0,0 +1,27 @@
use crate::config::FontAttributes;
use failure::Fallible;
use std::path::PathBuf;
#[cfg(all(unix, any(feature = "fontconfig", not(target_os = "macos"))))]
pub mod font_config;
#[cfg(any(target_os = "macos", windows))]
pub mod font_kit;
#[cfg(any(target_os = "macos", windows))]
pub mod font_loader;
/// Represents the data behind a font.
/// This may be a font file that we can read off disk,
/// or some data that resides in memory.
/// The `index` parameter is the index into a font
/// collection if the data represents a collection of
/// fonts.
pub enum FontDataHandle {
OnDisk { path: PathBuf, index: u32 },
Memory { data: Vec<u8>, index: u32 },
}
pub trait FontLocator {
/// Given a font selection, return the list of successfully loadable
/// FontDataHandle's that correspond to it
fn load_fonts(&self, fonts_selection: &[FontAttributes]) -> Fallible<Vec<FontDataHandle>>;
}

View File

@ -9,6 +9,8 @@ use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
pub mod loader;
pub mod system;
pub use self::system::*;