Three repairs in crates/pathops/src/addons/cleanup.rs grew with the square
of the input. Each now gives the same results as before, bit for bit.
- Collinear anchors: removing an anchor called Vec::remove, so a straight
run of n anchors took O(n^2) moves. The repair now tests each anchor once
against the nearest kept neighbors, with the same test order, neighbors
and stop rule, and moves the kept anchors into place once.
- Nearly Coincident Anchors (near_point_groups): every pair of anchors in
touching grid cells was compared, so a cluster of A anchors cost O(A^2)
checks. Groups now grow one anchor at a time and look only at anchors no
group has taken, by exact position, skipping quarter-cell squares that
lie out of reach.
- Rejoin Path Pieces (rejoin): every pair of ends within the gap was listed
and sorted, O(P^2 log P) for P pieces meeting at one place. Each end now
finds its first partner in the same order (turn, distance, then end
order), searching by direction among the ends still free, and two ends
that are each other's first partner meet.
Tests compare each repair with a copy of the old algorithm on generated
and focused inputs, count the work on dense cases (20,000-anchor runs,
4,000-anchor clusters, 2,000 pieces meeting at one point), and check Health
Check, Show and Fix on a 5,001-anchor path.
On a shaped frame, Inset Spacing keeps text that far from the frame's
edge, measured from the edge itself rather than along the line. Before,
the inset was trimmed from each end of a line after the frame's edge was
found, so on a sloped edge the text came closer than the inset: a
triangle (0,0), (100,0), (0,100) with a 10 pt inset gave the band
40..60 the span 10..30, where a 10 pt clearance gives 10..25.86. Holes
keep the same clearance.
A rectangular frame keeps its inset from each side as before, a
column's inner edges keep it once, and the gap kept beside a wrap
object along the line is unchanged.
With one Objects on Path group selected and an object chosen with its
Select/Move widget, Detach in the Properties panel's Objects on Path
Options section takes that object out of the group
(`object.objectsOnPath.detach {member?}`). The object goes just above
the group in the Layers panel, stays where it is drawn and is selected
alone. The other objects move up the path in their order: Auto Space
spreads them evenly again, and a Space value and the start are kept.
The group and its path stay with one object or none left. Hidden or
locked objects and groups are refused, and Detach is one undo step.
When the group is itself on another group's path, the object goes
above the outer group so it does not join that path.
Docs: docs/mcp.md, docs/target-app-parity.md. Detach and its undo name
have rows in every catalog, and the new message in the complete-message
catalogs.
The MCP unit tests wrote their files into one folder per process under
the temp dir (vectorcraft-mcp-test-<pid>, vectorcraft-mcp-fileio-<pid>,
testkit's mcp-cancel folder) and nothing removed them. The export-as and
links tests removed their folder at the end, so a failing test left it.
Each test that writes files now holds a TempFolder, a folder of its own
that starts empty and is removed with everything in it when the test
ends, also when it panics, as the findfiles tests' Tree guard does
(crates/engine/src/cmd/findfiles/tests.rs:49). A new test checks that a
leftover folder is emptied and that the folder is removed on drop and
after a panic.
The profiles Edit > Assign Profile gives a document stayed the active
color settings after another document came to the front, so a new,
opened or switched-to document drew and converted its colors through the
previous document's profile, and closing the last document left it in
use.
The session now puts the front document's profiles in use (the working
spaces where it has none, or no document is open) after a new or opened
document, a tab switch, a close, File > Revert, every command including
each batch step and Undo or Redo of Assign Profile, a failed batch or
plug-in call, a script's rollback and slice boundaries, a canceled
preview, undo group or undo scope, and for each document Export All Open
and the update of placed documents work in. The active settings are
rebuilt, and the documents redrawn, only when they change.
The cursor catalog's Smooth entry named only the Smooth tool and the
Pencil with Alt key toggles to Smooth Tool on. The tools also show it for
the Paintbrush with Alt held before a press while a path the Smooth tool
can act on is selected, and for the Blob Brush with Alt held before a
press or before the drag has moved, and through the drag that smooths.
PaintbrushClose and Paintbrush now say that Alt before a press shows the
closing ring only when no such path is selected.
The gesture tests check that the Paintbrush shows Smooth through an
Alt-press smoothing drag, with Alt let go too, and the closing ring for
Alt pressed after a stroke begins with a smoothable path selected.
document.export and document.serialize to .ai with useArtboards: false
wrote the one page of the visible art, but embedded the one-artboard
stand-in as the native document and as the editing copy for other apps.
Reopened, the file replaced the document's artboards with one artboard
around the art.
- The .ai of the art's bounds now leaves out both editing copies and
returns the warning "Preserve editing was left out: an .ai file of the
art's bounds would replace the document's artboards when reopened",
as the PDF of the art's bounds does.
- useArtboards: false with pdfCompatible: false is refused, with or
without editingData, since the file would have blank pages and no
editing copy.
- Save, Save As, Save a Copy and exports of the artboards keep both
copies. Legacy version 7 .ai files are written as before.
Docs: docs/mcp.md, docs/target-app-parity.md, document.export params.
Session::place_read and Session::place_queue_read placed a file, or
loaded the place cursor, in whichever document was active when the read
finished. A job prepared in one document could land in another one that
was activated meanwhile, or that stayed open after the first was closed.
Replace did not stop it when the other document held an equal object
under the same id.
PlaceJob, QueueJob and QueueRead now keep the uid of the document they
were prepared in. Both calls refuse a read whose document is not the
active one with "the document it was prepared for is no longer active",
before any selection, edit, tool change or journal entry. Switching back
to the original document places the file as before.
Preferences > Performance > Use Monitor Profile for Canvas (on by default,
`monitorProfileDisplay`) converts the canvas's art, artboard paper and
transparency grid from sRGB into the ICC profile of the display that shows
most of the main window, after any proof. Arranged panes and the render
worker's frames are converted too; the worker keeps its frame in sRGB.
- Windows: the display's default profile for its standard color mode
(ColorProfileGetDisplayDefault, GetICMProfileW where it is missing). A
display with Advanced Color on is left to Windows.
- X11: colord's profile for the RandR output, then the output's
`_ICC_PROFILE`, then the screen's when only one output is active.
- A Wayland session stays sRGB; macOS converts the window itself.
- A profile that is missing, larger than 1 MiB, not an RGB display
profile or unreadable leaves the canvas sRGB, with the reason in
`ui.inspect`'s `displayProfile`.
The conversion is sampled into a 33x33x33 table when a profile is read, on
a background thread. Exports, `ui.render` and the document are unchanged.
Join removed each merged anchor from the path's anchor list as it went,
which moved every anchor after it, so a long selected run in front of
many other anchors took time quadratic in the path's length. It also
looked up each anchor's selection in the selected-anchor set.
Join now marks the merged anchors and removes them in one pass at the
end, reading the selection from one flag per anchor. Each corner or
smooth conversion sees the same neighbors as before, so the resulting
anchors are unchanged. Anchor::smooth_between holds the smoothing that
SubPath::smooth_anchor applies.
Tests compare the new merge bit for bit with the old one on 30,000
generated paths, and count the anchors moved when 300,000 selected
anchors in front of 300,000 others merge: each of the others moves
once.
A graph draws its series groups again with no rows of their own, so a
fill, stroke, opacity or graphic style that a command put on a series
group was lost the next time the graph's data, type or size changed,
and the graph stored nothing. paint.setFill and paint.setStroke already
pass a series group's id on to the paths directly inside it.
- appearance.addFill, addStroke, setItem, removeItem, duplicateItem and
moveItem, graphicStyle.apply and transparency.set with a fill or
stroke item now edit the paths directly in a series group given by id
or picked with Group Selection, and the graph stores what they change.
A series group with no such path, or with a fill or stroke row of its
own, is still edited itself, and appearance.moveItem from "contents"
still moves the group's own Contents row.
- appearance.clear, appearance.reduceToBasic, appearance.showAllHidden
and graphicStyle.breakLink edit the group as well as its paths.
- graphicStyle.apply without add and appearance.transfer onto a series
group clear the group's own opacity, blend mode, isolation, knockout,
effects and style link, and graphicStyle.apply with add unlinks the
group. A transfer source that is one of the group's paths keeps its
look, and a source that is the group's only path is an error.
- graphicStyle.redefine passes the style to the paths of a linked series
group, other than the source and the linked paths whose look was
edited, and clears and unlinks the group.
- graphicStyle.new, graphicStyle.redefine and appearance.transfer read a
series group that holds no row, effect, opacity, blend mode,
isolation, knockout or style link of its own through the topmost path
directly in it, and a move clears each of those paths. A series group
that holds one of them is read itself, as before.
- The Graphic Styles panel reads the style link of such a selected
series group from that path.
Docs: docs/mcp.md, docs/target-app-parity.md. Not yet: the Appearance
panel and appearance.setActiveItem still read the selected group's own
rows, and the effect commands and the paint, stroke and gradient
commands with an item still edit the group itself.
Follows #5501.
- When the faces that overlap form a cycle of depth orders, the order
broke the cycle only after drawing every face with nothing to wait
for, so a cap could be drawn before the walls and they painted over
it. A face drawn last now keeps its place: no face moves across it.
- A face with a corner at or past the eye, which the perspective
projection holds just in front of the eye, no longer gets a plane,
so its depth is not measured on a plane its drawing does not match.
- docs/three-d.md states the masked member rule in Groups as the
Fills and strokes section does, and docs/target-app-parity.md cites
the Inflate test by its name.