From 860bc13e791f457fbfb9b644bf94231ff1d6b1a6 Mon Sep 17 00:00:00 2001 From: SusieeTheFemboy <96988330+SusieeTheLinuxUser@users.noreply.github.com> Date: Tue, 27 Oct 2026 01:14:05 +0100 Subject: [PATCH] M4: an emergency break can back up to right after the line's first letter (part of #1219) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The backward search for a safe break started at line_start + 2, so in a three-letter run like กเม it skipped the only safe boundary and left the line ending in a leading vowel. Co-Authored-By: Claude Opus 5.5 --- crates/text/src/behaviour_tests.rs | 16 ++++++++++++++++ crates/text/src/layout.rs | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/text/src/behaviour_tests.rs b/crates/text/src/behaviour_tests.rs index b2adcd2d..c2a935c8 100644 --- a/crates/text/src/behaviour_tests.rs +++ b/crates/text/src/behaviour_tests.rs @@ -334,6 +334,22 @@ fn thai_comes_from_a_thai_font_when_one_is_installed() { assert_eq!(drawn, want, "every Thai char is in a drawn cluster"); } +#[test] +fn thai_emergency_break_can_back_up_to_the_first_letter() { + // #1219: in "กเม" the overflow lands between the leading vowel and its consonant; the only + // safe break is right after the first letter, so the vowel moves down with "ม". + let s = "กเม"; + let thai = ["Noto Sans Thai", "Noto Sans Thai UI", "Leelawadee UI", "Thonburi", "Tahoma"]; + if face().is_none() || !thai.iter().any(|t| find_face(t, "Regular").is_some_and(|t| s.chars().all(|c| t.has_char(c)))) { + return; + } + let mut t = text(s, TextAutoResize::Height); + t.style.font_size = 16.0; + let two = layout(&t, None, None).caret(2).0; + let lines = layout(&t, Some(two + 0.5), None).lines; + assert_eq!(lines.get(1).map(|l| l.char_start), Some(1), "the leading vowel stays with its consonant"); +} + #[test] fn thai_emergency_breaks_keep_marks_and_leading_vowels_with_their_letter() { // #1219: Thai writes no spaces between words, so a paragraph is one run with no break diff --git a/crates/text/src/layout.rs b/crates/text/src/layout.rs index c10ea44d..b6a550da 100644 --- a/crates/text/src/layout.rs +++ b/crates/text/src/layout.rs @@ -524,7 +524,7 @@ pub fn layout(text: &TextData, box_width: Option, box_height: Option) let carry = (brk + 1..items.len().min(brk + 257)) .take_while(|&k| items.get(k).is_some_and(|it| it.ch != '\n' && it.ch != LINE_SEPARATOR)) .find(|&k| safe(k)); - brk = (line_start + 2..brk).rev().find(|&k| safe(k)).or(carry).unwrap_or(brk); + brk = (line_start + 1..brk).rev().find(|&k| safe(k)).or(carry).unwrap_or(brk); } lines.push((line_start, brk, false, para)); line_start = brk;