Merge pull request #5619 from dotCooCoo/fix/touch-type-upright-vertical-move

Type: Touch Type moves an upright character in vertical type down and across its column
This commit is contained in:
BFlat
2026-11-04 22:23:33 +07:00
committed by GitHub
2 changed files with 37 additions and 2 deletions
+8 -2
View File
@@ -58,7 +58,8 @@ struct CharBox {
pivot: Point,
/// A unit vector along its line in reading order.
along: Vec2,
/// A unit vector up from its line, without its rotation: the way baseline shift moves it.
/// A unit vector up from its line, without its rotation: the way baseline shift moves it. For
/// a glyph standing upright in vertical type, the line's cross axis (right of its column).
up: Vec2,
/// The glyph's own x axis and its up axis (with its rotation), unit vectors.
ex: Vec2,
@@ -174,6 +175,11 @@ fn char_box(t: &TextObject, lay: &TextLayout, gi: usize) -> Option<CharBox> {
}
let quad = [m * Point::new(x0, y0), m * Point::new(x1, y0), m * Point::new(x1, y1), m * Point::new(x0, y1)];
let d = Vec2::new(g.angle.cos(), g.angle.sin());
// Up from the glyph's frame without its rotation. For a glyph standing upright in vertical
// type, that up runs along the column, so the glyph takes the line's cross axis instead: the
// way baseline shift moves the column's sideways glyphs.
let up = unit(linear(m * g.unturned, Vec2::new(0.0, -1.0)));
let up = if d.cross(up).abs() > 1e-6 { up } else { Vec2::new(d.y, -d.x) };
let style = edit::slice_runs(&t.runs, g.byte, g.byte + g.len).first().map(|r| r.style.clone())?;
Some(CharBox {
start: g.byte,
@@ -181,7 +187,7 @@ fn char_box(t: &TextObject, lay: &TextLayout, gi: usize) -> Option<CharBox> {
pen,
pivot: m * g.pivot,
along: if g.rtl { -d } else { d },
up: unit(linear(m * g.unturned, Vec2::new(0.0, -1.0))),
up,
ex,
ey,
kerned: lay.glyphs.iter().any(|h| h.line == g.line && h.len > 0 && h.byte + h.len == g.byte && h.rtl == g.rtl),
+29
View File
@@ -176,6 +176,35 @@ fn a_character_rotated_near_a_quarter_turn_moves_across_its_line() {
}
}
/// In vertical type, a character standing upright (§) still splits a drag into kerning down its
/// column and baseline shift across it: down 10 pt and right 4 pt is `dx` 10 and `dy` 4. Every
/// arrow key nudges it.
#[test]
fn an_upright_character_in_vertical_type_moves_down_and_across_its_column() {
let (mut d, id, s) = doc_with_type();
if let Some(NodeKind::Text(t)) = d.node_mut(id).map(|n| &mut n.kind) {
**t = TextObject::point(Point::new(100.0, 200.0), "l§", CharStyle { size: 40.0, ..Default::default() });
t.vertical = true;
}
let p = paint();
let cx = cx(&d, &s, &p);
let mut t = TouchTypeTool { target: Some((id, 1)), ..Default::default() };
let q = quad(&t, &cx);
let at = q[0].midpoint(q[2]);
let acts = drag(&mut t, &cx, at, at + Vec2::new(4.0, 10.0));
let p1 = preview(&acts[1]);
assert!(close(p1["dx"].as_f64().unwrap_or(0.0), 10.0) && close(p1["dy"].as_f64().unwrap_or(0.0), 4.0), "{p1}");
for key in [ToolKey::Up, ToolKey::Down, ToolKey::Left, ToolKey::Right] {
let acts = t.key(&cx, key, Mods::default());
let moved = match acts.first() {
Some(Action::Exec(c, v)) if c == "text.touchType" => v,
other => panic!("{key:?}: {other:?}"),
};
let parts = [&moved["dx"], &moved["dy"]].map(|v| v.as_f64().unwrap_or(0.0).abs());
assert!(close(parts[0] + parts[1], 1.0) && (close(parts[0], 0.0) || close(parts[1], 0.0)), "{key:?}: {moved}");
}
}
/// In type scaled unevenly, a drag's parts are measured in document points: right 10 pt and up 4
/// pt of a quarter-turned character is `dx` 10 and `dy` 4.
#[test]