Merge pull request #6274 from dotCooCoo/fix/push-in-keeps-inline-art-gap

Type: a pushed-in line leaves the gap after inline art open
This commit is contained in:
BFlat
2026-11-09 11:22:12 +08:00
committed by GitHub
2 changed files with 35 additions and 3 deletions
+16 -3
View File
@@ -607,6 +607,17 @@ fn is_cjk_gap(glyph: usize, held: &[usize], after: &[Option<usize>], index: usiz
})
}
// May a pushed-in line close a CJK gap after `g`? Not after a list marker or an inline graphic,
// which the push-in's room does not count either.
fn may_squeeze(g: &SGlyph) -> bool {
g.len > 0 && g.inline.is_none()
}
// How much a pushed-in line's `squeeze` adds to the CJK gap after `g`.
fn squeeze_after(g: &SGlyph, squeeze: f64, vertical: bool) -> f64 {
if may_squeeze(g) { squeeze * squeeze_em(g, vertical) } else { 0.0 }
}
// What justification may change of glyph `j`: nothing of a `held` glyph, and no glyph
// scaling of a `hung` one.
fn flow_line_flex(glyph: usize, flex: &[Flex], held: &[usize], hung: &[usize]) -> Flex {
@@ -672,8 +683,10 @@ fn justify_flow_line(cx: &Ctx<'_>, paragraph: &ParagraphData<'_, '_>, line: &Lin
// the same share of the em of the glyph before it, at most [`PUSH_IN_SQUEEZE`].
let pushed_in = line.position.pushed_in && paragraph.regions.is_some() && cjk_gaps > 0 && width > room + EPS;
if pushed_in {
let ems: f64 =
(line.index..line.body).filter(|&j| is_cjk_gap(j, held, &after, line.index, sg)).map(|j| squeeze_em(&sg[j], cx.vertical)).sum();
let ems: f64 = (line.index..line.body)
.filter(|&j| is_cjk_gap(j, held, &after, line.index, sg) && may_squeeze(&sg[j]))
.map(|j| squeeze_em(&sg[j], cx.vertical))
.sum();
if ems > EPS {
squeeze = ((room - width) / ems).max(-PUSH_IN_SQUEEZE);
}
@@ -778,7 +791,7 @@ fn emit_flow_line(cx: &mut Ctx<'_>, pen: &mut Pen<'_>, paragraph: &ParagraphData
advance += justification.per_space;
} else if justification.per_cjk != 0.0 || justification.squeeze != 0.0 {
if is_cjk_gap(glyph_index, &line.held, &justification.after, index, sg) {
advance += justification.per_cjk + justification.squeeze * squeeze_em(glyph, cx.vertical);
advance += justification.per_cjk + squeeze_after(glyph, justification.squeeze, cx.vertical);
}
} else if !line.held.contains(&glyph_index)
&& drawn_after(index, glyph_index, &justification.after).and_then(|next| sg.get(next)).is_some_and(|next| !next.continues_tcy())
+19
View File
@@ -347,6 +347,25 @@ fn top_to_top_leading_spaces_inline_art_by_its_run() {
assert!((small0 - tall0).abs() < 1e-6 && (small1 - tall1).abs() < 1e-6, "{small0} {small1} / {tall0} {tall1}");
}
/// A pushed-in line closes the gaps next to its CJK characters and leaves the gap after inline art
/// open. Needs a font with full-width Japanese (skipped without one).
#[test]
fn a_pushed_in_line_leaves_the_gap_after_inline_art() {
let mut t = TextObject::point(Point::ZERO, "一二", style(20.0));
t.xf = Affine::IDENTITY;
t.runs.push(TextRun::inline(art(0.5), style(20.0)));
t.runs.push(TextRun::new("四五六七八九十一二三四五」六", style(20.0)));
t.para.kinsoku_type = vectorcraft_doc::KinsokuShoriType::PushInFirst;
t.kind = TextKind::Area { frame: PathData::from_bezpath(&Rect::new(0.0, 0.0, 300.0, 200.0).to_path(0.1)) };
let l = layout(FontDb::global(), &t);
if (l.glyphs[0].advance - 20.0).abs() > 2.0 {
return; // no font with full-width Japanese here
}
assert!(l.glyphs[1].advance < 20.0 - 0.5, "the other gaps close up: {}", l.glyphs[1].advance);
let art = inline_glyph(&l);
assert!((art.advance - 20.0).abs() < 1e-6, "the art keeps its advance: {}", art.advance);
}
#[test]
fn inline_art_moves_with_vertically_aligned_lines() {
use vectorcraft_doc::text::{AreaOptions, VerticalAlign};