A centred or right-aligned line of tracked type was measured with the
tracking after its last character, so it sat half that tracking
(centred) or the whole tracking (right-aligned) left of where the page
of users' .ai files draws it. That page aligns a line as wide as its
characters without that tracking.
Shaping now records the tracking each glyph's advance holds
(SGlyph::tracking), and a line that isn't justified leaves its last
character's out of the width it is aligned by. The last character is
the last one the line draws before a paragraph's end, a forced line
break or the spaces a wrap leaves; spaces or a tab typed before a
paragraph's end or a forced line break keep the letter's tracking, as
the page does. Forced line breaks and wraps aren't in the files: they
follow the rule so that turning a wrap into a paragraph or a forced line
break keeps the line in place. Hyphenated lines, lines whose last
character hangs, vertical and right-to-left lines and type on a path
keep it. The tracking stays in the glyph's advance, so the caret,
selections, line breaking and Fit Headline are unchanged.
LineInfo::trailing gives the amount. Right-aligned area type sets the
text after its last tab the same way.
What aligns by line widths follows. Convert To Area Type makes its
frame end where the lines are aligned, with room for the tracking, so
tracked type converted either way stays in place. Affinity import lines
up differently aligned paragraphs of artistic text by the aligned
widths. SVG import moves a centred or right-aligned letter-spaced line
back by its share of the last letter spacing, so it stays where a reader
draws it and SVG export, which anchors lines at the end of their
advances, reads back unchanged.
Centred and right-aligned tracked type lays out differently than before
in every document.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Under --automation-read-root, ui.inspect and ui.docking hid a library's
path only when its panel was in ui.library_panels. A library used as the
Color Guide's limit, or named by a closed panel's place in
ui.docking_hidden, a workspace layout or the docking layout, still showed
its full loaded/<path> id.
The ids to hide now come from every place the UI state refers to a
library: the library panels, the Color Guide's limit, and the panel ids in
the docking layout, closed panels, icon and collapsed lists and workspace
layouts. Typed text such as a command palette query is not read as an id.
Two hidden libraries with the same file name no longer share one id, which
dropped one of them from an object keyed by panel id. They show as
loaded/<file name>, loaded/<file name> (2) and so on, in the order of
their full ids, and a library has the same id in ui.inspect and
ui.docking.
Docs: docs/mcp.md.
A stop selected on a whole dynamic symbol instance's gradient stayed
selected after Direct Selection picked an object of that instance's art,
because the instance stayed the first selected object. The Gradient panel
kept the stop highlighted and the Gradient tool took Delete and the arrow
keys for it, while every gradient edit is refused for a picked object.
The stop's owner now records whether a part is picked, so the stop is not
selected while one is, and is selected again when the whole instance is.
The blending-mode test for a member of a 3D group now checks that every face of the multiplied member, and no face of the other member, is drawn inside the Multiply group, telling the members apart by height. Before, it only checked that some faces were multiplied and some were not, so it also passed when the mode went to the wrong member.
A filter's id can be any character, so when every letter and digit is in
use a pasted filter at the size limit with a one-letter name now tries the
other printable ASCII characters (`!` to `~`) before the paste is refused.
Filter names are case-sensitive, but a pasted filter at the size limit with a
one-letter name only tried the letters a to z and the digits 0 to 9 as a new
name. A paste was refused while every capital letter was still free. It now
also tries A to Z.
On a group, these effects drew every member's solids in Normal mode: only
an opacity mask on a member or on a group inside the 3D group was applied
to the solids it holds. A member's blending mode, and that of a group
inside the 3D group, now apply the same way, to the solids of the members
it holds together. Group Revolve already did this.
Under --automation-read-root, ui.inspect returned the paths of documents
still opening, the recent files, library panels' files and the folder
preferences even when they lay outside the read roots. The reply now
leaves them out, checked with file_access::check_read as ui.menu.list
checks recent files and listed scripts:
- opening and ui.recent_files keep only the readable paths, in order.
- A library panel keeps its row without its path; a library loaded from
outside the roots shows as loaded/<file name> in its id and panel id,
in ui.inspect and ui.docking.
- The folder preferences in ui.engine_prefs and in an open Preferences
dialog are left out; an empty folder and the scratch disk choices
Startup and None stay.
The app's own state is not changed. Without roots the replies are as
before.
Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md.
Follows #6592. Paste now also skips the names that effects in the
document's brush art use when it picks a free name for a pasted SVG
filter. When no free name keeps the filter within the 64 KB limit (a
one-letter name at the limit with every free letter and digit taken),
the paste is refused instead of keeping the name of the document's
filter. Clipboard::import_into and import_text_styles return a Result,
and their callers pass the error on before the document changes.
The test of #6580 compared only the enabled File > Open Recent Files
rows, so it also passed when ui.menu.list kept a file outside the read
root as a disabled row with its name. The test now compares every row,
marking disabled ones.
main lines a moved selection's edges and centre up with ruler guides
(snap_moved_to_rulers, #5746) but not when Shift keeps the move to its line. The
bounds now slide along that line onto a ruler guide the same way
(snap_moved_along_to_rulers), when nothing else lined up and the grabbed point is
not on a guide, within twice the Snap to Point distance along the line.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
An exception that a finally block passes on, or one that leaves a
built-in's callback, no longer becomes $.error again over an error thrown
after it; throwing a caught error again still makes it the last one.
$.sleep with more than 0 inside a getter, a conversion or a built-in's
callback now throws whether or not the platform has a clock, so the web
build throws there as the other builds do.
Paste renamed a pasted SVG filter to a name no filter of the document
held, but an effect could still use that name, for example after its
filter was deleted. Defining a filter of that name later changed both
effects. Paste now also skips the names the document's effects use,
read only when a pasted filter needs a new name.
A new name with a tab, line feed or carriage return was written into
the filter's id as is, which XML reads as a space, so the id no longer
matched the effect's name. svg_filter::with_id now writes those
characters as character references, and paste takes a name only when
the filter's id reads back as that name.
`leading: "12abc"` set 12 pt leading and returned success, while `size`
and `tracking` in the same command refused trailing text. `leading` now
reads its value with `length_given`, so a string must be a whole number
or a length with a unit. The error message is unchanged.
The compiler now keeps a function declaration's name with its code, so
$.stack no longer shows [anonymous] for a declared function that is
called after the function that declared it has returned. The member test
expects "Web" for $.os in the wasm build, as the engine gives there.
The side limit compared the region's height in points times the scale
with 32,768. Far from the origin the snapped region can come back a
fraction of a pixel over, so art that the renderer draws at exactly
32,768 pixels was refused (a rectangle at y = 100,000 rasterized at
400 ppi). The check now uses the renderer's own rounded pixel width and
height.