The web build has no system fonts and embeds no craft fonts, so an Arabic
(or Japanese, Chinese, Korean, Hindi) interface had no font for its labels:
served fonts were registered only in the document text engine. A served
script fallback now also joins the end of every egui font family, and the
font stack theme::install_fonts rebuilds on a language change includes it
again. The web shell asks for the interface language's script font, not
only the browser languages'.
Review finding on #10006.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts in perf/budgets.toml and docs/scorecard.md: both sides added perf rows (P80 here, P81 and P82 from #9942). Kept all three; scorecard regenerated with cargo xtask scorecard.
Track-only rows that check they hit the whole-document-redraw path and
print the refreshed pixel count: undo of a brush dab on a 16-bit
15000x10000 full-canvas layer (reps capped at 5) and a fill of a 2 %
selection on a 24 MP full-canvas layer.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Track-only row, the slow-frame recorder's worst case. A 24 MP photo plus
three full-canvas blended copies (Multiply, Screen, Overlay); each sample
toggles the top copy and times one harness.step(), so every frame
recomposites all 24 MP on the CPU (the photo's tiles are never uniform,
which keeps the reduced render's one-colour shortcut out of the way).
The row errors unless each frame recorded a CPU refresh covering at least
95 % of the canvas, so it can't silently take a fast path. 10 samples.
Maintenance keeps the existing installation context, and a major upgrade of an
existing per-machine installation without ALLUSERS=1 is rejected rather than
installed per-user.
CodeRabbit on #9775: the 12-of-181 count changed today, so ui-parity.md and gaps.md get the date in their status lines and a revision-history row, as AGENTS.md asks.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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>
CodeRabbit on #9775: Place::AutoEditable puts type, shapes, pastes, placed files and frames above a group whose lock would refuse them; ui-parity.md's status line and checklist row said every new layer goes into an open active group.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
CodeRabbit on #9775: FontLibrary::finish wrote a failed type.font.favorite to the status bar as plain information; it now sets status_error like the other status writes. The regenerated scorecard counts 12 of 179 preferences that do nothing; ui-parity.md and gaps.md still said 178.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Main moved the engine commands into crates/engine/src/cmd/ and the
dialogs and panels into submodules. The PR's placement calls follow
them, and main's new insert sites (new_adjustment in adjust_params.rs,
Place in file_cmds/open.rs, shapes in vector_cmds/shape.rs) use
layer_place::insert_new like the PR's originals. The New Group dialog
moves to dialogs/new_group_ui.rs; the Layers panel flyout's New Group…
opens it.
Main's Session::precheck now also checks layer.new.group's and
layer.new.groupFromLayers' new params (name, color, mode, opacity,
position), so precheck_agrees_with_execute holds. Main had since added
"New Group…" to every catalog: the PR's duplicate rows are dropped.
Main's newer tests that made a layer with an open group active now
open the group last, as the PR did for the older ones.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Character section: a style picked under a family's ">" with type layers
selected set the layers but not the style for new type (the options bar
did both). Pick "Inter > Thin" in Properties > Character: new type stayed
Regular.
- Faux bold: a pointed tip moved r/sin(half its angle) along its bisector,
uncapped (3.9 r at 30 degrees, an A apex grew a spike), and tips sharper
than about 20 degrees did not move at all. Every tip now moves at most
2r, continuously; inner corners (the crotch of a V) keep their exact
miter.
- Faux bold: each point searched past runs of coincident points for its
neighbours, O(n^2); a contour of 50 000 copies of one point took ~8 s per
glyph. Neighbours now come from one O(n) pass over the runs.
- prefs.reset {"path":"type"} and Preferences > Type > Reset Section wiped
the favourite fonts; they are kept now (type.favoriteFonts by name, or
Reset All, still clear them).
- An expanded family whose own row scrolled out of view lost its style
rows, so the list below jumped up.
- Show Similar Fonts re-sorted around each font an arrow step applied, so
Down went back and forth between two fonts; the list now compares with
the font current when the filter was turned on (or the menu opened).
- Docs: an uninstalled favourite is kept but not listed; FAUX_BOLD_RADIUS
and the raster budget describe the thickened outline; the unused
"Recent font list" rows are gone; docs/scorecard.md regenerated (the
favourite fonts are one more setting).
Co-authored-by: D-monized <341904702+D-monized@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Microsoft "Single Package Authoring": Package/Scope="perUserOrMachine"
writes ALLUSERS=2 and MSIINSTALLPERUSER=1, so the package installs
per-user by default (no UAC prompt) into %LOCALAPPDATA%\Programs\ArtCraftPhotoCraft (Windows Installer redirects the ProgramFiles folder in a
per-user install), and per-machine into Program Files\ArtCraft\PhotoCraft
through the setup wizard's "Install for all users" box or msiexec
ALLUSERS=1. Registry follows the context automatically: HKMU writes HKCU
per-user and HKLM per-machine, HKCR classes land in HKCU\Software\Classes
per-user, and components are keyed on registry values (ICE38).
Upgrades update the copy registered in the same context: the remembered
InstallDir is read from HKLM and HKCU separately, and installing in the
other context while a copy already exists is stopped with a message naming
the fix rather than creating a silent duplicate. The existing UpgradeCode,
ProductCode behaviour and per-machine upgrades are unchanged.
The Start Menu shortcut becomes non-advertised in its own component (an
advertised shortcut must target its component keypath, which is now a
registry value), as the ArtCraft Launcher's MSI already does.
Built and checked with WiX 5.0.2: full ICE validation and ICE50 pass, and
the built package's Property table, launch conditions, directory chain and
registry roots were read back from the MSI.
A reason other than the memory budget (a flipped view, Advanced Blending…)
now shows "CPU Rendering" even while the measured layer fit is over the
budget. perf.gpu_fallback is set in one place from the active document's
reason, also each frame after a switch of document, so a refresh of an
arranged cell or another window can't make it disagree with
perf.renderPath's current. The control protocol says a history entry's doc
is the changed document's id, or 0 for every document.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A clipped or Blend If adjustment preview runs on the CPU proxy. Its reason
lives in a slot of its own, separate from the canvas's per-document reasons
and the app-wide reason, so closing or retargeting the dialog ends only the
preview's entry and can never report the canvas back on the GPU.
Resolves the move of crates/engine/src/selection_cmds.rs to cmd/selection_cmds.rs: the two hunks apply at the new path, and modify_window.rs with its tests moves under cmd/selection_cmds/.
The PR read and wrote Halftone Pattern as `Sz ` and `Ptrn` (enum `HlfT`:
`Dt `/`Crc `/`Ln `). The reference application's Filter Gallery uses `HlSz`
for the size and a `ScrT` enum (`ScrD` dot, `ScrC` circle, `ScrL` line), so a
Halftone Pattern saved there still opened as an opaque filter, and one we saved
lost its size and pattern there without a warning. The tests built their fixture
with the same keys as the code, so they passed either way.
Now the keys match, a default Halftone Pattern (HlSz 1, Cntr 5, ScrD) opens as
{size 1, contrast 5, dot} (fails before this commit), and descriptors with the
old keys stay verbatim. The docs no longer claim reopen checks in the reference
application.
Co-authored-by: denstu473 <63150090+denstu473@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zlib-rs maps level 1 to deflate_quick, which writes static Huffman blocks
only, so every Compression::fast() caller (PDF export and print, brush
presets, PNG Fast) wrote 5-32% bigger streams than miniz's level 1 did.
Level 3 is the lowest level that is never bigger than miniz level 1 on the
docs/images photos, raw and Up-filtered (level 2 was +0.9% on one); it is
0-16% smaller and takes 1.2-3.4 times as long. The new test exports a
noisy-gradient RGB document as PDF and checks the image stream against
miniz level 1 of the same samples: 603007 vs 547315 bytes with fast(),
passes with level 3. The PR's doc no longer says the levels are unchanged.
Main moved the io integration tests into crates/io/tests/it/, so the new
deflate_compatibility.rs moves there and uses crate::common.
Co-authored-by: Rene Leonhardt <65483435+reneleonhardt@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PR's follow-up commit appended the reworded entries instead of
replacing the first ones, so both versions were in the doc. Keeps the
"at least 53 pt tall" wording.
Co-authored-by: hectorviov <1501713+hectorviov@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>