diff --git a/crates/typst/src/layout/inline/line.rs b/crates/typst/src/layout/inline/line.rs index d930f7071..1ac56e521 100644 --- a/crates/typst/src/layout/inline/line.rs +++ b/crates/typst/src/layout/inline/line.rs @@ -698,6 +698,12 @@ impl<'a> DerefMut for Items<'a> { } } +impl Debug for Items<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_list().entries(&self.0).finish() + } +} + /// A reference to or a boxed item. pub enum ItemEntry<'a> { Ref(&'a Item<'a>), diff --git a/crates/typst/src/layout/inline/linebreak.rs b/crates/typst/src/layout/inline/linebreak.rs index 7df65609a..2dc3edb5e 100644 --- a/crates/typst/src/layout/inline/linebreak.rs +++ b/crates/typst/src/layout/inline/linebreak.rs @@ -481,9 +481,19 @@ fn linebreak_optimized_approximate( let Entry { end, breakpoint, unbreakable, .. } = table[idx]; let attempt = line(engine, p, start..end, breakpoint, Some(&pred)); - let (_, line_cost) = + let (ratio, line_cost) = ratio_and_cost(p, metrics, width, &pred, &attempt, breakpoint, unbreakable); + // If approximation produces a valid layout without too much shrinking, + // exact layout is guaranteed to find the same layout. If, however, the + // line is overfull, we do not have this guarantee. Then, our bound + // becomes useless and actively harmful (it could be lower than what + // optimal layout produces). Thus, we immediately bail with an infinite + // bound in this case. + if ratio < metrics.min_ratio(false) { + return Cost::INFINITY; + } + pred = attempt; start = end; exact += line_cost; diff --git a/tests/ref/issue-4651-justify-bad-bound.png b/tests/ref/issue-4651-justify-bad-bound.png new file mode 100644 index 000000000..5b73fc66d Binary files /dev/null and b/tests/ref/issue-4651-justify-bad-bound.png differ diff --git a/tests/suite/layout/inline/justify.typ b/tests/suite/layout/inline/justify.typ index b35ff1fd6..83fbd0570 100644 --- a/tests/suite/layout/inline/justify.typ +++ b/tests/suite/layout/inline/justify.typ @@ -167,3 +167,8 @@ int main() { // an underfull first line. #set par(hanging-indent: 2.5cm, justify: true) #lorem(5) + +--- issue-4651-justify-bad-bound --- +// Test that overflow does not lead to bad bounds in paragraph optimization. +#set par(justify: true) +#block(width: 0pt)[A B]