From 6c2d54bbe3df70670afef6d3f61750daeb2adf34 Mon Sep 17 00:00:00 2001 From: PgBiel <9021226+PgBiel@users.noreply.github.com> Date: Fri, 20 Dec 2024 07:03:12 -0300 Subject: [PATCH] Fix crash when block or text have negative sizes (#5610) --- crates/typst-layout/src/flow/block.rs | 18 ++++++++++++++++ crates/typst-layout/src/flow/mod.rs | 20 ++++++++++++++++-- ...ue-5262-block-negative-height-implicit.png | Bin 0 -> 72 bytes ...sue-5262-block-negative-height-in-flow.png | Bin 0 -> 236 bytes .../ref/issue-5262-block-negative-height.png | Bin 0 -> 73 bytes tests/ref/issue-5262-text-negative-size.png | Bin 0 -> 73 bytes tests/suite/layout/container.typ | 14 ++++++++++++ tests/suite/text/font.typ | 5 +++++ 8 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 tests/ref/issue-5262-block-negative-height-implicit.png create mode 100644 tests/ref/issue-5262-block-negative-height-in-flow.png create mode 100644 tests/ref/issue-5262-block-negative-height.png create mode 100644 tests/ref/issue-5262-text-negative-size.png diff --git a/crates/typst-layout/src/flow/block.rs b/crates/typst-layout/src/flow/block.rs index 71eacc1c..6c2c3923 100644 --- a/crates/typst-layout/src/flow/block.rs +++ b/crates/typst-layout/src/flow/block.rs @@ -364,6 +364,12 @@ fn breakable_pod<'a>( /// Distribute a fixed height spread over existing regions into a new first /// height and a new backlog. +/// +/// Note that, if the given height fits within the first region, no backlog is +/// generated and the first region's height shrinks to fit exactly the given +/// height. In particular, negative and zero heights always fit in any region, +/// so such heights are always directly returned as the new first region +/// height. fn distribute<'a>( height: Abs, mut regions: Regions, @@ -371,7 +377,19 @@ fn distribute<'a>( ) -> (Abs, &'a mut [Abs]) { // Build new region heights from old regions. let mut remaining = height; + + // Negative and zero heights always fit, so just keep them. + // No backlog is generated. + if remaining <= Abs::zero() { + buf.push(remaining); + return (buf[0], &mut buf[1..]); + } + loop { + // This clamp is safe (min <= max), as 'remaining' won't be negative + // due to the initial check above (on the first iteration) and due to + // stopping on 'remaining.approx_empty()' below (for the second + // iteration onwards). let limited = regions.size.y.clamp(Abs::zero(), remaining); buf.push(limited); remaining -= limited; diff --git a/crates/typst-layout/src/flow/mod.rs b/crates/typst-layout/src/flow/mod.rs index df716b33..2f0ec39a 100644 --- a/crates/typst-layout/src/flow/mod.rs +++ b/crates/typst-layout/src/flow/mod.rs @@ -203,8 +203,14 @@ pub(crate) fn layout_flow( } else { PageElem::width_in(shared) }; - (0.026 * width.unwrap_or_default()) - .clamp(Em::new(0.75).resolve(shared), Em::new(2.5).resolve(shared)) + + // Clamp below is safe (min <= max): if the font size is + // negative, we set min = max = 0; otherwise, + // `0.75 * size <= 2.5 * size` for zero and positive sizes. + (0.026 * width.unwrap_or_default()).clamp( + Em::new(0.75).resolve(shared).max(Abs::zero()), + Em::new(2.5).resolve(shared).max(Abs::zero()), + ) }, }), }; @@ -354,6 +360,16 @@ struct LineNumberConfig { /// Where line numbers are reset. scope: LineNumberingScope, /// The default clearance for `auto`. + /// + /// This value should be relative to the page's width, such that the + /// clearance between line numbers and text is small when the page is, + /// itself, small. However, that could cause the clearance to be too small + /// or too large when considering the current text size; in particular, a + /// larger text size would require more clearance to be able to tell line + /// numbers apart from text, whereas a smaller text size requires less + /// clearance so they aren't way too far apart. Therefore, the default + /// value is a percentage of the page width clamped between `0.75em` and + /// `2.5em`. default_clearance: Abs, } diff --git a/tests/ref/issue-5262-block-negative-height-implicit.png b/tests/ref/issue-5262-block-negative-height-implicit.png new file mode 100644 index 0000000000000000000000000000000000000000..3b7b289b73cdad2452e3160dac9823b4a067d85f GIT binary patch literal 72 zcmeAS@N?(olHy`uVBq!ia0vp^6+q0z2qYN7zb@Yjr1(8u978H@CI9H>l3rb7w2FA*hOS+nB0rx$w~d(h;`g3L|MQ=0=5;<| zWCntI#{2Gfx3a{&+g{2!r~U9MmUn0RMLGApJR8N%nv?fjrC0y#7PZFT!qr|6%2cE# ztPwaabR$puxF^GZaTyjRi;u1auja=|?Xb|DZ`!LX)$yQUO@sK-B_9J0T(_y-9CH8; c_OsM8yqo=A{Qvx8J|J&+y85}Sb4q9e0HvT~u>b%7 literal 0 HcmV?d00001 diff --git a/tests/ref/issue-5262-block-negative-height.png b/tests/ref/issue-5262-block-negative-height.png new file mode 100644 index 0000000000000000000000000000000000000000..1a1146d8880aabfd175249cc0f924ca7f56ae9ee GIT binary patch literal 73 zcmeAS@N?(olHy`uVBq!ia0vp^6+kS^2qYMab-p|UQUabXjv*Ddl7IAbNx1#2_{lKy Vg7jxmma@MfHJ+}1F6*2UngCtA6c_*i literal 0 HcmV?d00001 diff --git a/tests/ref/issue-5262-text-negative-size.png b/tests/ref/issue-5262-text-negative-size.png new file mode 100644 index 0000000000000000000000000000000000000000..61e6dbae12a8c0baed58d889093cbb7a67a4caa3 GIT binary patch literal 73 zcmeAS@N?(olHy`uVBq!ia0vp^6+kS)2qYNtG>^mqDFIIx$B>F!$v^tJB;0