Commit Graph
8105 Commits
Author SHA1 Message Date
BFlat 74ccfdde05 Merge pull request #5563 from dotCooCoo/fix/many-anchors-editing
Render: a long stroke is outlined only near the view after an edit
2026-11-04 18:24:32 +07:00
BFlat 3c3ff35e8a Merge pull request #5564 from dotCooCoo/fix/hidden-group-floating-reply
Panels: showing a hidden floating group returns its window's panels
2026-11-04 18:24:17 +07:00
BFlat 093d90844d Merge pull request #5537 from dotCooCoo/fix/textedit-reject-bad-offsets
Type: text commands refuse negative or fractional byte offsets
2026-11-04 18:24:00 +07:00
BFlat 23e7e5011e Merge pull request #5558 from dotCooCoo/fix/i18n-term-tests-match-words
i18n: leading and Tracking term checks match whole words in the right label
2026-11-04 18:21:20 +07:00
dotCooCoo 3fbdf72231 Docs: the long-stroke line names the strokes of path objects 2026-11-04 16:55:30 +07:00
dotCooCoo 8d0f251c37 Examples: anchor_bench's doc comment says what the example prints 2026-11-04 16:55:30 +07:00
dotCooCoo d6190e79e0 Render: a filter layer's offscreen culls art and crops long strokes to its own area
On a multithreaded context, a drop shadow or glow drawn through a filter
layer is drawn into an offscreen that covers the art plus the blur's
spread, but its frame kept the view's visible rect. Art outside the view
but within the spread was culled, so it cast no shadow, and a long stroke
was outlined only near the view, so its far parts no longer fed the blur.
The offscreen's frame now takes its visible rect from its own area, and
the frame of content kept from an earlier split takes the window it is
drawn over.
2026-11-04 16:55:30 +07:00
dotCooCoo 676cc0ee8e Render: a long stroke is outlined only near the view after an edit
The renderer outlined the whole stroke of an edited path on every frame,
so dragging one anchor of a path with many anchors re-outlined every
segment. A stroke line of more than 1,024 elements without dashes or a
width profile is now outlined only for the segments within the stroke's
reach of the view, inflated by the view's own size on each side. The
cached outline keeps that region, and a frame outside it outlines the
stroke again. Closed subpaths that a wide stroke crosses over stay whole,
and a cut closed subpath is walked from a removed segment so no cut lands
where it starts and ends. The pixels are the same.

At 1600 x 1200, the frame after one anchor moves takes 28 to 30 ms
instead of 103 ms on an open path of 200,000 anchors, and 10 ms instead
of 30 ms on a closed path of 50,000 anchors (the new anchor_bench
example: cargo run --release -p vectorcraft-engine --example anchor_bench).
2026-11-04 16:55:30 +07:00
dotCooCoo af604625b3 Panels: showing a hidden floating group returns its window's panels
`window.panel` on a panel whose group was hidden returned the whole
layout and every floating panel in every window. It now returns
`{floating}` with the panels of the restored panel's window, as it
does when it shows a panel that already floats.
2026-11-04 16:55:26 +07:00
dotCooCoo e3a55b97fd Type: Text Tweaker leaves byte offsets to range_of
Remove Text Tweaker's own start and end check: range_of already refuses
a bad offset given with an id, and like the other type commands Text
Tweaker now ignores start and end without one. The test's "2" case
gets an id so it still reaches the check, and docs/mcp.md lists
addon.type.textTweaker with the commands that refuse such offsets.
2026-11-04 16:55:22 +07:00
dotCooCoo 595db10900 Type: refuse negative or fractional byte offsets in text commands
text.startList read a negative or fractional `at` as the end of the
text, so it could remove a typed list marker there and start a list.
The `start` and `end` of text.editRange, text.getRange,
text.setRangeStyle and the type shortcut commands given an `id` read
such values as the start or end of the text.

These now return "`at` must be a whole number" (naming the key) and
change nothing. Omitted or null keys keep their defaults, and 2.0 is
read as 2.
2026-11-04 16:55:22 +07:00
dotCooCoo 1d459796ad i18n: term checks match whole words and the Info row's Tracking label
The Leading check now matches each word of the Leading field as a whole
word in languages that separate words with spaces, so a longer word such
as "liderlik" no longer stands in for "lider". Chinese, Japanese and
other unspaced scripts keep substring matching.

