M7: inline art follows vertically aligned lines
align_vertically moved lines and glyphs but not TextLayout::inlines, so inline symbols in a centred or bottom-aligned area stayed where top alignment put them. The reflow path for non-rectangular frames also kept the previous pass's inlines, drawing each symbol twice.
This commit is contained in:
parent
2dcac5b48b
commit
56c975465c
|
|
@ -595,6 +595,15 @@ fn align_vertically(cx: &mut Ctx<'_>, paras: &[Range<usize>], t: &TextObject, re
|
|||
g.origin.y += d;
|
||||
}
|
||||
}
|
||||
// Inline art moves with its glyph's line.
|
||||
for i in &mut cx.out.inlines {
|
||||
let d = cx.out.glyphs.get(i.glyph).and_then(|g| offs.get(g.line)).copied().unwrap_or(0.0);
|
||||
if d != 0.0 {
|
||||
let m = Affine::translate((0.0, d));
|
||||
i.xf = m * i.xf;
|
||||
i.bounds = m.transform_rect_bbox(i.bounds);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
let laid_out = |out: &TextLayout| out.lines.last().map_or(0, |l| l.end);
|
||||
|
|
@ -624,12 +633,17 @@ fn align_vertically(cx: &mut Ctx<'_>, paras: &[Range<usize>], t: &TextObject, re
|
|||
return;
|
||||
}
|
||||
let before = laid_out(&cx.out);
|
||||
let prev = (std::mem::take(&mut cx.out.glyphs), std::mem::take(&mut cx.out.lines), std::mem::replace(&mut cx.out.overflow, false));
|
||||
let prev = (
|
||||
std::mem::take(&mut cx.out.glyphs),
|
||||
std::mem::take(&mut cx.out.lines),
|
||||
std::mem::take(&mut cx.out.inlines),
|
||||
std::mem::replace(&mut cx.out.overflow, false),
|
||||
);
|
||||
flow(cx, paras, t, Some(regions));
|
||||
if laid_out(&cx.out) < before {
|
||||
// Text no longer fits (lines got narrower, or flow around a wrap object): undo the
|
||||
// pass and try a smaller step.
|
||||
(cx.out.glyphs, cx.out.lines, cx.out.overflow) = prev;
|
||||
(cx.out.glyphs, cx.out.lines, cx.out.inlines, cx.out.overflow) = prev;
|
||||
for (r, (shift, gap)) in regions.iter_mut().zip(saved) {
|
||||
r.shift = shift;
|
||||
r.gap = gap;
|
||||
|
|
|
|||
|
|
@ -296,3 +296,33 @@ fn top_to_top_leading_spaces_inline_art_by_its_run() {
|
|||
let (tall0, tall1) = lines(3.0);
|
||||
assert!((small0 - tall0).abs() < 1e-6 && (small1 - tall1).abs() < 1e-6, "{small0} {small1} / {tall0} {tall1}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inline_art_moves_with_vertically_aligned_lines() {
|
||||
use vectorcraft_doc::text::{AreaOptions, VerticalAlign};
|
||||
// A rectangle (lines shift) and a triangle (text flows again lower down).
|
||||
let rect = Rect::new(0.0, 0.0, 400.0, 400.0).to_path(0.1);
|
||||
let mut tri = kurbo::BezPath::new();
|
||||
tri.move_to((0.0, 0.0));
|
||||
tri.line_to((800.0, 0.0));
|
||||
tri.line_to((400.0, 400.0));
|
||||
tri.close_path();
|
||||
for frame in [rect, tri] {
|
||||
for align in [VerticalAlign::Center, VerticalAlign::Bottom] {
|
||||
let mut t = text("A", art(1.0), "B", 20.0);
|
||||
t.kind = TextKind::Area { frame: PathData::from_bezpath(&frame) };
|
||||
t.area = AreaOptions { vertical_align: align, ..AreaOptions::default() };
|
||||
let l = layout(db(), &t);
|
||||
assert_eq!(l.inlines.len(), 1, "{align:?}");
|
||||
let g = inline_glyph(&l);
|
||||
let line = &l.lines[g.line];
|
||||
assert!(line.baseline > 100.0, "{align:?}: not aligned, baseline {}", line.baseline);
|
||||
// Still centred on the cap height above its (moved) baseline.
|
||||
let face = db().face("Source Sans 3", "Regular").unwrap();
|
||||
let cap = face.cap_height * 20.0 / face.upem;
|
||||
let b = l.inlines[0].bounds;
|
||||
assert!((b.center().y - (line.baseline - cap * 0.5)).abs() < 1e-6, "{align:?}: {b:?} baseline {}", line.baseline);
|
||||
assert!((b.x0 - g.origin.x).abs() < 1e-6, "{align:?}: {b:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue