Commit Graph
4129 Commits
Author SHA1 Message Date
Alan Rockefeller f75cfd5a56 Clone Stamp and Healing Brush clone from a source set in another open document (#10381)
* Clone Stamp and Healing Brush clone from a source set in another open document

Alt-clicking a clone source in one document and painting in another sampled the
painted document at the source point: a clone source slot held a point and a layer
but not the document. Slots now record the document (and its layer) they were set
in, and painting elsewhere samples that document, as in Photoshop.

- Engine: CloneSource gains `document` (serde default, so older slots read as
  "the document being painted"). Clone Stamp, Healing Brush, the live stroke, the
  Pattern Preview wrap and the brush-tip preview read the source document. Pixels
  are converted to the painted document's colour mode and depth like Edit > Paste
  (no ICC conversion, same as Paste). Current Layer / Current & Below use the
  layer the source was set on (that document's active layer if it was deleted);
  All Layers uses its composite.
- A source whose document was closed is an error asking for a new source, and
  stores no aligned anchor, instead of silently sampling the wrong document.
- cloneSource.set takes an optional `"document": index` (with `source`);
  cloneSource.list and set report each slot's document index.
- UI: the Clone Source panel names the source document (or says it was closed),
  the source crosshair isn't drawn over another document, and the brush preview
  cache includes the source document's revision.

Tests: engine tests for 8/16/32-bit with and without wrap, colour-mode conversion
(Gray > RGB16, RGB > CMYK), sampled layer, Healing Brush, live stroke vs commit,
preview, closed/invalid documents and cloneSource.set/list; a UI test that
Alt-clicks in one document and paints in another.

* Clone test: the aligned stroke past the smaller source document's edge leaves the destination unchanged

Review follow-up: with "aligned": false the stroke sampled inside the source, so it didn't test the edge its comment named, and nothing was asserted.

* Clone Stamp / Healing Brush: an empty Clone Source slot refuses to paint

clone_params fell back to ui.clone_source / ui.clone_offset when the active
slot was empty. Those coordinates carry no document, so after Alt-clicking in
one document and picking an empty slot in another, the stroke read the first
document's coordinates from the second one's pixels.

* fix: reject stale cross-document clone previews

* Clone Source: a copy opened after the source document closed isn't its source

A native copy keeps its document's ID, and a reopened document may keep its ID. A slot set in
a document that was then closed resolved that ID again once a copy was open, and painted from
the copy instead of reporting the closed source (CodeRabbit, clone_source.rs).

Session::close now marks the slots set in the closing document closed (CloneSources::forget_doc,
next to the other per-feature forget_doc calls). A closed slot refuses the stroke and its live
preview with the closed-source error, shows "Source: document closed" in the panel, reports no
`document` in cloneSource.list/set, and draws no overlay or crosshair, whatever document has the
ID now. Setting a new source clears it.
2026-11-12 18:00:54 +01:00
David Mann bc778cf4af Merge pull request #13442 from wanikhawar/fix/ellipse-path-menus-13235
Shape tools: Path operations, alignment and arrangement menus
2026-11-12 13:28:08 +01:00
David Mann 2b7977accb Merge pull request #9301 from DuBearte/feat/9269-black-white-auto
feat: Black & White Auto (#9269)
2026-11-12 13:27:10 +01:00
David Mann e165933772 Merge pull request #12430 from ljkx/atn-fit-image
Actions: map File › Automate › Fit Image (#10723)
2026-11-12 13:26:58 +01:00
Khawar Zamman Wani 4b16507738 Custom Shape: an operation adds the shape to the active shape layer
shape.create with addTo keeps a component's joined subpaths (holes)
joined, so a custom shape's hole doesn't become a component of its own.
2026-11-12 14:30:25 +05:30
Dylan M. Taylor 74330157cb Use craft-psd for PSD/PSB format code (#13414)
* Use craft-psd from craft-libs; remove crates/psd

* Regenerate the scorecard (28 crate roots)

* Take craft-psd at craft-libs 55d120f2

* Regenerate lockfile for current shared format crates

* Pin shared format crates to current craft-libs main

* Match brush import cap to shared decoder budget

* xtask: update layer fixtures after PSD extraction
2026-11-12 02:53:54 -05:00
David Mann eb3c99d653 Merge pull request #12237 from hectorviov/fix/perspective-crop-field-limits
Perspective Crop: W, H and Resolution clamp to the measured ranges with alerts
2026-11-12 03:01:42 +01:00
David Mann 54cde24340 Merge remote-tracking branch 'origin/main' into fix-9301 2026-11-12 02:45:44 +01:00
David Mann b554be38e7 Merge pull request #13303 from NaufalDzz/fix/issue-13244
Line tool: a drag is one History step named "Line Tool" (#13244)
2026-11-12 02:17:52 +01:00
David Mann 7755675ce7 Merge pull request #13342 from RickiNano/fix/13308-star-outer-corner-radius
Polygon tool: a rounded star rounds only its outer points (#13308)
2026-11-12 02:16:48 +01:00
Hector Villarreal bed2e22d8e Merge upstream/main into fix/perspective-crop-field-limits 2026-11-11 18:52:17 -06:00
David Mann 2bb1c3d0c6 Merge pull request #13141 from rmsff/fix/convert-point-drag-segment-12741
Convert Point: drag a segment as Direct Selection does
2026-11-12 01:35:41 +01:00
Dylan M. Taylor abeb16c96b paint: refuse a sequential-dab stroke whose working copy is too large (#11070)
* paint: refuse a sequential-dab stroke whose working copy is too large

apply_dab_stroke read the whole rectangle enclosing a stroke's dabs into
two dense f32 copies (and a third for the mix), sized by the area
between the dabs rather than what they paint. Two distant points asked
for gigabytes on a sparse document.

Check the three planes against a 4 GiB budget (1 GiB on 32-bit) before
reading, and paint nothing past it.

* address review: apply_dab_stroke returns Result so over-budget dab strokes fail with 'stroke too large'

* fix tests: apply_dab_stroke returns a Result

* fix tests: handle the Result of the dab-stroke functions
2026-11-11 16:31:47 -05:00
Dylan M. Taylor f7771c8545 Engine: check dense working buffers against a budget before expanding sparse content (#10964)
* Engine: check dense working buffers against a budget before expanding sparse content

A native document stores only the tiles it holds, so a few distant tiles (or a
huge empty canvas) make a small file whose content bounds span trillions of
pixels. Several commands read those bounds, or the whole canvas, into dense
f32 buffers without checking the size first, and ran the process out of memory.

- allocation::check_dense refuses an area whose dense buffers would pass
  MAX_DENSE_BYTES (the Image Size allowance), before anything is allocated.
- Adjustments run through process_surface, Apply Layer Mask, channel sources
  (Apply Image / Calculations / Load Selection), face detection and Multichannel
  conversion (both directions) check their buffers first.
- Auto-Blend checks the final work area too, not only the layers' union.
- Liquify's selection blend works over the part of the content the selection
  reaches, on a copy of the old pixels, and checks that area.
- Floating a selection visits only stored source or selection tiles when a
  default is empty, and checks the full grid otherwise.
- Frame from Layers and the Frame tool fill their mask without a dense buffer
  and check its area.
- Image Size checks every surface's resampled content bounds, off-canvas
  pixels included, not only the canvas.

* cargo fmt

* address review: propagate budget error out of adjust_as_filter

* address review: budget merged CMYK channel planes, frame mask GRAY8 source, Duotone inks and the stored surface in Multichannel conversions

* address review: budget the Frame mask at its tile footprint and Auto-Blend stack pyramids

* address review: non-seamless stack blend skips the fusion pyramids in its budget; canvas refresh returns smart-object refresh errors

* address merge: take main's resample_doc signature in Bitmap; fmt

* address merge: Image Size over distant tiles is bounded by main's resample budget; drop the duplicate test

* address merge: keep brush_clear_background_tests test-only

* address CI: a smart object that cannot re-render keeps its resampled fallback (main's tested behavior); drop the refresh error propagation
2026-11-11 16:31:22 -05:00
Dylan M. Taylor 479f8e643e Actions: charge skipped steps to the playback budget, bound batch nesting, clip the set override (#10969)
* Actions: charge skipped steps to the playback budget, bound batch nesting, clip the set override

- actions.play charges every stored step of a call (run, disabled or before
  `from`) to the playback tree, and refuses a call that no longer fits before
  copying the action, so repeated calls to a large disabled child stop at the
  shared limit.
- file.automate.batch and runDroplet refuse to nest more than MAX_BATCH_DEPTH
  deep, checked before the droplet is read; nested batches charge the shared
  step budget like batches inside played actions.
- actions.load clips the `set` override to the importer's name limit before
  copying it into every action.

* address review: check the script step limit before charging skipped playback steps

* address review: nested batches keep the shared playback count, and nesting or playback limits fail the enclosing input

* address review: a limit stop inside a called action or nested batch fails the enclosing input

* address review: keep begin_playback's signature; the call that starts mid-action uses begin_playback_from

* address review: keep child results in limit failures, history after the script-limit check, trim a clipped set name, open-document batches carry the nesting state
2026-11-11 16:30:57 -05:00
Dylan M. Taylor 2e10342cdb fix(engine): authorization for nested scratch sessions and preset calls, CSV and PostScript text escaping (#11188)
* fix(engine): authorization for nested scratch sessions and preset calls, CSV and PostScript text escaping

* address review: Batch checks the authorization gate for each save point

* address merge: restore the #[test] attribute

* address merge: batch save points answer to the authorization gate in the rewritten batch

* address review: neutralize leading line feeds and full-width formula characters; test the preset command gate

* address review: check formula prefixes after leading spaces
2026-11-11 16:30:33 -05:00
Dylan M. Taylor dd19c295d1 fix(engine): bound sparse remap, scaled clone sources, path reads, export format, name lookups (#11181)
* fix(engine): bound sparse remap, scaled clone sources, path reads, export format, name lookups

* address review: read footage frames by Path so non-UTF-8 file names still import
2026-11-11 16:30:07 -05:00
Dylan M. Taylor f373ec181c fix(format,engine): limit zstd windows, set bundle modes via the handle, refuse symlinked presets (#11145)
* fix(format): limit zstd windows, set bundle permissions through the handle, refuse symlinked presets

* test(engine): create the symlink test's directory

* address review: preset writes never follow a symlink swapped in after the check

* address review: a zstd window past the limit is a limit error; replacing a link never reads its target's attributes

* test: replacing a link to a FIFO does not block
2026-11-11 16:29:17 -05:00
Dylan M. Taylor e4efca36aa fix(engine): apply the metadata choice to WebP Quick Export (#11058) 2026-11-11 16:24:44 -05:00
Dylan M. Taylor 5a935b2830 Place: refuse a scale that makes the placed image exceed the render pixel limit (#11229)
* Place: refuse a scale that makes the placed image exceed the render pixel limit

* address review: bound the rounded-up resampled size when placing at a scale

* address review: the oversized-scale error names the placing command
2026-11-11 16:23:05 -05:00
RickiNano cb5298e9d4 Polygon tool: a rounded star rounds only its outer points (#13308)
live_path rounds a star's outer points and leaves its inner points
sharp corners, as the reference application does: a 5-point star at
Star Ratio 50 % with corner radius 10 has 15 anchors instead of 20.
Plain polygons keep rounding every vertex.

The on-canvas corner radius widget shows knobs at the outer points only
and takes its largest radius from them, so it previews the same path
as shape.create.
2026-11-11 20:41:00 +01:00
rmsff 28fd0f4c1e path.moveAnchors: take the Drag Path step name
The Convert Point tool names a whole-path drag as the reference does (#12741). Any other stepName is refused, as with path.convertPoint and path.moveHandle.
2026-11-11 22:02:49 +03:00
NaufalDzz ceb0f2a472 Line tool: a drag is one History step named "Line Tool" (#13244) 2026-11-11 18:28:52 +00:00
ljkx 0a2a49852a Merge remote-tracking branch 'origin/main' into atn-fit-image
# Conflicts:
#	crates/engine/src/cmd/atn_cmds.rs
2026-11-11 16:24:18 +01:00
rmsff 9ba9f581da Test the Paint Bucket refusing Bitmap documents 2026-11-11 17:30:01 +03:00
rmsff bbf9217c95 Paint Bucket: refuse Bitmap documents with the reference's alert
paint.bucket returns the reference's error text before it reads the
region or copies the document, so nothing changes and no History state
is added. A canvas click shows the text as a modal alert with OK.
2026-11-11 17:29:46 +03:00
David Mann 58e0a152b9 Merge pull request #13073 from TrevorBrown-dev/fix/delete-anchor-delete-key-12761
Delete Anchor Point: Delete with an anchor selected edits the path, never the layer (#12761)
2026-11-11 15:12:12 +01:00
David Mann afb2c28489 Merge pull request #12396 from hsmith-dev/fix/cam-color-edge
Fit Content-Aware Move's middle only for a brightness change
2026-11-11 14:53:41 +01:00
David Mann 91badc3a97 Merge pull request #12469 from ljkx/actions-artboard-section
Actions: map Layer › New › Artboard and Artboard from Layers (#10723)
2026-11-11 14:39:50 +01:00
David Mann 14e36a7457 Merge pull request #11228 from storytold/fix/sec-prefs-empty-path-segments
Preferences: refuse paths with empty segments and bound the alternate shortcut list
2026-11-11 14:30:08 +01:00
David Mann dc99d39fb6 Merge pull request #13147 from rmsff/fix/healing-refuses-indexed-12112
Healing Brush: refuse Indexed Color documents with the reference's alert
2026-11-11 14:26:20 +01:00
David Mann 00f9b7d60d Merge pull request #13106 from rmsff/fix/art-history-brush-depth-refused-12637
Art History Brush: refuse 16- and 32-bit documents with the reference texts
2026-11-11 14:25:30 +01:00
David Mann f48e61c7b7 Merge origin/main into #12396 (Content-Aware Move Color) 2026-11-11 13:36:57 +01:00
David Mann 582a840a12 Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	crates/ui-egui/src/tools/perspective_crop_ui.rs
2026-11-11 13:35:34 +01:00
Trevor BrownandClaude Sonnet 5.5 8cba9c8781 Merge remote-tracking branch 'upstream/main' into fix/delete-anchor-delete-key-12761
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove; Opus 5.5 briefed; Sonnet 5.5 wrote at medium
2026-11-11 07:27:05 -05:00
David Mann 83e987b2e8 Merge pull request #13077 from rmsff/fix/bucket-empty-history-state-12535
Paint Bucket: a click that fills nothing adds no history state
2026-11-11 13:21:14 +01:00
David Mann ef9630958e Merge pull request #12308 from hectorviov/fix/mixer-toggle-commands
Mixer Brush: Auto-Load, Auto-Clean and Sample All Layers commands for shortcuts (#11959)
2026-11-11 13:21:02 +01:00
David Mann ec695dcded Merge pull request #13091 from rmsff/fix/red-eye-outside-selection-12576
Red Eye: a press outside the selection does nothing
2026-11-11 13:20:04 +01:00
David Mann b04cdbda50 Merge pull request #12287 from DuBearte/fix/12018-gradient-sample-point
Gradient tool: sample each pixel where the reference application does, fixing Angle and Radial values
2026-11-11 13:19:53 +01:00
David Mann 93d9b6340f Merge pull request #12245 from hectorviov/fix/brush-shift-alt-sampler
Painting tools: Shift+Alt+click adds a colour sampler
2026-11-11 13:19:41 +01:00
David Mann 2634178507 Merge pull request #12175 from hectorviov/fix/sampler-sample-size
Color Sampler: Sample Size shared with the Eyedropper; every sampler reads the NxN average (#11732)
2026-11-11 13:19:29 +01:00
Dylan M. Taylor f8f1500c99 Merge remote-tracking branch 'origin/main' into fix/sec-prefs-empty-path-segments 2026-11-11 12:07:56 +00:00
rmsff 3c1e0d7d69 Healing Brush: test the Indexed Color refusal in the engine and on the canvas 2026-11-11 15:07:20 +03:00
rmsff 6f6e8f11e4 Healing Brush: refuse Indexed Color documents with the reference's alert
paint.healingBrush healed an Indexed Color document with colours outside
its colour table. It now refuses there with the reference application's
words, and the canvas shows them in an alert with OK at the Alt-click
that sets the source and at a stroke, changing neither the source, the
pixels nor the History. Bitmap, Duotone and Multichannel weren't
measured and heal as before.
2026-11-11 15:07:20 +03:00
FredApps 36bfc50fd3 Merge branch 'main' into feat/image-processor-open-documents
Resolve conflicts by keeping both the Image Processor source parameter
and main's pdfSpotPlates text, and by combining the Last updated
headers in docs/gaps.md and docs/target-app-parity.md.
2026-11-11 11:10:40 +01:00
Dylan M. Taylor 592841db79 Merge remote-tracking branch 'origin/main' into fix/sec-prefs-empty-path-segments 2026-11-11 09:00:40 +00:00
Tanish Manku 6d99175b18 Merge pull request #8579 from wwewtech/fix/atn-setprops-explicit-layers
fix(atn): an explicit layers list exports one Set per layer (#7246)
2026-11-11 00:32:38 -07:00
Tanish Manku 93c79f5c52 Merge pull request #11175 from hnoerenberg/fix/video-import-warnings-11113
fix(video): a salvaged truncated GIF or WebP import discloses its missing frames (#11113)
2026-11-11 00:28:26 -07:00
Tanish Manku 28d2b499b5 Merge pull request #11062 from yoriswind/codex/artboard-move-overflow
Reject cross-artboard moves whose required translation overflows
2026-11-11 00:27:05 -07:00
Tanish Manku 6c8140daf4 Merge pull request #10896 from yoriswind/codex/fill-dialog-mask-target
Fix Fill and Stroke for targeted masks
2026-11-11 00:24:24 -07:00