The bilateral smoothing pass worked out a squared colour distance, a powi, a
division and a weight for every pixel and neighbour, and called round() per
channel. The distance is a whole number up to 195,075, so the weights come from
a table built once per trace, and the rounding is a truncation plus a compare
that gives the same level as round() for 0..=255. Rows are read through slices.
The output is byte for byte what it was; tests compare the pass with the old
formula on several images and on every pair of grey levels.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add Anchor Points builds the new anchor list in one pass, Swatch Library add looks names up in sets, full_documents dedups placed keys with a set, width profile lookups and mark insertion use binary search, and the symbolism tools cap and thin the previews of a long drag as Liquify does.
For every hole (when growing) or island (when insetting), the check measured the
distance to every segment of the input with the nearest-point search and took the
minimum, so the cost grew with holes x segments. Segment bounding boxes are now
computed once, a segment whose box is farther than the offset distance is skipped,
and the search stops at the first segment that is close enough. The decision is the
same as before; a test compares it with the old full scan on random segment sets.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Of two files read off the UI thread and ready in the same frame, the
first could open and ask about its links or fonts, and the second then
became the active document under that dialog. poll now checks
may_switch after each file it opens too, and leaves the rest for a
later frame.
The queued-reopen test also checks that a later queued activation
stays queued.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A document asked for again while a dialog was open, and closed
meanwhile, opens again when the dialog closes and may ask about its
links or fonts. poll went on to finish the files read meanwhile, and
each became the active document under that dialog. It now checks
may_switch after each queued activation and leaves the rest, and the
files ready to open, for a later frame.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A document asked for again while a dialog was open was queued by path
only, and opened later in the scope of the frame that ran the queue. A
request confined to automation roots could then read a file outside
them, if the document was closed meanwhile and its path became a link
out of the roots. Each queued activation now carries its ScopeHandle
and runs in it, as background opens already do.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follow-ups to #5369 (#5420), from its last review:
- Home shown over the document asked for again gives way to it.
- Automation confined to some folders can't reach an open document
outside them: open_file checks read access before looking for a tab.
- While a dialog or a drag acts on the active document, a document asked
for again comes to the front once it ends (opening::poll), as a file
that finishes opening already does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Option errors and notes for a .ai save called the file a
"PDF-compatible .ai" even when the save wrote a version 7 file
(aiVersion: "7") or a file without PDF content (pdfCompatible: false).
- Option errors: a version 7 .ai is now called a "legacy .ai
(version 7)" in the errors for its artboard, artboards and range
options. A .ai saved without PDF content is called a
"non-PDF-compatible .ai" in every .ai option error (includeLinked and
embedProfiles included), and a "non-PDF-compatible .ait template"
when Save as Template writes it. aiVersion: "7" takes precedence over
pdfCompatible: false, as it does when the file is written.
- The error for encoding a version 7 .ai of several artboards as one
file names the legacy .ai.
- The note for a native option the file does not read (version,
preview, precision) names the same kind of file.
- The error for aiVersion: "7" on a .ait template no longer says that a
.ait template is always PDF-compatible, since Save as Template writes
one without PDF content. It now reads "aiVersion 7 writes legacy .ai
files, not .ait templates", with its rows in the message catalogs
updated.
A PDF-compatible file keeps its name.
A path made of straight segments and circular arcs (a slot, a D shape,
a rounded rectangle, a pie) was written as one SPLINE, or as a flattened
polyline in R12. It is now one polyline whose vertices carry a bulge
(group 42) for each arc: an LWPOLYLINE in R14 and later, a POLYLINE with
VERTEX entities in R12 and R13, closed when the path is closed. Each run
of cubics on one circle becomes one arc. A path with any other curve
stays a SPLINE, and whole circles, arcs and ellipses keep their CIRCLE,
ARC and ELLIPSE entities.
- The circle test's tolerance is 5e-4 of the smaller of the radius and
the curve's extent, so a shallow curve that is not circular is no
longer written as an ARC.
- The drawing extents take each ARC's and each bulge's furthest points.
Part of #1299
A projection now counts as invertible when its determinant, or its
adjugate's determinant, is more than 1e-15 times the largest of the six
products that determinant sums. The adjugate of the adjugate is the map
times a number, so the inverse of a projection that inverts also inverts,
is stored and reads back. The adjugate's cofactors are formed with exact
products, so the inverse of that inverse gives back the original map up
to scale, within 1e-6 of each row's largest entry, and a map whose third
row is the sum of its first two is still refused.
Homography::conjugated and Node::transform_projection judged the affine
map by an absolute determinant of 1e-15, so a scale by 1e-8 left type and
symbol instances in perspective with their old projection. Both now use
Homography::affine_is_invertible, which compares the determinant with
the two products it sums at any scale of the map. An affine map whose
determinant or inverse is not finite, such as a scale by 1e200 or
1e-200, is inverted through Homography::inverse. When the direct product
underflows to a map that is not invertible, as for a projection stored
at a subnormal scale, conjugated forms it again with its powers of two
kept apart.
- crates/geom/src/projective.rs: the_inverse_of_an_invertible_map_is_invertible,
conjugating_does_not_depend_on_the_scale_of_the_affine,
conjugating_a_map_at_a_tiny_scale_gives_an_invertible_map
- crates/doc/src/node/tests.rs: a_projection_follows_the_transform_or_is_removed
covers an invertible scale by 1e-8 and a singular map at that size
The lookup ran reg.exe and decoded its output as UTF-8, but reg.exe
writes in the console's code page, so a registered path with characters
outside ASCII came back wrong, and characters outside that code page
came back as "?". The path is now read with RegGetValueW.
With Snap to Point alone, an anchor behind the start could pull the
projected end behind it, and the measurement read 180 degrees from the
pointer's step. Such an end is now turned back onto the pointer's step,
keeping its length, as an end rounded nearer another step is.
With a Constrain Angle other than 0, the grid point a Shift-drag's end
rounds to can lie nearer another 45-degree step, and the measurement then
reported that step. A Shift-drag from (0, 0) to (5, -3) with a 30-degree
Constrain Angle and a 9 pt grid measured -15 degrees instead of 30. The
end is now turned back onto the step nearest the pointer's direction,
keeping its length.
docs/mcp.md (dataset.import) and docs/gaps.md (Recolor Artwork ›
Assign, Average & Join) quoted sentences from the reference app's help
pages. Each quote is replaced by a plain statement of the behavior, and
each help-page link stays as the source.
With SCALED_COMPONENT_OFFSET, a component's offset now scales each axis
by the length of that axis's basis vector, as the outline loader does,
instead of going through the whole matrix. A rotated or skewed
component's caret no longer lands away from its drawn point.
UNSCALED_COMPONENT_OFFSET now turns the scaling off when both flags are
set.
A composite glyph whose components expand into glyphs with no points
could make the contour-point caret lookup read billions of glyphs. The
whole lookup now shares a budget of 65,536 glyph reads and gives no
caret when it runs out, so the caret falls back to dividing the advance.