Commit Graph
43 Commits
Author SHA1 Message Date
dotCooCoo b89a6e8ba1 Type: Block's word gap leaves the paragraphs' word spacing as set
The word gap is now the Desired word spacing the layout uses for area type
with Block on (TextObject::layout_justification), with Minimum and Maximum
moved out to it when it lies outside them. The paragraphs keep their own
Justification values, so a wide gap no longer leaves a 1,000 % Maximum
behind, and turning Block off brings back the paragraph's own Desired
value. The SVG writer reads the same values.

- The Contextual Task Bar offers Dynamic Text for area type outside a
  thread, beside Convert To Point Type.
- type.dynamicText with wordGap or lineGap and no area type in the
  selection is an error instead of being ignored.
- Docs: docs/mcp.md, params text, docs/target-app-parity.md.
2026-11-11 15:49:16 -08:00
dotCooCoo fc767dad09 Type: Dynamic Text sets each line of area type to the frame width
Type > Dynamic Text (type.dynamicText) now also works on area type as
Block. Each line as typed (each paragraph, and each forced line break in
one) is set to the frame's width, less the inset, the column gutters and
the paragraph's indents, by changing its font size only. Lines are not
broken again. The first character's size moves in 0.1 pt steps within
0.1 to 1,296 pt, and the line's other characters keep their proportions.
The sizes are written into the characters and fitted again after every
edit to the text or the frame, in the same undo step.

- Word Gap (0 to 1,000 % of a word space, default 100) sets every
  paragraph's Desired word spacing; Line Gap (-1,296 to 1,296 pt,
  default 0) is added to each character's size for its leading. Both are
  VectorCraft's own ranges and defaults, saved in the area options only
  when they differ from the defaults.
- Area Type Options gains a Block fit (text.areaOptions fit "block",
  with wordGap and lineGap), and the Properties panel's Paragraph section
  shows a Dynamic Text checkbox with Word Gap and Line Gap rows.
- Block replaces Auto Size and Shrink Text to Fit. Off keeps the sizes.
  Threaded area type is refused, as for type on a path.
- Empty lines keep their size, a frame with no width changes nothing,
  vertical type fits each line to the frame's height, and right-to-left
  lines and list markers are fitted like other lines. A refit runs at
  most four extra layouts.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-11 13:53:20 -08:00
dotCooCoo 2606b70604 Type: Dynamic Text sizes type on a path to fill its brackets
Type › Dynamic Text (`type.dynamicText`, also on the Contextual Task Bar
for type on a path) scales the text by one factor so it fills the span
between its start and end brackets, and the layout fits it again after
each edit to the text, the path or a bracket. The first character's
size moves in 0.1 pt steps within 0.1 to 1,296 pt. Turning it off, or
threading the type, keeps the sizes it was drawn at.

- The model saves `dynamicText` only when on.
- SVG, the legacy .ai writer and the .ai editing data write the drawn
  sizes through `vectorcraft_text::drawn`; the editing data warns that
  the setting is not written.
- Shrink Text to Fit and Dynamic Text step the size the Character panel
  shows when a size measures the cap height, x-height or ICF box.

Docs: docs/mcp.md, docs/type-parity.md, docs/target-app-parity.md.
Part of #4134.
2026-11-11 10:42:49 -08:00
jmvergesandClaude Opus 5.5 df50bbf0f3 Type: tracking and manual kerning take the Horizontal Scale
In horizontal type, tracking and manual kerning are now thousandths of
the em as the Horizontal Scale draws it: at 50%, a tracking of 100 adds
0.05 em after each character. They were added at the full em while the
glyph advances took the scale, so narrow tracked type drifted from the
page of users' .ai files letter by letter. That page writes such type's
character spacing as the tracking itself in a text space as wide as the
scale, which PDF scales by it (ISO 32000-1 9.4.4). Vertical type keeps
the full em: its advances down the column don't all take the scale.

vectorcraft_text::spacing_scale gives the factor. Shaping, inline
graphics and the Optical pairs use it, and so do the conversions from
points back to thousandths of an em: the automatic kerning the Character
panel reads and Touch Type's limits (glyph_em), Combine Point Text, and
PDF import, whose tracking is now the file's Tc. Scale Text Attributes
now keeps tracked type where a horizontal stretch drew it.
SVG export writes letter-spacing in thousandths of the font size it
writes (the vertical scale), so uniformly scaled type keeps its spacing
in a viewer.

