Commit Graph
5312 Commits
Author SHA1 Message Date
dotCooCoo 0a13aca6ee Docs: gray photos need an eight-color error over 6 levels to count as continuous tone 2026-11-12 08:53:48 -08:00
BFlat a6aac579c0 Merge pull request #6904 from dotCooCoo/feat/ai-editing-data-s6c
.ai save: the editing copy keeps brushes and brushed paths
2026-11-12 23:53:38 +07:00
BFlat e618783377 Merge pull request #6084 from Taha-Mahmoodi/feat/glyph-alternates
Glyphs: alternates keep the word joined (feature values, one-piece shaping, unencoded glyphs)
2026-11-12 23:53:13 +07:00
BFlat 1c50241ddd Merge pull request #6702 from danngreen/fix/mac-cursor-after-move
macOS: the canvas cursor stays after the pointer moves (#6362)
2026-11-12 23:53:03 +07:00
BFlat 5f3c7f5425 Merge pull request #6906 from ruchirguitar/fix/pdf-indic-text-5235
PDF import: Indic type that would not draw as the file does keeps the file's glyphs (#5235)
2026-11-12 23:52:49 +07:00
dotCooCoo 89e52eaabc MCP: a folder preference is checked as trimmed, and only a %XX escape is decoded
Under automation read roots, `ui.inspect` kept a folder preference whose
stored value was readable even when the trimmed path the app uses was
not: ` /outside/fonts` reads as a name in the working folder, while the
app uses `/outside/fonts`. A folder preference now stays only when both
forms are readable. A reply string is decoded for path matching only when
it holds a `%XX` escape, so a string such as `width="100%"` is no longer
decoded and thrown away. The library list line in the progress doc now
states when a hidden library's `loaded/<file name>` id moves.
2026-11-12 08:50:46 -08:00
dotCooCoo 0ae706c592 Docs: the file-format doc's editing-copy paragraph and summary rows appear once
docs/file-format-parity.md held 36 copies of the paragraph on the
editing copy of a file. #6202 and #6249 each added a combined copy
without removing the copies it replaced, so the count went from 34 to
35 and then to 36. The section now holds one copy: #6249's combined
copy, with the Align to Path distance clause that seven of the other
copies carry from #6247. Every other clause of the removed copies is in
the kept one, word for word or in the newer, longer form another copy
wrote. The older Align to Path clause, with its measurements for one
font at 24 pt, is removed because #6247's wording replaces it. The
paragraph now starts with a capital letter.

The summary table also repeated its "Formats opened or placed" and
"Formats saved (Save As)" rows. The older row of each is removed: the
one that still lists HEIC/HEIF as missing, and the one that lists fewer
contents of the editing copy that `.ai` saves write.
2026-11-12 08:50:41 -08:00
dotCooCoo 9df4a83f07 Merge main into feat/blend-canvas-easing-handles 2026-11-12 08:46:06 -08:00
dotCooCoo fc1a08edbd Merge main into feat/brushes-ink-wash-library 2026-11-12 08:46:00 -08:00
dotCooCoo cc761c359e Color: a recent color drags into the Swatches panel to become a swatch
A Recent Colors chip in the Color or Swatches panel now starts a paint
drag. Dropped on the Swatches panel's list it becomes a swatch of its
color, in its color model, through swatch.new as one undo step: on a
color group or one of its swatches it joins that group, elsewhere it
joins the ungrouped swatches. A click on a chip still paints the
selected art, and a drag does not.

A paint Alt-dropped on Registration now becomes a new swatch instead of
ending in a "can't be edited" error from swatch.edit.
2026-11-12 08:35:15 -08:00
dotCooCoo 766e291e3c Save and Export: notes of what the file loses come before notes on options
Each writer marks its notes as a loss (something of the document that the
file leaves out or that reaches it changed) or as a note on the options
(an option it didn't apply or applied another way while the art reaches
the file as it looks, or something an option turns off). The PDF, SVG,
EPS, legacy .ai, DXF and HP-GL writers return their notes on the options
in a list of their own (`setting_notes`) beside `warnings`, and the
engine's `Encoded` does the same.

The replies of the save and export commands, and of
`clipboard.exportPdf` and `clipboard.exportPng`, list the losses first,
each kind in the order the writers gave them, across every file that
Export for Screens writes. The status bar names the first note, so an
export to lossy WebP of type in a font that isn't installed now names the
fallback-font note instead of the lossy WebP note. A print to a file
keeps the order its notes are given in.
2026-11-12 08:33:57 -08:00
dotCooCoo ff6dac4a5d Shaper: a click on an original shape's outline enters Construction mode
With a Shaper Group or one of its faces selected, a Shaper click within
3 screen pixels of one of the group's original shapes' outlines enters
Construction mode with that shape selected, also where the outline runs
through a merged face. shaper.select takes a tolerance in points
(default 3, at most 1000); hidden and locked shapes are skipped, and a
Shaper Group above the selected one still takes the click.
2026-11-12 08:33:29 -08:00
jmverges e0c5b0818a Merge remote-tracking branch 'upstream/main' into fix/ai-type-pattern-paint
# Conflicts:
#	docs/file-format-parity.md
2026-11-12 16:30:04 +00:00
jmverges 0e91edc4d2 Merge remote-tracking branch 'upstream/main' into fix/remaining-type-envelopes
# Conflicts:
#	docs/file-format-parity.md
#	docs/target-app-parity.md
2026-11-12 16:30:04 +00:00
jmvergesandClaude Opus 5.5 9d6188c47c .ai import: type keeps the manual kerning of its text document (#6899)
The text document reader never read a story's manual kerning, so type
kerned by hand in a .ai or EPS editing copy came in with automatic
kerning on every pair and drifted from the file's page from each kerned
pair on. Envelopes of such type drew apart from their drawn art and
kept it.

Key 8 of a story's text holds the kerning as runs of characters (key 1),
each with a value in thousandths of an em (key 0 of key 0) or empty
where the automatic kerning applies. Each character with a value now
takes it as its Kerning, the space after it, and the style runs split
where the value changes. A value that can't be read keeps the automatic
kerning, a run whose length can't be read ends the runs there, and past
65,536 runs the characters keep the automatic kerning.

- ate.rs: Story reads the runs (manual_kerning) and node() splits its
  text runs at them (Kerns), with a unit test over values, style-run
  boundaries, hostile values and the laid-out gap, and one that pins
  the limit of runs.
- tests_native.rs: an imported story with kerned and automatic runs.
- docs/file-format-parity.md: status line, mapping line, revision row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 16:29:22 +00:00
dotCooCoo a17acb852f Selection: Show Bounding Box While Moving and Drawing shows the box during moves and shape drawing
The new General preference Show Bounding Box While Moving and Drawing
(`boundingBoxWhileMovingAndDrawing`, off by default) keeps the bounding
box and its handles visible during two kinds of drag, with View › Show
Bounding Box on. While a drag moves the selection (a Selection tool
move, an Alt-drag copy, or a shape tool's move by the center point),
the box is drawn where the drag has moved the selection. The box is
measured once when the drag starts and offset by each step's move.
While the Rectangle, Rounded Rectangle, Ellipse, Polygon and Star tools
draw a shape, the box is drawn around the shape. A rotation and a
widget drag still hide the box until the release. The Line Segment
tool, the Pen, the Pencil and the Paintbrush draw no box.

With the preference off, the box hides during a move (#737, for #712)
and while a shape is drawn (#5839), as before. A Selection tool move
with Real-time Drawing off still moves the box with the pointer, and a
shape tool's move by the center point hides it in both modes.

With Real-time Drawing off, the box of a shape being drawn is measured
from the pending preview, in the color of the layer the shape goes on.
A shape being drawn shows no box until a preview step has succeeded,
so a failed preview does not show the box of the selection from before
the drag. The preference's label has a row in every catalog.

Session::deferred_move() is replaced by Session::move_drag_box(), which
returns the moved box, and Session::deferred_transform_box() now also
returns the layer color of the box.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-12 08:28:21 -08:00
dotCooCoo a5541ab42a Blend: steps of brushed strokes interpolate the pen pressure, tilt and angles
A blend between two strokes drawn with a pressure-sensitive brush gave
every step the pen recording of the nearer key, so the brush jumped at
the middle step. The steps now interpolate the pressure, tilt, bearing
and rotation at every position either key has a sample. A key without a
recording counts as half pressure, half tilt and 0 degrees, as brushes
read it. Angles turn the shorter way round, and steps and whole turns in
a recording stay in the steps. Different brushes still switch halfway.
2026-11-12 08:26:32 -08:00
BFlat 932830283d Merge pull request #6841 from dotCooCoo/feat/docinfo-spot-color-objects
Document Info: Spot Color Objects lists the objects that use spot colors
2026-11-12 23:10:59 +07:00
BFlat b85f546ace Merge pull request #6893 from dotCooCoo/test/command-sweep-path-keys
Plug-ins: `diffPath` is a file key and Slice Options' `url` is not; the command sweep uses these keys
2026-11-12 23:10:48 +07:00
BFlat cc6509827d Merge pull request #6878 from dotCooCoo/fix/opacity-mask-follows-reshape
Opacity masks: linked masks follow group effects, the Free Transform distort and envelopes
2026-11-12 23:10:24 +07:00
BFlat 0cb73d0d66 Merge pull request #6845 from dotCooCoo/feat/linux-screen-color-portal
Color: Sample Color from Screen works on Linux through the desktop portal
2026-11-12 23:10:13 +07:00
BFlat 3df161a972 Merge pull request #6903 from dotCooCoo/feat/gradient-repeat
Gradients: repeat or reflect a gradient's stops a set number of times
2026-11-12 23:10:02 +07:00
BFlat 12d72b3eb0 Merge pull request #6901 from dotCooCoo/fix/trace-smooth-area-contours
Image Trace: band borders in smooth areas follow the image's contours
2026-11-12 23:09:43 +07:00
BFlat 4920df33c0 Merge pull request #6885 from dotCooCoo/fix/screens-preset-folder-background
Export for Screens: an export into a preset's folder runs in the background
2026-11-12 23:09:16 +07:00
BFlat 3a1426eff3 Merge pull request #6898 from dotCooCoo/feat/justify-cluster-gap
Type: letter spacing and Full Justify keep shaped clusters together
2026-11-12 23:08:43 +07:00
BFlat a38903aa72 Merge pull request #6900 from dotCooCoo/feat/global-edit-highlight-similar
Global Edit: selecting one object highlights the similar objects before the start
2026-11-12 23:08:32 +07:00
BFlat f43d00aa11 Merge pull request #6902 from dotCooCoo/fix/eps-named-cid-show-operators
EPS import: charpath, cshow, kshow and glyphshow read named CIDFont type by its CMap
2026-11-12 23:08:23 +07:00
dotCooCoo 2defb49002 Font menu: one wide layout wherever it opens, with larger samples
The font menu opened at its field's width, so from the Control bar's narrow
Character field the filters wrapped one chip per line and family names were
cut off after a few letters.

- The filters keep the same four rows wherever the menu opens: the scripts;
  the star, Any Kind, Serif / Mincho, Sans Serif / Gothic and Rounded;
  Script / Brush, Monospaced and Decorative; Font Technology with Variable.
- The menu opens at least wide enough for those rows and for a family name
  up to 220 points wide with room for its sample, up to 60% of the window,
  and stays in the window. A field wider than that keeps its width.
- Where the row has room, the sample starts after the widest name instead of
  halfway along the row. It takes the row's whole height instead of 4 points
  less, so samples draw larger at every Font Preview Size.

Requested by POGO.
2026-11-12 08:06:24 -08:00
dotCooCoo e242eeb609 Actions: progress doc names the command that passes a limit only as it runs
A recorded command whose step passes a limit only from the values it adds
as it runs keeps its edit. The status bar names the limit, later recorded
commands do not run, and Stop Playing/Recording leaves its step out.
2026-11-12 08:01:39 -08:00
dotCooCoo e54519d6bd Merge main into feat/image-color-mask 2026-11-12 07:51:12 -08:00
dotCooCoo d3b18465f9 New Document: file.new and artboard.new take the same largest artboard side
file.new refused a side over 163,830 pt, while artboard.new took larger
artboards. Both now take each side more than 0 and at most 3,999,856 pt:
the 4,000,000 pt the canvas reaches from the origin, less a 72 pt bleed
on both sides. A side outside that range is refused with an error that
names the limit in points and, when the document's units are not points,
in those units, rounded down so the value shown is accepted.

artboard.new now refuses a supplied width or height of 0 or less instead
of making a 1 pt side, and refuses a size taken from a larger artboard.
Saved and Recent presets are read with sides up to the new limit.

Follows #6643.
2026-11-12 07:45:32 -08:00
makesomethingshit c36f863073 Merge upstream/main into fix/6865-ai-oversized-artboard 2026-11-13 00:44:37 +09:00
ruchirguitar b732d4f4b2 Merge remote-tracking branch 'upstream/main' into fix/pdf-indic-text-5235
# Conflicts:
#	docs/file-format-parity.md
2026-11-12 21:01:38 +05:30
dotCooCoo 04fd1b127b Brushes: Art Brush Options' Width can follow the pen's tilt, bearing and rotation
The Width menu now offers Tilt, Bearing and Rotation beside Fixed and
Pressure, each with the second width. Tilt goes from Width with the pen
lying flat to the second width upright; Bearing and Rotation go from
Width at -180 degrees to the second width at 180 degrees, as Scatter
Brush Options' modes do. A stroke drawn without that input is half way
between the two widths. brush.options takes width_mode tilt, bearing
or rotation.
2026-11-12 07:28:26 -08:00
dotCooCoo 2e968acc47 Align: the Align panel aligns and distributes the selected artboards
With the Artboard tool chosen, the Align panel's Align Objects,
Distribute Objects and Distribute Spacing buttons, their UI commands and
the Control bar's Align and Distribute buttons act on the artboards the
tool has selected, as the public page describes:
https://helpx.adobe.com/illustrator/desktop/create-manage-artboards/organize-manage-artboards/align-and-distribute-artboards.html

- artboard.align, artboard.distribute and artboard.distributeSpacing
  move whole artboards with their guides, and with the art inside them
  when Move Artwork with Artboard is on, in one undo step. No undo step
  is recorded when no artboard moves.
- Align To offers Align to Selection and Align to Artboard. Align to
  Artboard keeps the active artboard in place, and the Distribute
  buttons then send the Distribute Spacing value. A locked artboard
  stays where it is. These rules are VectorCraft's own.
- The Control bar shows the Align buttons, the Align To menu and the
  Distribute buttons after the artboard controls while it has room.

Docs: docs/mcp.md, docs/ui-parity.md.
2026-11-12 07:28:16 -08:00
ruchirguitar f18fb4e92d PDF import: Indic type that would not draw as the file does keeps the file's glyphs (#5235)
Gujarati text from a PDF came in jumbled even with its fonts installed:

- A glyph with no advance (a vowel sign or anusvara set over its letter)
  was taken for vertical type and opened as an object of its own, which
  type then drew on a dotted circle. In a font the file writes
  horizontally it now stays on its line.
- A line read glyph by glyph is not always the text that was set: the
  file draws a vowel sign before the consonant it follows, and may not
  name a conjunct. A line with characters of U+0900 to U+0DFF is now set
  again and its glyphs compared with the ink the file drew; when they
  differ the line keeps the file's glyphs as outlines, with a note.

Tests: crates/pdf/src/tests/reshaped.rs (two fail without the change).
2026-11-12 20:56:16 +05:30
Taha-Mahmoodi 2d62c35d69 Merge remote-tracking branch 'origin/main' into feat/glyph-alternates
# Conflicts:
#	docs/gaps.md
#	docs/roadmap.md
#	docs/target-app-parity.md
2026-11-12 19:55:05 +04:30
dotCooCoo 5d40a1c6d0 View: the art keeps its size at a zoom whatever the UI Scaling
Preferences > User Interface > UI Scaling sets egui's zoom factor, and the
canvas mapped one document point to one of the interface's points at
100%. A document point then covered UI Scaling times as many device pixels,
so the art grew and shrank with the interface.

The canvas now maps the document at the view's zoom divided by the UI
zoom (View::screen_zoom, Xf::at). The rendered frame, the pointer, rulers,
grids, Fit and Actual Size, pan, scroll, zoom and turn about a point, the
Zoom tool's marquee, Pixel Preview's check, tiled panes, the Navigator's
view box and the tools' tolerances use that mapping. The zoom value means
the same at every UI Scaling, and the interface still follows UI Scaling.
fit_zoom, zoom_about, rotate_about, pan_pixels and scroll_by take the UI
zoom, and Xf::new is now test-only.

Found while looking into a report by bortek about the art's size at 100%.
2026-11-12 07:24:43 -08:00
BFlat 10ea235ee4 Merge pull request #6659 from ruchirguitar/fix/numfield-short-drag-1326
Numeric fields: a sub-threshold pointer movement keeps its caret (#1326)
2026-11-12 22:21:11 +07:00
dotCooCoo fd81eae9b5 Type: text.create and the type style commands refuse a size outside 0.1 to 1296 pt
text.create clamped a size above 1296 pt to 1296 without an error, so a
request for 2835 pt type returned 1296 pt type. text.createInPath,
text.setStyle and text.setRangeStyle clamped the same way. Each now
refuses a size outside 0.1 to 1296 pt with "`size` must be from 0.1 to
1296" and changes nothing. Both ends of the range are still taken.

Follows #6643.
2026-11-12 07:20:37 -08:00
dotCooCoo fa0a0753bb Merge main into feat/weed-box-and-lines 2026-11-12 07:20:06 -08:00
dotCooCoo b4ffd4a97e MCP: a hidden path's file: URL shows as the file name, and rewritten keys keep every field
Under automation read roots, a reply replaced only the path inside a
`file:///outside/a.svg` URL, which left `file://a.svg`, a URL that names a
host. The whole URL of an absolute path, with `localhost`, another host or
no host, is now replaced with the file name, unless part of its scheme was
already replaced. A reply key rewritten to read the same as another key of
its object took that key's place and its field was lost; the rewritten key
now takes ` (2)`, ` (3)` and so on, and a key that is not rewritten keeps
its name.
2026-11-12 07:17:50 -08:00
dotCooCoo 07423c22d6 MCP: save and export replies keep the path the client gave under read roots
Under automation read roots, a reply shows each path outside the read roots
that the request sent by its file name. A save or export to a path the
client gave inside the write roots then answered with the bare file name in
`path`, where the save replies keep the given path. The `path` and `files`
entries of the reply's result, a `command.batch` step's result included,
that equal a path param the request gave inside the write roots now stay as
given; every other occurrence is still shown by its file name, and loaded
libraries outside the read roots keep their `loaded/<file name>` ids.
2026-11-12 07:17:50 -08:00
dotCooCoo 2ec278280a MCP: ui.dock targets, shortcut keys and native backslash paths keep hidden library ids
- ui.dock's move takes a hidden panel's shown id in target, as the other
  docking destinations do.
- Shortcut overrides keyed panel:<panel id>, saved and in an open
  Keyboard Shortcuts dialog, show the panel id shown for a library
  outside the read roots, also when nothing else refers to it.
- Outside Windows, a native path is matched only as written: a sent
  /out/weird/name.svg no longer renames a hidden library at
  /out/weird\name.svg, and a reply does not read one as a spelling of the
  other. Windows paths are still matched with either separator.
2026-11-12 07:17:48 -08:00
dotCooCoo d4bbce8982 MCP: hidden library names follow the platform's path rules
- Outside Windows a `\` stays part of a hidden library's or sent path's
  file name; another platform's absolute path is still split on `\`.
- A hidden relative path is matched after leading `./` and `../` parts
  only when they start the path, so `/work/./data/icon.svg` keeps its
  text.
- `ui.inspect` and `ui.docking` replies are hidden once, so a library
  at the top of the file system shows as `loaded/<file name>` with its
  separator.
2026-11-12 07:17:47 -08:00
dotCooCoo 6d7a8249a7 MCP: hidden library paths are matched before the paths a request sent
A sent path whose text overlapped part of a hidden library's path could
keep that path from being hidden; the hidden libraries' ids and paths
are now matched first. A hidden relative path is also hidden where a
reply shows the absolute path it reads as from the working folder, and
a hidden library sent by that other form shows as the sent path does.
2026-11-12 07:17:46 -08:00
dotCooCoo d1f7888ad4 MCP: a hidden library keeps the id it was first shown under
A library loaded from outside a confined client's read roots keeps its
`loaded/<file name>` id for the session, in ui.inspect, ui.docking and
the library commands, so an id taken from an earlier reply still finds
the same library after another library with the same file name is
loaded. swatch.library.copyToUser leaves out `path` when the file is
outside the read roots, as the saves do.

The ids come from the engine's concealed_library_ids, which now reads a
path written with either separator, counts another platform's absolute
path as outside the roots, and keeps each id in the session.
2026-11-12 07:17:46 -08:00
dotCooCoo d1e766173e MCP: a library saved with another platform's absolute path is hidden under a read root
Outside Windows, a library path that starts with a drive or a backslash counts as outside the read roots, since the file access check would read it as a name in the working folder.
2026-11-12 07:17:46 -08:00
dotCooCoo 62be2df058 MCP: replies hide each sent path the same way whatever the outcome
Each hidden id or path is replaced once, chosen from the reply as given,
so a hidden path inside another library's shown id is not replaced
again, and a readable id written with %XX escapes keeps the hidden path
it begins with. A path quoted with {:?} is matched with its quotes and
control characters escaped. A path outside the read roots that the
request sent is shown by its file name in a reply that succeeded as in
one that failed, and a path param counts with a relative path too. A
relative path is not replaced where it ends a longer path. Without a
read root, a file: URL that names another host stays in ui.inspect's
recorded steps.
2026-11-12 07:17:46 -08:00
dotCooCoo 61771e4ead MCP: a screenshot's reply hides library paths outside the read roots
The reply is sent after the request was handled, and now hides what any other reply hides.
2026-11-12 07:17:46 -08:00