A closed key that winds the other way is reversed keeping its start anchor.
Its dash offset was computed as if the reversed path ran back from position
0 instead of from the end of the subpath, so the dashes shifted by the
subpath length modulo the pattern period. The offset now uses the full
length in that case, and the dash test covers a closed key 40 long with a
7.5 period.
The WebP chunk walk added the chunk length to the offset without a
checked add, so a length near u32::MAX overflowed on 32-bit targets
(wasm32) with overflow checks on. It now reads the chunk through the
same checked slice helper as the PNG, JPEG and TIFF readers.
Measuring an instance of a symbol with 9-slice guides looked its map up
through Document::symbol_slice_map, which scanned the symbol list and
measured the art box again in new quick boxes, and NineSliceMap::place
and most_placed made new quick boxes of their own. Each of those boxes
built the symbol name index over the whole list on its first lookup, so
every 9-slice instance measured read every symbol once or more. Picking
an object inside a 9-slice instance's art with Direct Selection did the
same for each object of the art that holds a symbol instance.
- SymbolBoxes cuts the guides through the art box it has measured
(SymbolBoxes::slice_map), and places and counts the art with itself as
the boxes, in the mode quick boxes use. Art with no 9-slice map is
moved by the instance's transform without looking the map up again.
- Document::symbol_slice_map, place_symbol_art,
place_symbol_art_unclipped and edited_nine_slice use one set of quick
boxes for each call.
- symbol_part_at and symbol_part_outline keep one set of quick boxes
for the instance's art.
The new tests count the symbols read. Measuring 200 instances of a
symbol with guides and 200 of a symbol with guides holding it, among
2,002 symbols, read 1,205,204 symbols before; now each set of boxes
reads the list once. Picking in a 9-slice instance whose art holds 20
instances read 84,042 symbols among 2,001; now it reads the list at
most twice.
When two gradients with different stop counts are blended, the second stop at the other
gradient's step took the last stop within the step tolerance, so two close but distinct stops
became a hard step. It now takes the last stop of a step of its own there, and otherwise paints
what the gradient paints at that place.
A hue gradient that reflects unrolls through its curve, whose stops have no swatch links, so a
gradient along a closed key started elsewhere lost its links. The links now come from the
gradient's own stops unrolled as a Classic gradient's, in order, so stops at one place and the
stops where two runs meet keep their own links.
- A graph opened from a .ai file now saves `placedArt` too. Moving or
restyling one of its labels before the first redraw no longer moves or
stretches the plot.
- Type > Create Outlines on a graph's labels now adjusts the saved bounds,
so the outlines do not read as a move at the next redraw. A move of
the graph made before the outlining is still followed.
- A `placedArt` with no width or height falls back to the bounds of all
of the art, as a graph saved without it does.
- `art_bounds` moves to the doc crate so the .ai reader can use it.
- docs/mcp.md describes `placedArt`, `placed` and when a redraw follows
a move.
- Tests: a legend across the top, a legend after a right value axis and
legend labels of several lines keep the plot in place through label
size changes; moving a category label on its own; outlining labels
before and after a move; a flat `placedArt`; a label moved in an
opened .ai graph.
Only a pie with Legends in Wedges picks its legend labels' fill, white on
dark wedges. Paint visits and swatch mappings now leave its default black
legend fill out only for such a pie; other graphs draw the kept fill, so
it is visited and mapped like the other label fills. A color mode change
still leaves the default black legend fill as the default, so turning on
Legends in Wedges later keeps the white labels on dark wedges.
The next redraw of a graph compared the bounds of all its generated art,
labels included, with the bounds stored at the last generation, and took
any difference for a move or scale of the graph. Label edits that change
the size of the type (a new size, an indent, a legend size) changed those
bounds without a move, so the plot shifted and stretched when the graph
was drawn again.
The spec now also stores the bounds of the art without type
(`placedArt`), and moves and scales are measured on those. Graphs saved
without them are measured on the whole bounds as before. Moving one
label with Direct Selection no longer moves or stretches the plot at the
next redraw.
When a closed key path now starts where its stroke gradient steps between
two stops of one color linked to different swatches, the gradient's new
first stop takes the swatch link of the stop after the step instead of
the one before it.
Document::symbol_art_bounds measured a symbol's art without the
document, so an instance of another symbol in that art counted as the
20 x 20 square. It now measures the art through SymbolBoxes, so a nested
instance takes its own symbol's art, and an inline graphic of the outer
symbol is sized by it and follows it when that symbol changes.
- The inline resolve order also follows the instances that size a
symbol's art, so a symbol is measured after the type in the art of
the symbols it holds is laid out again.
- A symbol whose art reaches itself through an instance and an inline
graphic is an empty slot. Only instances that the measurement uses
count, so one a clipping path hides adds no dependency.
- A missing symbol, a symbol without art, a symbol that holds an
instance of itself, and nesting 32 deep still measure as the square.
- SymbolBoxes finds symbols through a name index built once, and the
inline resolve pass and inline_art_bounds share one index, instead
of scanning the symbol list for each lookup.
The image crate's filtered resize filters each channel on its own, which
is correct only for premultiplied pixels, and its thumbnail averages each
channel on its own too. Placed images, linked-image previews, MCP
captures and previews, metafile bitmaps, PDF downsampling and library
thumbnails passed straight RGBA to them, so the color under clear pixels
(usually black) bled into the opaque pixels beside them and darkened
cut-out edges.
vectorcraft_doc::resample scales such images with each pixel's color
weighted by its alpha: filtered resampling premultiplies the pixels in
place and divides them back after, and averaging takes the area-weighted
mean of the pixels each new one covers. Opaque and alpha-free images are
scaled as before. PDF export also multiplies the inks of a CMYK image
with alpha by that alpha before resampling them, and divides them by the
resampled alpha after.
A gradient stop linked to a spot ink that also carries process plates
(a DeviceN stop opened from a PDF) printed only its spot tint: print
separations and Separations Preview left its Cyan, Magenta, Yellow and
Black plates blank. They now print the stop's plates beside the tint.
With spots printed as process, each process plate prints the stop's
plate layered with the spot tint's process equivalent, as a separated
image's spot plates layer. Plates beside no spot link, or beside
Registration, still print nothing of their own.
The color visitor also skipped a freeform gradient's points, so print
plates kept their display colors and Document Color Mode left them
unconverted. The points are now visited as unlinked colors.
Document::guides_to_saved, remove_edit_layer, retain_guides and the
artboard guide moves now call the layer helpers in node/ops.rs
(held_guides, strip_held, map_held), which Node::strip_ruler_guides and
Node::map_ruler_guide_positions already use. The copies in
document_guides.rs (picked_in_layers, drop_picked, edit_picked) are
removed. Picked stays for the walks through objects and opacity-mask art.
Results, guide order, copies kept for undo and the number of nodes each
walk looks at are unchanged.