fix(edit): setting a paragraph's width no longer panics on text larger than a page (#4110)

rewrite_block clamps a requested paragraph width between the text's
size in user space (size * k) and the largest page PDF allows
(14 400 pt). f64::clamp panics when its minimum is the larger, so text
set above 14 400 pt crashed the app as soon as its paragraph was given
a width. The size comes from the file (`20000 Tf`, or `1 Tf` scaled up
by `Tm`) or from the request (the automation tools pass `size`
through).

The lower bound is now capped at 14 400 pt too, so such a paragraph
gets the widest width allowed. `f64::min` also turns a NaN size into
the cap.

Test: a 20000 pt Tf, a 1 pt Tf scaled 20000x by Tm, and a requested
size of 20000 pt each take a width of 200 without panicking (all three
panicked before).

Reported-by: BS.ehlas.cz

Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
Matej Vrzala
2026-10-23 10:20:35 -04:00
committed by GitHub
co-authored by Brandon Thomas
parent b174b12b0e
commit 75207dc8ed
2 changed files with 21 additions and 2 deletions
+18
View File
@@ -6356,6 +6356,24 @@ fn reading_keeps_dotted_leader_entries_whole_and_in_order() {
);
}
/// Text set larger than the widest page PDF allows (14 400 pt) panicked when its paragraph was given
/// a width: the width is clamped between the font size and 14 400 pt, and `f64::clamp` panics when
/// its minimum is the larger. The width is now capped at 14 400 pt whatever the font size: from the
/// file (`Tf`, or a small `Tf` scaled up by `Tm`) or asked for (the automation tools pass it through).
#[test]
fn width_on_a_paragraph_set_larger_than_a_page_is_capped_not_a_panic() {
let wide = text::BlockStyle { width: Some(200.0), ..Default::default() };
let huge = text::BlockStyle { size: Some(20_000.0), width: Some(200.0), ..Default::default() };
for (content, style) in [
("BT /F2 20000 Tf 72 700 Td (ab) Tj ET", &wide),
("BT /F2 1 Tf 20000 0 0 20000 72 700 Tm (ab) Tj ET", &wide),
("BT /F2 12 Tf 72 700 Td (ab) Tj ET", &huge),
] {
let mut doc = text_page(content);
text::rewrite_block(&mut doc, 0, 0, None, style).unwrap();
}
}
#[test]
fn added_text_is_wrapped_once_per_write() {
let mut doc = fixture();
+3 -2
View File
@@ -2780,8 +2780,9 @@ fn rewrite_block_from(
// A paragraph keeps its width (or takes the one asked for); a single line grows to the right
// (to the left when right-to-left), up to the page's margin.
let width = match style.width {
// Capped at the largest page PDF allows (14 400 pt).
Some(w) if w.is_finite() => w.clamp(size * k, 14_400.0),
// Capped at the largest page PDF allows (14 400 pt), even for text set larger than that
// (`clamp` panics when its minimum is the larger, or NaN).
Some(w) if w.is_finite() => w.clamp((size * k).min(14_400.0), 14_400.0),
Some(_) => return Err(EditError::Invalid("the paragraph's width must be a number".into())),
// Turned text: the page's margins are along another axis. A single line grows (below).
None if !upright => (frame[2] - frame[0]).max(size * k),