Commit Graph
4007 Commits
Author SHA1 Message Date
dotCooCoo a072cf16be View: Escape that cancels a ruler or Tools move does not reach the tool
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.
2026-10-31 06:10:57 +07:00
dotCooCoo 501ae57fef Canvas: pressing or releasing ` mid-drag updates the live preview
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.
2026-10-31 06:10:53 +07:00
dotCooCoo 7584b6335e Legacy .ai: colorized image pattern tiles keep their color
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.
2026-10-31 06:10:51 +07:00
bflatastic e13c4bc9d0 Add-ons: Path Precision Tools — live path effects 2026-10-31 06:10:47 +07:00
dotCooCoo fa89546397 PDF export: leave out an object whose opacity mask lost an image
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.
2026-10-31 05:42:51 +07:00
dotCooCoo 7d706ffa26 PDF: colorized images that can't be exported are cached as missing
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.
2026-10-31 05:42:41 +07:00
Don Omondi 20f7f8be1e Testkit: the temp_dir test pre-makes a private directory, as temp_dir 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.
2026-10-31 05:42:38 +07:00
Don Omondi b0cc17343e fix(pdf-import): take a group's knockout and isolate flags from the interpreter
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.
2026-10-31 05:27:13 +07:00
Don Omondi d4745fe046 fix(eps): a layer's state after its last blend stays the layer's
#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.
2026-10-31 05:11:04 +07:00
Don Omondi aa6a960062 fix(ai-import): compare a PDF of some artboards on the artboard its page shows
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.
2026-10-31 04:55:14 +07:00
Don Omondi c4d2480132 .ai/EPS import: a blend takes the transparency written after its record
Squashed from #4757 onto main.
2026-10-31 04:39:05 +07:00
Don Omondi a1fc3cfdb1 fix(eps): a masked gradient mesh takes the transparency after its mask
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.
2026-10-31 04:21:56 +07:00
bflatastic c9dc4fa857 Add-ons: Path Precision Tools — Corner Tool and Slide Anchor
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.
2026-10-31 04:21:26 +07:00
Don Omondi ff1f721013 fix(eps-import): keep a layer's opacity when its state block has the stroke style
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.
2026-10-31 04:02:35 +07:00
dotCooCoo 6a034c77c3 Transform tools: backquote drag transforms only the pattern
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.
2026-10-31 03:34:55 +07:00
dotCooCoo 5f9b524d1a Shortcuts: Shift+Comma and Shift+Period run their bindings where Shift types another character
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.
2026-10-31 03:34:52 +07:00
dotCooCoo 26ac7799e7 Shortcuts: Shift+Comma and Shift+Period also apply the last color and gradient
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.
2026-10-31 03:34:51 +07:00
dotCooCoo fc7ef3102f Object: Cmd/Ctrl+Alt+Shift+2 locks inside clip groups and isolation, with no menu item
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.
2026-10-31 03:34:47 +07:00
dotCooCoo a372d39a31 Object: Cmd/Ctrl+Alt+Shift+2 locks every unselected object
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.
2026-10-31 03:34:47 +07:00
Don Omondi bfe509bb38 fix(eps-import): read layers whose type is in the legacy format beside a page with text
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.
2026-10-31 03:34:40 +07:00
dotCooCoo 7a16e302d2 Panels: a panel's function key restores only the tabs its group hid
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.
2026-10-31 02:52:26 +07:00
dotCooCoo 78b01044fc Panels: a panel's function key hides and restores its whole group
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.
2026-10-31 02:52:26 +07:00
dotCooCoo a535d7b890 Panels: a second press of a panel's function key hides the panel
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.
2026-10-31 02:52:25 +07:00
dotCooCoo d792557bbe View: Escape during a canvas pan or zoom drag keeps full screen
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.
2026-10-31 02:52:22 +07:00
dotCooCoo 030baab798 View: Escape that cancels a ruler or Tools move ends nothing else
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.
2026-10-31 02:52:22 +07:00
dotCooCoo dcd4b437a5 View: Escape that ends a field, ruler or Tools move keeps full screen
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.
2026-10-31 02:52:22 +07:00
dotCooCoo 38a68c3b85 View: Escape returns full screen modes to Normal
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.
2026-10-31 02:52:22 +07:00
dotCooCoo 86f88dfc96 Type: Alt+arrow spacing steps turn with vertical type
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.
2026-10-31 02:52:17 +07:00
Don Omondi ef3b5b0c95 fix(eps): a layer's state after its last mesh stays the layer's
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.
2026-10-31 02:52:13 +07:00
Don Omondi c1971284ce Type: required lam-alef is not an alternate in fonts that put it in liga (#394)
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.
2026-10-31 02:52:05 +07:00
dependabot[bot] 414aad10bd chore(deps): bump the cargo-patch group across 2 directories with 4 updates
Bumps the cargo-patch group with 3 updates in the / directory: [rustix](https://github.com/bytecodealliance/rustix), [clipboard-win](https://github.com/DoumanAsh/clipboard-win) and [smallvec](https://github.com/servo/rust-smallvec).
Bumps the cargo-patch group with 1 update in the /crates/plugins/example directory: [serde_json](https://github.com/serde-rs/json).


Updates `rustix` from 1.1.5 to 1.1.6
- [Release notes](https://github.com/bytecodealliance/rustix/releases)
- [Changelog](https://github.com/bytecodealliance/rustix/blob/main/CHANGES.md)
- [Commits](https://github.com/bytecodealliance/rustix/compare/v1.1.5...v1.1.6)

Updates `clipboard-win` from 5.4.1 to 5.4.3
- [Commits](https://github.com/DoumanAsh/clipboard-win/commits)

Updates `smallvec` from 1.16.3 to 1.16.4
- [Release notes](https://github.com/servo/rust-smallvec/releases)
- [Commits](https://github.com/servo/rust-smallvec/compare/v1.16.3...v1.16.4)

Updates `serde_json` from 1.0.151 to 1.0.154
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.151...v1.0.154)

Updates `serde_json` from 1.0.151 to 1.0.154
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.151...v1.0.154)

---
updated-dependencies:
- dependency-name: clipboard-win
  dependency-version: 5.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: cargo-patch
- dependency-name: rustix
  dependency-version: 1.1.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: cargo-patch
- dependency-name: serde_json
  dependency-version: 1.0.154
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: cargo-patch
- dependency-name: serde_json
  dependency-version: 1.0.154
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: cargo-patch
- dependency-name: smallvec
  dependency-version: 1.16.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: cargo-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-31 02:23:04 +07:00
bflatastic e556dacbb6 Add-ons: Artwork Cleanup — text tools
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.
2026-10-31 02:05:58 +07:00
dotCooCoo a0da3faffe Swatches: a Shift-click after switching documents starts a new range
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.
2026-10-31 02:05:55 +07:00
Don Omondi 1a5f0fb099 fix(ai-import): space type on a path round curves as the file lays it out
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.
2026-10-31 02:05:52 +07:00
Don Omondi 7b4a65e231 fix(ai-import): put placed files where they draw closer to the page
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.
2026-10-31 02:05:48 +07:00
Don Omondi 67c8d86c6f .ai import: a page's type inside placed files needs no text object
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.
2026-10-31 02:05:43 +07:00
Don Omondi 2d4e9dc9c9 EPS import: the printer's crop marks after the layers aren't art outside them
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.
2026-10-31 02:05:42 +07:00
Don Omondi e5481bda98 fix(eps): a gradient mesh takes the transparency written after it
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.
2026-10-31 02:05:39 +07:00
Don Omondi dc6af04dcc fix(ai-import): read mesh corners whose handle weights are 0
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.
2026-10-31 02:05:35 +07:00
bflatastic 63a5889895 bs: language names keep their own name in the picker 2026-10-31 01:31:09 +07:00
nine-codesandClaude Opus 5.5 64b92627c2 Add Bosnian (bs) to the interface languages
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
2026-10-31 01:17:11 +07:00
bflatastic f38cdaeaa7 Testkit: temp_dir starts empty in each process, so a reused process id can't fail a test 2026-10-31 01:17:06 +07:00
bflatastic ebc5b7038c Add-ons: Color Effects — Duotone effect and Print Ink Fixes
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.
2026-10-31 00:26:18 +07:00
bflatastic 79fe17934a Canvas: Shift, Alt and Cmd/Ctrl pressed or released mid-drag apply with the pointer held still (#4711) 2026-10-31 00:26:15 +07:00
dotCooCoo a2d3841579 Image Trace: look up library swatches once per trace
Each traced path filtered the whole library for its color, twice when
no swatch of that color was linked. The color-to-paint lookup is now
built once before the paths are filled. The first linked swatch of a
color still gives the fill, and the first swatch of that color
otherwise.
2026-10-30 23:57:40 +07:00
dotCooCoo 65f7d3a699 Image Trace: Document Library links to a global swatch that shares a process swatch's color
When a process swatch listed before a global or spot swatch showed the
same color, a traced fill of that color took the process swatch and
stayed unlinked. Of the swatches that trace as one color, the first
linked one now gives the fill, and the first one otherwise.
2026-10-30 23:57:40 +07:00
dotCooCoo 8f56899df9 Perspective Selection: Cmd/Ctrl+Alt-drag copies objects in perspective
With the Perspective Selection tool, Ctrl+Alt-drag (Command+Option-drag on
macOS) now copies objects on their perspective plane, as Alt/Option-drag
does. Before, Cmd/Ctrl lent the last selection tool even with Alt held, so
the drag made a flat copy. Cmd/Ctrl alone still lends the last selection
tool, and the cursor follows the same rule.
2026-10-30 23:57:36 +07:00
Don Omondi 66c797a59b .ai import: outlines from the editing data keep their look and threads; mesh corners with non-numbers are unread
Follow-ups to the review of #4697 and #4698:

- With textAs: outlines, a .ai saved without PDF compatibility, read
  from its editing data alone, has its type outlined too, as an empty
  page or a text-only placeholder already did.
- Threaded type read from the editing data holds its story in its first
  frame: it now flows through its frames before it is outlined, so each
  frame's outlines show the text it holds, and the outlined frames
  leave their threads.
- Each outline group keeps its type's opacity, blend mode, isolation,
  opacity mask and effects (the same carry-over the flattener uses).
- A gradient-mesh corner (/N) holding anything but numbers is unread,
  instead of being read with the numbers after it shifted into its
  colour and opacity.
2026-10-30 23:55:32 +07:00
Don Omondi 1d58ea947d fix(ai-import): pages cropped to the art in UserUnit units, and their copies' type
A page cropped to the art is recognised in a UserUnit page's units too,
when the art's box is the page in those units and the artboard isn't the
page in points. Such pages are taken only when every page is the art's
box, and only the first page's type is read: the later pages are copies
whose type was moved by the first page's offset and could fill the
layers' text objects twice.
2026-10-30 23:55:28 +07:00
Don Omondi 75958ce7da fix(ai-import): weigh unseen text again at the placed files' other placement
prune_unseen ran before the retry that moves placed files to their box's
corner, and that retry cloned the pruned layers: text an image covered
only at its first placement was already gone, so the file came in without
it or as its PDF part. Clone the layers before pruning and prune each
placement on its own.
2026-10-30 23:55:22 +07:00