Merge pull request #6339 from christianlappin/codex/fix-6323-kashida-test-order

Tests: preserve duplicate glyph order in kashida ownership checks
This commit is contained in:
BFlat
2026-11-10 20:05:25 +07:00
committed by GitHub
+41 -3
View File
@@ -512,6 +512,43 @@ fn assert_authored_ownership(t: &TextObject, text: &str, l: &TextLayout, what: &
}
}
/// Repeated glyphs in one cluster can belong to differently painted runs. Match each authored
/// occurrence in order, without needing an installed font, and still reject a changed owner.
#[test]
fn duplicate_authored_glyphs_keep_occurrence_order() {
let mut text = TextObject::point(Point::ZERO, "\u{0651}", style(FAMILY));
text.runs.push(vectorcraft_doc::TextRun::new("\u{0651}", CharStyle { fill: red(), ..style(FAMILY) }));
let glyph = |run| PositionedGlyph {
outline: Default::default(),
run,
byte: 0,
origin: Point::ZERO,
advance: 0.0,
len: 4,
angle: 0.0,
line: 0,
font_id: 0,
gid: 7,
xf: Affine::IDENTITY,
rtl: true,
scale: 1.0,
image: None,
colour: None,
bend: None,
unturned: Affine::IDENTITY,
pivot: Point::ZERO,
carets: Vec::new(),
width: 0.0,
width_start: 0.0,
};
let before = TextLayout { glyphs: vec![glyph(0), glyph(1)], ..TextLayout::default() };
assert_eq!(assert_kashida_ownership(&text, &before, &before, &red(), "duplicate glyphs", false), 0);
let mut wrong = before.clone();
wrong.glyphs[0].run = 1;
assert!(std::panic::catch_unwind(|| assert_kashida_ownership(&text, &before, &wrong, &red(), "changed owner", false)).is_err());
}
/// Compare authored glyph run indices before/after Insert Kashidas (matched by byte and gid;
/// layout order can differ between point and justified area), and assert every inserted tatweel
/// uses the base letter's paint at the cluster start—not `mark_fill`. When `require_mark_last`,
@@ -525,16 +562,17 @@ fn assert_kashida_ownership(
what: &str,
require_mark_last: bool,
) -> usize {
let mut before_runs: std::collections::HashMap<(usize, u32), Vec<usize>> = std::collections::HashMap::new();
let mut before_runs: std::collections::HashMap<(usize, u32), std::collections::VecDeque<usize>> = std::collections::HashMap::new();
for g in before.glyphs.iter().filter(|g| g.len > 0) {
before_runs.entry((g.byte, g.gid)).or_default().push(g.run);
before_runs.entry((g.byte, g.gid)).or_default().push_back(g.run);
}
let mut after_n = 0;
for g in with_kashida.glyphs.iter().filter(|g| g.len > 0) {
after_n += 1;
let runs =
before_runs.get_mut(&(g.byte, g.gid)).unwrap_or_else(|| panic!("{what}: authored glyph {} at {} missing before kashida", g.gid, g.byte));
let want_run = runs.pop().unwrap_or_else(|| panic!("{what}: no remaining before-run for {} at {}", g.gid, g.byte));
// Duplicate glyphs at the same cluster byte retain their occurrence order.
let want_run = runs.pop_front().unwrap_or_else(|| panic!("{what}: no remaining before-run for {} at {}", g.gid, g.byte));
assert_eq!(g.run, want_run, "{what}: authored run at {} gid {}", g.byte, g.gid);
let want_fill = coloured.runs.get(want_run).map(|r| &r.style.fill).unwrap_or_else(|| panic!("{what}: missing run {want_run}"));
assert_eq!(&run_of(coloured, g).style.fill, want_fill, "{what}: authored fill at {}", g.byte);