The Info row check now looks for the whole Tracking name in the label in
front of {tracking}, after taking out a Kerning or Leading name that
contains it. A word of the name found in the Size label, or a Kerning
label that contains the Tracking name, no longer passes.

The Czech Auto Leading row uses the singular "proklad", as the Leading
field does.
2026-11-04 16:55:19 +07:00
BFlat f8841a2b21 Merge pull request #5481 from dotCooCoo/fix/ai-os18-e
.ai import: objects come in bound to their variables
2026-11-04 16:47:44 +07:00
BFlat 1295f92b14 Merge pull request #5561 from byoungyoon/fix-5555-web-paste-twice
Fix #5555: Cmd+V pastes once on the web
2026-11-04 16:45:15 +07:00
BFlat 75ad1299cd Merge pull request #5562 from storytold/fix/stale-endpoint-port-race
Single instance: the stale-endpoint test connects to no freed port
2026-11-04 16:44:36 +07:00
dotCooCoo a7acf43cb1 .ai import: objects come in bound to their variables
Squashed from #5481 onto main.
2026-11-04 16:33:25 +07:00
byoungyoonandClaude Opus 5.5 c82a1eb0e8 Fix #5555: Cmd+V pastes once on the web
eframe's web runner reports a Cmd+V press both as the key press and, with the
clipboard's text, as a Paste event; the app pasted on each (egui's window
integration sends only the Paste). The web shell now drops the paste key's
press when a Paste is in the same frame's input; its release stays for
PasteChord, and a Cmd+V with no text on the clipboard keeps its press.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:33:24 +07:00
bflatastic 1e3553843d Single instance: the stale-endpoint test connects to no freed port
The test bound a port, freed it and then connected to it as a gone app.
Tests run in parallel, so another test's listener could take that port
meanwhile and accept this connection in place of its own client's,
whose connection was then reset when the listener closed: the cause of
the intermittent tcp_connection_is_closed_after_junk failures on
Windows. The gone app is now a listener that closes without a greeting.
2026-11-04 16:08:43 +07:00
BFlat 61a236fe57 Merge pull request #5046 from dotCooCoo/fix/ai-os11-brushes
.ai import: brushes come in from the editing data
2026-11-04 16:05:29 +07:00
BFlat a2b06808b0 Merge pull request #5553 from dotCooCoo/feat/global-edit-control-bar
Control bar: the Global Edit Options dropdown shows while Start Global Edit can run
2026-11-04 16:05:03 +07:00
BFlat 59232854cd Merge pull request #5552 from dotCooCoo/fix/pdf-open-reads-once
PDF/.ai import: the file is read and checked once when it opens
2026-11-04 16:04:48 +07:00
BFlat 1421e4959d Merge pull request #5554 from dotCooCoo/feat/ai-blend-spacing
.ai import: blends keep their Specified Distance and Smooth Color spacing
2026-11-04 16:04:32 +07:00
BFlat da5eb0a0b7 Merge pull request #5551 from dotCooCoo/fix/stylistic-sets-feature-variations
Type: list stylistic sets whose lookups come from FeatureVariations
2026-11-04 16:04:16 +07:00
BFlat 9f852496c2 Merge pull request #5556 from dotCooCoo/fix/png-row-reader-room
Images: a PNG read a row at a time counts all of the reader's buffers
2026-11-04 16:04:00 +07:00
dotCooCoo 322f1c24db .ai import: brushes come in from the editing data
Squashed from #5046 onto main.
2026-11-04 15:41:24 +07:00
dotCooCoo f4469e16d6 Control bar: the Global Edit Options dropdown shows while Start Global Edit can run
While Select > Start Global Edit can run, the Control bar shows a Global Edit
Options dropdown after Recolor Artwork. It opens the Properties panel's Global
Edit Options (Match: Appearance, Size; On Artboards; Include Objects On
Canvas; Result(s)), so both set the same options, and it is off while Global
Edit is on, as the Properties dropdown is. The bar leaves it out when no room
is left for it.

