diff --git a/crates/layout/src/para.rs b/crates/layout/src/para.rs index 46b9a7e45..9aad1bdfb 100644 --- a/crates/layout/src/para.rs +++ b/crates/layout/src/para.rs @@ -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); diff --git a/crates/layout/src/tests.rs b/crates/layout/src/tests.rs index 2a509fb31..30a83b1c7 100644 --- a/crates/layout/src/tests.rs +++ b/crates/layout/src/tests.rs @@ -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 =