From 3e6d8f686b796ac1dd2e046e58892ab0042abf15 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Wed, 11 Nov 2026 09:59:01 +0000 Subject: [PATCH] Pass the runs' ordered flag with them to stay under the argument limit --- crates/text/src/layout.rs | 40 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/crates/text/src/layout.rs b/crates/text/src/layout.rs index 6ab393cd9..408efa437 100644 --- a/crates/text/src/layout.rs +++ b/crates/text/src/layout.rs @@ -634,6 +634,13 @@ fn runs_ordered(runs: &[(Range, TextStyle)]) -> bool { runs.windows(2).all(|w| w[0].0.end <= w[1].0.start) } +/// Style runs with whether they are [`runs_ordered`]. +#[derive(Clone, Copy)] +struct Runs<'a> { + list: &'a [(Range, TextStyle)], + ordered: bool, +} + /// The style run index covering global byte `b` (the run before it at a boundary, for empty /// paragraphs at the end). `ordered` is [`runs_ordered`] of `runs`. fn run_at(runs: &[(Range, TextStyle)], ordered: bool, b: usize) -> usize { @@ -721,8 +728,7 @@ impl<'a> Para<'a> { fn new( text: &'a str, base: usize, - runs: &'a [(Range, TextStyle)], - ordered: bool, + runs: Runs<'a>, primaries: &'a [Resolved], variation_ids: &'a [u32], para: &'a ParagraphStyle, @@ -731,8 +737,8 @@ impl<'a> Para<'a> { let default_level = para.rtl.map(|r| if r { Level::rtl() } else { Level::ltr() }); let bidi = BidiInfo::new(text, default_level); let base_rtl = bidi.paragraphs[0].level.is_rtl(); - let chars = char_forms(text, base, runs, ordered, primaries, &bidi); - let items = build_items(text, &chars, runs); + let chars = char_forms(text, base, runs, primaries, &bidi); + let items = build_items(text, &chars, runs.list); // Prefix widths and the preceding non-whitespace boundary make candidate line widths O(1). // Every-line composition evaluates O(n²) candidate breaks; summing each candidate's bytes // or rescanning its trailing whitespace would otherwise add another factor of text length. @@ -755,7 +761,7 @@ impl<'a> Para<'a> { } previous_non_ws[b + c.len_utf8()] = non_ws_end; } - Para { text, base, runs, primaries, variation_ids, para, width, bidi, base_rtl, chars, items, char_adv, prefix_adv, previous_non_ws } + Para { text, base, runs: runs.list, primaries, variation_ids, para, width, bidi, base_rtl, chars, items, char_adv, prefix_adv, previous_non_ws } } fn range_w(&self, r: Range) -> f32 { @@ -1037,11 +1043,11 @@ impl<'a> Para<'a> { } /// Each char with its shaped form, face, direction and run. -fn char_forms(text: &str, base: usize, runs: &[(Range, TextStyle)], ordered: bool, primaries: &[Resolved], bidi: &BidiInfo) -> Vec { +fn char_forms(text: &str, base: usize, runs: Runs, primaries: &[Resolved], bidi: &BidiInfo) -> Vec { text.char_indices() .map(|(b, c)| { - let si = run_at(runs, ordered, base + b); - let style = &runs[si].1; + let si = run_at(runs.list, runs.ordered, base + b); + let style = &runs.list[si].1; let primary = primaries[si].face; let face_of = |ch: char| if ch.is_whitespace() { primary } else { fonts::fallback_for(ch, primary) }; let all_small = style.opentype.all_small_caps && style.caps != Caps::All; @@ -1095,18 +1101,9 @@ fn build_items(text: &str, chars: &[CharInfo], runs: &[(Range, TextStyle) items } -fn paragraph( - text: &str, - base: usize, - runs: &[(Range, TextStyle)], - ordered: bool, - primaries: &[Resolved], - variation_ids: &[u32], - para: &ParagraphStyle, - width: Option, -) -> Vec { +fn paragraph(text: &str, base: usize, runs: Runs, primaries: &[Resolved], variation_ids: &[u32], para: &ParagraphStyle, width: Option) -> Vec { if text.is_empty() { - let si = run_at(runs, ordered, base); + let (runs, si) = (runs.list, run_at(runs.list, runs.ordered, base)); let pm = style_metrics(primaries, runs, si); // No text to resolve a direction from: the explicit one. let rtl = para.rtl == Some(true); @@ -1127,7 +1124,7 @@ fn paragraph( underline: None, }]; } - let p = Para::new(text, base, runs, ordered, primaries, variation_ids, para, width); + let p = Para::new(text, base, runs, primaries, variation_ids, para, width); let ranges = p.break_ranges(); let nlines = ranges.len(); ranges.into_iter().enumerate().map(|(li, r)| p.place_line(li, r, li + 1 == nlines)).collect() @@ -1189,7 +1186,8 @@ pub fn layout_rich_uncached(text: &str, runs: &[(Range, TextStyle)], para let mut plines: Vec<(usize, ParaLine)> = Vec::new(); for (pi, span) in paragraph_ranges(text).enumerate() { let p = text.get(span.bytes.clone()).unwrap_or_default(); - plines.extend(paragraph(p, span.bytes.start, runs, ordered, &primaries, &variation_ids, para_at(pi), width).into_iter().map(|l| (pi, l))); + plines + .extend(paragraph(p, span.bytes.start, Runs { list: runs, ordered }, &primaries, &variation_ids, para_at(pi), width).into_iter().map(|l| (pi, l))); } let mut baseline = 0.0f32; for (i, (pi, pl)) in plines.into_iter().enumerate() {