Commit Graph
377 Commits
Author SHA1 Message Date
David Mann bb7a1289b0 Merge remote-tracking branch 'origin/main' into pr-12049 2026-11-08 18:05:36 +01:00
Hector Villarreal 8272e6b9f4 Mixer Brush: refuse Indexed Color and Bitmap documents with the alert (#11958)
A Mixer Brush stroke in an Indexed Color or Bitmap document now fails before
anything is painted, with the reference's alert texts (convert to RGB Color /
Grayscale mode to edit); paint.mixerBrush returns that error and leaves the
document and History unchanged. A press on the canvas shows it as an Error
alert instead of a status-bar message. RGB, CMYK, Lab and Grayscale still
paint.
2026-11-08 00:28:08 -06:00
DuBearteandClaude Opus 5.5 be428bf90e Brush: Clear on the Background paints as Normal and the Mode reads Normal
Fixes #11897.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 09:59:39 -05:00
David Mann 83eaf7c0bc Merge pull request #11847 from hnoerenberg/fix/pressure-size-default-off-11809
fix(paint): Pressure for Size starts off, as the reference does
2026-11-07 12:10:48 +01:00
Hartmut Nörenberg ccc263e49e fix(paint): Pressure for Size starts off, as the reference does
BrushSettings::default() turned Pressure for Size on, so a fresh brush -
and the brush Reset Tool hands back, which is that default plus
Photoshop's 10 % smoothing - reported pressureSize: true from brush.get
and drew the options bar's "Always use pressure for size" button
highlighted, while the reference application leaves both pressure
toggles off after Reset Tool. Neither is on now.

The toggle itself is untouched: it still switches both ways, Shape
Dynamics' Pen Pressure control is unaffected, and path.stroke's Simulate
Pressure still tapers a brush that follows pen pressure. A brush JSON
that omits pressureSize now reads as off, as the reference's default is.

Two engine tests took their expectation from the old default and set
pressureSize explicitly instead: cmd::brush_cmds::tests::stroke_backwards_compatible
and cmd::vector_cmds::tests::stroke_path_simulate_pressure_tapers_both_ends.
The new crates/engine/src/brush_pressure_size_default_tests.rs covers the
default, brush.get on a fresh session, an omitted field, switching the
toggle, and that a pressure ramp with the default brush paints like
pressureSize: false.

