From f1cffdd8c09340edb069d17f3da8575b29b9c1e6 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sat, 14 Nov 2026 13:46:56 -0800 Subject: [PATCH] Type: a warichu line holds the ascent and descent of its outer block lines A block's line took the tallest ascent and deepest descent of its characters, or the height of the stack's em boxes, whichever was larger. The top block line's characters reach above the stack by their ascent past the em box, and the bottom line's below it by their descent, so with a wide Line Gap the line was too short for them. The line's ascent and descent now also take in each character's reach from its own block line's baseline. --- crates/text/src/layout/warichu.rs | 11 ++++++++--- crates/text/src/tests/warichu.rs | 18 ++++++++++++++++++ docs/mcp.md | 3 ++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/crates/text/src/layout/warichu.rs b/crates/text/src/layout/warichu.rs index dd816599c6..b68b69efd9 100644 --- a/crates/text/src/layout/warichu.rs +++ b/crates/text/src/layout/warichu.rs @@ -287,6 +287,10 @@ fn place_block(g: &mut [SGlyph], s: &WariStyle, (vertical, whole): (bool, bool)) let rtl = !vertical && g.first().is_some_and(|gl| gl.level.is_rtl()); let (inset, outset) = if rtl { (after, before) } else { (before, after) }; let length = inset + block + outset; + // How far the glyphs reach above and below the line's baseline, each from its block line's + // baseline. + let above = g.iter().zip(&places).map(|(gl, p)| gl.ascent - p.1).fold(0.0, f64::max); + let below = g.iter().zip(&places).map(|(gl, p)| gl.descent + p.1).fold(0.0, f64::max); let glyphs = g.len(); for (i, (gl, (along, across, advance))) in g.iter_mut().zip(places).enumerate() { let em = gl.face.units_per_em() * gl.sy / r; @@ -300,9 +304,10 @@ fn place_block(g: &mut [SGlyph], s: &WariStyle, (vertical, whole): (bool, bool)) if i + 1 < glyphs { gl.keeps_next = true; } - // The line keeps the height of the block's own size, and holds the whole stack. - gl.ascent = (ascent / r).max(-top); - gl.descent = (descent / r).max(bottom); + // The line keeps the height of the block's own size, and holds the whole stack with each + // block line's glyphs. + gl.ascent = (ascent / r).max(-top).max(above); + gl.descent = (descent / r).max(bottom).max(below); if s.auto_leading { gl.leading /= r; } diff --git a/crates/text/src/tests/warichu.rs b/crates/text/src/tests/warichu.rs index 6aee052cbd..cbefb86bb5 100644 --- a/crates/text/src/tests/warichu.rs +++ b/crates/text/src/tests/warichu.rs @@ -626,6 +626,24 @@ fn a_block_of_several_fonts_keeps_the_tallest_of_them() { assert!(first_short.0 >= plain[pair.0].0 - 1e-6 && first_short.1 >= deepest - 1e-6, "{first_short:?} {plain:?}"); } +/// The line holds each block line's characters at their own height: with a wide Line Gap, the +/// ascent of the top block line's characters and the descent of the bottom one's stay inside the +/// line. +#[test] +fn a_wide_line_gap_keeps_the_outer_block_lines_inside_the_line() { + let small = layout(db(), &point("x", style(10.0))); + let (ascent, descent) = (small.lines[0].ascent, small.lines[0].descent); + for lines in [2, 3] { + let l = layout(db(), &with_block("cdefgh", CharStyle { warichu_lines: lines, warichu_gap: 20.0, ..marked(20.0) })); + let line = &l.lines[0]; + let block = &l.glyphs[2..8]; + let top = block.iter().map(|g| g.origin.y).fold(f64::INFINITY, f64::min); + let bottom = block.iter().map(|g| g.origin.y).fold(f64::NEG_INFINITY, f64::max); + assert!(line.baseline - line.ascent <= top - ascent + 1e-6, "{lines}: {} {} {top} {ascent}", line.baseline, line.ascent); + assert!(line.baseline + line.descent >= bottom + descent - 1e-6, "{lines}: {} {} {bottom} {descent}", line.baseline, line.descent); + } +} + /// Warichu Settings on characters not marked Warichu leave their shaping alone: "fi" keeps its /// ligature when only the f has other settings. #[test] diff --git a/docs/mcp.md b/docs/mcp.md index fc03d070b6..b37f162985 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -8965,7 +8965,8 @@ Options). Warichu characters are set at `warichuScale` percent of their size (10 `warichuLines` lines (a whole number from 1 to 6, default 2) inside their line: one above the other in horizontal type and side by side across the column in vertical type, the first line above or to the right. `warichuGap` is the space between the lines in points (0 to 100, default 0, document points as `baselineShift`). The stack is centered across the -line on the center of the line's ideographic em box, and the line keeps the height of the characters' own size. +line on the center of the line's ideographic em box, and the line keeps the height of the characters' own size, or +more when the stack needs it: the line's ascent and descent take in the characters of the outer lines. A stretch of warichu characters is one block that takes the settings of its first character; a character with other settings, another size or the other kind of leading (Auto or a number) starts a new one, and a tab, a forced line break or a tate-chu-yoko character ends it. In vertical type a character marked `tateChuYoko` as well is set as tate-chu-yoko at its own size, and two or three digits