From 183feade3bc5e74541effd270dde175240302ab0 Mon Sep 17 00:00:00 2001 From: moppeeer Date: Thu, 15 Oct 2026 10:34:50 +0200 Subject: [PATCH] Fit Frame to Content puts a text frame's bottom on its last baseline The height search stopped up to 0.011 pt short of it (a line is set within 0.01 pt), so a fitted frame scaled up with its text came out overset. InDesign fits 70 pt Kanji_PA to 18.521 mm, its ascent. Co-Authored-By: Claude Opus 5.5 --- crates/engine/src/cmd/object.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/crates/engine/src/cmd/object.rs b/crates/engine/src/cmd/object.rs index ca32c517c..e9e511c2f 100644 --- a/crates/engine/src/cmd/object.rs +++ b/crates/engine/src/cmd/object.rs @@ -2066,7 +2066,7 @@ fn fitted_text_frame(d: &Document, id: ItemId, height: bool, width: bool) -> Res // First fit the height at the existing width, then measure the complete text's width. // Recheck height after fitting width, since a small width change can change a line break. if height { - out = fit_text_height(out, &mut compose)?; + out = fit_text_height(out, id, tf.options.inset[2], &mut compose)?; } if width && tf.options.columns <= 1 { let cs = compose(out); @@ -2077,13 +2077,18 @@ fn fitted_text_frame(d: &Document, id: ItemId, height: bool, width: bool) -> Res } } if height { - out = fit_text_height(out, &mut compose)?; + out = fit_text_height(out, id, tf.options.inset[2], &mut compose)?; } } Ok(Some(out)) } -fn fit_text_height(mut rect: Rect, compose: &mut impl FnMut(Rect) -> Arc) -> Result { +fn fit_text_height( + mut rect: Rect, + id: ItemId, + inset_bottom: f64, + compose: &mut impl FnMut(Rect) -> Arc, +) -> Result { let mut low = 1.0; let limit = 20_000.0; let mut high = rect.height().clamp(1.0, limit); @@ -2110,6 +2115,13 @@ fn fit_text_height(mut rect: Rect, compose: &mut impl FnMut(Rect) -> Arc rect.y1 && *b - rect.y1 <= 0.02) { + rect.y1 = b; + } Ok(rect) } @@ -3604,7 +3616,12 @@ mod fit_text_frame_tests { assert!(b.x0 == 100.0 && b.width() > 100.0 && b.width() < 250.0, "{b:?}"); let d = s.doc().unwrap().doc.clone(); let sid = d.item(id).unwrap().text_frame().unwrap().story; - assert!(!s.cache.get(&d, sid, None).is_overset(), "still fits"); + let cs = s.cache.get(&d, sid, None); + assert!(!cs.is_overset(), "still fits"); + // The bottom is on the baseline (Dansky's Exclude Overlap tutorial, 1:56: 70 pt Kanji_PA + // fits to 18.521 mm, its ascent), so a frame scaled up with its text still fits. + let baseline = cs.frame(id).unwrap().lines[0].baseline; + assert!((b.y1 - baseline).abs() < 1e-9, "{b:?} {baseline}"); } #[test]