Public reference:
https://helpx.adobe.com/illustrator/desktop/manage-objects/edit-objects/edit-similar-objects.html

The dropdown takes room ahead of the inline X/Y/W/H fields, so the ruler-origin
tests that read X/Y from the Control bar draw it 1700 px wide.
2026-11-04 15:41:15 +07:00
dotCooCoo a176ffae46 PDF/.ai import: the file is read and checked once when it opens
Opening a .ai or a PDF read and checked the whole file up to five
times: for the document it carries, for whether it holds the editor's
private data, for the import, for the editor's copy and for its File
Info. Each pass parses the file and walks every object, about 190 ms on
a 15 MB .ai.

- vectorcraft_pdf::open_pdf reads and checks the file once, on the
  import's deep-stack thread, and import_opened imports pages from that
  reading. document.open takes the carried document, the page count,
  the editor's copy and the File Info from it. The editor's copy is read
  after the page import and only when the file is not restored from a
  carried document; so is the File Info.
- A .ai saved without PDF compatibility opened with pages that name
  every page reads its editor's copy from the same reading.
- document.pdfInfo reads the file once for its pages and the thumbnail.
- The Open and Place dialogs read the file once to decide whether to
  ask for pages, instead of twice.

A file whose PDF part fails the check still reads its editing data
separately, as before.
2026-11-04 15:41:11 +07:00
dotCooCoo a8c6d078e5 .ai import: blends keep their Specified Distance and Smooth Color spacing
A blend's record in the editing data holds its Blend Options spacing.
Word 1 is the spacing: 0 is Smooth Color, 1 is Specified Steps and 2 is
Specified Distance. For Specified Distance, word 2 is the distance in
points as a 32-bit float. The reader took only records whose word 1 is
1, so every Smooth Color and Specified Distance blend came in as its
drawn steps.

A Smooth Color or Specified Distance blend now opens live with that
spacing where VectorCraft lays out as many steps between each pair of
keys as the file draws, in the same places and colors. Otherwise it
keeps its drawn steps with the existing note. The distance is read as
the shortest decimal that reads back as the stored float. The steps are
counted before anything is laid out, and a blend takes from the
import's budget only when its count matches. Specified Steps blends
are read as before, with the steps counted from the drawn ones.

Tests: import::ai::tests::a_blend_keeps_its_spacing,
a_blend_of_three_keys_keeps_its_distance_between_each_pair,
a_blend_whose_spacing_doesnt_lay_out_its_steps_keeps_them,
import::ai::blend::tests::records_say_their_spacing,
a_blend_takes_from_the_budget_only_when_it_is_laid_out,
a_distance_past_the_keys_lays_out_no_steps, and the fuzz case
ai_blend_spacing_never_panics.
2026-11-04 15:41:08 +07:00
dotCooCoo 663c3264ca Type: list stylistic sets whose lookups come from FeatureVariations
A variable font can leave an ssNN feature empty in GSUB or GPOS and
supply its lookups through a FeatureVariations substitution. The
OpenType panel skipped those sets because the default feature has no
lookups. A set is now listed when a substitution in a variation record
replaces its feature with one that has lookups, and its name is read
from the default feature or the substituted one.

Records after one without conditions are ignored, and at most 4096
variation records and 4096 substitutions are read per table.

