- io tests/it/psd_structure.rs: main's Duotone test compares the raw
block as a slice now that #5815 shares it as Arc<[u8]>.
- ru and fr catalogs: main and #6658 both added "Continue" with the same
translation; the second copy goes (bundled_catalogs_are_consistent).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Main's #8644 builds each crate's integration tests as one binary; #3356's
cmyk_export.rs and #5769's cylinder_warp.rs move into crates/io/tests/it.
docs/scorecard.md regenerated for the batch (#5485 DIST-220-1, #6055
UI-217-17, preferences).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
After merging main, the Layer Style dialog always sends From/To as 8-bit
hex (#7072). On a baked Gradient Overlay without a source record (PSD or
.asl import) the custom and no-record paths wrote those hex ends back,
so OK without a change rounded the curve's ends (a Smooth bake's white
end 0.99999994 became 1.0, Lab ends became RGB). Like edit_endpoint for
the recorded source, a hex end that only repeats the current end is now
left out. baked_overlay_is_unchanged_until_method_selection_then_edits_
the_whole_curve fails without this.
Co-authored-by: oRE-o <42003350+oRE-o@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
After merging main, the Type tool's path target fell back to the Work
Path over its whole inside, while main's #6551 only draws an unselected
Work Path for path tools. Ctrl-click Load as Selection (or deselecting
the Work Path) and a Type tool click inside it started area type in a
path nobody could see. Now the Work Path's inside counts only while it
is selected in Paths (drawn), its outline still takes type on a path
with main's 6 px band, and a missed shape path falls back to the Work
Path as on main. an_unselected_work_path_is_not_an_area_target fails
without this.
Co-authored-by: SillySilk <31193727+SillySilk@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- crates/ui-egui/src/layer_style.rs: values_of keeps the PR's method/smoothness keys and source-stop ends, and main's (#7072) unconditional From/To and geometry fields.
- crates/compose/src/cmyk_tests.rs (no textual conflict): add the PR's new `interpolation: None` field to main's CMYK test GradientOverlay literal.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
crates/io/src/lib.rs: kept main's ImportOptions; import_for_open/_with and import_stages now take &ImportOptions (plus the PR's damaged flag); import_with_options_and_interrupt delegates to import_for_open_with.
crates/engine/src/jobs.rs: open job decodes via import_for_open_with(&opts) so the damage flag reaches the held-open path; main's raw_defaults and docId kept.
crates/ui-egui/src/lib.rs: open_bytes_from uses main's import_options + raw_defaults and the PR's PSD damage check via import_for_open(&opts).
Also: moved crates/io/tests/psd_recovery_generated.rs to tests/it/ (mod added, support path fixed) and adapted PR tests to ImportOptions.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Conflicts:
- crates/ui-egui/src/i18n/{cs,de,el,es,fr,hu,id,it,ja,ko,nl,pl,pt-br,ru,sr,tr,uk,vi,zh-hans,zh-hant}.tsv: kept every key of both sides (main's block, then the PR's Color panel block); no duplicate keys.
- crates/ui-egui/src/panels.rs: took the PR's removal of color_picker/hsb_sliders/rgb_sliders (moved to color_panel_ui.rs); kept main's color_field_height doc comment; main's #5842 slider recolour tests ported to color_panel_tests.rs for the new HSB/RGB slider modes; main's black-HSB test dropped as the PR's hsb_sliders_take_values_on_black covers it.
- crates/ui-egui/src/color_panel_ui.rs (no textual conflict, adapted): set_color now goes through apply_color::foreground_changed with the gesture (was type_tool::foreground_changed), so every mode (sliders, ramp, alerts, wheel) recolours selected type/shapes tool-gated in one undo step per gesture; panel() calls apply_color::track_focus.
- crates/ui-egui/src/color_panel_tests.rs (adapted): new every_slider_mode_recolours_the_selected_shape test.
- docs/gaps.md, docs/ui-parity.md: union of both sides' status lines, rows and revision history; the PR's done row replaces the old "missing" Color panel row.
- docs/scorecard.md: generated, took b7-base's version.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- crates/engine/src/tests.rs: kept both tests (main's restore_layer_selection test and the PR's history_states_share_large_document_payloads).
- crates/io/src/psd_import.rs: kept main's parsed Duotone inks (duotone_map) with the PR's Arc<[u8]> psd_raw; also main's unknown-adjustment-key import (#6575) now builds Arc<[u8]> raw.
- crates/io/tests/adjust_warnings.rs: moved to tests/it/adjust_warnings.rs on main; PR's .into() edits applied there, plus #6322's Color Lookup test (raw.as_slice().into()).
- docs/architecture.md: union; status line names both changes, both revision-history rows kept.
- Adapted main-new sites to the PR's types: psd_export.rs (Duotone write-back via as_deref/to_vec, Unsupported block compare by slice), inspect.rs and ui-egui unsupported_marker_tests.rs (raw .into()), io tests/it/psd_unknown_adjustment.rs (slice compare).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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>
Conflicts resolved:
- crates/ui-egui/src/i18n/hu.tsv: kept base's Bevel & Emboss keys, then the PR's update-check keys
- crates/ui-egui/src/i18n/ru.tsv: kept base's Bevel & Emboss keys, then the PR's update-check keys
- crates/ui-egui/src/i18n/sr.tsv: kept base's added sections, then the PR's update-check keys
- crates/ui-egui/src/i18n/tr.tsv: kept base's Bevel & Emboss keys, then the PR's update-check keys
- crates/ui-egui/src/menus.rs: kept base's saved-workspace entries, then the PR's Help › Check for Updates reordering
- docs/gaps.md: base status line with the PR's G17 clause prepended; PR revision row above base's rows
- docs/target-app-parity.md: base status line (updated 2026-10-22) with the PR's clause prepended; PR revision row above base's rows
- docs/scorecard.md: generated, took b7-base's version
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Conflicts:
- crates/ui-egui/src/panels.rs: took b7-base's file (keeps align_bar in the Move bar and all other main changes) and re-applied the PR's change: dropped the six `if t.pro` guards (Marquee, Lasso, Paint Bucket, Perspective Crop, Crop, Move) and deleted the eight non-Pro hint/fallback arms (incl. the Studio Move arm, now covered by the Pro arm which already has Auto-Select, Show Transform Controls and align_bar); rustfmt reindent.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Restore suspended recording when the Displace map picker is canceled or fails. Reject control requests that replace a dialog continuation token. Cover failure and successful continuation paths with regression tests.
PR #8680
Exporting artboard assets at the full board wrote a blank, fully
transparent board-size PNG for an empty artboard, or one whose contents
all sit outside the board. main refused those with "the layer is empty",
and Photoshop's Generator refuses a zero-bounds pixmap before it pads to
the board. The board is now used only when its composite has a visible
pixel; otherwise the asset fails with "the layer is empty".
Test: image_assets_refuse_empty_artboards (an empty transparent board and
a board whose only layer is outside it) expects no files and two "the
layer is empty" errors; without the check both are written as blank PNGs.
Co-authored-by: IbrahimOezhan <89545837+IbrahimOezhan@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Main now builds each crate's integration tests as one binary (crates/ui-egui/tests/it). The PR's
tests/eyedropper_ring.rs moves to tests/it/eyedropper_ring.rs behind `mod eyedropper_ring;`,
and both wgpu tests take photocraft_testkit::gpu_lock() like their neighbours.
ring_reads_over_a_flat_area_of_its_own_colour still fails with main's canvas.rs and passes with the PR's.
Co-authored-by: mroxso <24775431+mroxso@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
When the file on disk is already version 2 (another instance saved the
migrated "on"), the save base took this instance's current value, so
turning the switch off here before the first save matched the base and
was never written; the file kept "on". The base now holds the migrated
value (on), so only a change made here since loading is written.
Test: turning_the_shift_tool_switch_off_is_saved_over_another_instances_migration
(fails with the previous base: true kept instead of false).
Co-authored-by: Higgs32584 <55243596+Higgs32584@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Photoshop constrains a Shift-mid-drag selection move to multiples of 45°
("Move a selection border"), and the Move tool's drag of selected pixels
already uses TRANSFORM_DIRECTIONS (8). selection_drag_to used
MOVE_DIRECTIONS (4), so a near-diagonal Shift drag (delta 13,11) snapped
to the horizontal axis (13,0) instead of 45° (12,12).
Test: shift_constrains_a_selection_drag_to_an_axis gains a diagonal case
(fails with 4 directions); the floating-drag test moves to (34,22) so it
stays an axis case with 8 directions.
Co-authored-by: mroxso <24775431+mroxso@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Apply Image dialog sends Channels-panel names in sourceChannel ("RGB" by
default, "Red", "Alpha 1"), but the export matched only lowercase keys, so a
dialog-recorded Apply Image failed strict .atn export. Channel names now map
case-insensitively (RGB/CMYK/Lab to the composite), an alpha channel is written
as a Chnl name reference and read back on import, and a numeric layer or channel
selector is refused instead of becoming the merged composite.
Tests: apply_image_dialog_channel_names_survive_a_strict_export (the dialog's
exact params) and apply_image_numeric_source_selectors_are_refused; both fail
without the fix.
Co-authored-by: VishnuByrraju <112673081+VishnuByrraju@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The two pixel/checker tests wrapped all of harness() in catch_unwind, so a
failing fixture command or a panic in the first 12 frames was reported as
"no offscreen graphics adapter" and the test passed without checking
anything (CodeRabbit thread on line 107). harness() now runs the fixture
commands first, catches only the wgpu renderer creation (the one step that
panics without an adapter) and builds and steps the harness outside it.
fixture_failures_are_not_skipped_as_a_missing_adapter feeds a 0x0 document:
with the old catch-all it was swallowed and the test fails; now it panics.
Co-authored-by: hogawish <60434858+hogawish@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The parallel build skipped a non-map pipeline whose creation raised an
error, so with new_with_format (errors logged, compositor still returned)
its key was missing from kit.pipelines and the first draw panicked on the
`self.kit.pipelines[&(kernel, acc)]` index. As before the PR, a failed
non-map pipeline now keeps its invalid handle (draws report GPU errors);
only a failed effect-map pipeline is skipped (all maps go to the CPU).
Test: a_compositor_with_failed_pipelines_draws_without_panicking builds
new_with_format(Rgb9e5Ufloat) on a device with an uncaptured-error
handler and renders: it panicked at the index without the fix. The PR's
test moves into tests/it (one test binary) and takes GPU_LOCK.
Co-authored-by: 00xJS <56056764+00xJS@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The PR gives an Outside stroke no share beneath fully covered pixels on the
CPU, but no test failed without it: under a Normal layer the opaque pixel hides
the stroke anyway. It shows with Blend Interior Effects as Group on a Multiply
layer: main multiplied the red interior with the blue stroke beneath it (black).
New test outside_stroke_under_multiply_layer_leaves_interior_to_backdrop
(raster and filled shape) fails on main's effects.rs, passes with the PR.
The GPU compositor mirrored the old math (outline_share 1 at full coverage, and
1 under an opaque pixel layer); compose.wgsl now matches the CPU. Blend Interior
Effects as Group itself renders on the CPU, so on the GPU this is consistency;
a parity case pins non-Normal layers with an Outside stroke.
Co-authored-by: seotarek <30214297+seotarek@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The PR's test only called blend_label/blend_ps. This adds one through the
import entry point: a Set Lyr step with Md enm("BlnM","softLight") and a
Make layer step with Usng Md "luminosity", written with atn::write and
imported, must give layer.setProps blend "Soft Light" and layer.new.layer
mode "Luminosity" with no unsupported steps. Without the PR's table rows
the Set step is unsupported (and the Make falls back to Normal).
Co-authored-by: justinjohn0306 <34035011+justinjohn0306@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>