mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-25 10:46:50 -06:00
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 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f56273f72e
commit
183feade3b
@@ -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<designcraft_compose::ComposedStory>) -> Result<Rect> {
|
||||
fn fit_text_height(
|
||||
mut rect: Rect,
|
||||
id: ItemId,
|
||||
inset_bottom: f64,
|
||||
compose: &mut impl FnMut(Rect) -> Arc<designcraft_compose::ComposedStory>,
|
||||
) -> Result<Rect> {
|
||||
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<designc
|
||||
}
|
||||
}
|
||||
rect.y1 = rect.y0 + high;
|
||||
// A line is set when its baseline is within 0.01 pt of the bottom, so the search stops just
|
||||
// short of the lowest baseline. The bottom goes onto it (plus the inset), as InDesign's does:
|
||||
// the frame then fits its text exactly and still does when it is scaled up.
|
||||
let lowest = compose(rect).frame(id).and_then(|ft| ft.lines.iter().map(|l| l.baseline).reduce(f64::max));
|
||||
if let Some(b) = lowest.map(|b| b + inset_bottom).filter(|b| b.is_finite() && *b > 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]
|
||||
|
||||
Reference in New Issue
Block a user