Type: Paragraph Direction instead of an Automatic alignment toggle; bidi only where needed (review of #300)

Illustrator sets a paragraph's direction (Left-to-Right / Right-to-Left
Paragraph Direction in the Paragraph panel, with the Middle Eastern
options) and keeps its alignment buttons physical; it has no automatic
alignment toggle. So:

- ParaStyle.direction (None: from each paragraph's first strong
  character, as before; written only when set), the Paragraph panel's two
  direction buttons with Show Indic Options (original icons), and
  text.setFormat {direction: "auto"|"leftToRight"|"rightToLeft"}. The
  layout uses it as the base direction.
- The Automatic alignment check box is gone. Justify::Auto stays as the
  start of the paragraph's direction, set on new type only (text.create,
  the Type tools, with the mojikumi default in one new_type_para()):
  TextObject::point is Left again, so importers (PDF, SVG, DXF, EMF) keep
  their own alignment. The alignment buttons show what Auto resolves to.
- Bidi only where there is something right to left: plain paragraphs skip
  the algorithm (no per-layout allocation), it runs once per paragraph
  (shaping takes the paragraph's levels instead of recomputing them; path
  type computed it four times), and the shaper keeps Han, Hiragana,
  Katakana and Bopomofo in one segment (splitting at every change of
  script cost Japanese text a shaper call per kana-kanji switch).
- Vertical type keeps its logical order, so its glyphs and lines are not
  marked right to left (the caret no longer runs backwards down a column).
- PDF import puts Hebrew and Arabic, which PDFs (and VectorCraft's own
  export) draw in visual order, back in logical order with the direction
  that shows it as drawn; with bidi layout it came back mirrored.
- SVG import pins the direction SVG implies (left to right unless
  direction: rtl); SVG export also outlines right-to-left paragraphs.
- Docs (development.md), ROADMAP (folded into the Type entry, Type core
  row) and README updated; catalog rows for the new labels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic
2026-10-08 05:25:01 +07:00
co-authored by Claude Opus 5.5
parent edc7c931dc
commit 0687d2d127
25 changed files with 375 additions and 150 deletions
+18 -20
View File
@@ -180,26 +180,24 @@ CI runs a few dozen cases each. Before touching an importer, run a deeper search
`PROPTEST_CASES=20000 cargo test --release -p vectorcraft-engine --test import_fuzz`. When it finds a
panic, fix the code and add the input as a regular test.
## Bidirectional type (M7.RTL)
## Bidirectional type
Horizontal point, area and path text automatically resolve paragraph direction using Unicode
first-strong detection. Hebrew and Arabic runs shape right to left; embedded Latin and numbers
retain their direction. Wrapping happens in logical order, followed by visual ordering of whole
shaping clusters. Text commands, pasted text and the Type tool use the same layout; stored text,
undo and style byte ranges remain in logical order. New text defaults to automatic alignment:
Hebrew/Arabic paragraphs align right and grow left from a point anchor, while LTR paragraphs
align left. Alignment is resolved again during edits and independently for each paragraph.
The Paragraph panel highlights the resolved alignment and provides an Automatic alignment toggle.
Explicit Left/Center/Right choices override detection; `text.setStyle {justify: "auto"}` restores
automatic mode. Saved documents retain the mode; existing explicit alignments are preserved.
Point, area and path type lay out Hebrew and Arabic with the Unicode bidirectional algorithm
(`unicode-bidi`, in `crates/text/src/layout.rs`). Each paragraph's base direction is its
`ParaStyle::direction` (Paragraph panel › Left-to-Right / Right-to-Left Paragraph Direction, shown
with Preferences › Type › Show Indic Options; `text.setFormat {direction}`), else its first strong
character. Text is shaped in logical order, right-to-left runs right to left (`shape.rs` splits
segments by bidi level and script), lines are broken in logical order and then each line's whole
shaping clusters are put in visual order. Stored text, undo and style ranges stay logical; the
caret, selection, hit testing and arrow keys follow the visual order. A paragraph with nothing
right to left in it skips the algorithm, so plain text pays nothing for it.
Combining marks stay with their bases and Arabic uses the font's contextual forms and ligatures.
Use an installed font covering the script; no new fonts are bundled. Web builds need a font with
Hebrew/Arabic coverage supplied through the existing font setup. SVG export outlines bidirectional
text to preserve its appearance; native files retain editable text. PDF and raster exports use the
same positioned glyphs as the canvas.
Alignment buttons are physical (Align Left is left in either direction). New type
(`text.create`, the Type tools) is aligned `Justify::Auto`, the start of each paragraph's direction:
Hebrew grows to the left of a point type's anchor. Imported text keeps its own alignment, and SVG
import pins the direction SVG implies (left to right unless `direction: rtl`).
Remaining refinements: explicit paragraph direction overrides, dual caret affinity at mixed-direction
boundaries, RTL tab-stop conventions, and editable bidirectional SVG export. Vertical type retains
its existing logical column order. Unicode direction detection is script based, not a language or
keyboard-layout classifier.
Vertical type keeps its logical order down the column. SVG export outlines text with right-to-left
lines (with a warning) until it is written with `direction`/`unicode-bidi`; PDF and raster exports
use the laid-out glyphs. No font is bundled for these scripts: the installed fonts' fallback
covers them (the web build needs a font with that coverage).