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:
parent
63222e4a94
commit
364ab2a35b
@ -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();
|
||||
|
@ -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")?;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user