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 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 5.5 committed 2026-09-30 15:04:36 +03:00
1 parent 41fb37505b
commit f17279244f
1 file changed
+19 -9
+19 -9
View File
@@ -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);
}