diff --git a/crates/typst-layout/src/inline/collect.rs b/crates/typst-layout/src/inline/collect.rs index fbcddee5c..23e82c417 100644 --- a/crates/typst-layout/src/inline/collect.rs +++ b/crates/typst-layout/src/inline/collect.rs @@ -256,8 +256,7 @@ impl<'a> Collector<'a> { } fn push_text(&mut self, text: &str, styles: StyleChain<'a>) { - self.full.push_str(text); - self.push_segment(Segment::Text(text.len(), styles)); + self.build_text(styles, |full| full.push_str(text)); } fn build_text(&mut self, styles: StyleChain<'a>, f: F) @@ -266,33 +265,33 @@ impl<'a> Collector<'a> { { let prev = self.full.len(); f(&mut self.full); - let len = self.full.len() - prev; - self.push_segment(Segment::Text(len, styles)); + let segment_len = self.full.len() - prev; + + // Merge adjacent text segments with the same styles. + if let Some(Segment::Text(last_len, last_styles)) = self.segments.last_mut() { + if *last_styles == styles { + *last_len += segment_len; + return; + } + } + + self.segments.push(Segment::Text(segment_len, styles)); } fn push_item(&mut self, item: Item<'a>) { - self.full.push_str(item.textual()); - self.push_segment(Segment::Item(item)); - } - - fn push_segment(&mut self, segment: Segment<'a>) { - match (self.segments.last_mut(), &segment) { - // Merge adjacent text segments with the same styles. - (Some(Segment::Text(last_len, last_styles)), Segment::Text(len, styles)) - if *last_styles == *styles => - { - *last_len += *len; - } - + match (self.segments.last_mut(), &item) { // Merge adjacent weak spacing by taking the maximum. ( Some(Segment::Item(Item::Absolute(prev_amount, true))), - Segment::Item(Item::Absolute(amount, true)), + Item::Absolute(amount, true), ) => { *prev_amount = (*prev_amount).max(*amount); } - _ => self.segments.push(segment), + _ => { + self.full.push_str(item.textual()); + self.segments.push(Segment::Item(item)); + } } } } diff --git a/crates/typst-layout/src/inline/linebreak.rs b/crates/typst-layout/src/inline/linebreak.rs index 236d68921..7b66fcdb4 100644 --- a/crates/typst-layout/src/inline/linebreak.rs +++ b/crates/typst-layout/src/inline/linebreak.rs @@ -971,11 +971,13 @@ where } /// Estimates the metrics for the line spanned by the range. + #[track_caller] fn estimate(&self, range: Range) -> T { self.get(range.end) - self.get(range.start) } /// Get the metric at the given byte position. + #[track_caller] fn get(&self, index: usize) -> T { match index.checked_sub(1) { None => T::default(), diff --git a/tests/ref/issue-5244-consecutive-weak-space-heading.png b/tests/ref/issue-5244-consecutive-weak-space-heading.png new file mode 100644 index 000000000..c1ef79249 Binary files /dev/null and b/tests/ref/issue-5244-consecutive-weak-space-heading.png differ diff --git a/tests/ref/issue-5244-consecutive-weak-space.png b/tests/ref/issue-5244-consecutive-weak-space.png new file mode 100644 index 000000000..7a102ddfb Binary files /dev/null and b/tests/ref/issue-5244-consecutive-weak-space.png differ diff --git a/tests/ref/issue-5253-consecutive-weak-space-math.png b/tests/ref/issue-5253-consecutive-weak-space-math.png new file mode 100644 index 000000000..a15646cad Binary files /dev/null and b/tests/ref/issue-5253-consecutive-weak-space-math.png differ diff --git a/tests/suite/layout/spacing.typ b/tests/suite/layout/spacing.typ index f59389956..d5cd122c4 100644 --- a/tests/suite/layout/spacing.typ +++ b/tests/suite/layout/spacing.typ @@ -58,3 +58,21 @@ This is the first line \ #h(2cm, weak: true) A new line // Non-weak-spacing, on the other hand, is not removed. This is the first line \ #h(2cm, weak: false) A new line + +--- issue-5244-consecutive-weak-space --- +#set par(linebreaks: "optimized") +#{ + [A] + h(0.3em, weak: true) + h(0.3em, weak: true) + [B] +} + +--- issue-5244-consecutive-weak-space-heading --- +#set par(justify: true) +#set heading(numbering: "I.") + += #h(0.3em, weak: true) test + +--- issue-5253-consecutive-weak-space-math --- +$= thin thin$ a