mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-29 04:56:58 -06:00
Merge PR #351 from dotCooCoo: Fonts: the font scan leaves out faces with no outline tables
This commit is contained in:
@@ -41,3 +41,7 @@ sync_github_name = true
|
||||
[people.Silvertree2010]
|
||||
display_name = "Netter"
|
||||
sync_github_name = false
|
||||
|
||||
[people.dotCooCoo]
|
||||
real_name = "Robert Lee"
|
||||
sync_github_name = true
|
||||
|
||||
@@ -393,9 +393,16 @@ fn legacy_names(f: &skrifa::FontRef<'_>, family: &str) -> Option<(String, String
|
||||
Some((legacy, name(f, &[StringId::SUBFAMILY_NAME]).unwrap_or_else(|| "Regular".into())))
|
||||
}
|
||||
|
||||
/// The tables skrifa reads glyph outlines from: `glyf` (TrueType), `CFF `, `CFF2` and `VARC`. For a
|
||||
/// face with none of them (bitmaps only, or outlines in Apple's `hvgl` table), [`FontDb::outline`]
|
||||
/// returns an empty path for every glyph.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
const OUTLINE_TABLES: [&[u8; 4]; 4] = [b"glyf", b"CFF ", b"CFF2", b"VARC"];
|
||||
|
||||
/// (family, style) of every face in the font file at `path`, reading only its table directories
|
||||
/// and `name` tables: a scan opens hundreds of font files, many of them megabytes long. A
|
||||
/// variable font is cataloged under its default style; its named instances appear once it loads.
|
||||
/// Faces with none of the [`OUTLINE_TABLES`] are left out.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn file_face_names(path: &std::path::Path) -> Vec<(String, String)> {
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
@@ -424,6 +431,9 @@ fn file_face_names(path: &std::path::Path) -> Vec<(String, String)> {
|
||||
let dir = read_at(start.into(), 12)?;
|
||||
let tables = u16::from_be_bytes(dir.get(4..6)?.try_into().ok()?) as usize;
|
||||
let records = read_at(u64::from(start) + 12, tables * 16)?;
|
||||
if !records.as_chunks::<16>().0.iter().any(|r| OUTLINE_TABLES.iter().any(|t| r.starts_with(*t))) {
|
||||
return None;
|
||||
}
|
||||
let rec = records.as_chunks::<16>().0.iter().find(|r| r.starts_with(b"name"))?;
|
||||
let (offset, len) = (be32(rec, 8)?, be32(rec, 12)?);
|
||||
if len > MAX_NAME_TABLE {
|
||||
|
||||
@@ -253,6 +253,36 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn faces_without_outlines_are_not_cataloged() {
|
||||
// Rename the Semibold's `glyf` table, as in fonts whose glyphs are bitmaps or are stored in
|
||||
// Apple's `hvgl` table. The face still maps "A", but its outline is empty. The new tag
|
||||
// keeps the table directory sorted.
|
||||
let mut semibold = include_bytes!("../tests/fixtures/legacy-semibold.ttf").to_vec();
|
||||
let tables = u16::from_be_bytes([semibold[4], semibold[5]]) as usize;
|
||||
let glyf = (0..tables).map(|i| 12 + 16 * i).find(|&r| &semibold[r..r + 4] == b"glyf").unwrap();
|
||||
semibold[glyf..glyf + 4].copy_from_slice(b"gxyz");
|
||||
let loaded = FontDb::with_font_dirs(Vec::new());
|
||||
assert_eq!(loaded.add_font(semibold.clone()), 1);
|
||||
let face = loaded.face("DeckCraft Legacy", "Semibold");
|
||||
assert!(face.covers('A'));
|
||||
assert!(loaded.outline(&face, face.glyph_for('A')).elements().is_empty());
|
||||
// The system font scan lists the Regular, which has outlines, and leaves out the Semibold
|
||||
// under both of its names.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
let dir = std::env::temp_dir().join(format!("deckcraft-fonts-outlines-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
std::fs::write(dir.join("legacy-semibold.ttf"), &semibold).unwrap();
|
||||
std::fs::write(dir.join("legacy-regular.ttf"), include_bytes!("../tests/fixtures/legacy-regular.ttf")).unwrap();
|
||||
let db = FontDb::with_font_dirs(vec![dir.clone()]);
|
||||
db.set_system_fallback(false);
|
||||
assert_eq!(db.styles("DeckCraft Legacy"), ["Regular"]);
|
||||
assert!(!db.has_family("DeckCraft Legacy Semibold"));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_document_fonts_are_drawn_in_calibri() {
|
||||
// PowerPoint draws a missing family in Calibri, whatever its panose or the theme says.
|
||||
|
||||
Reference in New Issue
Block a user