152 Commits

Author SHA1 Message Date
aiongg fab871dadb Merge pull request #10535 from davidmann4/integration-batch-11
Integration batch 11: 9 ATN PRs on main
2026-11-01 19:11:02 -05:00
David Mann 5f63b3fe4c Integration: address CodeRabbit review of batch 11
- #8714: a Camera Raw Filter step imports only with a process version
  the PSD mapping has verified (PrVN/PrVe 5/184549376 or 6/251920384)
  and a CrVe text; other steps stay kept steps that save back unchanged.
- #7642: the patternName fallback matches names only, so a pattern
  whose id equals that text no longer wins. A step that names its
  pattern only by patternName exports that name.
- #8327: the iso-2022-jp label is refused (its names are 7-bit escape
  sequences that would pass through as ASCII).
- #10417: the Levels export gate also refuses endpoints of the wrong
  shape (both ends text, a text gamma) and channels that aren't objects.
- #10459: a set paused at a step dialog keeps the rest of the set by
  action name, so actions.move while the dialog is open neither plays a
  foreign action nor skips one; "Played N steps" covers the whole Play
  (steps before the pause and the dialog's own step); the suggested .atn
  name is cut to 255 bytes at a character boundary; actions.list returns
  every set, empty ones too; set_names dedups with a HashSet.

Co-authored-by: FinnNk <1424666+FinnNk@users.noreply.github.com>
Co-authored-by: Silvertree2010 <133535268+Silvertree2010@users.noreply.github.com>
Co-authored-by: regexer <3689390+regexer@users.noreply.github.com>
Co-authored-by: marshiyar <57055687+marshiyar@users.noreply.github.com>
Co-authored-by: hectorviov <1501713+hectorviov@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 17:51:02 +01:00
Khawar Zamman Wani 209bce8d46 Budget PSD pattern expansion and bound multichannel conversion (#10541)
* Stream PSD user and real masks into tile rows

* Correct streamed-mask fixture metadata and test lint issues

* Budget PSD pattern expansion and bound multichannel conversion

---------

Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-11-01 16:00:21 +01:00
David Mann bb8edaf596 Merge PR #8327: Actions: read .atn step names in the code page Photoshop wrote them in (#6743)
# Conflicts:
#	contributors/people.toml
#	crates/engine/src/cmd/atn_cmds/tests.rs
2026-11-01 15:36:45 +01:00
David Mann 7e50896afb Integration: drop the glued-letter rule again (#8327)
The previous fix-up counted a letter glued to an ASCII letter as common
only when it was Latin. That turned ordinary windows-1251 names such as
"CMYKканал" or Ukrainian "Копiя" (Latin i) into a windows-1252 (or GBK)
reading of the whole set, with no warning, where the PR read them right.

Back to the PR's scoring for single-byte pages; the ¥ removal stays.
windows-1252 "Fläche m²" / "Preis £5" reading as windows-1251 is the
PR's own known limitation, now noted in the code. A Russian set plus
"CMYKканал" is pinned as windows-1251.

Co-authored-by: regexer <3689390+regexer@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:35:14 +01:00
David Mann bd04a88292 Integration: keep Mac Roman bullets and Latin words out of the wrong page (#8327)
Mac Roman 0xA5 is the bullet, windows-1252 0xA5 is ¥: with ¥ counted in
the windows-1252 re-weigh, Mac "Ebene • Kopie" read as "Ebene ¥ Kopie".
Drop ¥; the other kept symbols are no letter or typographic mark in Mac
Roman.

windows-1251 has І і д where windows-1252 has ² ³ ä, so "Fläche m²" read
as "Flдche mІ" (already so in the PR head; main showed it right). In a
single-byte page, a letter glued to an ASCII letter now counts as common
only when it is a Latin letter. Real Cyrillic names ("Новый слой",
"Копия слоя 2", "Канал RGB") still read as windows-1251. "Preis £5"
(Ј between a space and a digit) still reads as windows-1251; documented.

Co-authored-by: regexer <3689390+regexer@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:19:58 +01:00
David Mann 1d0bc23c3e Integration: don't count symbols on Mac Roman letters as windows-1252 (#8327)
The previous fix-up counted § ® ¾ ¿ (and ¹ » ¼ ½) as common windows-1252
text, but those bytes are Mac Roman ß Æ æ ø (π ª º Ω). Mac names with no
Unicode copy such as "Weiß", "Gaußscher Weichzeichner", "Størrelse",
"Lærredstørrelse" and "Æble" then tied and read as windows-1252 ("Wei§",
"St¿rrelse"), where the PR read them right.

Keep only the 12 symbols whose byte is not a letter in Mac Roman
(¡ ¢ £ ¥ © « ° ± ² ³ ¶ ·). Windows "Größe »", "50 °" and "« auto »" still
read as windows-1252; a name whose only non-ASCII character is ® ("Logo
®") reads as Mac Roman "Logo Æ" again, as on the PR head (tested as a
known limitation).

Co-authored-by: regexer <3689390+regexer@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:00:36 +01:00
David Mann af59f65b82 Integration: keep windows-1252 symbols in .atn step names (#8327)
The code-page guess counted only letters and typographic marks as common
text in single-byte pages, so a Windows step name with no Unicode copy and
a Latin-1 symbol read better as Mac Roman, whose letters sit on those
bytes: "Logo ®" showed as "Logo Æ", "Größe »" as "Grˆfle ª" (main showed
them right), and Save Actions wrote that text back.

When the guess lands on Mac Roman, weigh it against windows-1252 once more
with common Latin-1 symbols (© ® ° § « » ± ½ …) counted and the letters
windows-1252 has only at 0x80-0x9F left out. Mac Roman keeps the names
only when it still reads better; a tie goes to windows-1252, confident
with a Latin hint and flagged uncertain otherwise. Mac Roman "Größe",
"Ändern", "Contrôle", "Arrière-plan" and the corpus French sets still read
as Mac Roman.

Co-authored-by: regexer <3689390+regexer@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:43:03 +01:00
David Mann 5ff10e120d Integration: keep the NaN-safe .atn fuzz invariant (#7561)
The previous fix-up put main's atn fuzz target back. It compares the
parsed actions with assert_eq!, so any valid file holding a NaN double
fails the fuzzer falsely (NaN != NaN); the PR's own contract test
nan_payloads_signed_zero_and_infinities_survive_without_false_fuzz_failures
covers exactly that. The target now calls the shared check again, at its
new path under tests/it/common.

Co-authored-by: denstu473 <63150090+denstu473@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:30:55 +01:00
David Mann d86f678325 Merge main into #8327 2026-11-01 14:27:37 +01:00
David Mann 4b053e15ae Integration: keep the ATN contract tests, drop the extra workflow (#7561)
The contract tests no longer compiled on main (AtnItem::dictionary is now
Vec<u8>, so it is compared with b"Future event"), sat outside main's
tests/it layout, and the new atn.yml added six legs (two macOS) to every
PR against ci.yml's policy. Move the tests into tests/it so the existing
CI runs them, drop atn.yml and docs/atn-testing.md, keep main's ci.yml and
fuzz target, and note the committed fixtures in ATTRIBUTION.md.

Co-authored-by: denstu473 <63150090+denstu473@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:25:51 +01:00
David Mann 893d12bee2 Merge main into #7561 2026-11-01 14:19:49 +01:00
Khawar Zamman Wani 97a83f074f Bound PSD layer and mask import memory before decoding (#10503)
* Bound PSD import pixel storage before decoding

* Include ZIP inflater workspace in PSD preflight

* PSD import: budget unknown-mode layers, stop after a fatal layer error, keep best-effort for non-allocation limits (#8593 review)
2026-11-01 12:33:09 +01:00
Ben Huyck d8244139bc Actions: read .atn step names in the code page Photoshop wrote them in (#6743) 2026-10-30 09:43:49 +00:00
Ben Huyck fe7f48fe2e PSD: guess the legacy code page of 8-bit names (#6743) 2026-10-30 09:43:49 +00:00
Dylan M. Taylor ba25f585bd Refactor psd for strict Clippy checks 2026-10-27 23:47:06 +00:00
David Mann 5ccb6fb723 Merge main
Conflicts with main's batch #9880:
- psd file.rs / layer.rs: #5287 (PSB by encoded size, RLE tables widened on
  promotion) against #6583's lazy reader. Main's new widening and length code
  read `.data`, which #6583 leaves empty while the bytes stay in the source;
  it now goes through `encoded()` / `encoded_len()` (also the auto-merged
  lines in `rle_widening`, `encoded_len` and `LayerRecord::write`), and the
  lazy reader sets `write_as_psb: false`. New test
  `a_lazy_psd_promotes_to_the_same_psb_as_an_eager_one`: a lazily read PSD
  writes the same PSB bytes as an eager one; it fails with a `.data` read.
- direct_select.rs / vector_ui.rs: #9321's Type Path and #6353's hidden
  Work Path both kept.
- io tests main.rs: both modules. scorecard.md regenerated (12 of 181);
  ui-parity.md and gaps.md follow it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-27 19:49:42 +01:00
David Mann 3a689f217c Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	crates/engine/src/file_cmds.rs
#	crates/engine/src/retouch_cmds.rs
#	crates/engine/src/vector_cmds.rs
#	crates/io/src/psd_export.rs
#	crates/io/src/psd_import.rs
#	crates/io/src/smart_map.rs
#	crates/psd/src/layer.rs
#	crates/raster/src/lib.rs
#	crates/ui-egui/src/camera_raw_ui.rs
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/filter_dialog.rs
#	crates/ui-egui/src/gpu_canvas.rs
#	crates/ui-egui/src/panels.rs
#	crates/ui-egui/src/retouch_ui.rs
#	crates/ui-egui/src/transform_tool.rs
#	crates/ui-egui/src/vector_ui.rs
#	docs/gaps.md
2026-10-27 14:26:26 +01:00
David Mann c14a707d2a Merge PR #6583: PSD/PSB open without reading the whole file: channel data read as decoded, in bands into tiles (#5106)
Merged at the fix-up commit before its main merge (362947695d); the
conflicts with the batch are resolved here: psd_import.rs keeps both
sides' tests, tiff_layers.rs takes ImageData::new.
2026-10-27 13:50:37 +01:00
David Mann 362947695d Integration: a source read error in the layer records fails the open (#6583)
The lazy parse took any error from read_layer_info on a Layr/Lr16/Lr32
global block as a damaged block and dropped the layers. A failed read of
the source (PsdError::Read: a dropped network share, a file rewritten
while it opens) then let a 16/32-bit layered file open silently from its
merged image, with no damage warning, and a save replaced its layers.
A read error now fails the parse, as reading the whole file would.

The new test fails each read of a clean parse once, in turn, and checks
the parse either fails with the read error or matches from_bytes; with
the fix reverted, read 20 of the Lr16 sample drops the layers silently.

Found by CodeRabbit's review of the PR.

Co-authored-by: ptrinh <774083+ptrinh@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 13:28:32 +01:00
David Mann f428433ccb Merge main into fix/psd-size-encoded
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 02:59:27 +01:00
aiongg 1f0d1a4ef3 refactor(psd): move tiff.rs's transcode module to tiff/transcode.rs 2026-10-26 22:54:56 +00:00
aiongg 02d2de4b99 refactor(psd): move patterns.rs tests to patterns/tests.rs 2026-10-26 22:30:12 +00:00
aiongg 363a5797f8 refactor(psd): move compression.rs tests to compression/tests.rs 2026-10-26 22:30:11 +00:00
aiongg d314299d5b refactor(psd): move layer.rs tests to layer/tests.rs 2026-10-26 22:30:11 +00:00
aiongg 35107dccae refactor(psd): move tiff.rs tests to tiff/tests.rs 2026-10-26 22:13:07 +00:00
aiongg 5286968033 refactor(psd): move abr.rs tests to abr/tests.rs 2026-10-26 22:13:07 +00:00
David Mann 01adff1e5c Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	crates/io/src/psd_export.rs
#	crates/io/src/tiff_layers.rs
2026-10-26 14:32:07 +01:00
Phil Trinh 4915f0970e PSD/PSB open without reading the whole file: channel data read as it is decoded, in bands straight into tiles (#5106)
Opening a 2.14 GB PSD (2000×2000, 109 layers, 821 MB of embedded smart objects) peaked at
7.28 GB and took 6.8 s; it now peaks at 3.00 GB and takes 3.6 s (macOS peak memory footprint,
`cargo run --release -p photocraft-io --example psd_open_mem`).

- photocraft-psd: `PsdFile::from_source` parses from a `ReadAt` source (`FileSource`: pread /
  seek_read in bounded reads). Channel data and the merged image become `Stored` ranges read
  when decoded; the model equals `from_bytes`'s and writes back the same bytes (tests compare
  the two on every generated file, including Lr16/Lr32 layer blocks and truncated files).
- `ChannelData::row_decoder` decodes any band of rows: RLE via its row table (a stored channel
  reads only the band's bytes), raw by offset, ZIP inflated once.
- photocraft-io: `import_file` opens a path; PSD/PSB through `from_source`, other formats read
  whole. Layers decode in bands of whole tile rows (~32 MB) into tiles: no whole-layer plane or
  interleaved buffer. Global blocks move into the document instead of being copied; finding an
  embedded smart object no longer copies every file in `lnk2`.
- photocraft-raster: `Surface::share_uniform_tiles` + `TileInterner`; the PSD import shares
  single-value tiles (backgrounds, fill caches, masks) across layers.
- The background open job and the CLI/MCP (`automation::files::open`) use `import_file`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 02:37:20 +08:00
David Mann 38609e5615 Merge PR #8885: PSD: spot channels in Photoshop's polarity; PSDs from earlier PhotoCraft versions keep their ink
Merged with our fix-up branch pr-8885-fixup (8f6863f53) on the author's head 996b55eb4.

Conflicts resolved:
- crates/io/src/tiff_layers.rs: #9148's tiff_source (an empty LMsk gets Photoshop's 14 bytes)
  gives way to #8885's tiff_image_source, which writes the same bytes for an empty or short
  LMsk; #9148's test stays.
- crates/io/src/flat.rs: #8776's DDS alpha step and #8885's TIFF channel stamp both run.
- crates/io/Cargo.toml, Cargo.lock: #8402's zune dev-deps and #8885's tiff dev-dep.
- crates/io/tests/it/tiff_layers.rs, docs: unions; docs/scorecard.md kept as is, regenerated at
  the batch gate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 16:28:00 +01:00
David Mann 14693eb085 Integration: merge main 528491f9a, resolve conflicts
- crates/engine/src/edit_cmds.rs: copy_mask keeps #3297's filter-mask target and takes main's
  clipboard `source` (#8945).
- crates/cms/src/lutfile.rs: #9183's shaper doc comment next to main's UTF-16 decode_text (#9129).
- contributors/people.toml, docs: unions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 16:26:06 +01:00
David Mann 4365c0537d Integration: merge main, resolve conflicts (#8885)
psd_import.rs keeps main's warning for an incomplete merged extra channel
next to the PR's Photoshop spot polarity. people.toml takes main's entries
plus jasallen's own. Docs take both sides' status lines and revision rows;
docs/scorecard.md is regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 16:07:44 +01:00
Hector Villarreal 284f569264 fix(engine): defined and imported patterns survive a restart (#9317) (#9318)
* fix(engine): defined and imported patterns survive a restart (#9317)

The pattern library lived only in memory: patterns defined with Edit >
Define Pattern or imported from a .pat file were gone after a restart,
while their Patterns panel folders (saved with the preferences) still
named them. Photoshop keeps them.

The preset store now writes the user patterns (the library minus the
built-ins, in order) to patterns.pat, Photoshop's own pattern file
format, whenever their ids, names, sizes or order change, and loads
them when the store attaches. Like actions.json, a file that fails to
load is warned about and never overwritten. The web store accepts the
new record.

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

* Patterns: persist same-id pixel replacements, retry a failed removal

CodeRabbit (discussion_r4369506324, r4369506326):
- an imported .pat whose id is already in the library replaces its
  pixels, which the id/name/size key didn't show, so the old pixels came
  back after a restart; PatternLibrary::pixels_rev is bumped on such a
  replacement and is part of the key;
- a failed patterns.pat removal recorded the empty library as saved and
  was never retried, so the deleted pattern came back; it now stays
  pending, as a failed write does.

Tests: a_same_id_pattern_replacement_survives_a_restart,
a_failed_patterns_removal_is_retried.

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

* Patterns: persist replaced built-ins and ASL replacements

CodeRabbit (discussion_r4369536978, r4369536981):
- a .pat import that replaced a built-in pattern by id was filtered out
  as a built-in and never saved; only built-ins exactly as shipped
  (is_pristine_builtin) are skipped now, and on load a saved built-in
  takes the shipped one's place unless it changed before attachment;
- style.presets.importAsl replaced patterns by id without bumping
  pixels_rev; both imports now go through PatternLibrary::upsert.

Tests: an_imported_builtin_replacement_survives_a_restart,
an_asl_pattern_replacement_bumps_pixels_rev.

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

* .pat: refuse names and counts the reader won't load, on write too

CodeRabbit (review 5641404908, outside-diff, two findings): now that the
preset store writes the user patterns, a file its own loader rejects or
truncates loses patterns at the next start.
- a name of 65,536+ UTF-16 units (with its NUL) was written although the
  reader refuses it; write_pattern refuses it now;
- more than 100,000 patterns were written, and the reader kept the first
  100,000 without a word; both now refuse counts over MAX_PAT_PATTERNS.

Tests: a_name_the_reader_refuses_is_refused_on_write,
more_patterns_than_a_pat_file_holds_are_refused.

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

* Patterns: an early same-id import with other pixels is saved

CodeRabbit (review 5641454449, outside-diff, preset_store.rs:1191-1202):
a pattern imported before the store finished loading, with the id, name
and size of a saved one but other pixels, was appended (no pixels_rev
bump), won the merge, and then matched the loaded file's key, so it was
never written and a restart brought the old pixels back. The merge now
bumps pixels_rev when the copy it keeps differs from the saved one.

Test: an_early_same_id_import_wins_and_is_saved.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 10:18:23 -04:00
David Mann 5c51830482 Merge PR #8877: PSD: recognise Photoshop's MTrn merged-transparency marker
# Conflicts:
#	docs/file-format-parity.md
2026-10-25 14:26:41 +01:00
Roni Balthazar 81d842d307 fix(tiff): preserve PSD byte order in layered TIFF text descriptors (#9098) 2026-10-24 13:37:31 +01:00
David Mann 139f0c07f3 Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	crates/io/src/psd_export.rs
2026-10-24 02:38:23 +02:00
David Mann 8c04b175ec Merge remote-tracking branch 'origin/main' into integration-batch-7
# Conflicts:
#	crates/automation/src/rpc.rs
#	crates/automation/src/server.rs
#	crates/gpu/src/health.rs
#	crates/text/src/tests.rs
#	crates/ui-egui/src/i18n/zh-hans.tsv
#	crates/ui-egui/src/panels.rs
#	docs/control-protocol.md
#	docs/ui-parity.md
2026-10-24 00:23:15 +02:00
Michael Higgins 5697c40361 PSD: write pattern transparency where Photoshop keeps it (#8054) (#8756)
* PSD: write pattern transparency where Photoshop keeps it (#8054)

A pattern defined over transparency (delete the Background, Define
Pattern, then a Pattern Fill layer from it) was saved with its alpha
plane in the virtual memory array list's user mask slot (24), and
Photoshop refused the PSD. Photoshop keeps pattern transparency in the
last (sheet mask) slot and leaves the user mask unwritten (psd-tools
multichannel-pattern-fill.psd, written by Photoshop CC 2019). The same
writer serves `Patt`/`Pat2`/`Pat3`, `.pat` and `.abr`.

Files saved by older builds still open (the reader takes the first
written array after the colour channels as transparency), and saving
them again rewrites their pattern block instead of keeping the raw
bytes, which `block_has_user_mask` detects.

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

* PSD: rewrite only legacy pattern blocks, keep unreadable ones (#8054)

When the document's patterns are unchanged, a pattern block with
transparency in the user mask array is now rewritten in place from its
own patterns, and every other block (pattern blocks that fail to decode
included) is kept verbatim. Previously a legacy block forced the
replace-all path, which dropped an unreadable pattern block that an
unchanged save used to keep. Blocks are decoded in order with one shared
budget, as from_global_blocks does.

Addresses CodeRabbit review on #8756.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 17:41:08 -04:00
aiongg 7aaa59712a Merge main into integration-batch-7 2026-10-23 20:37:05 +00:00
Dylan M. Taylor 78ae50f7b2 security: bisect flat-table and gradient-stop lookups; charge ICC curve samples; bound PSD planes, RAW ljpeg retention and TIFF dump preview 2026-10-23 14:41:53 -04:00
Jason D e5be3083a7 Merge PR 1 (codecs, now on current main) into PR 3
Brings split/tiff-extra-samples-codecs at e6fca054, which merged main
1695f323. Conflicts:
- crates/io/src/lib.rs: main moved PSD import into import_psd(); it now
  passes PsdImportOptions::default().
- PsdExportOptions (psd_export.rs, tiff_layers.rs): main's new
  read_linked_files next to this branch's photoshop_spot_polarity.
- docs: main's newer status lines and rows, with this branch's TIFF
  statements re-applied (dated 2026-10-23). docs/scorecard.md is main's
  and is regenerated after PR 2 is merged too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 08:48:35 -04:00
Jason D 4e8605aea9 Merge current main into split/psd-mtrn-marker
Resolves docs/file-format-parity.md: main's newer status line and
revision rows, with this branch's MTrn entry on top (dated 2026-10-23).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 08:40:38 -04:00
Dylan M. Taylor 1695f323e6 fix(psd): retain pattern budget charges after parse failures (#8767)
Keep allocation charges monotonic when malformed pattern blocks fail, so later sections cannot reuse budget already consumed.

🤖 Generated with Codebuff

Co-authored-by: Codebuff <noreply@codebuff.com>
2026-10-23 08:38:15 -04:00
Dylan M. Taylor 9852baa4ba Merge pull request #8417 from dylanmtaylor/security/psd-slices-id-index
security: index slice IDs in PSD slices parser
2026-10-22 19:27:46 -04:00
David Mann 9487065314 Integration: merge main (one test binary per crate, #8644)
# Conflicts:
#	docs/file-format-parity.md
#	docs/gaps.md
#	docs/scorecard.md
#	scorecard/file_compat.toml
2026-10-22 19:55:06 +02:00
David Mann f5533e5d82 Integration: merge main into batch 6
Main merged #5940, #6472, #7838 and #7922 directly. Kept from the batch:
the snapshot/History-follow identity at the history limit (#5940,
c7ef3676a; main still had the 3-tuple HistorySpot) and the strokeless
shape at a 0 px width step (#6472, 962539607; main still added the
stroke). Main already carries the other two fix-ups (34c9d0ea4, dff8bfd0e).

Overlaps with main resolved:
- #5842 vs main's #5568: one path, apply_color, tool-gated as #5842
  has it, with #5568's float fill, kept fill opacity and lock skip;
  shape_fill_ui's duplicate foreground_changed/gesture dropped; #5568's
  tests run with a shape tool.
- #6230 vs main's #5180: one Type tool path click (path_target), no
  second type.attachToPath; vertical type does not start type on a path,
  as main has it; main's path_at/path_cursor and canvas arm dropped.
- #5452 moved the shape swatch to shape_paint_ui.rs: main's hex field
  (#6201) ported there.
- type_extra_cmds::with_text takes main's dpi form, pub(crate) for
  type_area_cmds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 19:20:26 +02:00
aiongg ffa400c754 Keep tests correct and docs current with one test binary per crate
- gpu: the test modules share one GPU_LOCK, and timing and vector_mask
  take it too, so one process drives one wgpu device at a time.
- ui-egui: the wgpu tests in pattern_preview_canvas, adjust_preview_gpu,
  marquee_autoscroll and layout_perf take gpu_lock().
- affinity compound_limits: the child process selects its test by the
  module path (compound_limits::<name>); with --exact, the bare name
  matches no test and the child passes without running the check.
- xtask scorecard reads crates/io/tests/it/corpus.rs.
- Docs and comments name the new test paths and the --test it filters.
2026-10-22 16:55:34 +00:00
aiongg a6428d3dfb Build each crate's integration tests as one binary
Every tests/*.rs file is its own executable that links the whole crate
graph. Move each crate's test files into tests/it/ as modules of one
tests/it/main.rs; helper modules under tests/common move with them.

These keep their own binary (own process):
- engine panic_hunt: a process-wide panic hook counts every panic.
- engine text_gamma: changes the process-wide text gamma.
- engine smart_filter_stages, mask_cache_purge: assert on global caches.
- codecs pnm_peak_memory: reads the process's peak RSS.
- photocraft mac_menu_appkit: harness = false.
2026-10-22 16:55:34 +00:00
aiongg 934eb71d84 Integration: merge main
crates/engine/src/file_cmds.rs: batch keeps the save-point closure (takes the output path) and also copies the session's authorize hook into each scratch session, as main now does.
crates/raw/src/sensor.rs: both sides cap the memory of retained tiles; kept the existing retained_segment_bytes check (checked multiplication, same limit) and dropped main's duplicate inline loop.
2026-10-22 15:39:51 +00:00
Dylan M. Taylor d0ad7ddb6f security(psd): check padding length before scanning it
FilterEffects::parse tested the trailing bytes with
rest.iter().all(|b| b == 0) before checking rest.len() <= 3, so every
loop iteration scanned the whole remaining buffer. A block with many
empty sections produced quadratic CPU work.

Reorder the short-circuiting && so the three-byte length check gates the
zero scan, making each padding check constant work. Behavior is
otherwise identical.

Finding: 4887ae49-cfda-43b0-9296-a1816fc1ddba (CWE-407)
2026-10-22 07:11:10 -04:00