Fixes #11809
2026-11-07 07:22:59 +01:00
Trevor BrownandClaude Fable 5.1 a475de6139 Merge upstream/main into feat/move-options-bar-distribute-gear-11381
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-06 17:40:51 -05:00
Trevor BrownandClaude Fable 5.1 2e4ced2469 Move gear: active_layer_changes is a change marker, not an exact count (#11381)
Session::active_layer_changes now documents its contract: it advances at least once whenever the active document or layer changes, so callers compare two readings for equality. A file.new or a document close may advance it twice (add_document and execute both note it); removing that is not a one-liner, so the wording covers it. Adds a test that file.new advances the marker and a same-layer select_layer does not.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-06 13:45:24 -05:00
Trevor BrownandClaude Fable 5.1 402b59bcde Move gear: every active-layer change counts, not only the ones through execute (#11381)
Session::note_layer_change(before) now backs the change count and is called by execute, start, finished jobs, select_layer, restore_layer_selection, layer_multi_cmds::set_selection, undo, redo, rollback and a new Session::set_active_layer; document switches (note_active_change) count too. The Pen tool's direct write of the active layer goes through set_active_layer.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-06 12:52:14 -05:00
Trevor BrownandClaude Fable 5.1 7fc8ec621c Move gear: the pick marker lasts until the next active-layer change, not a frame (#11381)
The counter lives in the engine: Session::active_layer_changes(), bumped by Session::execute whenever a command leaves a different active document or layer (selection commands, Action playback, undo, canvas picks). note_move_pick stores it with the picked id; layer_reveal::track accepts the marker only if the active layer is that id and the count is unchanged, so it survives a hidden panel for any number of frames and any later non-pick change (even back to the same id) invalidates it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-06 11:55:37 -05:00
David Mann 3af79c0cb7 Merge main 9b02eac2c4 into integration batch 18 2026-11-06 02:14:46 +01:00
David Mann 9bef3b2dc8 Merge pull request #6088 from davidmann4/fix/snapshot-followups
History snapshots: follow-ups to #3567 (#6087)
2026-11-06 01:32:54 +01:00
David Mann a77d7d6b53 Merge PR #11503: Layer > Smart Objects says Reveal in Explorer, Embed Linked and Embed All Linked, in the reference order, without the Warp rows (#11401) 2026-11-06 00:28:25 +01:00
David Mann 9f88425d83 Merge PR #11456: Shortcuts: Ctrl+Alt+0 also zooms to 100% and F9 also opens Actions, the reference's second keys (#11396) 2026-11-06 00:27:40 +01:00
6326117c53 Web build: big operations that won't fit fail with an error instead of trapping, and a trap says so (#10129)
* Raster: ask the allocator whether a big operation fits; PSD save reserves its whole output

New photocraft_raster::headroom: ensure(need) tries to reserve the need plus a margin and frees it
at once (web only; native always passes), below(bytes) tells whether less than that can be
allocated, and simulate_available fakes the answer for tests and diagnostics.

PsdFile::to_bytes reserved only the pixel data, so embedded smart-object data and other tagged
blocks grew the output by doubling, which on the web is one unrecoverable huge realloc. It now
reserves the exact encoded length.

* Big operations that won't fit in memory fail with an error instead of trapping

Place, Image Size, a smart-object re-render and Save now ask the allocator whether their estimated
need can be allocated before they start (photocraft_engine::memory_gate, estimates per operation,
photocraft_io::estimate_export_bytes for saves). A refusal changes nothing and says what the
operation needed and what to do (save, Edit > Purge > All, close documents).

A standing notice warns when less than 512 MiB can be allocated, with hysteresis, so the user can
save before anything traps. Notices can now be sticky, which keeps them past the auto-hide delay.

* Web build: a trap says so instead of freezing the page, and ?free-mb simulates low memory

index.html holds a hidden, static 'PhotoCraft stopped' message with a Reload link. web.rs reveals
it when the module traps (the window error event, or an unhandled rejection from a spawned
future), tells running out of memory from an internal error by the panic message a chained panic
hook kept, and skips the Leave site prompt once stopped. ?free-mb=N makes the memory gates and the
low-memory warning see only N MiB, for checking them in a browser.

* Docs: web build memory handling in the gaps list and the parity assessment

* Engine: use is_multiple_of in the megabyte formatter

* Cargo.lock: the web shell depends on photocraft-raster

* Web boot page: carry the stopped message too, as the test that keeps the two pages equal requires

* Save check counts one copy of the document, and runs once per save

The encoded file's buffer is reserved fallibly, so a save it doesn't fit
in fails with an error instead of trapping; counting it as well refused
saves that would have fitted. On the background-save path the check ran
in write_document and again in start_save, which other callers reach
directly; it now runs only in start_save there.

* Review fixes: warning check allocates nothing, PSD merged image counted, automation saves checked

The low-memory warning's periodic check reads the size of linear memory
instead of reserving a block: wasm memory never shrinks, so a trial every
few seconds raised the high-water mark by up to 768 MiB for nothing. The
operation checks keep their trial reservation.

PSD and PSB saves always build a canvas-sized merged image (a placeholder
without maximum compatibility) and hold it raw and encoded; the save
estimate now counts it. The synchronous automation save checks memory
before encoding, as File > Save does, and its test asserts the memory
error.

The trap listeners go in before the app is built, so a trap while
building it shows the stopped message too, and a memory access out of
bounds reads as unexpected rather than as running out of memory.

* Cover layered PSD preflight limitation

* Fix layered PSD test iteration

* Docs: layered PSD preflight limitation in the gaps list

* Web OOM gate: gate direct exports, truthful advice for unbounded PSD sources (#10024)

* Web OOM gate: estimate layered PSDs per layer instead of refusing every real PSD

The PSD check admitted a file only when its color-mode data, image
resources and layer section were all empty. Every Photoshop file has
image resources (at least the resolution), so on the web nearly every
real PSD was refused for Place, PSD smart objects could not render,
and Image Size was refused for documents holding one, whatever the
free memory (u64::MAX never fits).

The color-mode data and image resources hold no pixels, so they are
now only skipped. A layered file reads its layer count from the layer
info (signed, absolute value) and adds a canvas-sized surface and mask
per layer to the flat estimate. Files that are not 8-bit RGB or
grayscale, keep their layers in a Layr tagged block, or whose sections
can't be read stay unbounded and refused, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Web stopped page: match trap messages ignoring case

Safari reports the allocation-failure abort as "Unreachable code
should not be executed" and Firefox says "out of memory", which the
case-sensitive matching missed: the trap was not recognised, or was
shown as an unexpected stop instead of running out of memory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Export estimate: count the merged image OpenRaster writes

The ORA writer keeps the layers but also flattens the document for
mergedimage.png, a 16 B/px composite of the canvas, which the
estimate left out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 22:04:59 +01:00
Trevor BrownandClaude Fable 5.1 14d9de4f86 Merge upstream/main into fix/smart-objects-menu-11401
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-05 12:42:11 -05:00
Trevor BrownandClaude Fable 5.1 712da4f05e Layer > Smart Objects says Reveal in Explorer, Embed Linked and Embed All Linked, in the reference order, without the Warp rows (#11401)
Windows now reads "Reveal in Explorer", Convert to Embedded is "Embed Linked", and a new Embed All Linked command (layer.smartObjects.embedAllLinked) embeds every linked smart object of the document in one history step, refusing the whole step with an error that names a missing file. The three Warp rows leave the submenu; their commands stay registered for scripts and the Edit menu.

The menu parity floor drops from 660 to 658 because three live catalog rows were removed and one added.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-05 12:20:09 -05:00
Trevor BrownandClaude Fable 5.1 f1c7b034b1 Shortcuts: Ctrl+Alt+0 also zooms to 100% and F9 also opens Actions, the reference's second keys (#11396)
The reference application gives View > 100% a second key, Alt+Ctrl+0 beside Ctrl+1, and Window > Actions a second key, F9 beside Alt+F9. Both are now rows in ALTERNATE_SHORTCUTS (Cmd+Alt+0 in our notation, which is Ctrl+Alt+0 off the Mac), so the menus keep showing the main key and Edit > Keyboard Shortcuts lists and removes them like F2 for Cut.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-05 07:56:36 -05:00
David Mann f162c19e81 Merge remote-tracking branch 'origin/main' into integration-batch-17
# Conflicts:
#	crates/ui-egui/src/control/dispatch.rs
#	crates/ui-egui/src/control/params.rs
2026-11-05 12:44:02 +01:00
Khawar Zamman Wani e3ecd73569 feat(frame): rework the Frame tool's selection, handles and placement (#8920)
Thanks @wanikhawar — merging the Frame Tool rework.

Summary: Frame Tool selection/handles/placement now distinguish frame vs image (border / click / double-click and Layers thumbnails), with independent transforms, shape variants, Properties/options-bar stroke and fit commands, Convert to Frame, CLI/MCP `layer.frame.*` commands, native `.pcraft` persistence, and PSD export via editable groups + `pcFr` metadata (not Photoshop's native frame type). Tests cover selection, transforms, fitting, locks/hostile geometry, and native/PSD round-trips.
2026-11-05 12:39:02 +01:00
David Mann cf65810dda Merge remote-tracking branch 'origin/main' into integration-batch-17
# Conflicts:
#	crates/ui-egui/src/i18n/cs.tsv
#	crates/ui-egui/src/i18n/de.tsv
#	crates/ui-egui/src/i18n/el.tsv
#	crates/ui-egui/src/i18n/es.tsv
#	crates/ui-egui/src/i18n/fr.tsv
#	crates/ui-egui/src/i18n/hu.tsv
#	crates/ui-egui/src/i18n/id.tsv
#	crates/ui-egui/src/i18n/it.tsv
#	crates/ui-egui/src/i18n/ja.tsv
#	crates/ui-egui/src/i18n/ko.tsv
#	crates/ui-egui/src/i18n/nl.tsv
#	crates/ui-egui/src/i18n/pl.tsv
#	crates/ui-egui/src/i18n/pt-br.tsv
#	crates/ui-egui/src/i18n/ru.tsv
#	crates/ui-egui/src/i18n/sr.tsv
#	crates/ui-egui/src/i18n/tr.tsv
#	crates/ui-egui/src/i18n/uk.tsv
#	crates/ui-egui/src/i18n/vi.tsv
#	crates/ui-egui/src/i18n/zh-hans.tsv
#	crates/ui-egui/src/i18n/zh-hant.tsv
#	docs/gaps.md
2026-11-05 09:03:28 +01:00
Khawar Zamman WaniandFredApps 316e00a97e Bound Photomerge memory and safely reject out-of-budget jobs (#7851) (#10463)
* Reduce Photomerge input and fill memory

* Bounded working-memory budgeting and safe allocation for Photomerge

* Photomerge memory: estimate warped sizes, no RAM ceiling, shared RAM detection

- Budget is half of physical RAM (at least 1 GiB) with no 8 GiB ceiling.
- The pre-flight estimate uses each image's warped extent and the band
  grid's exact bound (band_bytes_bound), at the levels seam_blend uses.
- Auto-Blend keeps its old batching with no single-band cap.
- multiband returns a Result instead of a blank image on failure.
- Physical-memory detection moves to photocraft_engine::memory; the GPU
  budgets reuse it, so PHOTOCRAFT_RAM_MB means the same in both.
- Document memoryBudget; restore comments; tests for the band cap and the
  budget precedence.

* Photomerge: lower the blend's peak and estimate it by phase

- The band build makes its binary coverage straight from the alpha and
  writes each Laplacian level in place, so a band holds two fewer planes.
- The weight sums are freed before the collapse, which adds each level
  in place and frees it as it goes.
- The estimate is the largest phase (warp, ROIs, bands, collapse, output,
  fill) rather than the sum of all of them, and the bands get what is
  left of the budget after the ROIs and accumulators.

Every output pixel is unchanged: each change drops a plane or does the
same elementwise operation in place.

* Fix Photomerge band budget validation and fallible pyramid allocation

* Keep reference pyramid test helpers infallible

* Photomerge: bound source loading with the memory budget

Resolve the budget before any source is read, and admit each flattened
source before its surface is allocated. The accounting charges the
retained surface, the same-canvas temporary the flatten writes while the
source document is alive, and a file import's encoded bytes, with
saturating math so an overflow cannot wrap under a finite budget. Merge
to HDR Pro passes no budget and keeps its previous behaviour.

Tests cover the exact retained-plus-temporary charge, a refused source,
the within/over-budget command paths, the post-load estimate path, and
the unbudgeted HDR loader.

* Photomerge: bound source reads and imports by the remaining budget

Read each source file with what is left of the budget as its limit, lower the importer's own PSD/TIFF preflight or the flat decoders' pixel allowance to the remainder after the retained sources and encoded bytes, and refuse formats with no pre-decode estimate. Charge the decoded document's actual pixels (every layer) plus the flatten's working and output surfaces before flattening. Merge to HDR Pro keeps its unbudgeted read-and-import path.

* Remove redundant TIFF decode options update

* Clean up Photomerge budget Clippy findings

* Accept early decoder admission in source budget regression

* Photomerge: report unreadable sources as file errors; never reserve past a read limit

- A budgeted Photomerge reported a missing or unreadable source file as
  'not enough memory'. Only a file over the remaining budget, or one memory
  cannot hold, is a memory error now; others are file errors, as without a budget.
- read_all_with reserved a whole read chunk before checking the caller's limit
  for a file that grew after it was statted. It now refuses first and caps the
  reservation at the limit.

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-05 06:23:56 +01:00
yoriswind 1720af269d Merge current main while preserving recorded Batch safeguards 2026-11-04 10:47:01 -08:00
yoriswind 85fc78bb64 Merge current main into recorded Actions dialog support 2026-11-03 21:55:00 -08:00
yoriswind 211efca709 Keep paused action policy and spelling receivers bound 2026-11-03 19:39:45 -08:00
yoriswind 3028355333 Merge main and retain action history across Batch and Spelling 2026-11-03 12:42:57 -08:00
David Mann 822533a1e1 Merge remote-tracking branch 'origin/main' into fix/snapshot-followups
# Conflicts:
#	crates/ui-egui/src/app/commands.rs
2026-11-03 13:59:10 +01:00
David Mann 7329c700bb Merge remote-tracking branch 'origin/main' into integration-batch-13
# Conflicts:
#	apps/photocraft-cli/src/args.rs
#	crates/engine/src/jobs.rs
#	crates/engine/src/jobs/tests.rs
2026-11-03 13:52:30 +01:00
yoriswind 70aea3465d merge: integrate exact main scratch storage checkpoint
Merge 655295b2a2. Resolve generated scorecard conflict with exact upstream text only; actual source-bound regeneration and combined validation remain pending.
2026-11-02 23:30:10 -08:00
Khawar Zamman Wani 259b5590ae Merge origin/main (655295b2a2) into PR #10897 branch
Keep the PSD memory admission work and upstream's scratch storage
together. Conflicts resolved:
- Cargo.lock: both sysinfo versions are required. 0.40.1 serves
  photocraft-io's adaptive import budget; 0.37.2 serves
  photocraft-raster's scratch volume and memory supervision. Cargo
  metadata resolved the lock with no other changes.
- crates/engine/src/lib.rs: Session keeps pending_preflights and
  next_pending_preflight beside scratch_runtime and scratch_epoch.
  Session derives Default, so neither set needs a manual initializer.

Upstream: 655295b2a2
2026-11-03 12:54:59 +05:30
yoriswind d29cbec07e fix: consolidate action history after command transactions
Keep command-local history, purge and rollback intact, then consolidate affected documents at action completion or dialog suspension. Preserve semantic no-op identity and redo, visibility semantics and row identifiers. Bind dialog continuation to its exact document/history, inherit the setting in scratch sessions and carry droplet action names. Add the review counterexamples and focused continuation, Batch/droplet and history-option controls. Source is formatted; compilation and runtime qualification remain pending.
2026-11-02 19:02:08 -08:00
yoriswind 182da545ee feat: start persisted single-action history grouping
Add the default-on Actions history setting and a grouping scope shared by ordinary engine and shell playback entry points. Define public regressions for whole-play Undo/Redo, the off setting, failure prefixes, nesting, no-op and repeated-play boundaries, and persistence. This is an unvalidated draft increment: dialog continuation, direct compound edits, Batch/droplet boundaries and the complete edge-case qualification remain unfinished.
2026-11-02 18:30:27 -08:00
David Mann 2915849b07 Merge #4514: Record actions in a document-independent form (#219) [depends on #4496]
# Conflicts:
#	crates/engine/src/cmd/type_spell_cmds.rs
#	crates/engine/src/jobs.rs
#	docs/gaps.md
#	docs/target-app-parity.md
2026-11-03 00:36:40 +01:00
David Mann 98c2213e5c Merge #9211: Layers panel: the filter row lists linked, missing or embedded smart objects
# Conflicts:
#	crates/automation/src/server.rs
#	crates/ui-egui/src/control/tests.rs
#	crates/ui-egui/src/panels/layer_filter_ui.rs
#	crates/ui-egui/src/panels/layer_filter_ui/tests.rs
#	docs/control-protocol.md
#	docs/ui-parity.md
2026-11-03 00:34:07 +01:00
FredApps 9eddf1d8ca Pause and retry a failed or full scratch disk instead of turning spilling off
A scratch write or create failure, or a volume about to drop below max(1 GiB, 5%)
free space, now pauses spilling with exponential backoff (1 s doubling to 60 s)
instead of disabling it for the session. Tiles stay resident, set_budget keeps
the latest budget for the resume, preference changes retry at once, and
spill::epoch lets the engine re-apply History's byte limit while paused.
spill::set_size_cap adds an explicit size limit; free space comes from sysinfo's
disk feature.
2026-11-02 22:31:56 +01:00
FredApps b0f3c7516b Merge current main into codex/scratch-storage
Resolve conflicts with main's prefs UI split, session/execute.rs move, GPU memory
budget (gpuMemoryMb, 0 = auto, kept from main) and effective_memory_usage_mb history
budget. Port the Memory Usage % and Scratch Disks preferences into prefs_ui, the edit
integrity guard into session/execute.rs, and adapt main's new pixel readers to the
guarded TileBytes API. Cargo.lock regenerated; scorecard regenerated.
2026-11-02 22:16:22 +01:00
Fabio Lissi d1141d08f8 Merge branch 'main' of https://github.com/storytold/photocraft into feat/actions-record-independent 2026-11-02 12:40:52 -06:00
yoriswind 488ab1ab14 Merge commit '289dd0a874763d6528bab2184a87a1b53771c02a' into codex/atn-dialog-calculations 2026-11-02 09:37:49 -08:00
David MannandClaude Opus 5.5 aa20410a50 Merge main into fix/snapshot-followups
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-02 16:36:14 +01:00
Khawar Zamman Wani bcc060180f feat(io,engine,ui): adaptive PSD/PSB memory budget and interactive confirmation
- Distinguish available physical RAM from swap and commit headroom
- Adaptive soft and hard import thresholds with native fallback
- Interactive preflight confirmation modal before pixel decoding
- Headless and command parameters for explicit high-memory approval
- One-shot source-bound validation rejecting altered sources or degraded RAM
- Process-wide serialized decode gate with reentrancy support
- Documentation and synthetic regression test coverage
2026-11-02 17:11:03 +05:30
Khawar Zamman Wani 5d9c57e60d Linux: return memory of closed documents to the system (#8743) (#10515)
* perf: reuse large buffers so a pinned glibc trim threshold costs no speed (#10479)

With MALLOC_TRIM_THRESHOLD_ set (#8743), glibc maps every allocation over
128 KiB fresh, so tiles, compositor bands and filter scratch were page-faulted
in on every call: viewport compose 3.6x slower, Gaussian Blur up to 1.8x,
.pcraft save 2.4x.

- photocraft_raster::scratch: a process-wide, capped pool of large Vec
  buffers (u8/u16/f32/[f32; 4]). A miss drops the oldest buffers worth its
  size down to a 256 MiB floor, so peak memory stays near glibc's defaults.
  The engine releases the pool after any command that closes a document,
  Headless::close does too, and an idle thread releases it after 2 s unused.
- Tiles, compose Buffer/masks/bands, algo Image and the blur paths, engine
  adjustment/filter scratch, GPU tile upload and io import buffers go through
  the pool.
- .pcraft save reuses one zstd FrameCompressor per worker (byte-identical).
- interactive_bench reports minor page faults per run.

36 MP, trim threshold set vs glibc defaults: viewport 5.6 vs 6.1 ms (was
22.7), Blur r4 445 vs 437 ms (was 852), Curves CPU proxy 35.0 vs 35.7 ms
(was 50), flatten 146 vs 147 ms (was 237), save .pcraft 251 vs 230 ms (was
545). RSS after closing a 5400x7200 document: 21 MB with trim set.

* fix(linux): restart once with glibc's trim threshold set so closed documents return memory (#8743)

With glibc's default malloc, the memory of a closed document stays with the
process: freeing a large buffer raises glibc's dynamic mmap threshold, so
later tile buffers land in heap pages glibc keeps. A session that opened and
closed a 5400x7200 document held ~450 MiB afterwards.

photocraft_engine::malloc_tuning::apply(), called first in both binaries'
main, re-executes the binary once with MALLOC_TRIM_THRESHOLD_=131072 on Linux
with glibc: same PID, arguments, argv[0] and environment, in safe Rust
(CommandExt::exec). A malloc variable or glibc.malloc.* tunable the user or a
package already set is left alone, so setting MALLOC_TRIM_THRESHOLD_ opts
out. No-op on macOS, Windows, musl and wasm.

Depends on the scratch-buffer pool (#10479), without which the pinned
threshold slows filters, previews, flatten and .pcraft save by 26-209%.

* fix: corpus tests build again; return remaining pooled buffers (#10479 review)

- Corpus-gated io tests and the Photoshop-oracle test moved `.px` out of a
  `Buffer`, which now implements `Drop` (E0509 with `--features corpus`):
  use `into_px()`.
- io: masks, the merged image, extra channels, smart-filter masks,
  smart-object pixels and patterns give their `interleave` buffers back to
  the scratch pool after writing them.
- compose: recycle the mask values of a pass-through group, `effect_shape`
  and both `split_parts` callers.
- Styled Free Transform preview copies each band out instead of moving it,
  so the band returns to the pool.
- interactive_bench: the fault count covers each whole run, untimed setup
  included; say so.

* fix: corpus tests build again; return remaining pooled buffers (#10479 review)

- Corpus-gated io tests and the Photoshop-oracle test moved `.px` out of a
  `Buffer`, which now implements `Drop` (E0509 with `--features corpus`):
  use `into_px()`.
- io: masks, the merged image, extra channels, smart-filter masks,
  smart-object pixels and patterns give their `interleave` buffers back to
  the scratch pool after writing them.
- compose: recycle the mask values of a pass-through group, `effect_shape`
  and both `split_parts` callers.
- Styled Free Transform preview copies each band out instead of moving it,
  so the band returns to the pool.
- interactive_bench: the fault count covers each whole run, untimed setup
  included; say so.

* fix: recycle the masks of adjustment-atop and shape layers (#10479 review)

* fix: recycle the masks of adjustment-atop and shape layers (#10479 review)

* fix: recycle effect hiding masks (#10479 review)

* fix: recycle effect hiding masks (#10479 review)

* fix: recycle knockout, CMYK and GPU shape masks; release the pool when Split/Merge Channels close a document (#10479 review)

* fix: recycle knockout, CMYK and GPU shape masks; release the pool when Split/Merge Channels close a document (#10479 review)

* fix: release the pool when a closed document's cancelled workers exit; idle-release switch for tests; don't pool PSD planes (#10479 review)

* fix: release the pool when a closed document's cancelled workers exit; idle-release switch for tests; don't pool PSD planes (#10479 review)

* fix: release the pool for workers cancelled before their document closes; take the pool lock for budget and idle-release changes (#10479 review)

* fix: release the pool for workers cancelled before their document closes; take the pool lock for budget and idle-release changes (#10479 review)

* fix: idle release rechecks activity under the lock; try_take_exact releases the pool and retries before failing (#10479 review)

* fix: idle release rechecks activity under the lock; try_take_exact releases the pool and retries before failing (#10479 review)

* test: cover a successful try_take_exact miss; name the failed-reservation test for what it checks (#10479 review)

* test: cover a successful try_take_exact miss; name the failed-reservation test for what it checks (#10479 review)

* fix: pool the final GPU effect shape buffer and return it after use (#10479 review)

* fix: pool the final GPU effect shape buffer and return it after use (#10479 review)

* docs: describe scratch pool lifecycle regression invariants

* test: verify polling releases cancelled document scratch buffers

* perf: recycle remaining transform selection and PSD scratch buffers

* fix: free PSD gather bands before allocating channel planes

* test: assert exact scratch take reuses pooled storage
2026-11-02 09:30:46 +01:00
Fabio Lissi 03799b62bc Keep recorded layer targets portable across documents 2026-11-01 23:54:42 -06:00
yoriswind 4fc3b9ee83 Use supported saved RAW settings for noninteractive Batch opening 2026-11-01 21:29:19 -08:00
yoriswind d898e46030 Apply Batch profile policy without losing import diagnostics 2026-11-01 21:25:16 -08:00
Fabio Lissi 21c0444559 Merge current main and preserve portable action recording 2026-11-01 23:01:23 -06:00
yoriswind d656c0f6e1 Replay Batch Override Open with scoped input bindings 2026-11-01 21:00:59 -08:00
David Mann c5ad3ed53b Merge PR #9274: Support editing selected color channel sets
# Conflicts:
#	docs/gaps.md
#	docs/ui-parity.md
2026-10-30 14:28:46 +01:00
David Mann b2db24400e Merge main at b1cfff9d3 into integration batch 10
Conflicts resolved as unions of both sides: codecs re-exports (PngRows + TiffBands), smart_cmds source imports
(main's source_surface_from_buffer and cache API with #8571's svg_source_image_in/convert_svg_source; main's
duplicate rendering import dropped), io flat.rs test modules (#8536's banded TIFF tests and main's PNG ones),
menus/invoke.rs (#8571's smart SVG intercept and main's layer.selectUnderCursor), state.rs (#8311's
type_box_overflow and main's type_insertion_style), the canvas_geom test keeps the is_finite guard, docs
status lines keep both change lists, i18n catalogs keep both sides' rows (hi.tsv: main's wording where both
added the same string).
2026-10-30 14:28:02 +01:00
David Mann f5ae6d5276 Merge main into pr-9274-fixup
# Conflicts:
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/dialogs/adjust_editors/curves.rs
#	docs/gaps.md
#	docs/target-app-parity.md
#	docs/ui-parity.md
2026-10-30 13:16:39 +01:00
David Mann 355831f845 Merge PR #7621: Play .atn steps that switch to another open document
# Conflicts:
#	docs/gaps.md
2026-10-29 20:04:40 +01:00
FredApps 255ecc81d0 Remove 21 requested PR contributions from the 108-PR integration
Retain 87 PRs. Reconcile overlapping integration fixes and update testing scope.
Removed: #7153 #7742 #5493 #9282 #3455 #9172 #3139 #3967 #4783 #5453 #8347 #1991 #3345 #4042 #4305 #4883 #4890 #5090 #6621 #5870 #5939.

Combined CI pending for this source; historical portable artifact is not applicable.
2026-10-29 18:49:17 +01:00