In editing data and legacy .ai files, a lower-case l, c, v or y makes the
anchor the segment ends on smooth and an upper-case L, C, V or Y makes it a
corner. The reader used to guess each anchor's kind from whether its
handles are in line, so a lower-case l always read as a corner and an
upper-case C with handles in line read as smooth. A closed path's first
anchor takes the case of the segment back to it. Points and handles do not
move. Paths, compound paths, clipping paths, guide paths, area type frames
and type-on-a-path paths all keep the kinds.
Add the progress line for the symbol editing follow-ups next to the Symbol
editing mode entry in docs/target-app-parity.md, with the tests that cover
them.
Symbol editing copies the editing layer's art into the symbol before Text Wrap, list numbering and threaded re-flow update that layer, so moving a wrap object in the edit left the symbol, its other instances and the saved file with the old wrap. The edit now syncs the symbol again after those passes, and when that changes the symbol, inline graphics of it are refreshed and the threads holding them re-flow.
The appearance changes of the instances on the layers now follow the edited objects through the same pass as the instances in other symbols, graph designs, pattern tiles and brushes. That pass also reaches instances used as opacity-mask art, which keep their changes on the same objects when an edit reorders them and drop the change to an object the edit deletes.
Entering symbol editing mode from an instance puts a copy of the symbol's art on the editing layer in the instance's place, and the instance stays in the document. The view drew the instance dimmed under the copy, so art with transparency showed darker, and its edges showed a dimmed fringe.
The renderer now leaves that instance out of the screen view while the editing layer is isolated, with its masks and effects, and in Outline view inside a clip group. Exports and thumbnails draw it as before.
Editing a dynamic symbol moved each placed instance's appearance changes with the objects they
name, but an instance stored in the art of another symbol kept its changes at the old paths, so
placing that symbol showed a change on the wrong object. Those instances, opacity masks included,
now follow the edit too and keep only the changes to objects the art still has.
symbol.edit checks the new placement before it ends the symbol being edited, so a call with an out-of-range x or y fails and leaves the current edit open. While a symbol is edited, object.isolate refuses art outside the editing layer, and object.exitIsolation goes back to the editing layer only from a group inside it; from any other isolation it leaves symbol editing mode.
Headless tests cover a double-click on a symbol in Thumbnail View and List View, the panel
menu's Edit Symbol with and without a selected instance, the Control bar's Edit Symbol button,
and the Control bar's Exit Symbol Editing Mode and Exit Isolation Mode buttons inside the
symbol's art. The panel's module comment now says a double-click opens the symbol in symbol
editing mode, and docs/mcp.md lists symbol.edit's ids parameter.
Horizontal Scale and Vertical Scale accept any number above 0 and at most 4000000 %, and Baseline Shift accepts -4000000 to 4000000 pt, the limits the document model keeps a character style in. Character Rotation is stored from -180 to 180 degrees, as text.setFormat stores it. A scale outside its limit shows the new message "{label} must be a number above 0 and at most {max}", translated in every catalog that has Basic Character Formats.
charStyle.new now validates attrs against the target text's attributes, so a
language tag that is not in the list but that the selected run already holds
(a native file can store any tag) is kept. Any other unlisted tag is still an
error.
Character Style Options and New Character Style get an Advanced
Character Formats section with Horizontal Scale, Vertical Scale,
Baseline Shift, Character Rotation and Language. Empty fields stay
unset, an explicit 100%, 0 degrees or English: USA stays distinct from
unset, and Reset Panel on the section clears only these five. Scales
take 1% to 10000% and baseline shift -1296 pt to 1296 pt, as
text.setRangeStyle does; rotation is stored from -180 to 180 degrees.
Language sets the language the characters are shaped in; hyphenation
and spelling do not change.
A field still as it opened keeps its stored value without the range
check, so a style captured from a scaled type object can be renamed.
The same applies to Basic's Size and Leading minimum.
charStyle.edit keeps a language tag that is not in the list when the
style already has it, so a style read from a file with such a tag can
be edited.
The OpenType panel gets a Position menu after Figure, with Default
Position, Superscript, Subscript, Numerator and Denominator. `numr` and
`dnom` join the extra features (the existing bits keep their indices),
so they round-trip through the stored tags and reach the shaper.
text.setStyle and text.setRangeStyle take `featureChanges`, which turns
features on or off on top of each character's own features in one
command and keeps every tag the list does not name. The Figure menu,
the Position menu and the checkboxes send it, so on a selection whose
characters have different features each character keeps its other
features. Reset OpenType Features still sends `features`.
Catalog rows for Position:, Default Position, Numerator and
Denominator; one line each in docs/type-parity.md and
docs/target-app-parity.md.
A layer among the targets already stood only for its art that can be
edited. An object named in ids is now checked the same way: a hidden or
locked object, or one on a locked artboard, is refused with an error
instead of becoming the mask, being masked or getting an empty mask.
object.mesh.create with `at` ignored a failed line placement and still replaced the
path with a bare 1x1 mesh. When the new mesh can't place its lines at the point, the
object is left as it is, and when nothing was converted the command fails with
"point is outside the object" and adds no undo step.
With the Appearance panel's active row, the row belongs to the first
selected object, which need not paint first. effect.move reported where
the effect landed in the first target in paint order; it now reports
where it landed in the first selected object for the active row, and in
the first target for an explicit fromItem, as effect.apply does.
The backdrop that takes a click outside the slider strip sensed clicks
with Sense::click(), which egui makes focusable, so Tab stopped on an
invisible full-screen widget. It now uses Sense::CLICK, as the modal
dialog backdrop does; a click outside the strip still keeps the result.
Export for Screens compared names and folders by upper-casing each
character, which turned dotless ı into I. A row with the folder ı then
wrote into the folder i, and an artboard named ı was numbered as a
second i. NTFS keeps ı apart from i and I, and so does Unicode case
folding outside Turkic languages, so fold now leaves ı as it is.
With one Objects on Path group selected, the Selection and Objects on
Path tools show a round handle beyond the top of the group's first
object, joined by a line to its attachment point. Dragging it adds the
angle the pointer turns about that point to the group's Rotate, previewed
while dragging and kept as one undo step on release
(object.objectsOnPath.options). Shift turns in 15 degree steps, Escape
cancels the drag, and the pointer shows the rotate cursor over the
handle.
Docs: docs/target-app-parity.md, docs/mcp.md.
Gutters and the first-baseline minimum were capped at 10,000 before the
art's scale was applied, so a Large Canvas file could bring in a gutter
of up to 100,000 pt, past the limit text.areaOptions sets. The cap now
also applies to the scaled value.
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.
Every graphic in a version 7 wraparound group (`*w` … `*W`), before
or after its type, is now a wrap object with an offset of 0 instead of
the 6 pt default, and a group with no type in it marks all of its
graphics. A graphic before the type is below it, so the type flows
around it only after it is moved above. Operands on `*w` or `*W`, and
a `*w` inside a compound path, are errors.
Docs: docs/file-format-parity.md.
Area type whose frame a wrap object covers sets no line and overflows.
Area type wrapped around a shape of 10,000 anchors sets its lines beside
the shape.
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.
The status bar said "Opened with 1 note(s)", "Saved <path> with 1 note(s)",
"Discarded 1 recovered document(s)" and "Restored 1 recovered document(s)",
and the Global Edit options showed "Result(s): 1". They now use the singular
for 1 and the plural otherwise, in English through i18n::msg_n and in every
catalog through @msgplural rows (the Results line through an @plural row).
The engine's warnings for linked images and placed documents output as their
previews, and its errors for a page past a placed file's last page or
artboard, also name their counts in the singular or the plural.
The catalogs drop the rows no message reads any more: the plain "(s)" rows
of the changed messages and the @msg row for "Packaged {n} file(s){note}".
Follows #5002.
Reading a pattern library adds no pattern or swatch to the document. A
pattern added from it undoes and redoes with its swatch, and both are
kept after a save and reopen.
swatch.library.add looks for the library's pattern among the document's
patterns of that name or a numbered copy of it, instead of importing it
into a copy of the document. Only a swatch that paints with the pattern
unmoved counts as the pattern's swatch, so a swatch whose pattern was
moved in its space is not reused and applied in its place.
Window › Swatch Libraries and the Swatches panel's library menu get a
Patterns submenu with Geometric Patterns, a built-in library of eleven
black pattern swatches drawn in code (dots, stripes, a checkerboard, a
grid, diamonds, triangles, crosses and a zigzag).
- Clicking a pattern in its library panel adds the pattern and its
swatch to the document and applies it to the active fill or stroke
(Alt: the other one), as one undo step. A second click reuses the
swatch; a different pattern under the same name keeps its name and
the library's pattern comes in numbered.
- swatch.library.list lists the pattern libraries after the gradient
libraries (category "patterns"), and swatch.library.add brings a
pattern swatch's pattern as pasting art painted with it does.
- The library panel draws each pattern tile from the library's pattern.
- "Geometric Patterns" is translated in every catalog.
The Actions panel menu has Duplicate, between New Set… and Delete. With
an action selected it copies that action to right after it in the same
set; otherwise it copies the current set, with all its actions, to right
after that set. The copy is named after the original with " copy" added
and is selected, and a copied set gets an id of its own. Copies are
saved with the other sets.
ui.actionSet.duplicate {set?: index, action?: index} does the copy and
returns {set, action?}. An index past the last set or action is an
error. A recording into a later set and an open Set Options or Batch
dialog stay on their own set and action.
The bucket outlines the face under the pointer at its Width setting and an
edge at half of it (4 px and 2 px by default), as the help page says faces
are highlighted with a thick line and edges with a thin line. The Live
Paint Selection tool keeps one width for faces and edges.
A bin table that lists more than 100,000 runs of character or of paragraph
properties is refused while its pages are read. Every paragraph now counts
against the 100,000-paragraph limit, hidden and deleted ones and those in
field instructions included, and so does every line break. The properties
of the styles and of the property runs are read from one budget of 16 MiB,
and a document with more is refused.
Text inside a field's instructions is found with a count of the fields
open in their instructions instead of a search of the open fields for each
character.
Stshif.cstd counts the LPStd records of the style sheet and must be less than
0x0FFE. A sheet that ended before cstd records was read as far as it went, and
paragraphs in the missing styles were placed with the document defaults; a
cstd of 0x0FFE or more was cut to 0x0FFE. Both are now refused as a damaged
style sheet.
A paragraph style can set a logical start or end indent and the paragraph
itself only a physical left or right one, or the other way round. The
indent applied last now holds, after the sides are mapped for the
paragraph's direction; before, the logical indent always held, so a
paragraph's own indent was lost under its style's.
Each style's formatting is now worked out once, on top of the style it
is based on, and each property run's formatting once, so a document with
many hidden paragraphs or long style chains no longer resolves the
chains again for every paragraph and run. Character styles are applied
as a change to the paragraph's formatting.
A bin table whose file positions do not rise, a property page listed
twice, pages whose runs overlap, and styles based on each other in a
loop are refused as damaged, as MS-DOC requires (PlcBteChpx, ChpxFkp,
StdfBase). Property runs refer to their page instead of copying it.