M2: read Arial's MT suffix in any letter case (#5889)

is_arial compared the family and style without regard to case but
stripped the MT suffix case-sensitively, so arialmt and Arial-Boldmt
weren't read in Arial's glyph order (CodeRabbit review on #6210). The
suffix is now stripped in any case, slicing only at a char boundary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Sventurbo
2026-11-05 13:41:24 +01:00
co-authored by Claude Opus 5.5
parent 9aeab4b8a3
commit aeb7ff8391
2 changed files with 27 additions and 9 deletions
@@ -84,10 +84,20 @@ fn without_and_with_unicode(font: Font<'_>) -> (Vec<u8>, Vec<u8>) {
#[test]
fn an_arial_the_pdf_does_not_embed_draws_the_glyphs_its_codes_name() {
// Each face as Windows exporters name it, and as Word names a face it doesn't embed.
for base_font in
["ArialMT", "Arial-BoldMT", "Arial-ItalicMT", "Arial-BoldItalicMT", "Arial", "Arial,Bold", "Arial,BoldItalic", "ABCDEF+Arial-BoldMT"]
{
// Each face as Windows exporters name it, and as Word names a face it doesn't embed. The name
// is read without regard to case, `MT` included.
for base_font in [
"ArialMT",
"Arial-BoldMT",
"Arial-ItalicMT",
"Arial-BoldItalicMT",
"Arial",
"Arial,Bold",
"Arial,BoldItalic",
"ABCDEF+Arial-BoldMT",
"arialmt",
"Arial-Boldmt",
] {
for mapped in [false, true] {
let (without, with) = without_and_with_unicode(Font { base_font, subtype: "CIDFontType2", mapped, to_unicode: false });
assert!(without == with, "{base_font} (CIDToGIDMap {}): the codes draw \"Low É\"", if mapped { "stream" } else { "/Identity" });
+13 -5
View File
@@ -634,19 +634,27 @@ fn is_variation_selector(c: char) -> bool {
/// Arial faces as exporters name them: `ArialMT`, `Arial-BoldMT`, `Arial-ItalicMT`,
/// `Arial-BoldItalicMT`, or `Arial` followed by `,Bold`, `,Italic` or `,BoldItalic`. Arial
/// Narrow, Arial Black, Arial Unicode MS and Arial Rounded are other fonts, numbered their own
/// way.
/// way. Letter case doesn't matter, `MT` included.
fn is_arial(name: &str) -> bool {
let (family, style) = name.split_once([',', '-', ' ']).unwrap_or((name, ""));
let family = family.strip_suffix("MT").unwrap_or(family);
let style: String = style
.chars()
.filter(|c| !matches!(c, ',' | '-' | ' '))
.collect();
let style = style.strip_suffix("MT").unwrap_or(&style);
family.eq_ignore_ascii_case("Arial")
without_mt(family).eq_ignore_ascii_case("Arial")
&& ["", "Regular", "Bold", "Italic", "BoldItalic"]
.iter()
.any(|s| style.eq_ignore_ascii_case(s))
.any(|s| without_mt(&style).eq_ignore_ascii_case(s))
}
/// PdfCraft patch: `name` without a trailing `MT` in any letter case (Monotype's mark in
/// PostScript names such as `ArialMT`).
fn without_mt(name: &str) -> &str {
name.len()
.checked_sub(2)
.and_then(|stem| Some((name.get(..stem)?, name.get(stem..)?)))
.filter(|(_, suffix)| suffix.eq_ignore_ascii_case("MT"))
.map_or(name, |(stem, _)| stem)
}
/// PdfCraft patch: the largest CID (ISO 32000-2 §9.7.2; CIDs are at most two bytes).