From aeb7ff8391f6ebd5de8997ccb3e46afc46ce855e Mon Sep 17 00:00:00 2001 From: Sventurbo <94544175+Sventurbo@users.noreply.github.com> Date: Thu, 5 Nov 2026 02:44:46 +0100 Subject: [PATCH] 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 --- .../src/raster/tests/non_embedded_arial.rs | 18 ++++++++++++++---- vendor/hayro-interpret/src/font/cid.rs | 18 +++++++++++++----- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/crates/render/src/raster/tests/non_embedded_arial.rs b/crates/render/src/raster/tests/non_embedded_arial.rs index b64ea5d0f4..c434bbb7ab 100644 --- a/crates/render/src/raster/tests/non_embedded_arial.rs +++ b/crates/render/src/raster/tests/non_embedded_arial.rs @@ -84,10 +84,20 @@ fn without_and_with_unicode(font: Font<'_>) -> (Vec, Vec) { #[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" }); diff --git a/vendor/hayro-interpret/src/font/cid.rs b/vendor/hayro-interpret/src/font/cid.rs index 291e9dde2d..0ed6c20973 100644 --- a/vendor/hayro-interpret/src/font/cid.rs +++ b/vendor/hayro-interpret/src/font/cid.rs @@ -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).