Follows #5447.
2026-11-04 15:41:05 +07:00
dotCooCoo 9c191793e2 Images: a PNG read a row at a time counts all of the reader's buffers
The room estimate for a large PNG read a row at a time counted 32 bytes
a column. The png reader also keeps at least 128 KiB of rows already
read, the 32 KiB deflate window and a growth step in its stream buffer,
and up to four rows for wide images, so a decode could be approved with
less room than reading takes. The estimate now comes from the PNG
header's row length and these buffers, and a PNG is read a row at a
time only while that estimate fits the decode allowance.
2026-11-04 15:41:03 +07:00
BFlat a207c7b816 Merge pull request #5543 from dotCooCoo/feat/expand-selected-symbol-instances
Expand: selected symbol instances become their art, as Break Link places it
2026-11-04 15:34:10 +07:00
BFlat eaa7ebb0a5 Merge pull request #5511 from dotCooCoo/fix/same-symbol-reference
Select: Same Symbol Instance takes its reference from an object that can be selected
2026-11-04 15:33:55 +07:00
BFlat 1e992980d8 Merge pull request #5542 from dotCooCoo/feat/select-all-threaded-story
Type: Select All in a threaded frame selects the whole story
2026-11-04 15:33:39 +07:00
BFlat d4469e9920 Merge pull request #5538 from dotCooCoo/fix/convert-replaced-spine-handles-only
Blends: Convert on a replaced spine changes only its handles
2026-11-04 15:33:24 +07:00
dotCooCoo 146d30502a Expand: selected symbol instances become their art, as Break Link places it
Object > Expand with Object on now turns each symbol instance in the
selection, including one in a selected group or in a placed document's
art, into its art, as Break Link to Symbol places it. It goes one level
deep: the instances in that art stay instances. The art keeps the
instance's id and place in the stacking order, and Expand stays one
undo step.

- Instances with effects stay instances, and Expand Appearance bakes
  them as before. Instances with an effect on a fill or stroke,
  instances in perspective, and those in blends, repeats and Intertwine
  groups stay instances.
- The art keeps the instance's opacity mask, as Break Link gives it.
- A hidden or locked instance's art stays hidden or locked.
- A placed document in an instance's art is expanded too.
- When the instances' art would make more than 1,000,000 objects, they
  stay instances, the limit Break Link uses.
- The Fill and Stroke options (object.expand.info, and the Expand
  dialog) count the fills, strokes and gradients in the art of those
  instances, with a dynamic instance's own changes applied. The info
  reports under symbolArt which of them only that art holds, and the
  dialog enables those options only while Object is on.
2026-11-04 15:14:02 +07:00
dotCooCoo a79ab62712 Select: Same Symbol Instance takes its reference from an object that can be selected
Squashed from #5511 onto main.
2026-11-04 15:13:32 +07:00
dotCooCoo 92640179e5 Type: Select All in a threaded frame selects the whole story
While the Type tool edits a frame of threaded text, Select All selects
the text of every frame of the story, highlighted in each frame. The
tool edits the first frame that holds text.

- Typing, Delete and Cut replace the whole story as one undo step
  (`text.editRange` takes `clear`, the other frames whose text goes).
- Copy and Cut take the whole story (`text.getRange {id, story: true}`).
- Fills and strokes, `type.step`, `appearance.copyFrom`, the Character,
  Paragraph, OpenType and text style panels, the Tabs panel's tab
  stops, the font menus and the Justification dialog act on every
  frame's text (`text.setRangeStyle {id, story: true}` styles them in
  one edit).
- A caret move, a click or a word or paragraph selection ends it.

Select All in unthreaded type is unchanged.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-04 15:13:20 +07:00
dotCooCoo 40318753db Blends: Convert on a replaced spine changes only its handles
Convert to Smooth or Corner on a blend whose spine came from Replace
Spine stored key anchors with the converted spine, so the spine's
points then moved onto the key centers. It now changes only the
spine's handles: the points stay where they are and the keys stay
spread along the spine. Direct Selection's spine conversion and the
other spine edits are unchanged.
2026-11-04 15:13:18 +07:00
BFlat 6bde3c59a5 Merge pull request #5516 from dotCooCoo/fix/layer-options-template-keeps-set-lock-dim
Layers: Layer Options keeps a Dim Images that was set before Template changes
2026-11-04 15:05:59 +07:00
BFlat c06be0349c Merge pull request #5533 from dotCooCoo/fix/ai-layers-checked-on-every-page
.ai import: the layers are compared with every page of a multi-artboard file
2026-11-04 15:05:43 +07:00
BFlat d0c703328f Merge pull request #5535 from dotCooCoo/fix/placed-document-undecoded-marks
Render: placed-document bitmaps draw undecoded-image marks when the view does
2026-11-04 15:05:27 +07:00
BFlat 30c33c5048 Merge pull request #5536 from dotCooCoo/fix/perceptual-spot-stop-limit-docs
Docs: Perceptual spot gradients with more than 4,096 curve stops export as images
2026-11-04 15:05:12 +07:00
dotCooCoo 4aa8a8b0c8 Layers: Template always locks the layer in Layer Options
Template sets Lock again even when Lock was set in the dialog before it,
so a template layer is always locked. Only a Dim Images set before
Template keeps its value.
2026-11-04 14:56:41 +07:00
dotCooCoo 2ac1fa4cce Layers: Layer Options keeps a Lock or Dim Images that was set before Template changes
Setting Template in the dialog (the checkbox, or ui.dialog.set of template)
also set Lock and Dim Images, replacing a value set in the dialog earlier.
That value was then sent to every selected row, and ui.dialog.set gave
different results depending on the order of its fields. A Lock or Dim Images
set in the dialog now keeps its value when Template changes.
2026-11-04 14:56:41 +07:00
dotCooCoo e5834f7686 .ai import: the layers are compared with every page of a multi-artboard file
A .ai file whose PDF part has a page for each artboard had its layers
compared with the first page only. Art that the layers drew on a later
artboard and its page didn't, or that a later page drew and the layers
didn't, opened from the layers with no warning, and a text object that a
later page doesn't draw stayed.

