1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-27 12:23:46 +03:00

fonts: refactor: split out FontDataSource

This commit is contained in:
Wez Furlong 2021-04-08 11:34:58 -07:00
parent 63222e4a94
commit 364ab2a35b
8 changed files with 139 additions and 187 deletions

View File

@ -1,8 +1,8 @@
//! A font-database to keep track of fonts that we've located
use crate::ftwrap::Library;
use crate::locator::{FontDataHandle, FontDataSource};
use crate::parser::{load_built_in_fonts, parse_and_collect_font_info, FontMatch, ParsedFont};
use crate::FontDataHandle;
use anyhow::Context;
use config::{Config, FontAttributes};
use rangeset::RangeSet;
@ -95,10 +95,10 @@ impl FontDatabase {
Err(_) => continue,
};
let path = entry.path();
parse_and_collect_font_info(path, &mut font_info)
let source = FontDataSource::OnDisk(entry.path().to_path_buf());
parse_and_collect_font_info(&source, &mut font_info)
.map_err(|err| {
log::trace!("failed to read {}: {:#}", path.display(), err);
log::trace!("failed to read {:?}: {:#}", source, err);
err
})
.ok();

View File

@ -1,6 +1,6 @@
//! Higher level freetype bindings
use crate::locator::FontDataHandle;
use crate::locator::{FontDataHandle, FontDataSource};
use crate::parser::ParsedFont;
use anyhow::{anyhow, Context};
use config::{configuration, FreeTypeLoadTarget};
@ -490,12 +490,12 @@ impl Library {
/// Returns the number of faces in a given font.
/// For a TTF this will be 1.
/// For a TTC, it will be the number of contained fonts
pub fn query_num_faces(&self, handle: &FontDataHandle) -> anyhow::Result<u32> {
let face = match handle {
FontDataHandle::OnDisk { path, .. } => self
pub fn query_num_faces(&self, source: &FontDataSource) -> anyhow::Result<u32> {
let face = match source {
FontDataSource::OnDisk(path) => self
.new_face(path.to_str().unwrap(), -1)
.context("query_num_faces")?,
FontDataHandle::Memory { data, .. } => self
FontDataSource::Memory { data, .. } => self
.new_face_from_slice(data.clone(), -1)
.context("query_num_faces")?,
};
@ -503,29 +503,18 @@ impl Library {
}
pub fn face_from_locator(&self, handle: &FontDataHandle) -> anyhow::Result<Face> {
let (face, variation) = match handle {
FontDataHandle::OnDisk {
path,
index,
variation,
} => (
self.new_face(path.to_str().unwrap(), *index as _)?,
*variation,
),
FontDataHandle::Memory {
data,
index,
variation,
..
} => (
self.new_face_from_slice(data.clone(), *index as _)?,
*variation,
),
let face = match &handle.source {
FontDataSource::OnDisk(path) => {
self.new_face(path.to_str().unwrap(), handle.index as _)?
}
FontDataSource::Memory { data, .. } => {
self.new_face_from_slice(data.clone(), handle.index as _)?
}
};
if variation != 0 {
if handle.variation != 0 {
unsafe {
ft_result(FT_Set_Named_Instance(face.face, variation), ())
ft_result(FT_Set_Named_Instance(face.face, handle.variation), ())
.context("FT_Set_Named_Instance")?;
}
}

View File

@ -1,6 +1,6 @@
#![cfg(target_os = "macos")]
use crate::locator::{FontDataHandle, FontLocator};
use crate::locator::{FontDataHandle, FontDataSource, FontLocator};
use crate::parser::FontMatch;
use config::FontAttributes;
use core_foundation::array::CFArray;
@ -58,7 +58,8 @@ fn handle_from_descriptor(descriptor: &CTFontDescriptor) -> Option<FontDataHandl
let family_name = descriptor.family_name();
let mut font_info = vec![];
crate::parser::parse_and_collect_font_info(&path, &mut font_info).ok()?;
let source = FontDataSource::OnDisk(path);
crate::parser::parse_and_collect_font_info(&source, &mut font_info).ok()?;
for (parsed, locator) in font_info {
if parsed.names().full_name == family_name

View File

@ -1,5 +1,5 @@
use crate::fcwrap;
use crate::locator::{FontDataHandle, FontLocator};
use crate::locator::{FontDataHandle, FontDataSource, FontLocator};
use crate::parser::FontMatch;
use anyhow::Context;
use config::FontAttributes;
@ -44,8 +44,8 @@ impl FontLocator for FontConfigFontLocator {
);
let file = best.get_file()?;
let handle = FontDataHandle::OnDisk {
path: file.into(),
let handle = FontDataHandle {
source: FontDataSource::OnDisk(file.into()),
index: best.get_integer("index")?.try_into()?,
variation: 0,
};
@ -109,8 +109,8 @@ impl FontLocator for FontConfigFontLocator {
let file = pat.get_file().context("pat.get_file")?;
let handle = FontDataHandle::OnDisk {
path: file.into(),
let handle = FontDataHandle {
source: FontDataSource::OnDisk(file.into()),
index: pat.get_integer("index")?.try_into()?,
variation: 0,
};

View File

@ -1,6 +1,6 @@
#![cfg(windows)]
use crate::locator::{FontDataHandle, FontLocator};
use crate::locator::{FontDataHandle, FontDataSource, FontLocator};
use crate::parser::{parse_and_collect_font_info, FontMatch};
use config::FontAttributes;
use dwrote::{FontDescriptor, FontStretch, FontStyle, FontWeight};
@ -45,10 +45,12 @@ fn extract_font_data(font: HFONT, attr: &FontAttributes) -> anyhow::Result<FontD
// that we asked for.
let index =
crate::parser::resolve_font_from_ttc_data(&attr, &data)?.unwrap_or(0) as u32;
Ok(FontDataHandle::Memory {
data,
Ok(FontDataHandle {
source: FontDataSource::Memory {
data,
name: attr.family.clone(),
},
index,
name: attr.family.clone(),
variation: 0,
})
} else {
@ -59,10 +61,12 @@ fn extract_font_data(font: HFONT, attr: &FontAttributes) -> anyhow::Result<FontD
_ 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: Cow::Owned(data),
Ok(FontDataHandle {
source: FontDataSource::Memory {
data: Cow::Owned(data),
name: attr.family.clone(),
},
index: 0,
name: attr.family.clone(),
variation: 0,
})
}
@ -151,7 +155,8 @@ fn handle_from_descriptor(
let mut font_info = vec![];
log::debug!("{} -> {}", family_name, path.display());
if parse_and_collect_font_info(&path, &mut font_info).is_ok() {
let source = FontDataSource::OnDisk(path);
if parse_and_collect_font_info(&source, &mut font_info).is_ok() {
for (parsed, handle) in font_info {
if parsed.matches_attributes(attr) != FontMatch::NoMatch {
return Some(handle);

View File

@ -10,126 +10,99 @@ pub mod core_text;
pub mod font_config;
pub mod gdi;
#[derive(Clone)]
pub enum FontDataSource {
OnDisk(PathBuf),
Memory {
name: String,
data: Cow<'static, [u8]>,
},
}
impl FontDataSource {
pub fn name_or_path_str(&self) -> Cow<str> {
match self {
Self::OnDisk(path) => path.to_string_lossy(),
Self::Memory { name, .. } => Cow::Borrowed(name),
}
}
pub fn load_data<'a>(&'a self) -> anyhow::Result<Cow<'a, [u8]>> {
match self {
Self::OnDisk(path) => {
let data = std::fs::read(path)?;
Ok(Cow::Owned(data))
}
Self::Memory { data, .. } => Ok(data.clone()),
}
}
}
impl Eq for FontDataSource {}
impl PartialEq for FontDataSource {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::OnDisk(path_a), Self::OnDisk(path_b)) => path_a == path_b,
(Self::Memory { name: name_a, .. }, Self::Memory { name: name_b, .. }) => {
name_a == name_b
}
_ => false,
}
}
}
impl Ord for FontDataSource {
fn cmp(&self, other: &Self) -> Ordering {
let a = self.name_or_path_str();
let b = other.name_or_path_str();
a.cmp(&b)
}
}
impl PartialOrd for FontDataSource {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl std::fmt::Debug for FontDataSource {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
match self {
Self::OnDisk(path) => fmt.debug_struct("OnDisk").field("path", &path).finish(),
Self::Memory { data, name } => fmt
.debug_struct("Memory")
.field("name", &name)
.field("data_len", &data.len())
.finish(),
}
}
}
/// 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.
#[derive(Clone)]
pub enum FontDataHandle {
OnDisk {
path: PathBuf,
index: u32,
variation: u32,
},
Memory {
name: String,
data: std::borrow::Cow<'static, [u8]>,
index: u32,
variation: u32,
},
#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
pub struct FontDataHandle {
pub source: FontDataSource,
pub index: u32,
pub variation: u32,
}
impl FontDataHandle {
pub fn name_or_path_str(&self) -> Cow<str> {
match self {
Self::OnDisk { path, .. } => path.to_string_lossy(),
Self::Memory { name, .. } => Cow::Borrowed(name),
}
self.source.name_or_path_str()
}
pub fn index(&self) -> u32 {
match self {
Self::OnDisk { index, .. } => *index,
Self::Memory { index, .. } => *index,
}
self.index
}
pub fn set_index(&mut self, idx: u32) {
match self {
Self::OnDisk { index, .. } => *index = idx,
Self::Memory { index, .. } => *index = idx,
}
}
}
impl Eq for FontDataHandle {}
impl PartialEq for FontDataHandle {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(
Self::OnDisk {
path: path_a,
index: index_a,
variation: variation_a,
},
Self::OnDisk {
path: path_b,
index: index_b,
variation: variation_b,
},
) => path_a == path_b && index_a == index_b && variation_a == variation_b,
(
Self::Memory {
name: name_a,
index: index_a,
variation: variation_a,
..
},
Self::Memory {
name: name_b,
index: index_b,
variation: variation_b,
..
},
) => name_a == name_b && index_a == index_b && variation_a == variation_b,
_ => false,
}
}
}
impl Ord for FontDataHandle {
fn cmp(&self, other: &Self) -> Ordering {
let a = (self.name_or_path_str(), self.index());
let b = (other.name_or_path_str(), other.index());
a.cmp(&b)
}
}
impl PartialOrd for FontDataHandle {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl std::fmt::Debug for FontDataHandle {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
match self {
Self::OnDisk {
path,
index,
variation,
} => fmt
.debug_struct("OnDisk")
.field("path", &path)
.field("index", &index)
.field("variation", &variation)
.finish(),
Self::Memory {
data,
index,
name,
variation,
} => fmt
.debug_struct("Memory")
.field("name", &name)
.field("data_len", &data.len())
.field("index", &index)
.field("variation", &variation)
.finish(),
}
self.index = idx;
}
}

View File

@ -1,8 +1,7 @@
use crate::locator::FontDataHandle;
use crate::locator::{FontDataHandle, FontDataSource};
use crate::shaper::GlyphInfo;
use config::FontAttributes;
use std::borrow::Cow;
use std::path::Path;
#[derive(Debug)]
pub enum MaybeShaped {
@ -236,14 +235,16 @@ pub fn resolve_font_from_ttc_data(
data: &Cow<'static, [u8]>,
) -> anyhow::Result<Option<usize>> {
let lib = crate::ftwrap::Library::new()?;
let mut locator = FontDataHandle::Memory {
name: "".to_string(),
data: data.clone(),
let mut locator = FontDataHandle {
source: FontDataSource::Memory {
name: "".to_string(),
data: data.clone(),
},
index: 0,
variation: 0,
};
let num_faces = lib.query_num_faces(&locator)?;
let num_faces = lib.query_num_faces(&locator.source)?;
for index in 0..num_faces {
locator.set_index(index);
@ -293,10 +294,12 @@ pub(crate) fn load_built_in_fonts(
let parsed = ParsedFont::from_face(&face)?;
font_info.push((
parsed,
FontDataHandle::Memory {
data: Cow::Borrowed(data),
FontDataHandle {
source: FontDataSource::Memory {
data: Cow::Borrowed(data),
name: name.to_string(),
},
index: 0,
name: name.to_string(),
variation: 0,
},
));
@ -306,27 +309,20 @@ pub(crate) fn load_built_in_fonts(
}
pub(crate) fn parse_and_collect_font_info(
path: &Path,
source: &FontDataSource,
font_info: &mut Vec<(ParsedFont, FontDataHandle)>,
) -> anyhow::Result<()> {
let lib = crate::ftwrap::Library::new()?;
let locator = FontDataHandle::OnDisk {
path: path.to_path_buf(),
index: 0,
variation: 0,
};
let num_faces = lib.query_num_faces(&locator)?;
let num_faces = lib.query_num_faces(&source)?;
fn load_one(
lib: &crate::ftwrap::Library,
path: &Path,
source: &FontDataSource,
index: u32,
font_info: &mut Vec<(ParsedFont, FontDataHandle)>,
) -> anyhow::Result<()> {
let locator = FontDataHandle::OnDisk {
path: path.to_path_buf(),
let locator = FontDataHandle {
source: source.clone(),
index,
variation: 0,
};
@ -336,8 +332,8 @@ pub(crate) fn parse_and_collect_font_info(
for (variation, parsed) in variations.into_iter().enumerate() {
font_info.push((
parsed,
FontDataHandle::OnDisk {
path: path.to_path_buf(),
FontDataHandle {
source: source.clone(),
index,
variation: variation as u32 + 1,
},
@ -351,13 +347,8 @@ pub(crate) fn parse_and_collect_font_info(
}
for index in 0..num_faces {
if let Err(err) = load_one(&lib, path, index, font_info) {
log::trace!(
"error while parsing {} index {}: {}",
path.display(),
index,
err
);
if let Err(err) = load_one(&lib, &source, index, font_info) {
log::trace!("error while parsing {:?} index {}: {}", source, index, err);
}
}

View File

@ -59,15 +59,8 @@ fn locate_offset_table<'a>(f: &OpenTypeFile<'a>, idx: usize) -> anyhow::Result<O
impl ParsedFont {
pub fn from_locator(handle: &FontDataHandle) -> anyhow::Result<Self> {
let (data, index) = match handle {
FontDataHandle::Memory { data, index, .. } => (data.to_vec(), *index),
FontDataHandle::OnDisk { path, index, .. } => {
let data = std::fs::read(path)?;
(data, *index)
}
};
let index = index as usize;
let data = handle.source.load_data()?;
let index = handle.index as usize;
let owned_scope = ReadScopeOwned::new(ReadScope::new(&data));