An image in a DeviceN color space opened as an RGB image, losing its inks.
One of one colorant now opens as a Separation image does since #6347: a
grayscale image of its tints colorized by its ink. One of two to 32
colorants that are all process plates (the ink None may be among them)
opens as a CMYK image, each colorant's tint in its plate, its Decode array
applied (8 or 16 bits a sample). A DeviceN image that mixes a spot ink
with other colorants, such as a duotone, still opens as RGB.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With Use Preview Bounds on, the visual box of a butt-capped stroke on an
open path grew by half the stroke weight past each end of the path, where
a butt cap paints nothing. A 2 pt vertical line set to H: 10 mm in the
Transform panel drew about 9.3 mm long.
The box of an open subpath with butt caps no longer reaches past its
ends. A straight segment's box comes from the four corners of its stroked
rectangle, and a curve's box comes from the stroke at its ends and where
its tangent is square to an axis. Bevel joins, and miter joins the limit
bevels, are measured by the stroked corners, and round joins by the arc
they paint outside the turn, instead of half the weight all round. Round
and projecting caps, arrowheads, closed paths and miter tips measure as
before. Two cases can still measure larger than the stroke paints: a
curve that bends more tightly than half the weight, and a butt-dashed
path whose first or last dash is a gap, which is measured to the path's
ends.
A horizontal or vertical butt line now measures one stroke weight less
along its length in W or H, and Align places it by its end points. A
slanted line's box shrinks by less: the stroke's corners still reach
past the end points across the line. object.setBounds measures as drawn,
after each scale it tries, a butt-capped open path with a segment at a
slant, symbol instances' art included.
An image whose color space XC sets to one ink (n [c m y k /DeviceCMYK
(name) /Separation] XC) opened as a gray RGB image: its samples, the ink's
tints (255 at 100 %), were read as gray levels, so the tints drew inverted
and the ink was lost.
It now opens as a grayscale image of the tints, black at 100 %, colorized
by the ink at 100 %: its spot swatch, a process plate's CMYK color, or
Registration. Its alpha channel becomes its opacity mask, a reduced large
image's too (a colorized image reduced to fit the limits no longer keeps
its alpha in its pixels). 8-bit and 1-bit samples, binary or in hex
comment lines. A device space and the ink None change nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since #5331, a closed font family field in Character, Properties or the
Control bar took every plain vertical wheel turn while the pointer was
over it. When a panel scrolled the field under a still pointer, the
field took the rest of the turns: the panel stopped scrolling and each
turn changed the selected type's font.
The field now takes the wheel only when the pointer was moved onto it
after the field last moved, and the wheel stream began there. A stream
that began anywhere else, a sideways scroll included, stays there until
0.5 s pass with no wheel input. A stream that leaves its field does not
return to it. It leaves when the pointer moves off the field or out of
the window, when the field moves or misses a layout pass, and when a
turn arrives while an overlay covers the field. Trackpad momentum stays
with the stream it follows and never starts one on a field. The rule and
its 0.5 s are VectorCraft's own.
Wheel turns the field does not take stay in the input in their order.
Moving the pointer onto the field and turning the wheel still steps the
font, as #5253 asks, in floating panel windows too. When the pointer was
moved onto the field while a window or overlay covered it, the pointer
has to move again after the cover goes away before the wheel steps the
font.
With Zoom with Mouse Wheel on, a wheel turn that a touchpad began did not
end on the End or Cancel phase, so a whole Cmd/Ctrl notch within 150 ms,
or in the same frame, still zoomed instead of scrolling sideways. The
turn now ends on those phases, as it does in the Scroll Sideways branch.
Tests cover End and Cancel in the frame of the next notch, a Start phase,
the scroll timeout with no frame in between, a table of fine_steps cases,
and exact zoom and scroll amounts.
Follows #6360.
a_coarser_glow_kept_whole_draws_after_a_pan_as_made_again compared only
whole-pixel pans with a fresh render. At a fractional pan it now compares
the pixels right of the rectangle, where only the glow draws, with a fresh
render at the whole pixel nearest the pan (either neighbor on a half pixel).
RenderOptions::background and render_node_thumbnail's background are
straight-alpha colors, as over_background reads them; their docs said
premultiplied.
With anchors picked with Direct Selection, Edit > Cut removed only the
segments between them, so the picked anchors stayed in the path. Cut now
removes picked anchors and the segments attached to them from a path or
a compound path's member, as Clear does. Picked segments still lose only
those segments. When a path has picked segments, Copy and Cut leave out
anchors picked on its other contours, as Clear does.
Docs: docs/target-app-parity.md.
The Measure and Measure & Inspect tools ignored View › Snap to Glyph:
their press and end points snapped only to targets that hold no glyph
guides.
With Snap to Glyph, Smart Guides and Alignment Guides on, and Snap to
Grid and Snap to Pixel off, a drag's press and end land within the
snapping tolerance on the guides of live type that the Character
panel's options allow, except Anchor Point. A Shift-drag's end slides
along its 45° step to them, and the guide shows during the drag. With
Snap to Glyph off, the tools snap to the same targets as before and
show no guide. The targets are kept while the document, the window and
the snapping options stay the same, so a drag lays out the type once.
A group with a visible member that carries a geometry, Pathfinder or 3D effect, also in an opacity mask, keeps its previous copies. Copies stop at the budget with what each copy's own effects make, and a group's copies count the art of opacity masks.
The PDF and SVG tests for a group's image copies now expect the original on top.
The second sweep of `unite_all` joins contours that lie within the sweep
tolerance of each other, and the first sweep can leave such contours
apart. `solid::tests::meets_within_twice_the_boolean_tolerance` needs
that join. A single input now skips the second sweep only when no two
of its segments lie within twice the tolerance. The check compares at
most 512 pairs per segment and runs the second sweep past that.
`unite_parts` tests the single-input case before it builds the combined
path, and it takes `parts` and `inputs` by value so that both are freed
before the second sweep.
Edit Colors > Convert to Grayscale wrote the new image as an RGBA PNG, so
a PDF wrote it as DeviceRGB, in a CMYK document too. The image is now
stored as a gray PNG, with alpha only when some pixel is not opaque. Adjust
Colors with mode gray and convert does the same.
An RGB image whose pixels are already neutral now converts, and an image
already stored as gray with no visible change is left as it is.
A new test changes the document in place (Arc::make_mut, with no other
holder and no change of revision) and checks the answer is measured
again: keyed on the document's address alone, it would keep the old
answer. The kept answer's doc says what it holds after the measure,
and that the fonts set the bounds of all type. Should measuring ever
ask again while it runs, it is measured without being kept, rather
than borrowed twice.
The stack overflow fixed in d5d04f868 also hit EPS export, and the
parity rows now say so. Two test docs are corrected: the fill-only
clipping is an older bug on main, and the outline-view difference runs
both ways on a few dozen hairline pixels.
The engine reads null params as {}, but engine.commands listed every
schema with the root type "object", so a client that validated a call
against the schema refused one the engine accepts. A schema with no
required parameter now has the root type ["object", "null"]. A schema
with a required parameter keeps "object", because the engine refuses
null params for it as a missing parameter. Nested objects are unchanged.
The grid is view state of each open document, with no undo step, so its schema's x-writes is session rather than the default document. A test pins x-writes for all six View commands, and the level 1 schema hash is updated.
A Transform effect with copies on a group copied each member on its own,
so one member's copies lay over the fills of the next member. Each copy
is now a whole group, the original on top and each copy below the one
before. A path's copies follow the same order. Guides are not copied,
and the copies stop at the node limit. A group with its own fill or
stroke, a clipping group and live type keep their previous copies.
Check a new call's params against the schema in execute_spec, after the
key check and before the parser, and check every command.batch step
before the first one runs. menucmds::run_raw and the two other direct
runs go through the same check. Saved steps keep keys the schema does
not name and have the values it names checked.
Limit nesting to 16 levels, cut error text and paths to a fixed length,
and copy nothing before it has passed. Treat a whole number written
with a fraction as an integer. Check declared defaults and duplicate
names once at first use.
Give the five schema errors rows in the 22 complete-message catalogs.
- The parity rows say what the fix covers: a 3D effect on a fill or
stroke that builds nothing overflowed the stack with no effect of the
object's own too, on the canvas, in Object › Rasterize and in raster
exports.
- The builds-nothing test says the fill-only difference (a raster
effect clipped to the path, cutting Roughen's spikes, when drawn
without the 3D effect) is an older bug, not the design.
- The traced-shape test says why its area is bounded rather than drawn
again: a partial render in outline view differs from the whole by one
in alpha on 37 pixels, older than the test and unrelated to the edit.
- A doc comment rewrapped.
The answer whether Fit to Artwork Bounds has art to fit moves from a
function-local thread_local to DocState, beside any_empty_artboards, and
drops with the document. It is kept for that version of the document
(held weakly, as any_empty_artboards holds its own) and the artboards
asked about, and measured again when the installed plug-ins, whose
effects draw art, or the installed fonts, which set type drawn by its
effects' art, change: their generations are an explicit input of the
measure. A change of the selection or the view keeps it.
The test counts the measures, as the Delete Empty Artboards check's
does: a later frame, select.set and a view change keep the answer; an
edit, other artboards, and each generation measure again. Taking any
part out of the key fails it.
Flatten Transparency composited each region over white, so a blend mode
on the bare page read that white. Raster renders now draw their
background under the finished art, and the flattened color no longer
matched them: a Color Burn object on the bare page flattened to white
and rendered in its own color. The region now composites the art alone
and puts the white under it.
- Tests that relied on the white under the art now draw art under the
style (`every_builtin_style_paints_visibly_on_a_rectangle`) or compare
only whole-pixel pans with a fresh render
(`a_coarser_glow_kept_whole_draws_after_a_pan_as_made_again`).
- New tests cover every blend mode on white and blue backgrounds, a
thumbnail and the ink planes with a Screen glow, and
`over_background` at background and pixel alpha 0, 128 and 255.
With Scroll Sideways with Cmd/Ctrl + Wheel on, wheel() turned all
Cmd/Ctrl wheel motion into a sideways scroll unless it arrived as a
pinch event. A wheel turn now zooms about the pointer once it holds an
event from a trackpad source, point deltas from an unnamed source in the
desktop app, or line deltas that are not whole notches. Whole notches
keep scrolling sideways, and the option's default is unchanged. The same
rule applies with Zoom with Mouse Wheel on. egui-winit reports a wheel
source only on macOS, so the delta decides elsewhere.
Docs: docs/mcp.md, docs/target-app-parity.md.
`unite_all` and `try_unite_all` swept each input under its own fill rule
and then swept all the resulting contours again under NonZero. With one
input whose sweep split and dropped none of its segments, the second
sweep ran over the same simple contours and doubled the time. Such an
input is now refit from the first sweep's contours. Inputs that cross
themselves and unions of several inputs are still swept again, and the
input paths are converted once instead of twice.
fit_has_art kept its answer for the document's uid and revision, which
don't follow every change of what it measures: a document's tab coming
to the front replaces it with its composite fonts synced, and a plug-in
installed or removed changes what its effects draw, with no revision
moving either time. The answer is now kept for that document Arc, held
weakly as DocState::any_empty_artboards keeps its own, and the artboards
asked about, until the plug-ins' revision moves. A selection or view
change keeps it.
The test replaces the document with art on an artboard, its revision as
it was, and asks again: kept by revision, the answer was stale.
- A 3D effect that builds nothing: af754bcb2 said the object draws exactly
as without it under a Drop Shadow or Gaussian Blur. That holds only for
a stroked object. With only a fill, the raster effect draws from the
art made for the object, where without the 3D effect it is clipped to
the path, so Roughen's spikes differ: the earlier wording was right.
The test keeps the stroked cases exact and restores fill-only cases
with a Drop Shadow and a Gaussian Blur, which differ in under 4% of
the pixels and nowhere inside the path. Its reach check compares with
the object drawn without its raster effect, since Roughen alone
reaches past the path.
- The Vector Halftone test's bounds are a consistency check, and only
holding no art tests the branch: its doc no longer says no solid is
built (the free measure's halftone arm builds one). The overprint
test's area check is labeled likewise.
- Recoloring a traced shape bounds the area the renderer that drew the
trace object measures too, inflated by half the stroke and a pixel.
- The let-go test pins the nothing-to-draw branch: no frame, whole or
part, began since the measure.
- The parity doc's feature row names the stack overflow fix and its
test; a group test's doc says what its fixture holds.
A raster export filled its background into the page before the art, so
blend modes read it as art underneath: an Outer Glow in Screen mode, the
default, turned white on a white background and was missing from PNG and
JPEG files while the canvas showed it. Blending against nothing also
differed from the canvas for Difference and the other modes.
The background now goes under the finished art, in frames and in object
thumbnails. A blend mode reads only the art below it. A white object
under a Difference object still inverts.
Page Isolated Blending no longer changes a raster export on a bare page.
Docs: docs/mcp.md, docs/target-app-parity.md.
Review follow-ups:
- The test that art measured for an edit not drawn on this thread is let
go first checks that measuring the edit through the canvas's renderer
holds art, so a measure that held nothing can't pass it. Its worker is
a test channel whose job the test receives, in place of a real thread's
pending job, which a finished frame could clear. Taking out either
let_go_of_measured fails it.
- fit_has_art's comment says why its one kept answer can't be stale: a
document's uid is never reused in the process and its revision only
moves forward.