When the PDF part has a page for every artboard, each page is now
compared with the layers on its artboard, and the comparison fails when
any page differs by more than it allows. Text objects that a later page
doesn't draw are weighed there and left out, unless their layer doesn't
print. Art that differs on a later page is handled as on the first page:
such files now open from their PDF part with the usual warning, where
they opened from their layers before. A PDF part with pages for some of
the artboards, or with its pages cropped to the art, is still compared
on its first page only. Pages are compared until their comparison
drawings take 8,388,608 pixels (about 67 letter-size pages, or 4 when the
PDF part is only images), and at most 128 pages are compared. The type
share in the import's note is now that of the page whose type differs
most.

The layers are drawn once for the pages of the same size and cut into
each page's part. Each page moves by less than half a pixel to start on
a whole pixel, and the column or row the move takes past its artboard
isn't compared. Each page's drawing and result are kept until the layers
change, for the last two documents weighed. Taking a text object out
draws again only the pages within reach of it (every page when type
wraps).

An artboard, or the page of an EPS's editing data, whose sides are within
half a point of its page's is drawn on an area of the page's size, so
both drawings have the same number of pixels. Before, such a file could
open without its layers when the half point changed the rounded size of
its drawing, even when its layers matched the page.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-04 14:56:38 +07:00
dotCooCoo f15a16f2c1 Render: placed-document bitmaps draw undecoded-image marks when the view does
On screen, a placed document is drawn from a bitmap made in the
background, and that bitmap was rendered with the default options. An
image inside the placed file whose pixels cannot be decoded therefore
drew nothing in the bitmap, even though the canvas marks such images
with a crossed box. The bitmap now follows the frame's
mark_undecoded_images setting, the bitmap cache keys on it, and a
bitmap standing in for one still being made has the same setting.
2026-11-04 14:56:36 +07:00
dotCooCoo b9d3881872 Docs: state the stop limit for Perceptual spot gradient shadings
PDF export writes a Perceptual spot gradient as a Separation or DeviceN shading only when its expanded curve has at most 4,096 stops (MAX_INK_TINTS in crates/color/src/gradient.rs). Longer curves are written as images, with the process-color warning.
2026-11-04 14:56:35 +07:00
BFlat d977fd9181 Merge pull request #5447 from dotCooCoo/feat/ot-stylistic-sets
Add font-aware OpenType stylistic sets menu
2026-11-04 14:31:00 +07:00
BFlat d702bdfc23 Merge pull request #5527 from dotCooCoo/fix/parity-doc-wording
Docs: name glows with shadows in the pan raster entry, and mark VectorCraft's own values
2026-11-04 14:30:44 +07:00
BFlat afce54206a Merge pull request #5524 from dotCooCoo/fix/live-paint-face-attribution
Live Paint: preserve face colors at shared curved boundaries
2026-11-04 14:30:29 +07:00