The Symbol Stainer mixed the color of type characters painted with a
global swatch but kept the swatch name and tint, so the characters'
paint named a swatch whose color it no longer had, and a later edit of
the swatch could put the unstained color back. Their fill and stroke now
become plain colors, as a path's paint does.
With nothing selected, Cmd+/ and Cmd+Alt+/ ran the commands, which put
"select objects or give ids" in the status bar, and the command palette
listed both as available. Without ids and without an Appearance panel
subject (a targeted layer, group or object, or a selected one), the two
commands are now off in menus and the palette, as the panel's buttons
are, and their keys run nothing. Called with ids, they still add to those
objects.
The Paintbrush drops a sample less than a pixel from the last kept
point, and a release there keeps that point. The new test moves the
pointer inside Close Paths When Ends Are Within while the kept point
stays outside it, and checks that the cursor shows no closing ring and
that the release leaves the path open.
buffered_partial_control_line_also_expires and
stalled_control_line_is_refused_with_the_reason used short_timeouts(),
which gives a connection 150 ms before its first byte and 150 ms to write
a reply. When a test thread pauses longer than that, the server closes
the connection without a reply, the client reads end of stream, and the
test fails parsing an empty line (CI run 40212833958 on #4152).
The two tests now use line_timeouts(): the same 120 ms line deadline,
with idle and write budgets of 10 s. The other short_timeouts() tests
are unchanged.
Picks up the startup prompt without the glyphs a font may lack (storytold/craft-libs#343, #344): the close mark is painted and the version pill is ASCII, so apps that panic on a missing glyph no longer take the prompt down.
Part of tracking issue storytold/craft-libs#319
* feat: startup update prompt modal and direct self-updating
The update flow (check at start or on request, the startup prompt, the self-update worker) is craft-update's Updater; the app only supplies the suite, its close path and its status window. The check at start is opt-in for the desktop app, and the Windows update helper runs before argument parsing.
Ref: storytold/craft-libs#319
* refactor(updates): hold the install back while documents are unsaved
* fix(updates): drop the manual window's custom id; pin craft-update to craft-libs main (db19c37)
* fix(updates): address review feedback
Wake the UI when a manual check is queued from a menu callback; the update prompt owns the keyboard while it is open (LightCraft); Download opens through the desktop URL hook (FilmCraft); the Help menu dispatches through menus::invoke (FigCraft); print jobs and comment drafts hold an install back (WordCraft); Check for Updates is a registered command (GridCraft); an install holds back while documents are unsaved.
* fix(updates): localize the update status messages
* build: resolve the craft-update pin after rebasing
Boxes that touch at -0.0/+0.0 now count as overlapping, so the pair cap cannot be skipped. try_boolean_n, try_unite_all and try_area report a refused input, and the Pathfinder shape-mode unite and the Blob Brush use them to show an error. When the planar map is over its budget, the fallback leaves out paths that fill nothing so a flood of cutting lines cannot take the filled shapes down with it.
CodeRabbit findings #6, #19, #53, #59, #62, #167:
- Before a sweep builds a planar map (Boolean, normalize, Pathfinder, Offset Path, Live
Paint, Shape Builder), the pairs of segments whose bounds overlap are counted exactly in
O(n log n); past 4M the operation fails as `PathOpsError::TooComplex` (a crossing can only
lie where two segments' bounds overlap).
- Live Paint's winding crossings are sparse: the sweep keeps one per edge, and a vector as
long as the input count made disjoint shapes quadratic in memory.
- Gap detection groups the segments near a loose end by track once.
- 3D: ring containment checks bounds first and walks at most 50M edges; Inflate's mixed-cell
booleans take at most 4M outline segments together.
* Build: craft-libs at 2869b8cc
Pin craft-pdf, craft-print, craft-docpath, craft-ui, craft-keymap,
craft-window and the patched hayro/krilla backends to craft-libs
2869b8cc1077530bd07a7e192fb2b0e1304a1354, with the pdf-deps gate,
NOTICE, ASSETS.md and docs/pdf-backend.md at the same revision.
PDF: no modification date beyond the creation date, DeviceN images
are not JPEG-encoded, and clipping text draws nothing (its outlines
arrive as a clip path).
* Docking: compile against craft-ui at 2869b8cc
Floating windows are trees of groups: window_panels and window_active
read one as a flat group, and windows rebuilt from the legacy groups
keep their ids. Unknown dock actions are rejected, the new ones are
checked like the old, and every panel a close action removes keeps its
return location.
* Docking: panels and canvas on craft-ui's docking area
* Docking: tests for the dock area, flyouts, floating panels and the Tools panel
* Docking: catalogs without the old dock's strings
* Build: craft-libs at 8a503cfe
* Docking: floating panels in OS windows of their own on the desktop
* Docking: modal dialogs block panel windows; their keys and dropped files reach the main window
* Docking: art dragged onto a panel in its own window drops there
* Docking: module doc names the OS windows
* Build: craft-libs at a042cf26
* Docking: onto, above, below, collapsed, icon and column places on Float and Dock Panel; ui.docking
* Docking: command descriptions of Float, Dock, Move and Collapse Panel for the craft-ui layout
* Docking: control protocol describes the craft-ui layout, its commands and ui.docking
* Docking: rustfmt
* Docking: layouts saved before the canvas joined convert on load
Saved ui.json files and workspaces from before the shared layout held the
canvas (a dock-only tree plus floating_panels, docking_icons,
docking_collapsed, dock_collapsed and dock_width) convert into one layout:
the dock tree's groups in the main column, the icon column with the panels
dropped on it, floating groups and sets, sets docked as columns, collapsed
groups, the dock width and the places of closed panels. The legacy fields
are read, never written. A ui.json read only in part is copied to
ui.unreadable.json before anything saves over it.
* Docking: catalogs without the old collapse message
* Docking: converted floating sets start at most 720 points tall
* Docking: closed icon panels convert into the icon column; old floating rects, set heights and a copy of the file before conversion
* Build: craft-libs at 27e60765
* Docking: dock column places and icon count from the icon column; a docked column moves to a later place
* Build: craft-libs at d24e4bcc
* Build: craft-libs at 5bbe9f62
* Docs: floating panels in OS windows of their own close the other-monitor gap
* Docking: keys forwarded from a floating panel's OS window run shortcuts while the main window is unfocused
* Audit: document model bounds (id hashing, ranges, overprint migration, auto slices)
* Audit: nested Repeat bounds are measured once per level
* fix(slices): bound auto_slices accumulation strictly by MAX_AUTO_SLICES
* chore(text): use is_some_and instead of unnecessary map_or (clippy)
* Refuse automatic slice layout past a cut-rectangle bound
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
* Audit: EPS interpreter and import bounds
* Audit: EPS writer stops expanding at 256 MB of body
* fix(eps): enforce MAX_BODY budget before committing node and image output
* chore(text): use is_some_and instead of unnecessary map_or (clippy)
* Fix clippy unnecessary_map_or false-default in ITXT compression flag scan
* Reject EPSI previews with an odd number of hex digits
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Dylan Taylor <dylan@craftmaker.dev>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/format/src/lib.rs:690-717 (base64_decode)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/doc/src/lib.rs:363-373 (parse_measure pica branch)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/engine/src/cmd/fileio/screens.rs:168-177 (safe_file_name)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/engine/src/cmd/fileio/screens.rs:49 (ScreenSize::parse)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The old pen glyph was a crude pentagon with a floating dot and a stray
stem. Redraw it as the precision instrument it is: the pen-tool icon's
nib — sharp point on the hotspot, shoulders flaring to their widest
two-thirds back, a narrower flat heel, a slit widening into the round
breather hole — swung round onto the selection arrow's midline
(arrow_axis), so holding Cmd/Ctrl to swap between the Pen and the
selection tools no longer rotates the cursor under the pointer.
Badges keep their meanings (*, +, -, o, /, j, ^, ~) and multi-stroke
ones now draw all halos under all ink via strokes(), so neighbouring
strokes no longer cut each other into blobs.