From 521ceae889f15f2a93683ab776cd86a423e5dbed Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 11 Dec 2024 16:46:10 +0100 Subject: [PATCH] Fix crash due to consecutive weak spacing (#5562) --- crates/typst-layout/src/inline/collect.rs | 37 +++++++++--------- crates/typst-layout/src/inline/linebreak.rs | 2 + ...ue-5244-consecutive-weak-space-heading.png | Bin 0 -> 346 bytes .../ref/issue-5244-consecutive-weak-space.png | Bin 0 -> 194 bytes ...issue-5253-consecutive-weak-space-math.png | Bin 0 -> 138 bytes tests/suite/layout/spacing.typ | 18 +++++++++ 6 files changed, 38 insertions(+), 19 deletions(-) create mode 100644 tests/ref/issue-5244-consecutive-weak-space-heading.png create mode 100644 tests/ref/issue-5244-consecutive-weak-space.png create mode 100644 tests/ref/issue-5253-consecutive-weak-space-math.png 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 0000000000000000000000000000000000000000..c1ef792494783488b66a9fbf529e0fe999faf73f GIT binary patch literal 346 zcmV-g0j2(lP)oHuy~s?qsV*&_bGyBj{1L_kE8wX|LctLbg`Jx z7Mx;$Hb^|?thC$huoh3|IL|gp3%hOpI?7``~LqUEX%wAF+M*5 sF+be<11>;DD~VByM=c(;cu-gj0Q#vf!c~}!1^@s607*qoM6N<$g0-fy;s5{u literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7a102ddfb66053fd1a3e0f94a88e52bcea4856b1 GIT binary patch literal 194 zcmeAS@N?(olHy`uVBq!ia0vp^6+kS_0VEhE<%|3RQk|YIjv*Ddl7HAcG$dYm6xi*q zE4Ouqm00y2reNc(Vq4xWUw(ACv3m2%`d9zuqc2{5bg#cmpzYP?liV*dKECd0PTPJ! zXQ%Ae!2K`N3*T>CefiY^o!jv*Ddl7HAcG$dYm6xi*q zE4Q`cN)nguzuncJ)OSVJ?3U))*L1_$?|q(>fc*bBThlCunmaq**Bxp2QQ`X1X?ykJ fo0%|;608gidztzjdZ$;N0a@bd>gTe~DWM4fGX65$ literal 0 HcmV?d00001 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