Commit Graph
3872 Commits
Author SHA1 Message Date
Dylan M. Taylor 12414aa9f6 Make PDF export comparison deterministic 2026-10-28 19:53:43 +00:00
Dylan M. Taylor 0b821b3c54 Extract engine command and state helpers 2026-10-28 16:44:14 +00:00
Dylan M. Taylor 7043ef6f3d Extract geometry command helpers 2026-10-28 16:44:11 +00:00
Dylan M. Taylor 90ef99cb2c Simplify file import and export checks 2026-10-28 16:44:05 +00:00
dotCooCoo 3c0c010522 Merge main into feat/trace-keep-colors 2026-10-28 02:58:05 -07:00
dotCooCoo 33ea3f5300 Merge main into fix/batch-override-export-for-screens-folder 2026-10-27 23:06:19 -07:00
dotCooCoo 8b1ff5f32b Merge main into feat/character-anti-aliasing-method 2026-10-27 22:12:22 -07:00
dotCooCoo f3104b154c Undo: the budget test allows unreadable memory; docs name the 32-bit cap
the_default_budget_follows_the_installed_memory_read compares the default
budget with the 1 GiB fallback when the installed memory can't be read,
as default_history_budget does, instead of failing. The reader itself is
still checked by vectorcraft-render's installed_memory_is_read.

The undo history line in docs/target-app-parity.md says the budget is at
most a quarter of the address space in a 32-bit build.
2026-10-27 20:47:51 -07:00
dotCooCoo 5d5b775e27 Merge main into feat/native-save-precision 2026-10-27 20:34:51 -07:00
dotCooCoo 8dcffb3bd3 Merge main into feat/visibility-variables-drive-locked-art 2026-10-27 20:19:07 -07:00
dotCooCoo 86e1d1c2d1 Merge main into fix/undo-history-follows-memory 2026-10-27 18:56:49 -07:00
dotCooCoo 93677c26ec Shape Builder: a large selection merges on another thread
A Shape Builder click or drag over a selection of more than 128
segments merged on the UI thread, so the app stopped drawing and
answering until the merge was done. The tool now computes such a
merge on another thread from the map it built for the hover.
Meanwhile the canvas keeps drawing, the touched regions stay
highlighted and the pointer is the busy pointer. When the merge is
done, the tool runs shapeBuilder.merge with the gesture's params as
one undo step, and the command takes the computed shapes when it
would compute the same ones. The web build merges in the command, as
before.

A press while the map is still being built no longer waits for it on
the UI thread: the tool records the gesture and makes it once the map
is there.

Clicks, drags and the Shape Builder's arrow keys made during the
merge, and commands, menu items, the app's own dialogs, saves and tool
or document switches, run after it on the merged art; engine queries
that only read run at once. A change to the selected paths made
outside a command drops the merge. The headless host and ui.pointer
reply once the merge is applied.

The Shape Builder and the Live Paint Bucket keep their map of the
selection over a new revision of the document when the selected paths
and their outlines are unchanged, instead of building it again.
2026-10-27 17:26:38 -07:00
dotCooCoo d50ac14da2 Outline Stroke: a stroke whose geometry effects leave no path is outlined to nothing
A stroke-only path whose Offset Path or other geometry effect leaves no path
paints nothing on the canvas. Outline Stroke reported "no stroked paths
selected" for it, and Expand and Flatten Transparency kept the live stroke.
An empty group now takes the path's place.
2026-10-27 14:31:17 -07:00
dotCooCoo c273227cf8 Merge main into fix/outline-stroke-keeps-effects-on-outline 2026-10-27 13:51:06 -07:00
skylar 9952b4950c Merge main (8622d0c7) into fix/explicit-join-ends-3283 2026-10-27 12:20:09 -06:00
skylar 1ffc04506c fix(engine): honor explicit ends when joining direct selections 2026-10-27 11:11:36 -06:00
el-j 464a0710b7 Merge remote-tracking branch 'upstream/main' into fix/compound-path-pen-join 2026-10-27 14:33:06 +01:00
NetterSilverandClaude Opus 5.5 19d4adb39c Make SVG export def ids linear instead of quadratic
Writer::fresh_id probed prefix-1, prefix-2, ... from 1 on every call,
formatting and hashing each candidate, so writing N gradients, clip
paths or masks cost O(N^2). Ids are never released, so every number
below the last one handed out for a prefix is taken: remember where
the search for each prefix stopped and resume there. The ids written
are the same as before.

