open_menu_with waited once for the samples rendering and then drew its
last frame. A frame starts at most four samples, and none while eight
are rendering, so that last frame could start the samples of the rows
it showed instead of drawing them, and
show_samples_on_white_draws_dark_type_on_white_in_every_brightness
failed with "dark: samples are drawn" when the workers were slow.
wait_for_samples now returns whether any sample was rendering, and the
helper draws and waits until a frame leaves none rendering. Only test
code changes: wait_for_samples is cfg(test) and open_menu_with is a test
helper.
Diagnosis and approach by Taha-Mahmoodi in #7093.
Spot Color Objects listed every spot color linked from a gradient's stops
once any stop was above opacity 0. A spot stop at opacity 0 between other
clear stops, at the end of the ramp after a clear stop, or meeting an
opaque stop only at one offset was listed though it prints no ink, and so
was an opaque stop out of order whose pairs have no width.
A stop now counts when it bounds a stretch of some width that the
gradient sampler mixes and either stop of that stretch is above opacity
0, or when it is the first or last stop and above opacity 0, since those
color the offsets before and after the others. Stops in any order are
judged by the stretches the sampler uses. A freeform gradient keeps the
old rule, since it draws from its points. Type runs follow the same rule.
The document.info params text, docs/mcp.md and the progress line
describe it.
object.distort warped the anchors of paths, groups, compound paths and
clip groups but left their bounding-box angle as it was, so a rotated
path kept its old box after a warp and an upright one stayed square to
the page however far the warp tilted it. Text, images and symbol
instances already took the angle of the warp's affine approximation.
- Each path, group, compound path and clip group now takes the angle
the warp turns its x axis to at its own center before the warp, the
members of a warped group and the art of a linked opacity mask each
at their own. An unlinked mask's art keeps its angle. Mirroring keeps
the nearer angle and a collapsing warp keeps the old one. Reset
Bounding Box squares the boxes again.
- Each subtree's bounds are measured once while it is warped.
- Corners that equal the corners of the box being warped change
nothing and add no undo step.
Docs: object.distort params text, docs/mcp.md, docs/target-app-parity.md.
Spreading two keys along a spine whose length overflows splits nothing, so
it returned the end anchors, and a closed spine was then opened at its start.
spread_anchors now rejects a length that is not finite before it makes any
target, so two keys get no anchors and the path stays as it was, as for
three or more keys.
The outline of the area a Blob Brush or Eraser drag covers was outlined
again for the whole stroke on every frame, so a long stroke slowed the
canvas as it grew.
- The drag is outlined in pieces of up to 32 segments (one segment each
with Size set to Pressure), and a frame outlines again only the pieces
it added segments to. A grid of squares lists the segments near each
square, and each piece's outline drops the parts inside the rest of
the area, so the pieces show as one edge.
- One frame takes at most 256 new points and a fixed amount of work;
Tool::overlays_pending makes the canvas draw again until the rest is
done with the pointer still. Points not outlined yet show as a thin
line, and the tip shows at the pointer.
- The settled outline is kept in joined paths of 64 pieces, and a frame
joins again only the paths that changed. The grid's size is capped.
- The Blob Brush's length label and the Size-by-pressure check keep
running values instead of rescanning the stroke each frame. With Size
set to Pressure the outline shows only the edge of the whole area.
The release sends the same path.blob and path.eraseRegion parameters.
Several threaded-text paths in threads.rs searched a list once for each
frame, so their work grew with the product of the frame count and the
list length:
- leave_threads (Create Outlines, Expand Appearance, Rasterize, Flatten
Transparency, symbol replacement, opening with text as outlines)
searched the threads for each frame that stayed and ran continued over
that frame's whole thread again, about n^2 frame visits for a thread of
n frames. It now marks each changed thread with one continued call,
and keeps the frames that left in a map instead of a list.
- has_thread_selection (the availability of Release Selection and Remove
Threading), with_threads, keep_shown_text and cut_to_shown, release and
remove test ids against a hash set instead of a list.
- create finds the thread of each selected frame from a table built
once, and each frame still takes in the first thread not yet merged
that lists it.
- release writes each thread back at its own index instead of searching
the thread list for an equal thread.
Marks, thread membership, frame order, text and overflow are unchanged.
A 256-frame thread that loses one frame visited 65,025 frames before
this change and at most 256 now. Six tests on many threads count the set
lookups: with a list in place of the set they make 67,650 to 258,226.
Another test compares the marks with a scan of the frames before each
one.