diff --git a/crates/compose/src/lib.rs b/crates/compose/src/lib.rs index 3dd7c25b3..4a9cbabac 100644 --- a/crates/compose/src/lib.rs +++ b/crates/compose/src/lib.rs @@ -768,6 +768,18 @@ fn compose_with_db(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &C designcraft_doc::Leading::Auto => base_size * pp.auto_leading, designcraft_doc::Leading::Points(v) => v, }; + // The paragraph mark is a character of the last line: its leading counts there like any + // other character's. It doesn't set the line's ascent or descent. A hidden or deleted + // mark takes no room. + let mark_leading = story.text.get(prange.end..).filter(|t| t.starts_with('\n')).and_then(|_| { + let props = doc.styles.resolve_char(&base_chars, story.format_after(prange.end)); + let hidden = props.change == designcraft_doc::ChangeMark::Deleted + || (!props.conditions.is_empty() && props.conditions.iter().all(|c| sub.hidden_conditions.contains(c))); + (!hidden).then_some(match props.leading { + designcraft_doc::Leading::Auto => props.size * pp.auto_leading, + designcraft_doc::Leading::Points(v) => v, + }) + }); let spacing = spacing_for(&pp, base_size); // A paragraph set across the columns moves on to the next frame where others move on to // the next column. @@ -914,6 +926,10 @@ fn compose_with_db(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &C let (s, e) = (g0 + b.start, g0 + b.end); let line_glyphs = &glyphs[s..e.max(s)]; let (asc, desc, lead) = line_metrics(line_glyphs, &glyphs, s, base_leading, base_chars.size, db, &base_chars); + let lead = match mark_leading { + Some(m) if k + 1 == breaks.len() => lead.max(m), + _ => lead, + }; let reference = cjk_line_reference(line_glyphs); let mut baseline = cur.next_baseline(f, col, lead, asc, &pp); if cur.last_baseline.is_some() { diff --git a/crates/compose/src/tests.rs b/crates/compose/src/tests.rs index 0d1fe2d27..4380186f9 100644 --- a/crates/compose/src/tests.rs +++ b/crates/compose/src/tests.rs @@ -2771,3 +2771,22 @@ fn empty_paragraphs_get_no_bullet_or_number() { assert_eq!(list_labels(&cs, LABEL_CHARS), ["1.", "", "2.", ""], "list `{name}`"); } } + +#[test] +fn paragraph_mark_size_counts_in_its_line_auto_leading() { + let gaps = |mark_size: f64| { + let (mut d, sid, _) = doc_with("One\nTwo\nThree", Rect::new(36.0, 36.0, 300.0, 300.0), ParaAttrs::default()); + d.story_mut(sid).unwrap().format_chars(7..8, |f| f.over.size = Some(mark_size)); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + let b: Vec = all_lines(&cs).iter().map(|l| l.baseline).collect(); + assert_eq!(b.len(), 3); + (b[1] - b[0], b[2] - b[1]) + }; + // A 12 pt line ending in a 14 pt return: 14 × 120% above it, the next line unchanged. + let (above, below) = gaps(14.0); + assert!((above - 16.8).abs() < 1e-6, "{above}"); + assert!((below - 14.4).abs() < 1e-6, "{below}"); + let (above, below) = gaps(12.0); + assert!((above - 14.4).abs() < 1e-6, "{above}"); + assert!((below - 14.4).abs() < 1e-6, "{below}"); +}