#[cfg(not(target_arch = "wasm32"))]
use std::collections::HashMap;
#[cfg(not(target_arch = "wasm32"))]
use std::path::{Path, PathBuf};
#[cfg(not(target_arch = "wasm32"))]
use std::sync::Arc;
#[cfg(not(target_arch = "wasm32"))]
use skrifa::raw::FileRef;
#[cfg(not(target_arch = "wasm32"))]
use skrifa::string::StringId;
use skrifa::MetadataProvider;
#[cfg(not(target_arch = "wasm32"))]
use crate::FontData;
#[cfg(not(target_arch = "wasm32"))]
#[derive(Default)]
pub(crate) struct Files {
loaded: HashMap<PathBuf, FontData>,
}
#[cfg(not(target_arch = "wasm32"))]
impl Files {
pub(crate) fn read(&mut self, path: &Path) -> Option<FontData> {
if let Some(data) = self.loaded.get(path) {
return Some(Arc::clone(data));
}
let file = std::fs::File::open(path).ok()?;
let map = unsafe { memmap2::Mmap::map(&file) }.ok()?;
let data: FontData = Arc::new(map);
self.loaded.insert(path.to_path_buf(), Arc::clone(&data));
Some(data)
}
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn face_index(bytes: &[u8], postscript_name: &str) -> Option<u32> {
let collection = match FileRef::new(bytes).ok()? {
FileRef::Font(_) => return Some(0),
FileRef::Collection(collection) => collection,
};
let names: Vec<Option<String>> = (0..collection.len())
.map(|index| {
collection
.get(index)
.ok()
.and_then(|face| {
face.localized_strings(StringId::POSTSCRIPT_NAME)
.english_or_first()
})
.map(|name| name.to_string())
})
.collect();
let exact = names
.iter()
.position(|name| name.as_deref() == Some(postscript_name));
if let Some(index) = exact {
return Some(index as u32);
}
let stem = family_stem(postscript_name);
names
.iter()
.position(|name| name.as_deref().map(family_stem) == Some(stem))
.map(|index| index as u32)
}
#[cfg(not(target_arch = "wasm32"))]
fn family_stem(postscript_name: &str) -> &str {
postscript_name
.rsplit_once('-')
.map_or(postscript_name, |(stem, _)| stem)
}
pub(crate) fn covers(bytes: &[u8], index: u32, character: char) -> bool {
skrifa::FontRef::from_index(bytes, index)
.map(|face| face.charmap().map(character).is_some())
.unwrap_or(false)
}