A click put the caret among the six digits and the text box holds seven
characters, so only the first character of a pasted code went in. The
field then held no new color, and Enter closed the dialog with the old
color. A press on a field drawn before the hex field also dropped what
was typed, while Tab and Enter applied it.
The hex fields of the Color Picker, Swatch Options, Recolor Artwork, the
Color panel, Document Setup, Duotone, Color Themes and Perspective Grid
now share one set of rules:
- A click or keyboard focus selects the digits.
- A code of six digits, with or without #, replaces the digits wherever
the caret is.
- A code of three digits also replaces them, unless the paste holds only
those digits and exactly three digits stay. Those digits then edit the
text in place.
- A paste of only one, two, four or five digits edits the text in place
when it does not cover all of the text and the result has at most six
digits.
- Any other paste leaves the field as it was.
- A press elsewhere commits the text in the frame of the press.
- A commit returns the digits without # and writes a three-digit code out
as six, so Duotone reads a typed # and Perspective Grid, whose parser
reads six digits only, takes a three-digit code.
Part of #5013
The file-format entry states the 20,000-name limit across brush art and per section, the first-definition rule, and that colors past the limit still count toward the color mode.
Stair Step's glyphs stay upright, so their matrices never show the path
turning and the spacing fit found no turn at all. The fit now takes the
path through each glyph's origin, which lies on the path, and measures
how far it turns over a step from the circle through three origins in a
row.
Each brush art section keeps only the first definition of each color name, and at most 20,000 names. The art of the brushes that come in brings at most 20,000 different color names in all, every section's color operators before any section's gradient stops, so art that no brush uses or that a later section replaces takes no places. Colors left out still count toward the color mode.
A test also checks that a global process color which only a brush's art defines with its color operator stays a process color when a gradient stop names it.
The reader kept a brush's art but dropped the colors it read from it, so
a spot color that only a Scatter or Art brush's art used made no swatch,
and the art's process colors did not count toward the document's color
mode.
The reader now keeps each brush art section's colors with its art. When
the document is finished, the colors of the art that a kept brush uses
are added after the rest of the file's, in the order the art was read:
its spot colors make swatches and its colors count toward the color
mode. Art that no kept brush uses (a pattern brush's tiles, a section
that a later one of the same name replaced, a section inside a symbol's
definition) brings none of its colors, and a spot color that the page's
art, a pattern or a symbol also defines keeps the value defined there.
Part of #637.
3D Ribbon's level baseline faces the way the path runs, so where the path
runs left its baseline and foot are turned round. The spacing fit read
that as a half turn and left the pair out, so a short run on either side
of a vertical tangent came in with no spacing. The fit now turns those
glyphs back first. With an alignment, the two glyphs either side of that
point lie on opposite sides of the path, and that pair is left out.
The spacing fitted from a type-on-a-path layout measured each turn against
the glyph's own foot. Skew's feet stay upright, so on a tilted or leftward
path the turn picked up a false angle and the fitted spacing was wrong (a
straight path at 30 degrees gave -9.7 instead of 0). Effects other than
Rainbow and 3D Ribbon now measure the turn against the baseline turned a
right angle.
The file-format doc states that a frame whose options set key 6 to true
keeps the default effect, alignment and Flip.
`rdp` measured each sample to the infinite line through the ends of the
line that would replace it. A sample beyond either end could be far from
that line segment and still be dropped: a line to (100, 0), a 0.2 pt
U-turn and a line back to (50, 0.2) became one line at a tolerance of
1 pt, leaving the tip 50 pt away. `rdp` now measures to the segment, so a
sample beyond an end is measured to that end, and a zero-length chord
measures to its point as before.
The test `a_path_that_turns_back_past_its_end_converted_to_straight_lines_keeps_its_tip`
covers that path.
Type on a path from a file's text document opened as Rainbow on its
baseline, not flipped, whatever Type on a Path Options the frame kept.
Each frame now keeps its effect (Rainbow, Skew, 3D Ribbon, Stair Step,
Gravity), Align to Path (Ascender, Descender, Center, Baseline) and Flip.
A code or flag that can't be read leaves that option at its default.
Flipped type opens with the frame's path reversed once, after a copied
object takes its own art path, and an open path's end bracket stays so
the type starts where the file's range ends.
Spacing is still fitted from the file's layout. The fit now measures along
the path when Align to Path moves the baselines off it, and it follows the
glyphs' feet under 3D Ribbon, whose baselines stay level.
The test's path zigzags by 0.1 pt. At level 100 the tolerance is 1/32 pt,
and a fit now stays within it, so the preview at that level leaves the
path as it was. Level 0's 32 pt tolerance takes the zigzag out.
Object > Path > Smooth weighed every sample within three spreads of each
point, so the work grew with the square of the anchor count on traced
paths: 360 steps per sample for 1,000 anchors and 2,949 for 16,000.
Consecutive samples within 1/16 of a spread of each other are now
weighed together as their count at their mean place, found through a
tree of sums over the run's samples. A traced outline takes 203 to 286
steps per sample from 1,000 to 64,000 anchors, and every smoothed point
stays within a thousandth of a spread of weighing the samples one by
one (300 random runs).
The curve fitter split a piece over the tolerance at its worst point and
accepted any piece at depth 41 whatever its error. A worst point near the
end of a piece peels off a few points, so a long path refitted nearly all
of its points at every level. A serpentine of 200,000 anchors kept pieces
with a fitted error of up to about 1,598 pt at a tolerance of 1 pt.
Simplify also took at most 256 samples per segment, so the lines between
the samples on a long arc could be farther from it than the tolerance.
- `fit_rec` moves a split that is near an end of its piece to two fifths
of the piece from that end, so the depth is logarithmic, and it keeps no
piece over the tolerance. A piece of 32 points or more is first fitted
to about 16 of them, and it is split when that fit is over the tolerance.
- A curve is also rejected when it is over the tolerance from the lines
between the points it fits, with samples close enough that it stays
within 1% of the tolerance of the chord between them. A pair of points
that would need more than 1,024 samples counts as too far.
- `join_pieces` joins neighboring pieces when one curve fits them, up to
33 pieces per curve.
- `sample_steps` takes enough samples of a curved segment to keep it within
0.5% of the tolerance of the lines between them. A segment that would
need more than 65,536 samples stays as it is, and so does a segment
after a run's first 16,777,216 samples or 2,097,152 result segments. With
Convert to Straight Lines such a segment becomes evenly spaced lines, up
to 65,536. A fit holds at most 1,048,576 samples, so a longer run is
fitted in parts.
- Simplify fits at 98% of the tolerance, since turning a nearly straight
curve into a line moves it by up to 1.5%.
- Above slider level 0, Object > Path > Smooth fits a whole closed path
with no corner along one direction across its start, when no segment
stays as it is and the path is fitted as one part. A direct-selected
section does not get this. The start can still have a kink: a first or
last fitted curve that is nearly straight becomes a line, which leaves
along its chord, and a refit with more anchors than the path is
discarded, so the path stays as it is.
A closed subpath that refits to one curve is still dropped, as on main, so
it can end up farther than the tolerance from the result. docs/mcp.md
states this.
The anchors of every simplified path can differ from before, and so can
the results of the Pencil, Blob Brush and Smooth, which use the same fit.
Session::execute ran check_params only in the engine's own tests, so a
direct execute in a release build ran a misspelled key with the
command's default. It now checks every call, the commands a command runs
included, as MCP and the control port already did. A command.batch or
an action.batch is checked before its first step runs, and each step is
checked again as it runs, so an effect.setParams step is checked
against the effects the steps before it added.
Saved steps play through Session::replay, which takes keys a command no
longer reads, so an action recorded by an older version still plays and
Session::replay still plays an older journal. The Actions panel's Play
(Accelerated, Step by Step and Pause For, its function keys and
ui.action.play) and the Batch dialog use it.
Docs: the cmd/params.rs module doc, the Parameter keys section of
docs/mcp.md and a line in docs/target-app-parity.md describe both
paths.
- The compiler charges each working list's added capacity before it
grows (capacity doubles), the code that joins alternatives, and the
flattened code with its stack, instead of an estimate from
instruction and fragment counts.
- The scan for capturing groups and the syntax check before compiling
each take one unit of fuel per unit of the pattern.
- Bytes a dropped HeldBytes released leave the heap's total at the
next limit check, not at the next collection.
- The progress line lists the deletable RegExp.prototype flag
properties among the test262 failures.
Extrude & Bevel (Classic) has no lighting presets; its lights are set in
its own options. effect.lightingPreset now refuses a target whose effect
at the index is Extrude & Bevel (Classic) with an error that names it,
before any object changes. Before, every preset failed on it with an
unknown-parameter error for lightColor. The params text and docs/mcp.md
state the rule.
The buffer that join, JSON.stringify, the URI functions, escape and
unescape write into takes one unit of fuel for every 16 code units
written, so writing a long run of separators or copying a long string
over and over ends with the fuel limit. Its bytes are added back to the
heap total after each collection until the string is finished, and a
native call that ends early gives them back, so a collection while a
string is being built no longer lets the heap estimate drop below what
is in use.
Array.prototype.join now reads and converts the object's length before
it converts the separator, and still converts the separator when the
length is 0, as ECMA-262 5.1 section 15.4.4.5 steps 2 to 6 give them.
Number objects made by ToObject now carry their primitive value, as
String and Boolean objects already did (ECMA-262 5.1 sections 8.6.2
and 9.9). JSON.stringify reads it for a value, a replacer list entry
and the space argument (section 15.12.3, Str step 4, step 4.b.ii and
step 5) when the method that ToNumber or ToString calls first is not
found before the object's own prototype, so JSON.stringify(Object(3))
gives 3 and JSON.stringify(Object('abc')) gives "abc". A valueOf or
toString on the object or on its prototype still runs.
A live effect that declares commands may list `doc.write` and `state`, and
gets them when its manifest leaves `permissions` out, as a filter does. Only
its commands use them: drawing the effect changes no object and keeps no
data. Before, every output of such a command that changed an object was
refused, since a live effect could never hold `doc.write`.
The help text of appearance.addFill, addStroke, clear, reduceToBasic,
removeItem, duplicateItem, moveItem, copyFrom, showAllHidden and transfer,
paint.default, and graphicStyle.apply and redefine said the graph stores
only the paint and weight of the topmost visible fill and stroke. These
commands also store that row's opacity and blend mode, as
appearance.setItem's help and docs/mcp.md already say.
Native code now holds the Rust memory it works in against the heap limit
until it is done with it: a matcher's capture state and stack, a pattern
being compiled, the matches and pieces of a replacement, and the text
Date.parse reads. A collection counts these bytes as live while they are
held.
- replace reads its replacement pattern once into parts that refer to
ranges of the pattern, so literal text is not copied for each match.
Each piece takes fuel for its units, and the result's length is
checked against the heap as each piece is added.
- The regular expression compiler charges heap through its callback as
it builds, including the ranges of a character class, and each class
atom and range takes fuel. A compiled form counts the capacity of its
lists.
- Clearing the groups inside a quantifier and clearing the matcher's
state before each attempt take fuel.
- Flattening a rope in a String, RegExp or Date method reserves the
flat copy on the heap and takes fuel for it.
- A RegExp object's bytes are reserved together with its compiled form,
so a collection between the two does not drop the compiled form from
the heap count.
Section 15.4.4.13 steps 6 and 7 move every element by the argument count, so with no arguments each element is read and put back in place: getters and setters run, and a read-only element throws a TypeError.
The Keyboard Shortcuts entries and the default keymap were made again
for each set of installed plug-in commands and kept for the rest of the
process. They are now shared values kept only for the current set of
plug-in commands, so an older one is freed once nothing holds it.
The test that compares the keymap's catalog with the entry list reads
both for one set of plug-in commands, so a test that installs a plug-in
alongside it no longer makes it fail.
Section 15.2.3.4 leaves the order of the names open. An array's length now comes after its indices and other properties, so Object.getOwnPropertyNames([0, 1, 2]) gives 0,1,2,length, as later editions and test262 expect. length is not enumerable, so Object.keys and for-in are unchanged.
On a large canvas no art style is written, so the editing data holds an
object's geometry effects only as the artwork they made: the effects can
no longer be edited when the file is opened again. The warning now says
that the geometry effects are applied to the artwork and can no longer be
edited, and that the object's other effects are left out.
Takes #6178's rooting of every native call's arguments, the fuel per argument apply reads and the Error objects as NativeError prototypes. The bound-function and apply arm that rooted arguments only for those calls is removed, since every native call now roots them; the parsing line in docs/target-app-parity.md takes #6178's wording.
Function.prototype.apply reads up to 65,536 elements from an array-like
object. Each element read now takes a unit of fuel, so a long list ends
the run with the fuel limit as other loops in the interpreter do.
Section 15.4.5.1 steps 3.c and 3.d convert the new length once with
ToUint32 and once with ToNumber. [[Put]] reaches that algorithm through
[[DefineOwnProperty]], so a.length = v now calls v's valueOf twice, the
same as Object.defineProperty(a, 'length', {value: v}).
Tests count the valueOf calls on both paths, check that JSON.stringify
converts Number and String objects with ToNumber and ToString, and check
that toLocaleString calls each primitive element's method on the object
ToObject makes.
plugin.run and plug-in commands read `ids` strictly: a value that is not
a list, or an entry that is not a non-negative integer, is an error
naming `ids` ("ids must be an array of non-negative integer object
ids"). Left out or null, `ids` is still the selection.
A new test shows that a plug-in command that runs out of its
instruction budget leaves the document and the undo history unchanged,
and that the error names the plug-in and the command.
docs/plugins.md and docs/mcp.md name MCP's `command_list` and
`list_commands` as the listings that show plug-in commands, and the
params text, docs and progress line describe the `ids` rule.
parseInt collected every digit into a vector outside the heap count and
then copied the digits again for a base-10 parse, and parseFloat copied
its whole decimal prefix the same way, so one call on a long string could
allocate more than the heap limit. parseInt now counts the digits in
place, reads bases other than 10 straight from the string, and both
functions reserve heap for the base-10 copy before they make it. A
concatenation that the global functions flatten is charged to the heap,
as sort keys are.
A realm now has String, Number, RegExp and Date as ECMAScript 5.1
sections 15.5, 15.7, 15.9 and 15.10 define them, with Annex B's substr,
getYear, setYear and toGMTString.
- String: every ES5 prototype method; split, replace, match and search
take strings and RegExps. Each new string's length is checked against
the heap limit before it is built, and scans take fuel.
- Number: toString(radix), toFixed, toExponential and toPrecision
format from the number's exact decimal value.
- RegExp: a backtracking matcher keeps its choice points and capture
state on the heap, within the heap room left, and takes fuel for every
step, so a catastrophic pattern stops at the fuel limit. Patterns
nested past Options::max_depth give a SyntaxError. Flags g, i and m,
lastIndex, exec, test and toString.
- Date: chrono converts days to calendar dates, shifting by whole
400-year cycles past its years. Realm::set_clock and
Realm::set_time_zone set the clock and local time (UTC by default).
Without a hint, a Date converts to a primitive as a string.
cargo xtask test262 also runs the suite's built-ins tests for the four
and prints their counts.
Covers what review asked for: each edge and the centre on its own guide from
either side, two guides at once, which line wins a tie and that a nearer one
wins, the snap distance in screen pixels at several zooms, and a ruler guide
that is hidden (guides off, or its layer hidden) pulling nothing.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113uEh4wFdhVAzX8oKSWCHC
A host function has no own length, so a script can define one with a
fraction, and the bound function's length kept it. Function.prototype.bind
now converts the target's length to an integer before it subtracts the
bound arguments, as later editions specify.
The commands list is read one entry at a time from the manifest itself,
so a command's dialog shows its parameters in the order the manifest
declares them, and a parameter declared twice in a command is refused
with an error naming the command.
Object.defineProperty, Object.defineProperties and Object.create added
each new property without checking the heap limit, so one call could
take the heap estimate past the limit before the run stopped. The
property's size is now reserved before it is added, with the object and
the descriptor's values kept reachable while a collection runs.
registry::install now changes the revision while it holds the plug-in set's write lock, so a reader that sees the new revision and lists the plug-ins always finds the new one. command_specs also skips caching a list when the revision changed while it was listing. Before, a menu or shortcut lookup that ran during an install could keep the old command list until the next install or removal.