As in Photoshop, the Move tool's Show Transform Controls box and handles are an Extra: hiding
Extras hides them, and their handles stop responding (no hover cursor, a press doesn't start Free
Transform). Cmd+H again brings them back. Show Transform Controls and the layer are unchanged.
Fixes#6699
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- 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.
Merges main (8f09d122d). Conflicts: the replay_save doc comment (main added
file.export.exportAs replay) and the status lines and history rows of
docs/file-format-parity.md and docs/gaps.md; both sides kept.
The docs called FILE-215-19 done and said only Save As and Save a Copy ask.
Photoshop's JPEG Options also has Matte, the progressive scan count
(Scans 3-5) and the size preview, none of which is offered, and Baseline
Optimized writes the same file as Baseline for RGB (4:2:0). The row is now
partial with those gaps named, and the docs say File > Save asks too.
docs/scorecard.md is regenerated.
Adds jpeg_options_ui::tests::the_answer_reaches_the_encoder. Every UI test
used a fake exporter, so dropping `opts.encode.jpeg_format` from
ExportSettings::io_options (the desktop and web save path) left them all
green; this test writes a real JPEG through io_options and fails without it.
Co-authored-by: Michael Higgins <55243596+Higgs32584@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 20 i18n catalogs: main and the PR both appended a block at the end;
both kept, main's first. docs/gaps.md: main's text with the PR's
TYPE-218-2 change applied (G8 Missing, Evidence 5 done / 4 partial /
0 missing, revision row), dated 2026-10-22. docs/scorecard.md
regenerated with cargo xtask scorecard.
The TYPE-218-2 note now also says PSD doesn't store the paragraph
direction (crates/text psd.rs maps only the vertical WritingDirection),
so a direction set with the new buttons reopens from a PSD as Auto.
docs/localization-parity.md: the Arabic row said paragraph direction has
no UI (TYPE-218-2); it now has the buttons, the RTL caret is still missing.
Co-authored-by: tareqziad1998 <83318513+tareqziad1998@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 32-bit branch cut the slider to floor(|s| * 255) / 255, which only matches
Photoshop near 25 and 50 %: measured at every whole percent from -100 to +100
on a 32-bit document, Photoshop lowers by 1 - floor(|s| * 256) / 256 and raises
by 255 / (255 - floor(s * 254)) taken to 1/256 and capped at 32767/256 (201 of
201 exact). +100 gave 512x where Photoshop gives 128x, +90 9.8x for 9.44x.
It also kept the HSL saturation unclipped, which is inf at HSL lightness 1 and
0 and negative above 1: (2, 0, 0), red at +1 stop, turned NaN with any edit,
Hue +40 alone included, where Photoshop gives (2, 1.333, 0). The 32-bit branch
now scales the chroma around the lightness instead (same result in gamut),
on the CPU and in the shader, in whole numbers on both. Colorize clamps its
saturation before the 32-bit scaling, so a PSD's out-of-range value renders
the same on the GPU.
Tests (fail without this): thirty_two_bit_saturation_steps_match_photoshop,
thirty_two_bit_hue_saturation_keeps_bright_colours, the GPU parity
hdr_hue_saturation_bright_colours. Photoshop-oracle floor 188 -> 190 of 258,
measured after merging main.
Co-authored-by: Timothy Daly <100327160+timothydaly1@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merges main through #3283 (Smart Filters: distinct editors, shared
disclosure and stable alpha).
filter_dialog.rs: main's split of the preview into is_smart_edit,
smart_preview_factor and scale_preview_params is kept. The plug-in branch
from #7524 (plugin_cmds::scale_for_preview scales only declared pixel
lengths) moved into scale_preview_params, so it applies to a plug-in run
on its own and to a plug-in recorded as a smart filter.
smart_ui.rs open_editor: main's smart_filter_dialog::target flow and the
shared adjust/filter dialog opening are kept; the Liquify re-open with
recorded strokes (r4) stays ahead of it. The old per-adjustment
edit_filter call is dropped with main's rewrite.
Resolutions: CLI usage, flag lists and flag parsing carry both --tiff-compression (t15) and
--jpeg-format (t16); file.saveACopy, batch, imageProcessor and layersToFiles param specs carry
both tiffCompression and jpegFormat; file_cmds keeps tiff_compression_param and
jpeg_format_param; atn_cmds keeps flag_set/applies_at_canvas_bounds (t15) and UNHOLDABLE (t16),
edit.transform uses the pixel_target guard (t15) with layer_ref(p)? (t16); ui-egui open paths
build ImportOptions (t16) and apply raw_defaults (t15); docs headers/rows unioned; atn tests keep
both sides; tr.tsv "Keep Using CPU" kept once.
crates/io/tests/corpus.rs: kept main's pass_floor 188 (the PR's 187 would lower it; not re-measured here)
docs/file-format-parity.md: kept main's header and PSD/PSB rows; added the PR's change-log row without its floor figure
docs/gaps.md: kept main's header and evidence line; added the PR's change-log row without its floor figure
docs/scorecard.md: ours
crates/io/tests/corpus.rs: kept main's pass_floor 188 (TAKE-FIX: drop the PR's 186 hunk)
docs/file-format-parity.md: kept main's header and PSD/PSB rows; added the PR's change-log row without its floor figure
docs/gaps.md: kept main's header and evidence line; added the PR's change-log row without its floor figure
docs/scorecard.md: ours
docs/gaps.md: header and change-log row once each (the PR's row on top).
docs/ui-parity.md: header and change-log row once each; the Selection row keeps main's #6549 sentence and adds the PR's #6548 sentence.
The Hand tool's held Zoom goes through `zoom_tool::drag`, so with Scrubby
Zoom off a ⌘-drag draws a zoom rectangle rather than scrubbing. Say so in
the parity row, and test that case.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
crates/format/src/store.rs: the Windows tiles/blobs directory flush goes before main's manifest write (main publishes the manifest before removing stale previews), and that write takes the PR's fs argument; the PR's second manifest write is dropped.
crates/ui-egui/src/lib.rs: replay_save doc comment names both Export As and JPEG; replay_save uses the PR's FormatChoices::from_step, after main's export_dialog::replay branch.
docs/file-format-parity.md: header keeps main's text plus the JPEG Options item (last updated 2026-10-19); TIFF row is main's, JPEG row is the PR's; change-log rows once each, newest first.
docs/gaps.md: header keeps main's text plus the G10 item (last updated 2026-10-19).
Conflicts:
docs/gaps.md: header line is ours plus the PR's missing change item (later Last updated date); change-log rows kept both, newest first
docs/file-format-parity.md: same
crates/engine/src/float_cmds.rs: kept main's cut_piece (parallel, shares full tiles) and try_lift_coverage, and the PR's CutParts::outline; the outline is read from the piece's alpha, which holds min(alpha, selection) as the PR's own lift loop computed, instead of replacing cut_piece with that loop.
crates/engine/src/float_cmds/tests.rs: git interleaved the two sides' new tests; took main's file and appended the PR's added tests whole.
docs/ui-parity.md: header line keeps main's text plus the PR's #7538 item.
Conflicts:
docs/gaps.md: header line is ours plus the PR's missing change item (later Last updated date); change-log rows kept both, newest first
docs/file-format-parity.md: same
crates/ui-egui/src/i18n/*.tsv (20 catalogs): both sides appended rows at the same place; union, no duplicate keys.
crates/ui-egui/src/state.rs: both new ToolOptions fields (type_style_defaults, type_direction) and defaults.
crates/ui-egui/src/tool_reset.rs: Type tools reset both type_direction and type_style_defaults.
crates/ui-egui/src/type_tool.rs: new type is created from default_style_params (main); direction added to it, and apply_defaults stores a direction edit in type_direction.
docs/gaps.md: header and G8 evidence from main, G8 missing text reworded for direction buttons, change-log lines of both.
docs/scorecard.md: ours (regenerated at combine).
crates/ui-egui/src/lib.rs: union in the PhotocraftApp fields, the initialiser and set_wgpu (main's window_device/window_lost/window_recovery_retry and set_available, the PR's gpu_render_state/gpu_fault).
docs/control-protocol.md: ui.gpu.simulateLoss line takes the PR's text and keeps main's destroy: true sentences.
crates/ui-egui/src/i18n/ru.tsv: both sides added rows at two places; kept both (union).
docs/gaps.md: header from main, change-log lines of both.
docs/localization-parity.md: change-log lines of both.
crates/format/src/store.rs: kept both field sets in PcraftWriter::default (main's blob_hash_cache/compressed_budget and the PR's lock_wait) and both setters (set_compressed_cache_budget, set_lock_wait).