Pass the runs' ordered flag with them to stay under the argument limit

This commit is contained in:
Dylan M. Taylor
2026-11-11 09:59:01 +00:00
parent 8b47a9bd4b
commit 3e6d8f686b
+19 -21
View File
@@ -634,6 +634,13 @@ fn runs_ordered(runs: &[(Range<usize>, 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<usize>, 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<usize>, TextStyle)], ordered: bool, b: usize) -> usize {
@@ -721,8 +728,7 @@ impl<'a> Para<'a> {
fn new(
text: &'a str,
base: usize,
runs: &'a [(Range<usize>, 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<usize>) -> 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<usize>, TextStyle)], ordered: bool, primaries: &[Resolved], bidi: &BidiInfo) -> Vec<CharInfo> {
fn char_forms(text: &str, base: usize, runs: Runs, primaries: &[Resolved], bidi: &BidiInfo) -> Vec<CharInfo> {
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<usize>, TextStyle)
items
}
fn paragraph(
text: &str,
base: usize,
runs: &[(Range<usize>, TextStyle)],
ordered: bool,
primaries: &[Resolved],
variation_ids: &[u32],
para: &ParagraphStyle,
width: Option<f32>,
) -> Vec<ParaLine> {
fn paragraph(text: &str, base: usize, runs: Runs, primaries: &[Resolved], variation_ids: &[u32], para: &ParagraphStyle, width: Option<f32>) -> Vec<ParaLine> {
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<usize>, 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() {