examples/still-life.vectorcraft (12k gradients, 6.3 MB SVG) exported
in about 8.6 s (median); it now takes about 0.15 s. Output is byte-identical
for every document in examples/.

Add crates/engine/examples/export_bench.rs to time document.export
on the example documents, and a test pinning the generated id
sequence when object names already take some of the numbers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 11:52:22 +01:00
Adam 565235b54b Merge remote-tracking branch 'origin/main' into feat/width-smooth-profile
# Conflicts:
#	crates/doc/src/appearance.rs
#	crates/render/src/lib.rs
#	crates/ui-egui/src/dialogs/width_point.rs
2026-10-27 10:01:09 +01:00
ham9zah 0365cf3ae3 Appearance: shared rows map one by one, and effect dialogs edit each copy (#4174)
Review follow-ups:

- items_per_target maps each requested row on its own. Rows deleted or
  duplicated together, one shared and one not, fell back to the literal
  indices in every object, so the other objects could lose the wrong
  items. The first object takes its own rows; each other object takes
  its copies of the shared ones only.
- effect.dialog takes `aligned` (the panel passes it on a mixed
  selection's shared effect row), and its OK and preview run
  effect.setParams with it, so the dialog edits each object's own copy
  of the effect instead of the first object's index in every object.

Tests: removing a shared stroke with an unshared fill leaves the other
object's fills; an aligned dialog's command carries `aligned`.
2026-10-27 14:36:13 +07:00
ham9zah 8305ccf998 Appearance: a mixed selection lists the attributes its objects share (#4174)
With several objects selected whose appearances differ in anything (two
circles whose fills differ but whose stroke and effect are the same),
the Appearance panel showed only "Mixed Appearances": no stroke, effect
or opacity row, so attributes the objects share couldn't be edited
together. It now lists what they share, as the issue describes:

- `vectorcraft_doc::appearance::SharedStack` (with `align`, a stacking-
  order longest-common-subsequence match) gives the fills, strokes and
  object-level effects every object has an equal copy of, and where each
  is in every object's own stack.
- The panel's object row names the objects' common kind ("Path",
  "Ellipse"; "Mixed Objects" only when kinds differ, as the Control bar
  does), with an italic "Mixed Appearances" row under it when they
  differ, then only the shared rows with their usual controls. The
  Opacity row reads "Mixed" when opacity or blend mode differ (an edit
  sets them all). The object row shows no fill chip when the fills
  differ. Rows aren't dragged in a mixed selection: where a row would go
  in each of several different stacks isn't one place.
- The engine maps a shared row to each object's own item: the active
  item (a row of the first selected object's stack) always does, so the
  Color, Stroke and Transparency panels edit every object's matching
  item, and the item and effect commands do with `aligned: true`
  (appearance.setItem / removeItem / duplicateItem, effect.remove /
  duplicate / setParams / lightingPreset, transparency.set), each as
  one undo step. moveItem and effect.move refuse aligned rows of
  differing stacks. Without `aligned`, explicit indices keep their
  meaning for single objects and scripts.
- "Mixed" is added to every catalog.

Tests: the shared stack of the issue's case, of a stroke at another
index, of nothing alike and of equal stacks, and that matches never
cross; editing the shared stroke edits both strokes (at index 1 and 2)
in one undo step that restores both, also through stroke.set on the
active row; removing a shared effect and adding a fill reach both, and
reordering differing stacks is refused; the panel lists kind, note,
Stroke, Feather and Opacity, not Fill, the full stack for alike objects
and "Mixed Objects" for a path and type. The existing object-row test
now expects the kind for two rectangles and the shared rows when their
opacity differs.
2026-10-27 14:36:13 +07:00
NetterSilverandClaude Haiku 5.5 23f0d323b0 Accept whole-number floats and reject invalid counts for polygon, star and spiral
Found while testing crates/engine/src/cmd/create.rs:344 (polygon) and :358 (star; shape.spiral `segments` at :507 reads the same way)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 14:36:12 +07:00
dotCooCoo 8a3d393596 Merge main into feat/jxl-import
Keep JPEG XL format registration and tests in the reorganized file I/O modules.
2026-10-26 19:23:03 -07:00
aiongg ef991b9c8a refactor(engine): move lib.rs items to {command_sets,doc_state,error,history,interaction,prefs,sanity,session,session/documents,session/edit,session/execute,session/undo}.rs 2026-10-26 22:01:25 +00:00
aiongg 4f7dd93268 refactor(engine): move cmd/variablecmds.rs items to cmd/variablecmds/{csv,library}.rs 2026-10-26 22:01:25 +00:00
aiongg 43ae75d4dc refactor(engine): move cmd/object.rs items to cmd/object/{align,arrange,bounds,commands,compound,props,shape,spans,transform}.rs 2026-10-26 22:01:25 +00:00
aiongg c662e76b84 refactor(engine): move cmd/live.rs items to cmd/live/{blend,commands,common,envelope,mesh}.rs 2026-10-26 22:01:25 +00:00
aiongg f209d2aba2 refactor(engine): move cmd/graph.rs items to cmd/graph/{axis,columns,commands,data,designs,edit,generate,labels,markers,series}.rs 2026-10-26 22:01:25 +00:00
aiongg f02cf1cb7d refactor(engine): move cmd/flatten.rs items to cmd/flatten/{analysis,apply,commands,compose,options,presets,report}.rs 2026-10-26 22:01:25 +00:00
aiongg fa1848be4c refactor(engine): move cmd/fileio.rs items to cmd/fileio/{access,commands,export_names,formats}.rs 2026-10-26 22:01:25 +00:00
aiongg 2a90e82736 refactor(engine): move cmd/fileio/affinity.rs items to cmd/fileio/affinity/{document,import,layout,master_copies,nodes,paint,text}.rs 2026-10-26 22:01:25 +00:00
aiongg 71aef5cc85 refactor(engine): move cmd/draw2.rs items to cmd/draw2/{anchors,commands,common,cut,freehand,smooth}.rs 2026-10-26 22:01:25 +00:00
aiongg c75c6a9586 refactor(engine): move cmd/distortcmds.rs items to cmd/distortcmds/{perspective}.rs 2026-10-26 22:01:25 +00:00
aiongg c2ead918b1 refactor(engine): move cmd/buildcmds.rs items to cmd/buildcmds/{live_paint,shape_builder,trace}.rs 2026-10-26 22:01:25 +00:00
aiongg 48b3ea91f0 refactor(engine): move cmd/brushsym.rs items to cmd/brushsym/{brushes,symbols}.rs 2026-10-26 22:01:24 +00:00
dotCooCoo 70e70924c8 Merge branch 'fix/image-cache-follows-memory' into fix/undo-history-follows-memory
Brings in 8404fa42, which merges main e2a8280. The history budget keeps reading vectorcraft_render::physical_memory, now backed by main's Windows, macOS and FreeBSD readers.
2026-10-26 12:54:45 -07:00
aiongg f1d427762b style: cargo fmt on files moved without formatting 2026-10-26 19:32:10 +00:00
dotCooCoo 803a7edbcb Merge main into feat/jxl-import 2026-10-26 11:59:56 -07:00
aiongg 52ff7aea1a refactor(engine): move cmd/effectcmd.rs lighting preset tests to cmd/effectcmd/ 2026-10-26 18:33:16 +00:00
aiongg 83eec43b18 refactor(engine): move tests_*.rs to tests/<topic>.rs 2026-10-26 18:26:56 +00:00
aiongg 9accfee5d4 refactor(engine): move cmd/effectcmd.rs tests to cmd/effectcmd/tests.rs 2026-10-26 18:18:17 +00:00
aiongg db60090f24 refactor(engine): move cmd/textstyles.rs tests to cmd/textstyles/tests.rs 2026-10-26 18:18:17 +00:00
aiongg e8a069ebc2 refactor(engine): move cmd/threads.rs tests to cmd/threads/tests.rs 2026-10-26 18:18:16 +00:00
aiongg 14540d6a44 refactor(engine): move cmd/typecmd.rs area_tests to cmd/typecmd/area_tests.rs 2026-10-26 18:18:16 +00:00
aiongg 2cd1a3a3f1 refactor(engine): move cmd/graph.rs tests to cmd/graph/tests.rs 2026-10-26 18:18:16 +00:00
aiongg 62261b17c9 refactor(engine): move cmd/mod.rs cmd/fileio/mod.rs cmd/findfiles/mod.rs cmd/place/mod.rs to foo.rs files 2026-10-26 18:15:21 +00:00
nrq6993-a11y b7b107ce24 G11: Join tool connects endpoints near scrub line ends
Squashed from #4272 onto main.
2026-10-26 22:07:58 +07:00
dotCooCoo 6ed4608d82 Images: an image past the 2 GiB decode allowance draws at reduced size instead of a crossed box
A PNG, JPEG, GIF or WebP image that takes more than the decode
allowance as RGBA (2 GiB, 512 MiB in the web app), such as a 24000 ×
24000 JPEG, was placed with the warning "too large to draw" and then
drew as a crossed gray box on the canvas and was left out of raster
exports. A 16-bit PNG whose decoded samples were past the allowance
was shown the same way, with the same warning, although its RGBA fits.

The renderer now decodes such an image at the largest size, keeping its
proportions, that fits the allowance as RGBA. Each pixel of the result
is the mean of the image's pixels it covers. A PNG that isn't
interlaced is read a row at a time; other images are decoded whole when
their decoded samples fit the allowance. A 16-bit PNG that isn't
interlaced and whose RGBA fits is read a row at a time at its own size.
An image of more pixels than the allowance has bytes still draws as the
crossed box, and so does one whose decoded samples are past the
allowance, other than a PNG that isn't interlaced. The renderer
decodes an image at reduced size only while the result and the memory
reading it takes (the image decoded whole, or the PNG reader's row
buffers) fit beside the images being painted; otherwise the image is
not decoded on that render (on the canvas it draws as the crossed box)
and is tried again on the next render. The document keeps the whole
file for saving and export. A placed document's saved preview past the
allowance is decoded the same way, at the size it is drawn at or at the
reduced size when that is smaller.

Open, Place and the Links panel say "an image of W × H pixels is shown
at reduced size" for an image drawn smaller. They say nothing for an
image drawn at its own size, and they say "too large to draw" for one
that is not drawn at reduced size.

Docs: docs/mcp.md, docs/target-app-parity.md (the crossed box's line
now names an image over the allowance that can't be drawn at reduced
size).
2026-10-26 21:41:42 +07:00
nrq6993-a11y fff6227351 #4122: File → Open starts in the last opened file's folder
Squashed from #4263 onto main.
2026-10-26 20:34:53 +07:00
dotCooCoo ac16d957fb Undo: the history keeps steps within a quarter of installed memory on every desktop OS
Each document's undo history drops its oldest steps once they keep more
memory than a budget. The engine read the installed memory only on
Linux, so the budget was 1 GiB on Windows, macOS and FreeBSD, and an
eighth of the memory, at most 1 GiB, on Linux.

The default budget is now a quarter of the installed memory, with no
fixed ceiling and at least 64 MiB, read with the image store's reader,
which vectorcraft-render now exports as physical_memory. It stays
1 GiB where the memory can't be read and 256 MiB in the web build, and
a 32-bit build keeps at most a quarter of its address space.

Docs: docs/target-app-parity.md.
2026-10-26 05:53:46 -07:00