Port behavior and regression coverage into current modules; preserve current upstream behavior.
Extended current crop menu with Reset and shield toggles, preserving newer preset management, overlays, ownership checks and no-menu-during-gesture logic. Ported reset-frame no-op/undo semantics into current CropState/release and crop commit; retained original regression cases in split modules.
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Ported hanging punctuation into current line placement and kerning modules, preserving forced breaks, bounded edge-tip row merging, justified-last-line behavior, area exclusions and independent Roman orientation shaping; kept PSD/engine/UI regression coverage.
davidmann4's round-3 review of #8347: a marks row the box had to split
out of a run folded row after row into one line running past the edge by
almost the whole run, and a row merged into a justified paragraph's last
line kept the row above's spread instead of the last-line align.
- A marks-only row steps back only while it is at most two clusters (the
tip that hangs at the edge); a row above that already ends in a
hangable mark takes no more.
- A justified paragraph's last row keeps its own align (centered, right
or left): the placed clusters already carry the spread, and the merge
only moves x1/range.end.
- hanging_marks_of_a_split_run_keep_their_breaks pins that a run keeps
its rows and no line outgrows the box by more than two marks;
hanging_marks_stay_off_a_justified_paragraphs_last_line pins the
JustifyCenter/Right/All last lines. The old merged-row test now pins
the tip (a_stepped_mark_row_keeps_its_clusters_and_glyphs_in_step).
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>
Earlier PhotoCraft versions kept the 1053 of a Photoshop file they opened
and wrote it back unchanged, while storing spot channels added there
straight. A transparent Photoshop document carries 1053 = [0], so a white
plate added to it in 0.16.0 or earlier sat behind a 1053, and the rule
read that file in Photoshop's polarity: the added spot opened inverted.
A 1053 that lists fewer channels (non-zero ids; 0 is the transparency's)
than the file has after its transparency now counts as kept, with the
PhotoCraft 1057 and DisplayInfo spot conditions unchanged. Planes the
kept 1053 lists stay in Photoshop's polarity (they are the Photoshop
file's own); the ones after them are read straight. Photoshop and this
version write one id per extra channel, so their files are unaffected.
Known limit, as before: channels reordered there, or as many deleted as
added, can't be told apart from the Photoshop file's own.
The earlier versions are 0.1.0 to 0.16.0, not 0.11.1: every release
since writes the same 1057 and straight spot planes without a 1053.
Co-authored-by: jasallen <615848+jasallen@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
Merged with our fix-up pr-3297-fixup (1de1e9eb58) on top of the author's head 053e1e0d03.
Conflicts resolved: channel_cmds.rs routed() keeps the PR's PAINT_IDS list plus the batch's
paint.artHistoryBrush; paint_cmds.rs Paint Bucket params keep the batch's "mode" and the PR's
"filterMask" target; docs/scorecard.md takes the batch's numbers with FILE-215-3 done.
Merged with our fix-up d5139d177 (pr-1199-fixup), which merged main as of 8f09d122d.
Conflicts with main since then and with batch 8:
- photocraft-cli: main split the CLI into clap modules (#7071); the model wiring
(local_headless, configure_cli_models, batch's shared backend, droplet) is re-applied there.
- Cargo.lock regenerated: crates/ml pins ureq =3.4.2, so the app's ureq goes 3.5.0 -> 3.4.2.
- cutout_cmds: main's subject area (#8235) kept for the classical path beside the model path.
- file_cmds batch: main's per-input closure takes `s` later, so the backend and
integrations prefs are read before the closure instead of inside it.
- prefs_ui: model-choice filter with #4573's pref_choice_label; Integrations stays visible
(#4097) with the model choices only where models run; the translation-coverage test main
deleted (c3aa3f9e5) stays deleted; old section_fields test calls take PreferenceFieldOptions.
- Semantic clashes git did not flag: #4097's Integrations test literals in
apps/photocraft take ..Default::default() for the new model fields; main's and #4573's
section_fields test calls pass PreferenceFieldOptions.
- engine lib.rs, prefs.rs, smartselect tests, snapshot example, jobs_ui_tests, people.toml,
docs and i18n catalogs merged as unions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main moved the shape options bar and paint swatch out of vector_ui.rs into
shape_options.rs and shape_paint_ui.rs (#5452). Carry the PR's gradient paint
over: PaintChange::Gradient, paint_param and the swatch's Gradient tab live in
shape_paint_ui.rs, the tool gradients and set_tool_paint in shape_options.rs,
and shape_gradient_ui.rs is its own module. Both sides' new tests are kept.
Co-authored-by: Denis <179751626+deniskhud@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#6923 develops the Camera Raw dialog's preview on the GPU whenever no spatial stage is set,
from `per_pixel`'s stages. #5128 adds Calibration (primaries and Shadows tint) to the CPU
develop between white balance and Dehaze, which those stages don't run, so with both merged
a Calibration-only change previewed unchanged on the GPU while Open applied it. `per_pixel`
now returns None when Calibration is set, so the dialog develops on the CPU then. The
white and black points stay as they were, so the dialog's points cache is still right once
Calibration goes back to neutral. The hardware parity doc and BUG-204-3's note now say so.
Co-authored-by: Fabio Lissi <3223836+FabioLissi@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts:
- crates/ui-egui/src/canvas_tool_menu.rs: keep both the upstream type-layer
menu field (#7324) and this PR's crop menu fields (#6561) in the struct
literals and the auto-close condition.
- docs/context-menu-parity.md, docs/scorecard.md, scorecard/ui.toml: keep
both sides' status-line, revision-history and UI-217-8 note entries.
Semantic fix from the merge: crop_size::resamples called target() with the
old two-argument signature; pass the Point Size preference like the other
callers.
Resolves the conflicts with main's area type (TextShape::Area): EngineData keeps main's area arm beside the path comment, and a Txt2 frame of an area layer becomes a text box over the path's bounds, as its EngineData describes it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
prefs.rs keeps main's demosaic default and the PR's write_xmp_sidecars, and
unhides the Camera Raw Defaults the PR makes live; the raw-open RawOpen built
without the dialog gains main's developed_with/demosaic; i18n and docs as
unions; docs/scorecard.md is regenerated in the fix-up.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Tolerance defaulted to 50 and averaged alpha into the difference, so an
ordinary edit (e.g. #c03030 -> #d04848) was never painted back, and a stroke
that wrote nothing still left an empty History step. Photoshop's default is
0; the difference is now the larger of the mean colour change and the
alpha change (the Eraser keeps colour and lowers alpha), and a stroke that
writes nothing is an error instead of an empty step.
- Each tile copied a source window of tile +- halo per dab: a leftward stroke
or a curl across x = 64 read empty pixels there (seam), and a size-1000 click
copied ~5e9 floats (11.9 s). The rotated read stays inside the dab, so it now
samples the source directly; bilinear reads at pixel centres, so an
unrotated dab copies the history pixel instead of a 2x2 blend.
- The brush used its own history lookup (state 0 by default): it now takes
the History Brush's source (history.setSource, snapshots, refusal after a
canvas size change).
- TOOL-213-20 is partial (8 of 10 styles, Area scales spacing); docs follow.
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts with #5547 (Animated Zoom) resolved in wheel_nav.rs, canvas.rs and
panels.rs: the Navigator and canvas pass both Animated Zoom and
!animations_off; with Animation Effects off, the sideways part of an
animated wheel zoom pans by the frame's own events folded by their
modifiers (#4573's unsmoothed scroll) instead of the plain-event raw.x,
so Ctrl + wheel still pans sideways there. #4573's modifier test runs
with Animated Zoom off and on.
Translation catalogs keep main's strings plus the Art History Brush ones
(fr: main already has Area; hi: added the brush strings). docs/scorecard.md
regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Photoshop's documented hang list carries weights: period, comma, quote,
apostrophe and hyphen hang 100%, colon, semicolon, ellipsis and dash hang
50%; ! and ? are not in the list (davidmann4). The drawn positions never
change: the weights only come out of the composed width.
- A marks-only row after a forced break keeps its row: the merge-back must
not cross the author's break (CodeRabbit).
- The merge-back reads its pair style from the mapped byte; the box slack
and the justify-all path take the shaped advance scaled once and the
(already scaled) trim on top, so horizontal scale no longer scales the
trim twice; area type keeps its planned rows (hanging applies to point
and box lines only).
- The Styles editor row label goes through tl!, the dock comment loses its
(#...), space-before keeps upstream's arrow order, tests get abs() and
exact centering assertions; hi.tsv carries the label.
The row's own note says the window's Marquee tool and the Stamp's Heal modes
are still missing, so it stays partial; the scorecard is regenerated to match.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A preview job still running when the document changed stored its base
selection back, and the next preview reused it for the new pixels.
BaseCache now records its revision and compute reuses it only on a match.
Also describe TOOL-214-1 as the full-window workspace.
Brings in 412 commits from main (cf9ff2a2). Two conflicts:
- crates/ui-egui/src/lib.rs: main added updates_ui::tick right after
prefs_ui::tick, where this branch calls wheel_nav::unsmooth. Both stay,
main's first; the update tick reads no input.
- Cargo.lock: main's, with cargo adding back this branch's one line (the
desktop app's direct windows dependency).
docs/scorecard.md is regenerated; it differs from main only in UI-217-10.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in 72 commits from main (bde13687). Two conflicts:
- apps/photocraft-web/Cargo.toml: main added the web-sys RequestMode feature;
the list is main's plus this branch's MediaQueryList.
- crates/ui-egui/src/prefs_ui.rs: main deleted the translation-coverage test
preference_labels_are_translated (c3aa3f9e, missing translations are now
reported by xtask ci); this branch had only adjusted it, so it goes.
docs/scorecard.md is regenerated; it differs from main only in UI-217-10.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Select > Select and Mask... opens a full-window workspace laid out as
Photoshop's, replacing the parameter dialog:
- options bar: tool, add/subtract, Size, Hardness (Brush), Sample All
Layers, Select Subject, Refine Hair (greyed: #2671)
- tools: Quick Selection W, Refine Edge Brush R, Brush B, Object
Selection W, Lasso and Polygonal Lasso L (one slot), Hand H, Zoom Z;
Shift+W / Shift+L cycle
- the document under its tab, shown in the chosen view
- Properties: Remember Settings, View Mode (view letters, Show Edge J,
Show Original P, Real-Time Refinement, High Quality Preview,
Transparency/Opacity, Overlay colour and Indicates), Refine Mode
(Object Aware greyed: #2788), Edge Detection, Global Refinements with
Clear Selection and Invert, Output Settings; Reset, OK, Cancel
The tools become select.refineEdge `edits` (the Refine Edge Brush its
`refineStrokes`): OK is one history step, Cancel drops everything,
Ctrl+Z undoes per edit. The preview runs in the background on a reduced
copy (full size with High Quality Preview), reusing the selection after
the edits it already applied; Real-Time Refinement previews the stroke
being drawn. A targeted layer mask is refined and output to the mask.
Closes#7069. Closes#8148.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings split/tiff-channels-io at f53aa0b9 (PR 1 and PR 2 on main
1695f323). Resolutions:
- PsdExportOptions: main's read_linked_files kept; PR 3's
photoshop_spot_polarity switch stays removed, as this branch does.
- crates/io/src/lib.rs: main's import_psd(), calling
psd_to_document_decoded without the removed PsdImportOptions.
- docs: PR 3's and main's text, with this branch's PSD statements
re-applied (dated 2026-10-23). docs/scorecard.md is regenerated next.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
select.refineEdge takes `edits`: the Select and Mask workspace's Quick
Selection, Brush, Lasso, Object Selection, Select Subject, Clear Selection
and Invert, applied in order to the starting selection (or layer mask)
before the edge is refined. Cancel discards them, OK is one history step,
and agents drive them over MCP and the control channel.
- engine/select_mask_edits.rs: parse (bounded, every bad field an Err)
and a pure apply/apply_one the workspace preview can share
- algo matting::brush_region: soft round brush coverage (hardness)
- ATN export reports steps with edits instead of dropping them
- "Edits" label in the 21 catalogs
Part of #7069 and #8148 (the workspace UI follows in a second PR).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in 2794 commits from main (98de85c6). Resolved as the PR review
suggested:
- wheel_nav.rs, canvas.rs, panels.rs: main's read_with(.., smooth,
touch_gestures) stays, and its callers (the canvas's two wheel reads and the
Navigator) pass the resolved Animation Effects value,
!app.prefs_rt.animations_off, instead of the removed
interface.enable_animations. That flag works in every window, a second OS
window for a document included; unsmooth stays for the main window's panels
and lists.
- apps/photocraft/Cargo.toml: main's NSGraphics feature (Beep When Done) next
to this branch's NSAccessibility and NSWorkspace.
- docs/scorecard.md is regenerated; the UI-217-10 note says where the glide
is taken out now.
- French and Russian gained their own "On" entries on main, so this branch's
copies are dropped.
Co-Authored-By: Claude Opus 5.5 <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>
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>