Two installed versions of one font are two fonts of the set, so each
keeps its own /5. The generated variable test font now has a version
(name ID 5), and the test checks each variable record writes it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A new test walks every code point from U+0000 to U+10FFFF, surrogates
left out, and compares the start and part checks with Unicode Standard
Annex #31's general-category definition of ID_Start and ID_Continue,
written out in the test. The test also checks the set sizes against the
totals in Unicode 16.0's DerivedCoreProperties (141,269 and 144,541).
- The Other_ID_Continue test covers every code point of the property,
U+136A to U+1370 and the zero width non-joiner and joiner included.
- The zero width non-joiner and joiner are part of the Other_ID_Continue
list in chars.rs instead of a separate case.
A drop guard restores egui's app-wide option, so a panic in the popup's panel
(caught by the app's guard) no longer leaves presses ending every field's edit.
is_id_start now accepts the Other_ID_Start characters (U+1885, U+1886,
U+2118, U+212E, U+309B, U+309C), and is_id_part the Other_ID_Continue
characters (U+00B7, U+0387, U+1369 to U+1371, U+19DA, U+30FB, U+FF65),
as Unicode's ID_Start and ID_Continue properties and the ECMAScript
Names and Keywords clause define them. Letters, marks, digits and
connectors that are Pattern_Syntax are refused, which replaces the
U+2E2F special case. Escaped identifier characters go through the same
check. A supplementary letter right after a number is now the
"identifier starts immediately after numeric literal" error.
Letter categories still come from Unicode 16.0, so characters assigned
in later versions are not identifier characters yet.
Docs: docs/mcp.md, docs/target-app-parity.md.
docs/mcp.md and docs/target-app-parity.md said that a width or height
typed with Measure Type by Glyph Bounds on changes the font size by the
scale. The font size follows the vertical scale only: a width typed
alone, out of proportion, changes the horizontal scale and keeps the
font size, and a height typed alone changes the horizontal scale the
other way. A new test checks both.
The Properties panel's Stroke link and the Appearance panel's Stroke: row open
the Stroke panel as a popup. A click outside closed it without drawing it
again, so the dash field (or any other field in it) never saw itself lose the
keyboard, and what was typed went back. A popup closing while one of its
fields has the keyboard now draws once more first: the field lets go of the
keyboard to the click and commits, as it does in a panel. The Appearance
popup closes on the press, before it is a click, so for that last frame a
press is what lets go of the keyboard. Escape still drops what was typed.
A variable font's CoolTypeFont record in the text document now carries
/4 (its design vector, one 16.16 value per fvar axis) and /5 (its
version string), and the font set keys on name plus design vector, so a
named instance or a run's own axis setting no longer opens at the
font's default instance. Static fonts are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Inflate's grid clipped every ring of the outline in each cell the
outline crosses and tested every edge for each cell's center, so its
work grew with the outline's points times the cells: a comb of 4,000
teeth (16,002 points) took 1.1 to 1.3 s and one of 16,000 teeth 8.8 to
9.1 s. Inflate now counts that work (the edge index's entries, the edges
its queries look at and the ring points its cells clip) and refuses the
shape with "The 3D surface is too complex; simplify the shape" once it
passes 268,435,456, VectorCraft's own value (about 0.65 s). The index
takes at most 16,777,216 entries (64 MiB). Each row's inside test reads
the sorted crossings of its line, and a cell clips only the rings whose
bounds meet it, so a 65,536-point circle inflates in 0.66 s instead of
1.0 to 1.2 s.
The effects test of a stroke past the limits uses 40,000 corners, so its
outline passes the 65,536 points a solid takes.
Docs: docs/three-d.md, docs/mcp.md.
A script.run that a control request started in the app's frames was
advanced by later frames, which run unconfined, so its vc.run file
commands could read and write outside the caller's automation roots.
The job now keeps the file-access scope of its script.run and runs
each slice in it, as background opening and the folder walker do.
Both commands show the Separations Preview panel (#4542), whose Color Settings
section, with the Assign row, comes after the plates and Proof Setup. A
floated panel fits its content only up to 320 points, so the section opened
out of sight and the panel looked like the wrong one. The commands now leave a
one-shot flag that scrolls the section into view, without animation, the next
time the panel draws. Window › Separations Preview and edits made in the panel
leave the scroll alone.
Each Extrude & Bevel and Inflate solid now takes up to 65,536 outline
points (was 2,048) and 163,840 faces (was 32,768), VectorCraft's own
limits, as Revolve's. Before any point is sampled, the outline's lines
and curves are counted with each curve's tolerance pieces, and the faces
the walls, bevels and caps (Extrude) or the sides (Inflate) need. When
they do not fit, every curve takes fewer pieces, down to 4; a shape that
does not fit at 4 is refused with the existing surface error before any
face is built. The subpath count is capped at the point limit too. The
error texts are unchanged.
A closed path of 2,000 curves now extrudes with a bevel and inflates,
and paths of 5,000 and 10,000 curves build at the default settings.
Docs: docs/three-d.md, docs/mcp.md, docs/target-app-parity.md.
The put-back after a failed page check replaces each live envelope with
its drawn art in one go, which fails as a whole when one envelope lies in
another's art: only the outermost are put back now. A live envelope of
type removes its hidden type only once it has found the drawn art it
replaces. The file format docs lose a revision row left twice by a rebase.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A variable library binds the text object a slot of the envelope's
contents became, which stays hidden beside the drawn art. Once the
envelope opened live that hidden text object went, and its type in the
envelope has an id of its own, so a visibility binding was dropped and
counted as one that wasn't made. A slot bound to a text variable
already kept the drawn art; one bound to a visibility variable does
too now, with the note, so the binding is kept.
Carrying the binding over to the type in the live envelope would bind
an object inside an envelope's contents, which nothing in the import,
the data sets or the .ai writer is known to handle, so it is left for
later.
Part of #3179.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An envelope of type opens live only where the layers with it draw as
the page. Two ways of using layers that don't left it live all the
same: the editing data trusted (they come from it with a note), and
the objects that draw differently coming in as the page's art. In both
the envelope now keeps its drawn art and its type, hidden, with the
note, as where its drawn art is put back. A .ai whose layers would
open alone, without its PDF part, then opens alone again, as it did
before envelopes of type could open live, rather than compared with
the page.
The type put back no longer carries the mark of type made from the
text document in its name.
Part of #3179.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The comparison with the page counts the area of each text object that
shows as type, which it holds to less (type laid out again from the
file's text can sit a little apart from the page's). It took the text
object in a live envelope's contents for such type, at its own unbent
box, so most of what an envelope of type draws went unweighed: one
opened live where the page draws other art there, with only a note
that the type differs. The envelope draws its type bent, as art, and
is now weighed as such, as the drawn art it takes the place of is.
Part of #3179.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An envelope whose contents hold type kept its drawn art, with the type
hidden, because the type is laid out from the text document only after
the layers are read. It now waits for that, as warped type does: once
its text slots hold their type, the envelope is made of that type and
drawn by VectorCraft's own rule, and where it draws as the drawn art the
file saves (the same check and budget as other envelopes) it takes the
drawn art's place, with the type visible and editable in Edit Contents.
The hidden copy of the type goes.
As other live envelopes are, it is held to the page: when the layers
with it don't draw as the page, its drawn art and hidden type are put
back. A .ai whose layers would open alone, without its PDF part, now
waits on the PDF part when an envelope of type is in them; where none
opens live, the layers open alone as before. Layers built without a page
leave envelopes of type their drawn art.
Elsewhere it keeps its drawn art and hidden type, with the note: type in
a font that isn't available, a slot without made type (threaded, bound
to a text variable, a wrap object, type a look draws), an envelope that
doesn't read, no check left, or one that draws differently. Envelopes in
a symbol's or a pattern's art keep their drawn art.
Part of #3179.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Done ran text.spelling.removeWord and text.spelling.addWord one word at a
time, each saving the file, so a save that failed after a delete was saved
left that word deleted even after Cancel. text.spelling.editDictionary
{remove, add} makes every change, saves once and takes all of them back when
the save fails; Done runs it once.