From 3dd12d13f81ec5920e6d23248933a11c54ddb590 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Thu, 14 Sep 2023 13:36:39 +0200 Subject: [PATCH] Fix invisibles on final page (#2141) --- crates/typst-library/src/layout/mod.rs | 16 ++++++++++------ crates/typst-library/src/shared/behave.rs | 9 +++++---- tests/ref/bugs/pagebreak-bibliography.png | Bin 0 -> 1860 bytes tests/typ/bugs/pagebreak-bibliography.typ | 5 +++++ 4 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 tests/ref/bugs/pagebreak-bibliography.png create mode 100644 tests/typ/bugs/pagebreak-bibliography.typ diff --git a/crates/typst-library/src/layout/mod.rs b/crates/typst-library/src/layout/mod.rs index d9e8ec9aa..018cf1a69 100644 --- a/crates/typst-library/src/layout/mod.rs +++ b/crates/typst-library/src/layout/mod.rs @@ -250,7 +250,7 @@ fn realize_root<'a>( let mut builder = Builder::new(vt, scratch, true); builder.accept(content, styles)?; - builder.interrupt_page(Some(styles))?; + builder.interrupt_page(Some(styles), true)?; let (pages, shared) = builder.doc.unwrap().pages.finish(); Ok((DocumentElem::new(pages.to_vec()).pack(), shared)) } @@ -375,7 +375,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> { .to::() .map_or(false, |pagebreak| !pagebreak.weak(styles)); - self.interrupt_page(keep.then_some(styles))?; + self.interrupt_page(keep.then_some(styles), false)?; if let Some(doc) = &mut self.doc { if doc.accept(content, styles) { @@ -424,7 +424,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> { if self.doc.is_none() { bail!(span, "page configuration is not allowed inside of containers"); } - self.interrupt_page(outer)?; + self.interrupt_page(outer, false)?; } else if local.interruption::().is_some() || local.interruption::().is_some() { @@ -462,10 +462,14 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> { Ok(()) } - fn interrupt_page(&mut self, styles: Option>) -> SourceResult<()> { + fn interrupt_page( + &mut self, + styles: Option>, + last: bool, + ) -> SourceResult<()> { self.interrupt_par()?; let Some(doc) = &mut self.doc else { return Ok(()) }; - if !self.flow.0.is_basically_empty() || (doc.keep_next && styles.is_some()) { + if (doc.keep_next && styles.is_some()) || self.flow.0.has_strong_elements(last) { let (flow, shared) = mem::take(&mut self.flow).0.finish(); let styles = if shared == StyleChain::default() { styles.unwrap_or_default() @@ -588,7 +592,7 @@ struct ParBuilder<'a>(BehavedBuilder<'a>); impl<'a> ParBuilder<'a> { fn accept(&mut self, content: &'a Content, styles: StyleChain<'a>) -> bool { if content.is::() { - if !self.0.is_basically_empty() { + if self.0.has_strong_elements(false) { self.0.push(content.clone(), styles); return true; } diff --git a/crates/typst-library/src/shared/behave.rs b/crates/typst-library/src/shared/behave.rs index 471daa189..ed7a2593b 100644 --- a/crates/typst-library/src/shared/behave.rs +++ b/crates/typst-library/src/shared/behave.rs @@ -32,10 +32,11 @@ impl<'a> BehavedBuilder<'a> { /// Whether the builder is empty except for some weak elements that will /// probably collapse. - pub fn is_basically_empty(&self) -> bool { - self.builder.is_empty() - && self.staged.iter().all(|(_, behaviour, _)| { - matches!(behaviour, Behaviour::Weak(_) | Behaviour::Invisible) + pub fn has_strong_elements(&self, last: bool) -> bool { + !self.builder.is_empty() + || self.staged.iter().any(|(_, behaviour, _)| { + !matches!(behaviour, Behaviour::Weak(_) | Behaviour::Invisible) + || (last && *behaviour == Behaviour::Invisible) }) } diff --git a/tests/ref/bugs/pagebreak-bibliography.png b/tests/ref/bugs/pagebreak-bibliography.png new file mode 100644 index 0000000000000000000000000000000000000000..43de1574465eb89a6e02c2e75f1e444986c60f05 GIT binary patch literal 1860 zcmV-K2fO%*P){^f~bpv3L^}Qpw+NPq5B+WW{ zk3-!>lH$vXpBra)dLimNK^hM*K~nZNK3d8L;7Td4=}4}3m8986u_mmxJq$<y(Ti61ortePsRAcN5DoC~_zel81P+iiK0wgFr%T}R#J zQqQ%(p>H~`f_v?Y0g5KYr2a4DNZ!ucq-V3WxBYWq{iL{*JnPIKo+zm>gK%EoFAeXM z{x$CXyri`N4SnKIHMh&-kU#cYLz2olZ&B3MTN(l|&GvREirWRL?8jlUq&>hgDK7<$ zL+yftFyH<<)Y)DKz$hs(^6|ks8>ZOzL!q75kml4gP&Gh`zmY~5{u;a_X$HU(lI{Z7 z9GlsWHKBHfq$!O6CrQIH2q|E^?G@Pw*Gj4c2HRr*?z4RdTxwqk^s=La&-W$0PW|6f zu&~?7JK+&Y#Q@VK9RMCof9RIN*h?A<(9lon-vCVSQP-Y@kuj2f-5SD7+w-y!3L}I) zwxmz z3~ujS*1ibElDf2pFvs?iRuGoho(w?J&Ihis3#(??>ElK=!kgbtob`v_Nm`zb&=`|O zwTi%HwpXV5Ol#kB0&ht=zBPoO*?zATgm-P92|&Ug0yGWn6LbFAf92m09*cQ8ES2<1 zHo{IxSG11smhJJ6#WuGKLU9YiZzO#OV6b#*=F3O{-;D|$=S#=56vhgmw;eABDs2A* zxY*kp_8q?UgcgK`q`eN7+I}?~;c3Y)0vjaV2QWYyp1%4UcFq^Zw$F*NNYZHlWd%~_ z4FJbW0|6#P2&rS7zXxDMrqE55v>kZX_HDp?yZa899c>~l87C>K?eE%N2*0(x7~o3V z2Y~aW$p9})x)q>j`iKJj$+ll;7lejOB_)c=*FW4}N6K`5j3zYV;{cQ9$J*7d9%qWo5_baoa zU&2Gw{#Y7S1vE~PG^zoLEXC4i_vQk7Ank#0d$*S1PN!YB1K^96q}b{3wUg%@@9uf= zb9Vs@ib;}tzH?1nlH6k(ux7Y*Y&>V;PJos9&ZPGiCgen|{Q%3lNypsVI7-U7sxCrE z_DZC9I9X(Q|_DXXlht|;AIav;-HR$f(8Q&nCLuWY4p z>+%)pk<#+2nwqM;B~3M@l~DtL+6~J#XZ}D<8#wNap#`07`>RxzRo2v0m6t?A2RFW0 z3-v2ssm;`c>NT%cMPqe)DyrYF-dn={(#o2es`5SQ+nw^6eeHs9B-1=8+8djTZ?JRQ zJn&~~LYpbgy^0Qp@PPerx_QD!Jk1{q;d*cGcnH(&>!Mb5%#XD>b*k;^HfQ{O$=uv? z>39ggvh&^mXu2?QciU6Xx4o&Y2~XILt?qyb^=H|+Ke+S8DFv6j(dNVzg`I4VoO|%Y zr`&JH?xF)C!0MYW8$adNCu=@p+T0me7ZzS~)%3j|J|*?YoY(1?2>)FP2mv7=1cZPP y5CTF#2nYcoAOwU@j1UqM5)u*;5)u;9O8yBr)Q->ir1vub0000