summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2024-09-17 13:56:23 +0200
committerGitHub <noreply@github.com>2024-09-17 11:56:23 +0000
commitc145e05f01746a72a9455d7fad95f927f568e2fd (patch)
treecabcc1683d0c680837b1c60afb1644d819aa7f0e /crates
parentea145ff33bb6c3babb9765b5d0059612b2ea54f0 (diff)
Fix bad bound in forcibly overflowing optimal paragraph layout (#4975)
Diffstat (limited to 'crates')
-rw-r--r--crates/typst/src/layout/inline/line.rs6
-rw-r--r--crates/typst/src/layout/inline/linebreak.rs12
2 files changed, 17 insertions, 1 deletions
diff --git a/crates/typst/src/layout/inline/line.rs b/crates/typst/src/layout/inline/line.rs
index d930f707..1ac56e52 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 7df65609..2dc3edb5 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;