From f17279244fb80d9916bb265f9bb7ee2fb1d7c1ee Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Wed, 30 Sep 2026 15:04:36 +0300 Subject: [PATCH] fix(shx): unifont subshapes are two-byte codes Since 2026.39 reads `unifont 1.0` files (isocp.shx and its family among them) instead of falling back to a substitute, a glyph built from a subshape went wrong: code 7 is followed by a two-byte code point in a unifont, but only big fonts read two bytes, so the low byte ran on as a drawing opcode. ISOCP's `9` came out at x-height as a small bowl. Fixes #1556 Co-Authored-By: Claude Opus 5.5 --- src/scene/text/shx.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/scene/text/shx.rs b/src/scene/text/shx.rs index f36ed052d..4bbf1e248 100644 --- a/src/scene/text/shx.rs +++ b/src/scene/text/shx.rs @@ -544,16 +544,26 @@ fn interpret( } } 7 => { - let mut sub = *b.get(i).unwrap_or(&0) as u16; - i += 1; - // A big font references subshapes by a two-byte code: - // `7, 0, hi, lo`. - if file.kind == ShxKind::Bigfont && sub == 0 { - let hi = *b.get(i).unwrap_or(&0) as u16; - let lo = *b.get(i + 1).unwrap_or(&0) as u16; + let two_bytes = |i: usize| { + ((*b.get(i).unwrap_or(&0) as u16) << 8) | *b.get(i + 1).unwrap_or(&0) as u16 + }; + // A unifont names its subshape by a two-byte code point + // (`7, hi, lo`); read as one byte, the low byte ran on as an + // opcode and the glyph came out mangled (ISOCP's `9`, #1556). + // A big font uses `7, 0, hi, lo`; a shape file one byte. + let sub = if file.kind == ShxKind::Unifont { i += 2; - sub = (hi << 8) | lo; - } + two_bytes(i - 2) + } else { + let sub = *b.get(i).unwrap_or(&0) as u16; + i += 1; + if file.kind == ShxKind::Bigfont && sub == 0 { + i += 2; + two_bytes(i - 2) + } else { + sub + } + }; if !skipping && sub != 0 && sub != shape_number { interpret(file, sub, st, cur, out, depth + 1); }