The Tabs panel's ruler shows an upper marker at the first line's position
(left indent plus first-line indent) and a lower marker at the left
indent. Dragging the upper marker sets the first-line indent. Dragging the
lower marker sets the left indent and keeps each paragraph's first line
where it was; Ctrl-dragging it (Command on macOS) moves both markers.
Marker drags land on whole points, or on ruler ticks with Snap to Unit or
Shift, and each release is one undo step through text.setFormat. With a
marker selected, the X (or Y) field shows and sets its position.
When the touched paragraphs have different left indents, only the upper
marker is shown, and its position applies to every touched paragraph.
Path Precision Tools gains the Shared Edge Merge Tool, kept out of the
toolbars (All Tools drawer and Object › Plug-ins › Path Precision Tools,
no shortcut), and Keep Shared Points Together:
- Shared Edge Merge Tool (sharedEdge): over two paths touching at two
coincident anchors (tolerance 0 to 3 pt) hovering shows the two
stretches and the merged edge; a click replaces both with it, half way
between them, or following the upper (Shift) or lower (Alt) path. Both
paths stay closed or open, anchors either stretch has inside are
matched on the other, one undo step.
- Making ends: near anchors meet on a click and an anchor one path lacks
is added to match; Shift+Alt asks for this inside a stretch.
- Keep Shared Points Together: an option that makes Slide Anchor Along
Path, Extend Path and Set Anchor take coincident anchors along. Nothing
else in the app changes.
- Shared Edges section in the Anchor Inspector: brush diameter,
coincidence and the option.
- Commands addon.pathtools.mergeEdge and movePointsTogether, params
validated and covered by the command sweep.
- Cursor stand-in, catalog rows in every language, docs and tests.
With the Live Paint Bucket, Alt-click on vector art samples its fill,
stroke and stroke weight into the paint defaults, and on a placed image
it samples the pixel as a solid fill with no stroke. Alt+Shift-click
samples only the color under the pointer, including an intermediate
gradient color or image pixels, into the active fill or stroke. Neither
click paints or changes the selection or selected art, and the next
Bucket click paints with the sampled paint. While Alt is held, the
Bucket shows the Eyedropper cursor and no face or edge highlight.
appearance.copyFrom takes `defaultsOnly: true` to update only the paint
defaults, and paint.sampleColor takes `clearStroke: true` to clear the
stroke default after an image sample into the fill.
A knockout element with one opaque Normal solid fill (a path or
compound, no mask, effects or isolation) is drawn once under
AntiAlias::None, including the internal hard-edge frame of Art
Optimized supersampled exports, instead of being erased and added back
through per-element backdrop layers. Analytical antialiasing keeps the
existing compositor and rounding.
Exact-pixel tests compare against the general knockout path for paths
and compound holes across precision, supersampling, translucent parents
and copied backdrops, and check that the backdrop rasters are skipped;
translucent fills keep their knockout compositing.
# Conflicts:
# docs/roadmap.md
# docs/target-app-parity.md
With a path selected that the Smooth tool can change, Alt held at a
Paintbrush press now switches the drag to the Smooth tool: it smooths the
selected paths under the drag with the Smooth tool's radius and Smooth Tool
Options' Fidelity, and the cursor shows the Smooth tool before the press.
Alt pressed after a stroke begins still closes the path on release. With no
such path selected (nothing, only text or an image, or only a two-point
line), Alt at the press draws the closed stroke as before.
The Paintbrush no longer reads the Pencil's "Alt key toggles to Smooth Tool"
setting: its Alt close and Alt smoothing do not depend on it.
An Escape that cancels a ruler-origin drag or a floating Tools panel move
now stops there: the active tool does not receive it, so a tool's own
Escape action (for example Intertwine returning to the Selection tool)
waits for the next press. The ruler-origin test also covers the drawer
and Global Edit.
A Selection or transform drag held still now gets another drag event when
the backquote key goes down or up, as it already did for Shift, Alt,
Cmd/Ctrl and Space, so the preview switches between a pattern-only and an
ordinary transform without waiting for the next pointer move.
Saving a legacy .ai with transparent images flattened expands pattern
fills whose tile image is see-through or has opacity or a blending mode,
so the tile images flatten with the art under them. A pattern whose tile
is an opaque grayscale image with a colorize paint was not expanded, so
the writer drew the source gray pixels over white. A colorize paint now
counts too.
An unclipped opacity mask is drawn on a white backdrop. When an image in
the mask art could not be written (a colorized image whose color channel
is over the size limit, an image that can't be decoded, or one placed
beyond the coordinates a file holds), the backdrop stayed white and the
masked object showed in full where the image should hide it.
The exporter now records an image left out while it writes mask art,
and leaves the masked object out instead of applying the incomplete
mask, with a warning. A failure in a nested mask makes the outer mask
incomplete too.
colorized_image returned before its cache insertion when the image was
missing, left out or undecodable, or when its color channel was larger
than MAX_RASTER_ALLOC. Every placement of such an image then decoded it
and computed its coverage again. Both cases now cache None for the key,
as load_image does.
a_temp_dir_starts_empty_in_a_process_and_stays_for_later_calls
pre-created the "earlier process" directory with create_dir_all, which
under a usual umask gives others access, so temp_dir refused it as not
private and the test failed on every Unix run (main's CI included).
The test now makes it with mode 0o700; temp_dir and the assertions are
unchanged.
The import read each form's /Group /I and /K from the file in order and
matched them to the transparency groups the interpreter pushed. The
interpreter draws a group that adds nothing (full opacity, Normal, no
mask, neither flag) straight onto its parent without pushing it, so every
group after one took another group's flags. Blend steps written as a
knockout group of falling opacity then painted over each other and drew
as solid dark shapes instead of light rings.
The interpreter already reports the flags right after pushing a group
(set_knockout, set_isolated); the import now uses those and drops the
file-order list. That list was capped at 10,000 entries, past which a page
failed to import; that limit goes with it.
#4757 gives a blend the Xy written after its record. When the blend is a
layer's last object, the layer's own state block (Xy, Xd, 7 () XW, LB)
went to the blend instead, and the layer stayed opaque. The blend's state
is now tentative like a mesh's (#4748): its own 6 () XW confirms it, the
layer's LB gives it to the layer and the blend keeps what it had.
Also records the .ai/EPS audit fixes under G9, the File formats row and M4.
A PDF saved with Illustrator editing data for only some of its artboards
has pages for those artboards, while the editing data keeps them all. The
layers were compared with the first page on the first artboard, so a page
showing a later artboard never matched and the file came in as its PDF
part, without its layers.
With fewer pages than artboards, the first page is now taken to be the
artboard of its size whose art draws most like it (up to 16 weighed), and
the pages' type goes to that artboard and the ones after it. All the
artboards still come in, and the comparison still decides whether the
layers are used.
A gradient mesh with an opacity mask has its own state (`Xy`) after the
mask's dictionary, not right after its `/End X!`. The operators of the
mask's art, on `%_` lines, cleared the flag that says a mesh just ended,
so the state was read as the next object's and each masked mesh in a
run drew with the blend mode of the one before it.
The flag now goes back to what it was when a dictionary opened once it
closes, as `after_object` does.
Path Precision Tools gains two tools, kept out of the toolbars (All Tools
drawer and Object › Plug-ins › Path Precision Tools, no shortcuts):
- Corner Tool (cornerTool): editable corners on any path through the
existing Live Corners. Hover shows an eligible anchor, a click cuts a
corner with the tool's radius and kind, a drag sizes it (Shift: whole
values), a corner's marker selects it and loads its values, resizes it
and removes it at 0 or on a double-click; a corner never grows past
what fits; an Alt-marquee cuts every eligible anchor inside.
- Corners section in the Anchor Inspector: radius, kind, selected count,
Apply to Selected Anchors.
- Slide Anchor Along Path (slideAnchor): a drag runs an anchor along its
curve, the neighbouring segments refitted by the keep-shape kernel;
Shift snaps where the tangent is a multiple of 45° from the constrain
angle.
- Commands addon.pathtools.cornerSet, cornerRemove and slideAnchor, one
undo step each, params validated and covered by the command sweep.
- Cursor stand-ins, catalog rows in every language, docs and tests.
A layer's own state block (Xy, Xd, 7 () XW before LB) can have the
stroke style (J j w M d XR) between its Xy and Xd. Read as the art moving
on, it dropped the layer's opacity, so a layer at 17% drew opaque and the
file came in as its page. The stroke style now keeps the pending layer
state, and the state a mesh before it had; an object's own 6 () XW block
still isn't the layer's.
Holding backquote while dragging with the Selection tool (move, bounding-box
scale or rotate) or the Rotate, Reflect, Scale or Shear tool applies the drag
to the selected objects' pattern fills and strokes and leaves their geometry
in place. The key state at release decides the result: the key may be pressed
after the mouse button goes down, and releasing it before the button comes up
commits an ordinary transform. Objects without pattern paint do not move.
PointerEvent gains a `backquote` flag (false when absent). The desktop canvas
reads it from the held key on every pointer event, and `ui.pointer` and the
`pointer_gesture` tool accept it per event or as a default for the gesture.
On layouts such as German, Shift+Period types `:` and Shift+Comma types
`;`, so the key event carries the Colon or Semicolon key and the
`Shift+.` and `Shift+,` bindings did not run. A shifted press at the
Comma or Period key position now runs the chord bound to that position
when no binding exists for the typed character; a binding the keymap
has for the typed character, such as a user's `Shift+;`, still wins.
Each press runs one command.
The tests send the key events these layouts produce, and the text
editing test checks after each press that fill and stroke stay as they
were.
Apply Last Color keeps `,` and also gets `Shift+,` as a default key;
Apply Last Gradient keeps `.` and also gets `Shift+.`. The keymap
catalog takes the extra defaults from a small alias table, the
Keyboard Shortcuts dialog lists every default key of a row, and reset
restores both.
A shifted punctuation chord that the active keymap binds now runs from
its key press, once per press, so a user binding such as `Shift+;`
works and layouts where Shift+Period types another character still run
the bound command. Text editing still types the characters.
The toolbar tips read "Color (, or <)" and "Gradient (. or >)", with
rows in every catalog.
object.lock.unselected is now reached by its key and as a command only:
the Object > Lock > Unselected Artwork menu item is removed, and the
command stays in the registry, the shortcut editor and automation.
In a partly selected clip group or compound path it now locks the
unselected members, the clipping path included, and leaves the container
and the selected members unlocked. It locks unselected guides while Lock
Guides is on. Hidden art and art on a locked layer stay unlocked, and a
selected layer's art counts as selected.
With a selection in isolation mode the command is enabled and locks only
the unselected art inside the isolated group. The other Lock and Hide
items keep their isolation behavior.
Lock and Hide still share one selector. A lock flag on it selects the
clip group, compound path and guide cases above; Hide > Unselected
Artwork keeps its behavior, and a test covers both directions.
Docs: docs/mcp.md, docs/target-app-parity.md.
The reference app locks all deselected artwork on Cmd/Ctrl+Alt+Shift+2.
VectorCraft had no command for it: Object > Lock held Selection, All
Artwork Above and Other Layers.
The new command, object.lock.unselected (Object > Lock > Unselected
Artwork), locks in one undo step the objects that Hide > Unselected
Artwork hides: every object that Select All takes and that is neither
selected nor holds a selected object. It returns the count. Hidden
objects stay unlocked. The selection stays as it is, Unlock All unlocks
the objects again and selects them, and with nothing to lock the
command records no undo step. Both commands now share one function,
which locks or hides the objects that the existing unselected helper
returns.
In isolation mode the menu item is disabled, and the command returns
the error "not available in isolation mode" that Hide > Unselected
Artwork returns there, and changes nothing.
Docs: docs/mcp.md, docs/target-app-parity.md.
An EPS saved for Illustrator 10 keeps its type in the editing data as
legacy text objects (`To` ... `TO`), with no `/AI11Text` slot for the
page's type to go in, so a file whose page had text came in as its page.
Those text objects are now the layers' own: the page's type isn't put
anywhere, and the comparison with the page decides as before. Type the
editing data keeps only as outlines stays outlines, with a note counting
the page's text objects that are.
Hiding a group with a panel's function key records the tabs it closed, and the next press reopens only that set with the panel in front. A tab closed on its own before the group was hidden, or reopened and closed again while the group was hidden, stays closed. The record is saved with the workspace.
When Brushes, Color, Layers, Info, Gradient, Stroke, Attributes, Graphic
Styles, Appearance, Align, Transform, Pathfinder, Transparency or
Symbols is in front of an expanded dock group or a floating group, its
function key now hides the whole group instead of closing only that
tab. The next press brings the group back in the same place with every
tab and the panel in front, and Window > a hidden sibling also restores
the group. A background tab still comes to the front on the first
press, and in an icon column the key opens and closes the flyout.
Other panel shortcuts and plain window.panel calls keep their behavior.
The function key shortcuts for Brushes, Color, Layers, Info, Gradient,
Stroke, Attributes, Graphic Styles, Appearance, Align, Transform,
Pathfinder, Transparency and Symbols now run window.panel with
toggle: true, as the Window menu items do. A second press hides an
active panel in the expanded dock, and the next press restores it in
its group. A chord the user assigns to one of these panels toggles the
same way. Plain window.panel calls still only show the panel.
A Hand or Space drag, a middle-button pan, a Zoom tool drag, a Rotate View
drag or a touch gesture is held in the canvas's drag state, which the tool
busy check does not see. Escape pressed while one is held no longer leaves
Full Screen Mode, closes the Edit Toolbar drawer or ends another action; an
Escape after the release does.
An Escape press that cancels a ruler-origin drag or a floating Tools
panel move no longer also closes Edit Toolbar's drawer, leaves pattern
edit, isolation or Global Edit, closes the tool flyout or resets a
rotated view. A later Escape does that action as usual.
In Full Screen Mode and Full Screen Mode with Menu Bar, an Escape that
leaves a focused text field, cancels a ruler-origin drag or cancels a
floating Tools panel move no longer also returns to Normal Screen Mode;
the next Escape does. Tests cover a dialog, a focused field, a tool that
claims Escape, pattern edit, Global Edit, a tool flyout and the rotation
reset pair in both modes.
In Full Screen Mode and Full Screen Mode with Menu Bar, an unmodified
Escape that nothing earlier in the Escape chain takes (a popup, dialog,
field, drawer, tool gesture, edit mode, flyout or the view rotation
reset) runs view.screenMode with mode 0. Presentation Mode and the F
cycle are unchanged.
In vertical type, Alt+Down/Up (with or without Shift) steps kerning at a
caret or tracking of selected text, Alt+Left/Right steps leading, and
Alt+Shift+Right/Left steps baseline shift; Cmd/Ctrl makes five steps.
Horizontal type keeps its mapping. Selected type objects follow the same
rule when all of them are vertical, and a selection that mixes horizontal
and vertical type takes the horizontal mapping in one undo step.
An Xy right after a gradient mesh's /End X! is the mesh's only when the
mesh's own 6 () XW follows. When the layer's LB follows (directly or
after the layer's Xd and 7 () XW) it is the layer's, as before, and the
mesh keeps the state it had. Also corrects the revision-history row that
still said meshes with handle weights of 0 aren't read.
Highlight Alternate Glyphs compares each glyph with required shaping
alone, which turns liga and calt off. Older Arabic fonts (such as the
legacy Arial of the Microsoft core fonts) put the mandatory lam-alef
ligature in liga instead of rlig, so every lam-alef was highlighted.
A lam + alef cluster (any alef form, marks allowed) is now never an
alternate candidate, whatever feature the font uses.
Adds a test font built in code (lam-alef under liga or rlig) and
host-independent regressions. Also two equivalent one-line repairs
strict Clippy needs on main: a nonminimal_bool in the Path Precision
Tools inspect check and is_none() in a gradient panel test.
Object › Plug-ins › Artwork Cleanup and a hideable Text row in its panel
gain text tools, each one undo step:
- Break Text into Lines / Paragraphs / Words / Glyphs: point type pieces
placed by the glyph of their first character, keeping their styles.
- Combine Point Text: one-line point type merged into as few objects as
it can, every glyph staying where it was (tracking and spaces, checked
against the layout).
- Split Text at Cursor, Remove Line Breaks, Remove Paragraph Breaks,
Set Alignment, Keep Position, Reset Text Transform and Replace
Missing Fonts.
The panel cleared its swatch selection when the active document or the
selected art changed, but kept the Shift-click range anchor. A Shift-click
in the other document then selected every swatch from a name clicked in
the first document (for example White) to the clicked one. The anchor is
now cleared with the selection, so the Shift-click selects only the
clicked swatch.
Type on a path from the editing data's text document came in at the
font's advances, while the file's own layout (and its page) closes the
glyphs up round the outside of a curve and opens them up round the
inside, even where the frame keeps no spacing. Round a circle the type
ran on past where the page ends it.
The spacing (Type on a Path Options > Spacing) that reproduces the
layout is now fitted from the layout's glyph positions, advances and
turns, using the text engine's own model, and set on the imported text
object. Corners and straight runs are left out of the fit.
The corner placement of placed files was tried only when the first
placement failed the comparison with the page. A small logo in the wrong
place differs too little to fail, so it stayed there. When the corner
placement draws closer to the page and still matches it, use it.
A .ai whose layers hold placed (linked) PDFs and no text object came in as
its PDF part, saying its layers had no text objects for its page's text.
The PDF part draws each placed file, type and all, where the layers show
its preview, so type that lies inside the placed files (at either of their
placements) is theirs and needs no text object. Type outside them still
does.
An Illustrator EPS draws its crop marks after the last layer, between
%AI3_BeginCrops and %AI3_EndCrops (inside userdict /AI3_noCropMarks known
not { ... } if). The reader took them for art outside the layers, and the
whole file came in as its page in one layer. The section is now skipped,
as other non-art sections are; the crop area is %AI3_Cropmarks.
In the editing data of a .ai or EPS file, a gradient mesh's own state
(`Xy`) comes right after its `/End X!`, before its `Xd` and `XW`, as a
group's comes after its `U`. The reader took it as the next object's, so
a Multiply shadow mesh came in as Normal and painted opaque white over
the art under it, while the file's page shows the shadow.
An `Xy` read straight after a mesh ends now also applies to that mesh.
An `Xy` after the mesh's `Xd` and `XW` stays the next object's.
Some files write a handle weight of 0 on some gradient mesh corners. The
reader took only weights of 1, so the mesh and the whole file's layers
were unread. A weight of 0 draws as the same cubic edge against the files'
pages; other weights still leave the mesh unread.
bs.tsv: Bosnian (Latin script, Ijekavian) catalog covering every key of
VectorCraft's other catalogs, its wording shared with storytold/craft-i18n
locales/bs/ and the strings craft-i18n lacks translated new. Every bs-*
locale selects it; counts use one/few/other. Locale and plural tests,
localization docs and an attribution entry (AI-assisted, not yet
reviewed by a native speaker).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Tayw8nmxoLLmKv13jK93z
Effect › Color Effects › Duotone… (addon.color.duotone, also in Object ›
Plug-ins › Color Effects) prints the grey-equivalent tone of each colour
with one to four inks, each with its own tone curve. It is a colour
adjustment like the add-on's others, so it stacks with them and works as
a filter through addon.color.filter.
- One tone of a swatch the document has gives a tint of that swatch,
linked, so a spot tone separates onto its plate; several tones give
the CMYK mix of their tints (the inks overprint, so they multiply).
- Colour adjustments now map paints with their swatch links
(ColorMap::apply_link); the existing adjustments behave as before.
- Skip Objects with Spot Colors leaves spot-linked colours as they are.
- The dialog has a row per tone and the picked tone's curve (the Curves
graph, reused), its points and Reset to Linear / Inverse.
Print Ink Fixes (addon.color.printFixes, Object › Plug-ins › Color
Effects › Print Ink Fixes…) scales CMYK colours over a total ink limit
down to it, removes white overprint and sets black overprint (Overprint
Black's logic) in a CMYK document, as one undo step, and reports what
changed. RGB documents are refused.
The panel opens both under Inks.
Deferred: an opaque undercoat, tones for type only, extra gradient stops
for smoother tints, curve flip and all-100 % buttons.