Type with both a Horizontal Scale other than 100% and tracking or manual
kerning lays out differently than before, in every document.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 07:16:55 +00:00
ruchirguitar 74ae6fdd05 #3565: Direct Selection shows and drags type on a path's direction handles
Direct Selection showed and dragged the anchors of type on a path's path
(#3980) but not their direction handles: handle_anchors read only a
path's own data, and the canvas draws only a path's handles.

- text.setPathHandle moves a handle of type on a path's path, in
  document space, as path.setHandle moves a path's; the brackets keep
  their fractions and the text reflows. One undo step.
- Direct Selection draws the handles of selected type on a path and
  drags them with it (Alt: one side, Shift: 45 degree steps).
2026-11-10 19:35:29 +05:30
dotCooCoo a1949095c6 Type: an option fits a text object's bounds to its glyph outlines
Measure Type by Glyph Bounds (`typeGlyphBounds`, off by default) is in
Preferences > Type > Glyph Bounds and the Transform panel menu. With it
on, the bounding box, the Transform, Control bar and Properties X, Y, W
and H, `object.setBounds`, the transform tools' reference point and the
Arrange commands measure point type selected on its own by the ink of
its glyphs instead of its em box. A typed W or H scales the live type
until its ink has that size.

- The engine caches each type object's ink in text space with its
  layout bounds; the cache is not saved.
- Use Preview Bounds adds the characters' strokes, and type with
  geometry effects is measured as drawn. Skewed type is measured by its
  outlines.
- Type that draws nothing, area type, type on a path and type inside a
  selected group are measured as before. Align and Distribute keep
  following Align to Glyph Bounds.

Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md,
object.setBounds params text.
2026-11-09 21:07:55 -08:00
dotCooCoo 3ea13d88d3 Merge main into feat/kinsoku-shori-type
# Conflicts:
#	crates/engine/src/cmd/panelcmds.rs
2026-11-08 16:47:29 -08:00
dotCooCoo 0ce616da4b Merge main into feat/kinsoku-shori-type
# Conflicts:
#	crates/engine/src/cmd/panelcmds.rs
#	crates/text/src/layout/breaking.rs
#	crates/ui-egui/src/panels/paragraph.rs
#	docs/target-app-parity.md
2026-11-08 16:13:35 -08:00
dotCooCoo d8ff63f5d0 Merge main into feat/character-anti-aliasing-method-r 2026-11-08 13:24:43 -08:00
dotCooCoo 7b8d5ba8f5 Type: Tab and Shift+Tab move a list item down and up a level
Squashed from #5037 onto main.
2026-11-09 03:39:05 +07:00
dotCooCoo 11f1d228de Type: Align to Path moves each character by its own font's metrics
Align to Path moved the whole line by the largest ascent and descent
among its characters. Each character now moves by its own font, size
and vertical scale. Ascender runs the top of the font's em box along
the path: the ideographic em box that the font's BASE table gives, or
in a Chinese, Japanese or Korean font the one that its typographic or
hhea box, a one-em box-drawing cross or its ideographs give; else an
em box centered on the cap height. Descender runs the bottom of the font's
bounding box along the path, and Center runs a line at half the height
of the top of the font's H along it. In vertical type, Ascender and
Descender move the characters half an em, and Center leaves them on
the path.

Existing documents with Align to Path set to Ascender, Descender or
Center lay their type out at a new distance from the path.
2026-11-09 03:14:41 +07:00
dotCooCoo b88f4ce311 Merge main into feat/character-anti-aliasing-method-r 2026-11-08 12:08:40 -08:00
dotCooCoo c94269ff72 Type: Composite Fonts… sets each class of character in a font of its own
Squashed from #6244 onto main.
2026-11-09 03:08:23 +07:00
bflatastic 2464ac02be Type: a continued paragraph's list test types *, since # now starts a square bullet 2026-11-08 23:50:35 +07:00
dotCooCoo 246b8ed8cd Type: typed +, # and > start lists with a hollow circle, square and dash
Typed list detection gave every bulleted trigger the filled dot. Now
`*` and a space start a list with the filled dot (•), `+` with the
hollow circle (◦), `#` with the filled square (▪) and `>` with the dash
(–), each one of the existing Bullets presets. `1.`, `1)`, `A.` and `A)`
start the same numbered lists as before.

Only the list a typed trigger starts changes. Lists already in a
document keep their bullets, pasted triggers start no list, and Undo
and Redo of a typed list work as before.

Docs: docs/mcp.md (typed list paragraph), docs/target-app-parity.md.
2026-11-08 23:50:35 +07:00
dotCooCoo c8701a18cd .ai import: legacy binding punctuation opens as Burasagari's Force setting
The legacy reader skipped `bindrepeat Tg` (section 15.3.4 of the version 7
file format specification). It now reads the binding punctuation bit:
1 and 3 set the paragraph's Burasagari to Force, and 0 and 2 set it to
none, which is VectorCraft's own mapping. The value is modal, lasts into
the next text object, and an operand other than 0 to 3 leaves it as it
was. The repeat character, `TG`, `Xu` and `Tu` are still skipped.

docs/mcp.md and the `ParaStyle::burasagari` doc comment name the legacy
`.ai` case as the exception to imported text keeping `none`.
2026-11-08 13:21:08 +07:00
jo-quast bddb834231 Part of #394: each run hyphenates in its own language; Default Language sets new type's
Squashed from #2818 onto main.
2026-11-05 12:17:33 +07:00
dotCooCoo 7d0666346a Merge main into feat/character-anti-aliasing-method-r 2026-11-04 11:56:01 -08:00
dotCooCoo 88b5170622 Glyphs panel: alternates for the current text selection
Squashed from #5442 onto main.
2026-11-04 22:29:53 +07:00
dotCooCoo ccf4252a73 Type: typing a list's start in a continued paragraph starts no list
In a threaded frame whose first paragraph continues from the frame
before, the text at the frame's start is not the start of a paragraph,
and the frame draws no list marker for it. Typing "* " or "1. " there
removed the characters and set a list that never showed. typed_list_at
now returns None for that paragraph.
2026-11-04 14:08:20 +07:00
dotCooCoo 6d38e94f19 Merge current main into Kinsoku Shori Type 2026-11-03 12:25:55 -08:00
dotCooCoo 63ac1395fd Type: control Kashidas for selected characters 2026-11-03 23:29:52 +07:00
dotCooCoo 588ff039a9 Type: Tate-chu-yoko offsets in character style definitions stay in range
A character style whose Up/Down or Left/Right offset lies past MAX_COORD
either way now opens with the nearer end, as text runs already do, so
text that takes the style no longer gets the out-of-range offset. An
offset within range is not rewritten.
2026-11-02 06:32:52 -08:00
dotCooCoo e13cf73ae0 Type: Tate-chu-yoko Settings move a block up, down, left or right
Squashed from #5206 onto main.
2026-11-02 14:32:59 +07:00
dotCooCoo f46427167c .ai import: area type keeps its rows, columns, gutters and first baseline
Area type made from the editing data's text document came in with one
row, one column, the 18 pt gutter and the Ascent first baseline,
whatever its frame kept. Each area frame now keeps its rows and columns,
the gutter between rows and the gutter between columns, and its first
baseline (Fixed, Cap Height, Leading or x Height) with its minimum,
scaled with the art's units. Each frame of a thread keeps its own, and a
key that is missing or can't be read leaves that option as it was. A
first baseline the frame keeps is no longer replaced by the fixed one
that matches the file's first line.

AreaOptions gets row_gutter (rowGutter, left out while unset), which
layout spaces rows by; text.areaOptions takes and reports rowGutter, a
gutter given alone sets both, and the Area Type Options dialog shows
Row Gutter.
2026-11-02 12:04:07 +07:00
dotCooCoo d4f5004580 .ai import: area type flows around its text wrap objects
Fixes #2763. An object whose editing-data dictionary holds the text wrap
options keeps them (offset in points, 6 pt by default, clamped to
±1000 pt; Invert Wrap), and the objects after the text in a version 7
wraparound group (`*w` … `*W`) are wrap objects at the default options.
Area type below a wrap object in its layer flows around it before the
layers are compared with the page, and threaded type flows on into its
next frames. A Large Canvas file's offset is scaled with its art.

The wrap resolver moves into `vectorcraft_doc::text::resolve_wrap` for
the import and the edit-time refresh, and builds each wrap object's
outline once per layer. A file whose wrap shapes would copy more than
2,000,000 anchors is not read from its editing data.

Docs: docs/file-format-parity.md.
2026-11-02 12:04:05 +07:00
dotCooCoo b5cf31950b Merge main into feat/kinsoku-shori-type 2026-11-01 06:26:35 -08:00
dotCooCoo 83227d368d Merge main into feat/character-anti-aliasing-method-r
# Conflicts:
#	crates/engine/src/cmd/panelcmds.rs
#	crates/ui-egui/src/panels/character.rs
2026-10-31 22:16:39 -07:00
dotCooCoo d9dc0ea7e7 Merge main into feat/character-anti-aliasing-method-r
# Conflicts:
#	crates/engine/src/cmd/panelcmds.rs
#	crates/ui-egui/src/panels/character.rs
2026-10-31 21:29:22 -07:00
dotCooCoo e1440a3a90 Paragraph: Kinsoku Shori Type chooses Push In First, Push Out First or Push Out Only
The Paragraph panel menu (with the East Asian options) gains Kinsoku Shori
Type, and text.setFormat takes kinsokuType. Where the Kinsoku Set keeps a
character off the start of the next line or the end of this one, Push In
First sets it on the line and closes the line's gaps next to CJK
characters to fit, each by at most a tenth of an em of the character
before it; a line that cannot close up that much, or that holds a tab,
pushes out. With Optical Margin Alignment or Roman Hanging Punctuation
on, the gaps that hanging punctuation keeps open are not counted. Push
Out First pushes in only when pushing out would leave the line more than
an em short. Push Out Only, the default, is the line breaking area type
had before, so existing documents lay out unchanged. The setting does
nothing with Kinsoku Set None, is saved only when it is not Push Out
Only, and paragraph styles carry it. Reset Panel sets it back to Push
Out Only.

Docs: docs/mcp.md, docs/type-parity.md, docs/target-app-parity.md.
2026-10-31 21:14:57 -07:00
dotCooCoo 427bce12b0 Character: Font Size can measure the cap height, x-height or ICF box
Squashed from #5026 onto main.
2026-11-01 11:08:55 +07:00
dotCooCoo ece78f052f Type: Standard Vertical Roman Alignment stands half-width characters upright in vertical type
Character panel menu > Standard Vertical Roman Alignment, with Show East
Asian Options, is now a check item. It sets a new character attribute,
`standardVerticalRoman` (text.setFormat, text.setRangeStyle), off by
default and saved only when on. In vertical type the marked Latin
letters, digits and other characters that would lie on their side stand
upright one below the other, each in its upright cell. Spaces keep their
width and tate-chu-yoko blocks stay across the column. Horizontal type
keeps the mark and does not change. A combining mark shaped as its own
glyph turns with its letter, in Latin and CJK upright type alike.

Character Style Options labels the Character Alignment row "Character
Alignment" and gives Standard Vertical Roman Alignment its own checkbox.
Reset Panel turns the attribute off. PDF and SVG export place the glyphs
from the layout and need no change.
2026-11-01 08:32:55 +07:00
dotCooCoo c3b88e3e92 Merge main into feat/character-anti-aliasing-method
# Conflicts:
#	crates/engine/src/cmd/panelcmds.rs
#	crates/ui-egui/src/panels/character.rs
2026-10-31 18:10:03 -07:00
bflatastic 7d8f1d4e06 Fix #4978: Area Type Options › Text Flow by rows or by columns 2026-11-01 06:11:11 +07:00
bflatastic b8365d6197 Fix #4942: native Indic digits in the Digits menu 2026-11-01 03:36:40 +07:00
bflatastic a85487ad39 Fix #4940: text is shaped in its language
Characters get a language (CharStyle::language, a BCP 47 tag of one of
Document Setup's languages; none for the default, English: USA, saved
only when set). The shaper sets it on the HarfRust buffer, so fonts use
their language forms (OpenType locl): Turkish keeps fi apart and the dot
on its i. Runs in different languages are shaped apart. New type takes
the document's language.
2026-11-01 01:39:11 +07:00
dotCooCoo 9896f633da Type: Kerning has an Optical option that spaces characters by their shapes
Squashed from #4825 onto main.
2026-11-01 01:22:04 +07:00
dotCooCoo d29db00c07 Type: import the anti-aliasing types the merge with main needs
main made the render and doc crates' imports explicit, so the merged
branch named TypeAntiAlias, TypeEdgeEntry, Pixmap, AntiAlias,
single_threaded_context and MAX_RASTER_SIDE without importing them.
2026-10-29 02:21:10 -07:00
dotCooCoo 5a2e3c3d82 Merge main into feat/character-anti-aliasing-method 2026-10-28 21:55:37 -07:00
dotCooCoo 8b1ff5f32b Merge main into feat/character-anti-aliasing-method 2026-10-27 22:12:22 -07:00
Dylan M. Taylor 3d0188a5bc refactor(doc): name text model dependencies explicitly 2026-10-27 17:47:12 +00:00
aiongg 901c72b089 refactor(doc): move text.rs items to text/{area,char_style,object,para_style,runs,tabs_lists}.rs 2026-10-26 21:17:08 +00:00
aiongg d133961eb3 refactor(doc): move text.rs tests to text/tests.rs 2026-10-26 18:18:18 +00:00