diff --git a/crates/eps/src/ai_editing/tests.rs b/crates/eps/src/ai_editing/tests.rs index 32d7c9c74..28f67f215 100644 --- a/crates/eps/src/ai_editing/tests.rs +++ b/crates/eps/src/ai_editing/tests.rs @@ -7379,7 +7379,7 @@ fn bindings_and_values_the_reader_cant_take_are_left_out() { } /// Type in a variable font's named instance names the instance's place in the font's design space -/// (`/4`, each axis as 16.16 fixed) in its font record, so the app that opens the file doesn't take +/// (`/4`, each axis as 16.16 fixed) and the font's version (`/5`) in its font record, so the app that opens the file doesn't take /// the font's default instance (#6388); a run's own Variable Font setting is a font of its own, and /// a static font's record has no design vector. Each comes back as the style it was set in. #[test] @@ -7414,6 +7414,10 @@ fn variable_font_instances_name_their_design_space() { assert!(td.contains("VaritestSans-Bold) /2 1 /4 [ 42598400 ]"), "a setting of its own is a font of its own: {td}"); let static_name = vectorcraft_text::FontDb::global().face(&style_of(12.0).font_family, "Regular").unwrap().postscript_name(); assert!(td.contains(&format!("{static_name}) /2 1 >>")), "a static font has no design vector: {td}"); + // Each variable font's record names the font's version (name ID 5) after its design vector. + // (The string is UTF-16 after a byte order mark, so the match starts after it.) + assert_eq!(td.matches("] /5 (").count(), 3, "{td}"); + assert_eq!(td.matches("Version 1.000) >>").count(), 3, "{td}"); assert_eq!(td.matches("/CoolTypeFont").count(), 5, "four fonts and the hidden characters' font"); let back = read_back(&doc); diff --git a/crates/eps/src/ai_editing/writer/texts.rs b/crates/eps/src/ai_editing/writer/texts.rs index 9bd2ab4f3..1e02941c3 100644 --- a/crates/eps/src/ai_editing/writer/texts.rs +++ b/crates/eps/src/ai_editing/writer/texts.rs @@ -569,7 +569,10 @@ impl TextDoc { /// The index of the font of `st` in the font set. fn font(&mut self, st: &CharStyle) -> i64 { let font = font_name(st); - let same = |f: &FontRecord| f.name == font.name && f.design.iter().map(|v| fixed(*v)).eq(font.design.iter().map(|v| fixed(*v))); + // Two installed versions of one font are two fonts, so each keeps its own `/5`. + let same = |f: &FontRecord| { + f.name == font.name && f.version == font.version && f.design.iter().map(|v| fixed(*v)).eq(font.design.iter().map(|v| fixed(*v))) + }; let i = match self.fonts.iter().position(same) { Some(i) => i, None => { diff --git a/crates/text/src/test_fonts.rs b/crates/text/src/test_fonts.rs index cbb2c20d2..aab7f0e1f 100644 --- a/crates/text/src/test_fonts.rs +++ b/crates/text/src/test_fonts.rs @@ -59,7 +59,8 @@ pub const VARIABLE_WIDEN: f32 = 0.25; /// axis (400–700, default 400, the face itself being Regular) whose maximum makes the glyphs of /// [`VARIABLE_CHARS`] [`VARIABLE_WIDEN`] wider (outlines and advances, through `gvar`), with the /// named instances Normal (the default, the face Regular), SemiBold (550) and Bold (700), plus an instance without -/// a name and one named like another (`BOLD`), which style lists leave out. `None` when it can't +/// a name and one named like another (`BOLD`), which style lists leave out. Its version (name ID 5) is +/// `Version 1.000`. `None` when it can't /// be built. pub fn variable_font() -> Option> { const BASE: &[u8] = include_bytes!("../../../assets/fonts/SourceSans3-Regular.ttf"); @@ -106,6 +107,7 @@ pub fn variable_font() -> Option> { (1, VARIABLE_FAMILY), (2, "Regular"), (4, "Varitest Sans Regular"), + (5, "Version 1.000"), (6, "VaritestSans-Regular"), (256, "Weight"), (257, "Normal"),