Layout: a drop cap in a font over 1000 pt no longer panics (#389)

The drop-cap letter's size was `clamp(rc.size, 1000.0)`, and `f32::clamp` panics when the
minimum is above the maximum, which happens as soon as the paragraph's text is larger than
1000 pt (Word allows up to 1638). Layout, PDF export and saving run outside `Session::run`'s
panic guard, so the desktop app panicked on every frame, and `wordcraft-cli convert` failed.
Use `.min(1000.0).max(rc.size)`, which never panics and keeps the letter at least as large as
the text.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
loganj
2026-10-10 19:29:27 -04:00
committed by GitHub
co-authored by Claude Sonnet 5.5
parent 4615cef878
commit da07540f31
2 changed files with 20 additions and 1 deletions
+2 -1
View File
@@ -694,7 +694,8 @@ pub fn layout_para(p: &Paragraph, env: &ParaEnv) -> ParaLayout {
let lines = rp.drop_cap as f32;
// Capital height is ~0.7 em: the letter's cap spans from line 1's caps to line N's baseline.
let mut big = (*rc).clone();
big.size = (((lines - 1.0) * line_h + rc.size * 0.7) / 0.7).clamp(rc.size, 1000.0);
// `clamp` would panic here when the text itself is larger than 1000 pt.
big.size = (((lines - 1.0) * line_h + rc.size * 0.7) / 0.7).min(1000.0).max(rc.size);
let before = b.clusters.len();
b.shape(first, 0, &Arc::new(big), None);
let w: f32 = b.clusters.get(before..).map(|c| c.iter().map(|c| c.adv).sum()).unwrap_or(0.0);
+18
View File
@@ -1282,6 +1282,24 @@ fn repeated_header_is_followed_by_the_next_row_even_when_it_overflows() {
assert!(pages.iter().all(|p| p.first() == Some(&0)), "{pages:?}");
}
/// A drop-cap paragraph in a font larger than 1000 pt used to panic in layout (`clamp` with min > max).
#[test]
fn drop_cap_with_a_huge_font_lays_out() {
for size in [999.0, 1000.0, 1001.0, 1638.0] {
let cp = wordcraft_doc::CharProps { size: Some(size), ..Default::default() };
let mut p = wordcraft_doc::Paragraph::with_text("Hello drop cap world", cp);
p.props.drop_cap = Some(3);
let mut d = Document::from_text("x");
d.body = vec![wordcraft_doc::para_block(p)];
let l = lay(&d);
let Some(pl) = l.pages[0].items.iter().find_map(|i| if let Placed::Lines { para, .. } = i { Some(para.clone()) } else { None }) else {
panic!("no lines at size {size}")
};
let (nc, lines, _) = pl.drop_cap.unwrap_or((0, 0, 0.0));
assert_eq!((nc, lines), (1, 3), "size {size}");
}
}
#[test]
fn drop_cap_indents_its_lines() {
let mut p =