Skip to content

Type: a burasagari mark hangs only where it is drawn at the line's right end - #7810

Merged
bflatastic merged 6 commits into
storytold:mainfrom
dotCooCoo:fix/burasagari-and-push-in-on-a-tabbed-right-to-left
Nov 15, 2026
Merged

bflatastic merged 6 commits into
storytold:mainfrom
dotCooCoo:fix/burasagari-and-push-in-on-a-tabbed-right-to-left

Conversation

@dotCooCoo

Copy link
Copy Markdown
Contributor

What and why

The help page describes Burasagari as letting single-byte and double-byte periods and commas fall outside the paragraph bounding box, and its Regular setting as hanging that punctuation without pushing ragged lines out to the edge of the box (the help page). In three cases the line breaker kept an overflowing mark on the line as if it hung, but the line was not drawn that way:

  • In a right-to-left paragraph, prepare_line_geometry (crates/text/src/layout/flow.rs) never hangs the mark, so the mark was drawn inside the line at full width and the line ran past the frame, with or without a tab.
  • On a line with a tab and right-to-left text, which is measured as drawn, the burasagari return in break_line (crates/text/src/layout/breaking.rs) skipped the drawn-width check. The line before the mark could be too wide as drawn, and the mark could be drawn inside the line instead of at its right end.
  • When No Break or Bunri-Kinshi kept the character after the mark on the line, the breaker treated the mark as hanging, but the drawer hangs a mark only when it is the line's last glyph. Both the mark and the character after it were drawn inside the line, and the line ran past the frame.

Changes:

  • place_flow_line passes Burasagari None to break_line for a right-to-left paragraph, so the line ends at a break where it fits with the mark.
  • break_line hangs a mark only when the mark is all the characters kept together at that break.
  • On a tabbed line measured as drawn, break_line hangs a mark only when the new drawn_last finds the mark's cluster last in the line's visual order (the levels reordered as UAX Raster export: refuse sizes the renderer can't produce instead of crashing #9 L2, with each tab and the spaces before it at the paragraph's level, as the drawer reorders them), the line before the mark has no line-end trim on its last glyph, and it fits as drawn. Otherwise the line ends at the latest legal break that fits as drawn.
  • push_in already returns nothing for a line with a tab and right-to-left text, so Push In First cannot end such a line past the measure; a test now covers that.
  • docs/target-app-parity.md has one line for the change next to the Line-end Punctuation Half Width entry.

The help page does not say which side a mark hangs on in right-to-left text or how hanging works with tabs; both rules above are VectorCraft's own. Lines that change: a right-to-left paragraph, a tabbed line with right-to-left text, and a mark kept with the next character by No Break or Bunri-Kinshi now break earlier instead of drawing past the frame. Other burasagari lines, Force included, break as before. No user-visible string changed.

How it was tested

New tests in vectorcraft-text:

  • layout::wrapping_tests::a_tabbed_burasagari_mark_hangs_only_at_the_drawn_end_of_a_fitting_line: on a tabbed line with right-to-left text, 。 hangs when it is drawn at the right end of a line that fits (also at level 2 after a left-to-right glyph, and alone at level 1 after one), and the line ends before 漢 when the line before 。 is too wide as drawn, fits only with 漢 trimmed, or 。 is drawn inside a right-to-left run. Fails without the change.
  • layout::wrapping_tests::a_burasagari_mark_kept_with_the_next_character_does_not_hang: 。 alone hangs, and with No Break on 。漢 the line ends at an earlier break. Fails without the change.
  • tests::hang::right_to_left_burasagari_keeps_the_line_inside_the_frame: a right-to-left paragraph in a frame narrower than the whole line by half the stop breaks into two lines, and every glyph other than spaces stays inside the frame. Fails without the change.
  • layout::wrapping_tests::push_in_leaves_a_tabbed_right_to_left_line_to_push_out: Push In First, Push Out First and Push Out Only all push the closing bracket out on a tabbed line with right-to-left text, where the same widths without them push it in. It covers existing behavior and passes without the change.

The visual-order check and the check that the mark is alone were each removed from the final break_line code, and a test failed each time.

Focused checks on the final tree, main at df984b2 merged:

  • cargo fmt --all -- --check
  • cargo clippy -p vectorcraft-text --all-targets -- -D warnings
  • cargo check --workspace --tests
  • cargo test -p vectorcraft-text --lib filtered to burasagari, wrapping_tests::, hang::, push_in_leaves_a_tabbed and no_break: 55 passed, 0 failed.
  • cargo xtask brands, layers (30 crates) and assets (337 files)
  • cargo xtask ci runs in this pull request's CI.

Checklist

  • cargo xtask ci passes (fmt, clippy, tests, assets, brands, layers, wasm).
  • No panics in shipped code: no unwrap(), expect(), panic!, unreachable!, todo! or
    unimplemented! outside tests, and no unchecked indexing on data from files, parameters or
    messages. Errors are returned as Result and shown to the user
    (why and how).
  • Clean-room: nothing copied from Adobe products or GPL/AGPL code (AGENTS.md).
  • Every new asset has a row in ASSETS.md.

…e frame

A right-to-left paragraph draws a comma or full stop inside its line,
but the breaker still kept an overflowing mark on the line as if it
hung, so the line was drawn past the frame. The breaker now ends such a
line at a break where it fits with the mark.

In a left-to-right line with right-to-left text and a tab, the breaker
hung an overflowing mark without measuring the line as drawn. It now
hangs the mark only when the mark is drawn at the line's right end and
the line before it fits as drawn; otherwise the line ends at the latest
legal break that fits as drawn.
On a tabbed line measured as drawn, a full stop or comma now hangs when
it is last in the visual order of the line's levels (UAX storytold#9 L2, with
each tab and the spaces before it at the paragraph's level), whatever
its own level. A mark at level 2, or a lone right-to-left mark after
left-to-right text, hangs again; a mark inside a right-to-left run
still ends the line at an earlier break.

A mark that No Break or Bunri-Kinshi keeps with the characters after
it no longer ends the line as if it hung: the line would end with
those characters, which are drawn inside it, so it ends at an earlier
break.
@coderabbitai

coderabbitai Bot commented Nov 15, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 35 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration

Commits

Reviewing files that changed from the base of the PR and between df984b2 and b595d5b.

Files selected for processing: 5

  • crates/text/src/layout/breaking.rs
  • crates/text/src/layout/flow.rs
  • crates/text/src/layout/wrapping_tests.rs
  • crates/text/src/tests/hang.rs
  • docs/target-app-parity.md
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@bflatastic
bflatastic merged commit 7350a7a into storytold:main Nov 15, 2026
7 checks passed
@bflatastic

Copy link
Copy Markdown
Member

Merged, thanks @dotCooCoo! It passed its CI checks.

Nissaar pushed a commit to Nissaar/vectorcraft that referenced this pull request Nov 15, 2026
storytold#7814 made SubPath::anchors an Anchors, and storytold#7810's seam fills, merged in the same batch,
passed it to SubPath::new, which takes a Vec, so vectorcraft-trace doesn't compile on main.
A closed subpath whose every segment is marked is its own run: clone it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants