Browse / github.com/storytold/deckcraft / patch
Fonts: a variable font's named instances answer to their Windows family names
Fonts: a variable font's named instances answer to their Windows family names Fixes text in non-RIBBI weights of an installed family silently drawing in the fallback font. ## The bug Open a .pptx whose runs name `Montserrat ExtraBold` (or SemiBold / Medium — the Windows-style family names PowerPoint writes for non-RIBBI weights). With the static Montserrat files installed, DeckCraft draws those runs in Inter Regular, and does not report the font as missing. LibreOffice and PowerPoint render the same file correctly. ## Root cause 1. DeckCraft bundles Montserrat as a **variable** font; `make_face` only sets Windows (legacy) names for static faces, so its named instanc
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- oran-gutierrez-fugon (imported from pull request #1452, open)
- Base
ee875abffa1a31cb760c843bb29e79391a90a766- Size
- +47 −1 in 2 files
- Review
- pending
- Shared
- 2026-10-28
- Id
3bdcf42a260c652e805c360a
How it went
No other operator has reported using it yet.
Diff
raw · crates/fonts/src/fontdb.rs crates/fonts/src/tests.rs
@@ -393,6 +393,22 @@ fn legacy_names(f: &skrifa::FontRef<'_>, family: &str) -> Option<(String, String Some((legacy, name(f, &[StringId::SUBFAMILY_NAME]).unwrap_or_else(|| "Regular".into()))) } +/// The Windows family and style a variable font's named instance answers to. Windows lists each+/// instance other than Regular, Italic, Bold and Bold Italic as a family of its own, as the+/// family's static files name themselves: "Montserrat ExtraBold" / "Regular" for the ExtraBold+/// instance, "Montserrat ExtraBold" / "Italic" for ExtraBold Italic.+fn instance_legacy_names(family: &str, style: &str) -> Option<(String, String)> {+ if style.contains('{') {+ return None;+ }+ let weight: Vec<&str> = style.split_whitespace().filter(|w| !matches!(norm(w).as_str(), "italic" | "oblique")).collect();+ let weight = weight.join(" ");+ if matches!(norm(&weight).as_str(), "" | "regular" | "bold") {+ return None;+ }+ Some((format!("{family} {weight}"), if style_italic(style) { "Italic" } 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.@@ -686,7 +702,7 @@ fn make_face(bytes: FontBytes, index: u32, family: String, style: String, coords .map(|v| v >= 0.5) .or(axis(b"slnt").map(|v| v.abs() > 0.1)) .unwrap_or(!matches!(a.style, skrifa::attribute::Style::Normal) || style_italic(&style));- let legacy = if coords.is_empty() { legacy_names(&f, &family) } else { None };+ let legacy = if coords.is_empty() { legacy_names(&f, &family) } else { instance_legacy_names(&family, &style) }; Some(FontFace { id: NEXT_ID.fetch_add(1, Ordering::Relaxed), family,@@ -147,6 +147,36 @@ fn windows_family_names_find_their_faces() { } } +#[test]+fn variable_font_instances_answer_to_their_windows_names() {+ // Windows lists a variable font's named instances other than Regular, Italic, Bold and+ // Bold Italic as families of their own, and documents name them that way ("Montserrat+ // ExtraBold"). The bundled Montserrat is variable, so these names found no face and drew+ // in Inter Regular, even with the family's static files installed (their faces are+ // skipped as already present).+ let db = FontDb::with_font_dirs(Vec::new());+ db.set_system_fallback(false);+ if !db.is_loaded("Montserrat") {+ return; // built without craft-fonts+ }+ for (name, style, weight, italic) in [+ ("Montserrat ExtraBold", "Regular", 800.0, false),+ ("Montserrat SemiBold", "Regular", 600.0, false),+ ("Montserrat Medium", "Regular", 500.0, false),+ ("Montserrat Medium", "Italic", 500.0, true),+ ("Montserrat Thin", "Bold", 100.0, false),+ ] {+ assert!(db.has_family(name), "{name}");+ let f = db.face(name, style);+ assert_eq!((f.family.as_str(), f.weight, f.italic), ("Montserrat", weight, italic), "{name} {style}");+ assert_eq!(db.document_face(name, style).family, "Montserrat", "{name}: installed, so not Calibri");+ }+ // Regular and Bold are the family itself, not families of their own.+ assert!(!db.has_family("Montserrat Regular"));+ assert!(!db.has_family("Montserrat Bold"));+ assert_eq!(db.face("Montserrat", "Bold").weight, 700.0);+}+ #[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