fix(text): stroke aliases txt/monotxt must ignore a same-named TTF

Face::resolve routes a name to a system TrueType face when installed_alias
reports that an alias names a real TTF face (the #1764 escape hatch, added so
an installed ISOCPEUR draws that face instead of its LFF stand-in).

That hatch also caught TXT/MONOTXT: on a machine with a font family matching
"txt" (e.g. a "Txt Regular"), the DXF stroke text font resolved to that
TrueType face instead of the embedded stroke substitute, contradicting the
documented contract that a missing .shx draws with the stroke substitute and
never with a similarly-named TrueType face.

TXT/MONOTXT are stroke aliases, so exclude them from the hatch. ISOCPEUR keeps
its #1764 behaviour.

Eight tests failed on such a machine and now pass: the four font-face/LFF
assertions (shx_name_stays_lff, lff_falls_back_to_ttf_for_uncovered_glyph,
big_font_pairing_routes_ideographs_and_leaves_latin_alone,
lff_tessellation_golden) and the four searchable-PDF assertions that route
through the same Face::resolve. Adds a regression test for the contract.
This commit is contained in:
Karim Jerbi committed 2026-10-17 05:56:14 +01:00
1 parent 0e4c4c311d
commit ddf348af22
2 files changed
+35 -2

No files matched your search

+11 -2
View File
@@ -96,6 +96,13 @@ const ALIASES: &[(&str, &str)] = &[
("EXTFONT", "unicode"),
];
/// Aliases that always mean the reference's *stroke* font and so never defer
/// to an installed TrueType face of the same name: `txt`/`monotxt` are the DXF
/// stroke text fonts, and a coincidental `Txt Regular` is not that font. The
/// `installed_alias` escape hatch stays for aliases that genuinely name a
/// TrueType face (ISOCPEUR, #1764).
const STROKE_ALIASES: &[&str] = &["TXT", "MONOTXT"];
/// The space advance of the reference's stroke fonts, in glyph units (cap
/// height 9), measured from their text extents: the SHX names these LFF
/// fonts stand in for keep the reference's word gaps.
@@ -529,11 +536,13 @@ pub fn is_builtin(name: &str) -> bool {
/// draws with the stroke substitute, not the installed `.ttf` (measured).
fn installed_alias(stem: &str, name: &str) -> bool {
use crate::scene::text::sysfont;
let stem = stem.trim().to_ascii_uppercase();
!is_shx_name(name)
&& !STROKE_ALIASES.contains(&stem.as_str())
&& ALIASES.iter().any(|(alias, _)| *alias == stem)
&& (sysfont::family_for_file(name).is_some()
|| sysfont::canonical_family_name(stem)
.is_some_and(|family| family.eq_ignore_ascii_case(stem)))
|| sysfont::canonical_family_name(&stem)
.is_some_and(|family| family.eq_ignore_ascii_case(&stem)))
}
/// Whether `name` is written as an `.shx` file name.