mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 10:05:42 +00:00
Type: a tabbed right-to-left line whose last break read precedes a forced line break ends after it
When the last of the bounded breaks such a line reads came right before U+2028, the line ended at that break and the next line held only the forced break, drawing an empty line. The line now reads on to the forced break and ends there when it fits as drawn.
This commit is contained in:
@@ -379,8 +379,9 @@ pub(super) fn word_width(g: &[SGlyph], i: usize, line_end: &[f64], kinsoku: Kins
|
||||
/// [`MAX_DRAWN_CHECKS_STEPPING_BACK`] when a glyph of the line has a negative advance, the earlier
|
||||
/// ones without a hyphen are bisected); hyphenation points are measured the same way. Once such a
|
||||
/// line holds a glyph with a negative advance and has been wider than `width` in the order of its
|
||||
/// text, it reads at most [`MAX_DRAWN_CHECKS_STEPPING_BACK`] legal breaks further and ends at the
|
||||
/// latest of the breaks read that fits as drawn.
|
||||
/// text, it reads at most [`MAX_DRAWN_CHECKS_STEPPING_BACK`] legal breaks further, and a forced
|
||||
/// line break right after the last of them, and ends at the latest of the breaks read that fits as
|
||||
/// drawn.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(super) fn break_line(
|
||||
text: &str,
|
||||
@@ -538,8 +539,9 @@ pub(super) fn break_line(
|
||||
// breaks past where it first overflowed in the order of its text, and ends at the
|
||||
// latest break read that fits as drawn: each of those breaks is measured one by one.
|
||||
// A soft hyphen ending the text draws no hyphen there, as at the end of the text below.
|
||||
// A break right before a forced line break reads on to it: the line ends there.
|
||||
breaks_past_overflow += usize::from(overflowed && back > 0.0);
|
||||
if breaks_past_overflow >= MAX_DRAWN_CHECKS_STEPPING_BACK {
|
||||
if breaks_past_overflow >= MAX_DRAWN_CHECKS_STEPPING_BACK && g.get(cluster_end).is_none_or(|n| n.ch != '\u{2028}') {
|
||||
return settle(tabbed, checks(back), (cluster_end, hyphenated && cluster_end < g.len()), &breaks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -745,6 +745,32 @@ fn a_tabbed_line_stepping_back_ends_at_a_final_soft_hyphen_without_a_hyphen() {
|
||||
assert_eq!(ended, (len, false));
|
||||
}
|
||||
|
||||
/// A tabbed line with glyphs stepping back whose last break read comes right before a forced line
|
||||
/// break ends after the forced break, so the next line does not start with it and draw empty.
|
||||
#[test]
|
||||
fn a_tabbed_line_stepping_back_keeps_a_forced_break_after_its_last_break_read() {
|
||||
// The 1,024th space is the 1,024th break past the overflow, and glyph 3075 after it is U+2028.
|
||||
let text = format!("a\ty{}\u{2028}bbb", "bz ".repeat(1024));
|
||||
let specs: Vec<_> = text
|
||||
.char_indices()
|
||||
.map(|(byte, ch)| {
|
||||
let adv = match ch {
|
||||
'y' | 'z' => -1.0,
|
||||
' ' | '\u{2028}' => 0.0,
|
||||
_ => 1.0,
|
||||
};
|
||||
(byte, ch.len_utf8(), adv, ch)
|
||||
})
|
||||
.collect();
|
||||
let glyphs = synthetic_glyphs(&specs);
|
||||
assert_eq!(glyphs[3075].ch, '\u{2028}');
|
||||
let drawn_fits = |end: usize, _hyphenated: bool| end <= 10 || end >= 3075;
|
||||
let fits: Option<&dyn Fn(usize, bool) -> bool> = Some(&drawn_fits);
|
||||
let ended =
|
||||
break_line(&text, &glyphs, 0, 30.0, &[], 0.0, None, Burasagari::None, Kinsoku::None, KinsokuShoriType::PushOutOnly, false, false, &[], fits);
|
||||
assert_eq!(ended, (3076, false));
|
||||
}
|
||||
|
||||
/// A tab to a default or left stop does not read the text after it, which only right, center and
|
||||
/// decimal stops align: the first tab of a long paragraph does not read the paragraph to its end.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user