mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
More robust ratio computation (#4976)
This commit is contained in:
parent
c145e05f01
commit
0abd46c379
@ -490,7 +490,7 @@ fn linebreak_optimized_approximate(
|
|||||||
// becomes useless and actively harmful (it could be lower than what
|
// becomes useless and actively harmful (it could be lower than what
|
||||||
// optimal layout produces). Thus, we immediately bail with an infinite
|
// optimal layout produces). Thus, we immediately bail with an infinite
|
||||||
// bound in this case.
|
// bound in this case.
|
||||||
if ratio < metrics.min_ratio(false) {
|
if ratio < metrics.min_ratio {
|
||||||
return Cost::INFINITY;
|
return Cost::INFINITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,6 +536,11 @@ fn ratio_and_cost(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Determine the stretch ratio for a line given raw metrics.
|
/// Determine the stretch ratio for a line given raw metrics.
|
||||||
|
///
|
||||||
|
/// - A ratio < min_ratio indicates an overfull line.
|
||||||
|
/// - A negative ratio indicates a line that needs shrinking.
|
||||||
|
/// - A ratio of zero indicates a perfect line.
|
||||||
|
/// - A positive ratio indicates a line that needs stretching.
|
||||||
fn raw_ratio(
|
fn raw_ratio(
|
||||||
p: &Preparation,
|
p: &Preparation,
|
||||||
available_width: Abs,
|
available_width: Abs,
|
||||||
@ -548,30 +553,39 @@ fn raw_ratio(
|
|||||||
// to make it the desired width.
|
// to make it the desired width.
|
||||||
let delta = available_width - line_width;
|
let delta = available_width - line_width;
|
||||||
|
|
||||||
// Determine how much stretch is permitted.
|
// Determine how much stretch or shrink is natural.
|
||||||
let adjust = if delta >= Abs::zero() { stretchability } else { shrinkability };
|
let adjustability = if delta >= Abs::zero() { stretchability } else { shrinkability };
|
||||||
|
|
||||||
// Ideally, the ratio should between -1.0 and 1.0.
|
// Observations:
|
||||||
//
|
// - `delta` is negative for a line that needs shrinking and positive for a
|
||||||
// A ratio above 1.0 is possible for an underfull line, but a ratio below
|
// line that needs stretching.
|
||||||
// -1.0 is forbidden because the line would overflow.
|
// - `adjustability` must be non-negative to make sense.
|
||||||
let mut ratio = delta / adjust;
|
// - `ratio` inherits the sign of `delta`.
|
||||||
|
let mut ratio = delta / adjustability.max(Abs::zero());
|
||||||
|
|
||||||
// The line is not stretchable, but it just fits. This often happens with
|
// The most likely cause of a NaN result is that `delta` was zero. This
|
||||||
// monospace fonts and CJK texts.
|
// often happens with monospace fonts and CJK texts. It means that the line
|
||||||
|
// already fits perfectly, so `ratio` should be zero then.
|
||||||
if ratio.is_nan() {
|
if ratio.is_nan() {
|
||||||
ratio = 0.0;
|
ratio = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the ratio exceeds 1, we should stretch above the natural
|
||||||
|
// stretchability using justifiables.
|
||||||
if ratio > 1.0 {
|
if ratio > 1.0 {
|
||||||
// We should stretch the line above its stretchability. Now
|
// We should stretch the line above its stretchability. Now
|
||||||
// calculate the extra amount. Also, don't divide by zero.
|
// calculate the extra amount. Also, don't divide by zero.
|
||||||
let extra_stretch = (delta - adjust) / justifiables.max(1) as f64;
|
let extra_stretch = (delta - adjustability) / justifiables.max(1) as f64;
|
||||||
// Normalize the amount by half the em size.
|
// Normalize the amount by half the em size.
|
||||||
ratio = 1.0 + extra_stretch / (p.size / 2.0);
|
ratio = 1.0 + extra_stretch / (p.size / 2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ratio
|
// The min value must be < MIN_RATIO, but how much smaller doesn't matter
|
||||||
|
// since overfull lines have hard-coded huge costs anyway.
|
||||||
|
//
|
||||||
|
// The max value is clamped to 10 since it doesn't really matter whether a
|
||||||
|
// line is stretched 10x or 20x.
|
||||||
|
ratio.clamp(MIN_RATIO - 1.0, 10.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the cost of a line given raw metrics.
|
/// Compute the cost of a line given raw metrics.
|
||||||
@ -595,7 +609,7 @@ fn raw_cost(
|
|||||||
// If the line shall be justified or needs shrinking, it has normal
|
// If the line shall be justified or needs shrinking, it has normal
|
||||||
// badness with cost 100|ratio|^3. We limit the ratio to 10 as to not
|
// badness with cost 100|ratio|^3. We limit the ratio to 10 as to not
|
||||||
// get to close to our maximum cost.
|
// get to close to our maximum cost.
|
||||||
100.0 * ratio.abs().min(10.0).powi(3)
|
100.0 * ratio.abs().powi(3)
|
||||||
} else {
|
} else {
|
||||||
// If the line shouldn't be justified and doesn't need shrink, we don't
|
// If the line shouldn't be justified and doesn't need shrink, we don't
|
||||||
// pay any cost.
|
// pay any cost.
|
||||||
|
BIN
tests/ref/issue-4938-par-bad-ratio.png
Normal file
BIN
tests/ref/issue-4938-par-bad-ratio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 277 B |
@ -97,3 +97,7 @@ Lorem ipsum dolor #metadata(none) nonumy eirmod tempor.
|
|||||||
--- issue-4278-par-trim-before-equation ---
|
--- issue-4278-par-trim-before-equation ---
|
||||||
#set par(justify: true)
|
#set par(justify: true)
|
||||||
#lorem(6) aa $a = c + b$
|
#lorem(6) aa $a = c + b$
|
||||||
|
|
||||||
|
--- issue-4938-par-bad-ratio ---
|
||||||
|
#set par(justify: true)
|
||||||
|
#box($k in NN_0$)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user