diff options
| author | 7sDream <7822577+7sDream@users.noreply.github.com> | 2023-10-26 00:38:08 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-10-25 18:38:08 +0200 |
| commit | b80382b216d79b56358002687ab288241873bb5b (patch) | |
| tree | 2b25cc3a6290cf9bb7ec1dd702b3735d64982e16 /crates/typst-cli/src | |
| parent | e686a11ae7410dc9e99ad755881663303b2301d9 (diff) | |
Use fontdb to search fonts, with basic fontconfig support (#2472)
Diffstat (limited to 'crates/typst-cli/src')
| -rw-r--r-- | crates/typst-cli/src/fonts.rs | 104 |
1 files changed, 32 insertions, 72 deletions
diff --git a/crates/typst-cli/src/fonts.rs b/crates/typst-cli/src/fonts.rs index 9eeb15e2..7c785716 100644 --- a/crates/typst-cli/src/fonts.rs +++ b/crates/typst-cli/src/fonts.rs @@ -1,12 +1,10 @@ use std::cell::OnceCell; -use std::env; -use std::fs::{self, File}; -use std::path::{Path, PathBuf}; +use std::fs; +use std::path::PathBuf; -use memmap2::Mmap; +use fontdb::{Database, Source}; use typst::diag::StrResult; use typst::font::{Font, FontBook, FontInfo, FontVariant}; -use walkdir::WalkDir; use crate::args::FontsCommand; @@ -67,12 +65,39 @@ impl FontSearcher { /// Search everything that is available. pub fn search(&mut self, font_paths: &[PathBuf]) { + let mut db = Database::new(); + + // Font paths have highest priority. for path in font_paths { - self.search_dir(path) + db.load_fonts_dir(path); } - self.search_system(); + // System fonts have second priority. + db.load_system_fonts(); + + for face in db.faces() { + let path = match &face.source { + Source::File(path) | Source::SharedFile(path, _) => path, + // We never add binary sources to the database, so there + // shouln't be any. + Source::Binary(_) => continue, + }; + + let info = db + .with_face_data(face.id, FontInfo::new) + .expect("database must contain this font"); + if let Some(info) = info { + self.book.push(info); + self.fonts.push(FontSlot { + path: path.clone(), + index: face.index, + font: OnceCell::new(), + }); + } + } + + // Embedded fonts have lowest priority. #[cfg(feature = "embed-fonts")] self.add_embedded(); } @@ -114,69 +139,4 @@ impl FontSearcher { add!("DejaVuSansMono-Oblique.ttf"); add!("DejaVuSansMono-BoldOblique.ttf"); } - - /// Search for fonts in the linux system font directories. - fn search_system(&mut self) { - if cfg!(target_os = "macos") { - self.search_dir("/Library/Fonts"); - self.search_dir("/Network/Library/Fonts"); - self.search_dir("/System/Library/Fonts"); - } else if cfg!(unix) { - self.search_dir("/usr/share/fonts"); - self.search_dir("/usr/local/share/fonts"); - } else if cfg!(windows) { - self.search_dir( - env::var_os("WINDIR") - .map(PathBuf::from) - .unwrap_or_else(|| "C:\\Windows".into()) - .join("Fonts"), - ); - - if let Some(roaming) = dirs::config_dir() { - self.search_dir(roaming.join("Microsoft\\Windows\\Fonts")); - } - - if let Some(local) = dirs::cache_dir() { - self.search_dir(local.join("Microsoft\\Windows\\Fonts")); - } - } - - if let Some(dir) = dirs::font_dir() { - self.search_dir(dir); - } - } - - /// Search for all fonts in a directory recursively. - fn search_dir(&mut self, path: impl AsRef<Path>) { - for entry in WalkDir::new(path) - .follow_links(true) - .sort_by(|a, b| a.file_name().cmp(b.file_name())) - .into_iter() - .filter_map(|e| e.ok()) - { - let path = entry.path(); - if matches!( - path.extension().and_then(|s| s.to_str()), - Some("ttf" | "otf" | "TTF" | "OTF" | "ttc" | "otc" | "TTC" | "OTC"), - ) { - self.search_file(path); - } - } - } - - /// Index the fonts in the file at the given path. - fn search_file(&mut self, path: &Path) { - if let Ok(file) = File::open(path) { - if let Ok(mmap) = unsafe { Mmap::map(&file) } { - for (i, info) in FontInfo::iter(&mmap).enumerate() { - self.book.push(info); - self.fonts.push(FontSlot { - path: path.into(), - index: i as u32, - font: OnceCell::new(), - }); - } - } - } - } } |
