From c145e05f01746a72a9455d7fad95f927f568e2fd Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 17 Sep 2024 13:56:23 +0200 Subject: [PATCH] Fix bad bound in forcibly overflowing optimal paragraph layout (#4975) --- crates/typst/src/layout/inline/line.rs | 6 ++++++ crates/typst/src/layout/inline/linebreak.rs | 12 +++++++++++- tests/ref/issue-4651-justify-bad-bound.png | Bin 0 -> 207 bytes tests/suite/layout/inline/justify.typ | 5 +++++ 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/ref/issue-4651-justify-bad-bound.png 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 0000000000000000000000000000000000000000..5b73fc66def6c71ce5f6d492b5a45e6ae08924eb GIT binary patch literal 207 zcmeAS@N?(olHy`uVBq!ia0vp^6+o=P0VEg%8WVp4scD`rjv*Ddl7HAcG$dYm6xi*q zE4Ouqm00y2DT!|XbYCD@ZGVfm