Commit Graph
10785 Commits
Author SHA1 Message Date
dotCooCoo 47db0b7a8a JavaScript: declarations check the heap before they are bound
Declaration binding instantiation reserves an upper bound of what a script's,
eval's or function's variables and function declarations add to the heap
before making them, and each declaration and parameter takes a unit of fuel.
A long declaration list now ends with the heap limit without growing the
estimate past it.

Realm::set_limits recomputes when the next collection runs, so a lowered heap
limit applies to the next run instead of after the old threshold.

ToNumber skips the same white space and line terminators as the lexer, so
U+180E is no longer white space in a numeric string.
2026-11-07 14:07:07 -08:00
dotCooCoo e1cc8d5de6 JavaScript: names and host error messages count toward the heap when they are made
A new property or binding now adds its name's code units to the heap
estimate when it is inserted, so names declared by eval or Function
source move the estimate toward a collection. Function parameter and
catch bindings no longer count their entries twice.

A host function's error message reserves its size in the heap before
the error object is made, so a message larger than the heap ends the
run with the heap limit.

The Function constructor sums its arguments' lengths and checks the
source limit before flattening or copying any of them, and builds the
source from their code units, so a lone surrogate in an argument is
kept.
2026-11-07 13:49:13 -08:00
dotCooCoo dfd0b1c949 JavaScript: a finally block keeps the try block's completion value, and host strings count toward the heap
In script and eval code a finally block that ends normally leaves the completion value of its try or catch block (ECMA-262 5.1 section 12.14), so try { 1; } finally { 2; } completes with 1. A new GetCompletion instruction saves the value when the finally block starts, and SetCompletion sets it back when the block ends normally; a break, continue or throw out of the finally block still replaces it.

A string returned by a host function is charged to the heap, and one that does not fit after a collection ends the run with the heap limit.
2026-11-07 13:32:53 -08:00
ruchirguitar 90d4e3d65f M2.1: verify preserved path geometry after deletion (#3380) 2026-11-08 02:51:51 +05:30
dotCooCoo d16ff70fd3 JavaScript: a collection counts the code units of property and binding names
A collection counted each property or binding at a fixed 64 bytes and
never counted the name's own buffer. Once the string that produced a long
name became garbage, the name kept its buffer alive while the estimate
dropped it, so a script could hold megabytes of names past the heap
limit. trace_object and trace_env now add each name's buffer, counting a
buffer that a flat string value or another name shares once.
2026-11-07 13:19:19 -08:00
dotCooCoo f045adba2b JavaScript: a function made by the Function constructor does not bind the name anonymous
The constructor compiles its source as (function anonymous(...) {...}), and the
compiled function bound anonymous to itself as a named function expression does.
That binding shadowed a global variable of the same name. ES5.1 section 15.3.2.1
creates the function with the global environment as its scope and no name binding,
so the constructed function now leaves the name unbound.
2026-11-07 13:09:41 -08:00
dotCooCoo e85cecfa99 JavaScript: for-in over a String object checks the heap before listing its indices
Listing a String object's index names for for-in built one name per UTF-16 unit before any
limit check, so a string within the heap limit could make the loop allocate many times that
limit. The heap budget for all the names is now checked first, after a collection if needed,
and each name takes a unit of fuel. A wrapper made by ToObject stays rooted while the names
are listed.
2026-11-07 13:02:26 -08:00
dotCooCoo 5d61122b77 JavaScript: a strict realm runs scripts as strict mode code, and apply unroots its arguments when one throws
Realm::run compiles the script with the realm's Options::strict instead of always as sloppy code, so a realm made with strict: true rejects with statements and calls functions with an undefined this. Indirect eval and Function keep their own strictness (ES5.1 10.4.2, 15.3.2.1).

Function.prototype.apply drops the temporary GC roots it holds for the argument values when an index getter throws, as it already did when reading succeeds. Before, a caught throw left them rooted until the run ended, so a loop of such calls could reach the heap limit.
2026-11-07 12:54:06 -08:00
Ahmed Gomaa cdd00ff3bc G13: expose glyph and alignment toggles in Snapping (#6164) 2026-11-07 22:51:09 +02:00
dotCooCoo 188142a792 .ai save: a symbol first defined inside a drawn look warns of its art's effects
A symbol whose first instance is written in the drawn look of an object
with a style (through a member's scatter brush) was defined while the
look's flag was set, so the warning for the effects its art loses was
left out, and the cached definition kept it out for later instances.
The definition now writes its art with the flag cleared and restores it
afterwards.
2026-11-07 12:49:12 -08:00
ruchirguitar 84341cc1cf 5949: keep panel wheel turns out of canvas zoom glides 2026-11-08 02:16:49 +05:30
dotCooCoo ba9e78ebfd JavaScript: a run clears the last uncaught exception and checks source length before encoding
Realm::run now resets the exception that bind_last_thrown binds, so a run
that completes, reaches a limit or does not parse leaves it undefined. The
script source, the text built by Function and the strings given to eval are
checked against the run's remaining max_source_units before they are encoded
or flattened, so an oversized source is rejected without being copied.
2026-11-07 12:45:02 -08:00
dotCooCoo d026e6ae26 JavaScript: interpreter with a garbage-collected heap and execution limits
vectorcraft-js gains a Realm that runs ECMAScript 5.1 scripts. The parsed
script compiles to stack-machine bytecode, a verifier checks every jump
target, handler, constant index and stack depth before the code runs, and
the interpreter keeps JavaScript calls on its own frame stack. Closures,
this, arguments, with, direct and indirect eval, new Function,
try/catch/finally, labeled break and continue, and for-in in insertion
order follow sections 10 to 14 of ECMA-262 5.1. Variable references are
resolved before the right-hand side of an assignment runs (11.13).

Objects and environments live in an arena with a mark-and-sweep
collector and index handles. Built-ins are limited to Object and
Object.prototype's basic methods, Function with call and apply, eval
and the error constructors.

Every run is bounded by fuel, heap bytes, frames, nested host calls and
an interrupt flag another thread can set, with smaller defaults in the
wasm build. A run that reaches a limit ends with a limit error that a
script's try cannot catch. Source passed to eval and Function counts
against Options::max_source_units.

cargo xtask test262 also runs the suite's ES5 test/language tests that
need only these built-ins and prints their counts apart from the parse
counts. Nothing in the app calls the interpreter yet.
2026-11-07 12:36:48 -08:00
ruchirguitar c232919dd3 M2.1: clarify deletion evidence and function documentation (#3380) 2026-11-08 02:02:31 +05:30
dotCooCoo 600ce68bc7 Docs: only filled even-odd paths lose their live effects in a saved .ai
A stroke-only path or compound path that uses the even-odd rule keeps
its live effects in the editing copy; the art-style writer leaves out
only paths that fill by the even-odd rule.
2026-11-07 12:28:17 -08:00
Ahmed Gomaa d8f8ff0222 Docs: the Type core row keeps the harakat paint limit
Fonts without GDEF mark classes and some AAT ligatures can still leave a mark painted as its letter. Scores and estimates are unchanged.
2026-11-07 22:24:41 +02:00
Ahmed Gomaa 11cfde2661 Type: harakat tests tell letter dots from authored marks
Noto Sans Arabic draws a letter's dots as zero-advance GDEF marks, so the tests expected a beh's dot to take its kasra's colour. Compare against the glyphs of the bare letters instead. Strict colour, geometry and kashida ownership assertions stay as they were.
2026-11-07 22:24:41 +02:00
dotCooCoo 9c0e7ccb80 .ai save: the editing copy keeps graphic styles and links to them
The editing copy of a PDF-compatible .ai left out the Graphic Styles
panel's styles and objects' links to them, with a warning. They are now
written as art styles:

- The panel's styles come first in %AI9_BeginArtStyles and are listed in
  its order in %AI9_BeginArtStyleList after the palette, with their
  fills, strokes, transparency and effects. Fills and strokes may have
  transparency and effects of their own, and a style may also hold Warp,
  Transform, Free Distort, Pucker & Bloat, Twist, Zig Zag or Gaussian
  Blur. A style of an object's own holds the same effects as before.
- A path, compound path or group linked to a graphic style names it when
  it has the style's appearance, the style is written, and the reader
  reads that style on that object. Objects linked
  to a new document's styles keep their link: the panel is written for
  them too.
- The writer reads each style back with the reader before it writes
  it. A style with gradient or pattern fills, with anything the
  reader does not read back, with a name another style has, with a name
  over 1,024 bytes or past 4,096 styles is left out with a warning. Other
  links are left out with a warning, and a panel with no style written
  warns that it opens with a new document's styles. No graphic style is
  written on a large canvas, with a warning.

Graphic styles:
https://helpx.adobe.com/illustrator/desktop/special-effects-styles/apply-graphic-styles/apply-graphic-styles.html

Tests: the round trip of the panel's styles and of links; each effect a
style can hold; the forms written; the list's limits; duplicate names; an
empty panel; links left out; a style's opacity at the written precision;
a large canvas; Twist and Transform on an object with no link; a link
to a style whose Transform moves the outline, with and without an
opacity mask; the
reader's reading of warp numbers; fuzz cases for damaged written styles.

Docs: docs/file-format-parity.md.
2026-11-07 12:02:18 -08:00
dotCooCoo 8374e694d8 Docs: effects are kept only where the writer supports the appearance
The editing copy keeps live effects on qualifying objects only when the art-style writer supports their appearance and effects. README, ROADMAP and the progress docs now say so and link to docs/file-format-parity.md for the limits.
2026-11-07 11:57:54 -08:00
dotCooCoo f9788771db Docs: art styles cover eligible objects only
The .ai editing copy writes an art style for paths, compound paths and groups with live effects only when they have at most a fill and a stroke, fill by the non-zero rule, and are not on a large canvas. README, ROADMAP, gaps, roadmap and target-app-parity say so.
2026-11-07 11:28:29 -08:00
dotCooCoo 1f6be41d8a Docs: the .ai editing copy keeps live effects on simple objects only
The fallback for objects that can't use an art style keeps their vector
art with geometry effects applied and leaves out their other effects,
such as Drop Shadow, the glows and Feather. README, ROADMAP, gaps,
roadmap and target-app-parity no longer say every live effect is left
out, and target-app-parity lists the round-trip tests.
2026-11-07 10:59:50 -08:00
dotCooCoo 6bb3d3dfbe JavaScript: a for-in variable initializer is a SyntaxError in strict mode code
Current test262 (ECMA-262 2017 Annex B.3.6) accepts `for (var x = 1 in o)` only outside strict
mode code. The parser now rejects the initializer in strict code, with the error at `in`.
2026-11-07 10:51:53 -08:00
M Balazs PC c78d4c4402 Merge branch 'fix/ai-type-leading-forced-breaks' into fix/ai-right-aligned-tabs
# Conflicts:
#	docs/file-format-parity.md
#	docs/roadmap.md
#	docs/target-app-parity.md
2026-11-07 19:45:08 +01:00
M Balazs PC 1e43455d7c .ai/EPS import: the docs give frame fitting's exact limit and qualify the file format status line (#6137) 2026-11-07 19:44:48 +01:00
M Balazs PC bef4661d04 Merge branch 'fix/ai-type-leading-forced-breaks' into fix/ai-right-aligned-tabs
# Conflicts:
#	docs/file-format-parity.md
#	docs/roadmap.md
#	docs/target-app-parity.md
2026-11-07 19:43:03 +01:00
M Balazs PC 61afca297a .ai/EPS import: the progress docs say frame fitting may show more of a frame's last lines, not that it always does (#6137) 2026-11-07 19:42:33 +01:00
Ahmed Gomaa e3d5fee42c Type: colouring Arabic marks preserves joining and glyph ownership
Paint-only harakat runs stay inside one shaping cluster so letters keep
their joining forms and marks their attachment. When a character-level
shaping pass matches the monotone glyphs, a glyph may take a later
in-cluster character's run only if GDEF classifies it as a mark (class 3)
and that character is a harakat; otherwise ownership stays at the cluster
start. Conservative: a mark may miss its colour; a base letter must never
take a mark's. Fonts without GDEF and AAT faces fall back the same way.
Insert Kashidas tatweels take the base letter's paint, not a trailing
mark's. Private harakat module; type-parity, target-app-parity and roadmap
M7 evidence updated (scores unchanged). Tests cover paint_only / ranges /
own_chars (wide mark, equal advance, multi-component, single-glyph
ligature, review counterexample), colour, hide, repeated glyph ids,
kashida, forced mark-last emit_kashida, and installed fonts.
2026-11-07 20:41:37 +02:00
dotCooCoo 74caec60d4 Commands: the View commands check their params against machine-readable schemas
A new standalone crate, vectorcraft-apischema, describes a command's
parameters: type (number with range and unit, integer, boolean, string,
enum, id, id list, color, point, object, array), whether each is
required, the default of an omitted value, whether null counts as
omitted, the API levels it was added and deprecated at, and the lenient,
cost and writes fields. It validates a params object and names the
parameter of the first problem, writes the params text, writes the
schema in the shape of a JSON Schema 2020-12 object schema, and hashes a
set of schemas.

CommandSpec gains an optional schema (both builders: the cmd! macro and
the text style specs). Session::execute checks the params of a command
that has one before anything else, refusing a value of the wrong type,
out of range or not in its list, a missing parameter or an unknown key
with an error naming the parameter, and fills in defaults; the journal
keeps the params as given. engine.commands lists each schema.

The six commands in cmd/views.rs have schemas, and their params text is
the text the schema writes. schemas::API_VERSION is 1, and a test fails
when a schema changes without a new row in SCHEMA_HASHES.

Docs: docs/mcp.md (Parameter schemas), docs/target-app-parity.md.
2026-11-07 10:37:02 -08:00
M Balazs PC 8561ef351c Docs: the line layout functions the tab fix touches say what they do 2026-11-07 19:34:47 +01:00
M Balazs PC 2beae3e7b4 .ai/EPS import: the tab stop fixes are noted on M4 and M7 and in the feature revisions (#6147) 2026-11-07 19:31:52 +01:00
M Balazs PC 0234de1302 Merge branch 'fix/ai-type-leading-forced-breaks' into fix/ai-right-aligned-tabs
# Conflicts:
#	docs/roadmap.md
#	docs/target-app-parity.md
2026-11-07 19:31:52 +01:00
M Balazs PC 4bfd7a207d Docs: the functions the line layout fixes touch say what they do 2026-11-07 19:30:49 +01:00
M Balazs PC 66be035055 .ai/EPS import: the progress docs state the limits of the line layout fixes and note them on M4 and M7 (#6137) 2026-11-07 19:30:49 +01:00
dotCooCoo 05c1be3548 JavaScript: parser for ES5 scripts, with cargo xtask test262
New crate vectorcraft-js reads ECMAScript 5.1 source into a syntax tree
with source positions: a UTF-16 lexer (line and column tracking, automatic
semicolon insertion, the regexp and division goals), preprocessor lines
read as directive tokens, a recursive-descent parser to an arena tree, and
the ES5 early errors, strict mode included. Nesting deeper than
Options::max_depth (200 by default) gives a SyntaxError with its line and
column rather than overflowing the stack. Nothing runs scripts yet.

cargo xtask test262 downloads test262 at a pinned commit, checks its
SHA-256, unpacks it into the gitignored corpus/ folder and runs the ES5
syntax tests. A differential test in the engine compares the lexer with
scriptcheck on line counts, directives and unterminated literals.
2026-11-07 10:29:51 -08:00
dotCooCoo 72c46b8aa2 Path ops: boolean contour passes test the shapes covering each face instead of a flag per shape
The contour passes of the two-path boolean operations, Offset Path and
the many-shape boolean (`boolean_n`, used by compound shapes and
Intertwine) built a flag for every input shape for each winding they
tested. They now test the list of inputs that cover the face, ascending,
refilled in one buffer per pass, so a test costs the size of the cover
rather than the number of shapes. `boolean_n` and `try_boolean_n` take
that list; the compound shape and Intertwine tests read it directly.

The contours, their order and the output are the same: a new test
compares every pass's test with the flag form on overlapping, nested,
touching and apart squares and on 72 overlapping squares, and another
checks that a pass over 100 squares apart hands its test one input at
most.
2026-11-07 10:28:25 -08:00
M Balazs PC fe3b9b3a4d .ai/EPS import: the parity assessment's evidence and revision history record the tab stop fixes (#6147) 2026-11-07 19:25:54 +01:00
M Balazs PC d8134e8bd6 Merge branch 'fix/ai-type-leading-forced-breaks' into fix/ai-right-aligned-tabs 2026-11-07 19:25:54 +01:00
M Balazs PC 1b364b955d .ai/EPS import: the parity assessment's evidence and revision history record the line layout fixes (#6137) 2026-11-07 19:25:43 +01:00
M Balazs PC b46d321c2b .ai/EPS import: the parity assessment and roadmap record the tab stop fixes (#6147) 2026-11-07 19:25:01 +01:00
M Balazs PC 4c5ba22fdd .ai/EPS import: a paragraph's tab stops past the limit are reported too 2026-11-07 19:25:01 +01:00
M Balazs PC d9fdd7a072 Type: the last tab of right-aligned area type leaves room for the hyphen a hyphenated line ends with 2026-11-07 19:25:01 +01:00
dotCooCoo 6c285d3042 .ai save: the editing copy keeps live effects
The editing copy of a PDF-compatible .ai wrote an object's live effects
as their result (geometry effects) or left them out (the others).
Objects with effects the .ai reader reads are now written as art styles:

- An object is written as its drawn look (a group of its vector art as
  its geometry effects leave it, without shadows, glows or feathers,
  with the object's transparency after it), then the object itself on
  %_ lines (its points painted with nothing, or with its gradient fill
  placed on the outline it draws; a group with its members), its name
  and opacity mask, and
  1 (style) XW naming its style.
- Styles are written in a non-printing block after the symbols, in
  %AI9_BeginArtStyles: a chain of the stack of fills and strokes (with
  the contents where the appearance puts them), the effects and the
  object's transparency. Objects of the same appearance share a style.
- The effects written are the ones the reader reads on objects, with
  their settings in the units it reads them in: Drop Shadow, Inner Glow,
  Outer Glow, Feather, Round Corners, Scribble, Convert to Shape, Offset
  Path, Outline Object, Outline Stroke and Pathfinder > Add.
- Each style is read back before it is written, by a new reader
  function, read_art_style, which runs the reader's style parser and its
  reading of a graphic style with the object's own gradient. An object
  whose style reads back differently (several fills or strokes, fills
  or strokes with transparency or effects of their own, pattern fills,
  other effects), a filled object that fills by the even-odd rule (a
  style's fill fills by the non-zero rule), a group whose effects change
  its members' outlines while a member is written on another outline
  (strokes as filled outlines, pattern fills as tiles, gradients that
  fit their object), or one in a container whose own
  effects change its members, is written as its drawn look with the
  warning, and a style that is not written leaves no gradient
  definition behind. Graphic styles and links to them are left out with
  a warning. No art style is written on a large canvas.

Appearance attributes:
https://helpx.adobe.com/illustrator/using/appearance-attributes.html

Tests: the round trip of objects with each effect, a gradient fill, a
group with transparency and a mask, Pathfinder > Add and a hidden
effect; the same bytes on a second write; the forms written; the
objects the reader would not read; a large canvas; the warning for
graphic styles; filled even-odd objects; a gradient placed on the
outline Offset Path draws; a style that is not written; effects in a
pattern a drawn look uses; the reader's check of a style; fuzz cases
for damaged written styles.

Docs: docs/file-format-parity.md.
2026-11-07 10:17:51 -08:00
M Balazs PC d889390731 Tests: the right-aligned tab test uses its own example text 2026-11-07 19:14:21 +01:00
M Balazs PC 36511e1bbd Merge branch 'fix/ai-type-leading-forced-breaks' into fix/ai-right-aligned-tabs 2026-11-07 19:10:42 +01:00
M Balazs PC c0341c3fff Type: a paragraph ending in a soft return justifies the line the soft return ends
A paragraph that ends in a soft return ends with the empty line after it,
so the line the soft return ends is justified like any other; it was taken
for the paragraph's last line and left aligned.
2026-11-07 19:10:21 +01:00
M Balazs PC 88bc2ac06a .ai/EPS import: type keeps its paragraphs' tab stops
Key 30 of a paragraph's attributes holds its tab stops: each its position
(key 0) and alignment (key 1: 0 left, 1 center, 2 right, 3 decimal).
They were not read, so tabs fell on the default stops. At most 1,024 are
read a paragraph and 2^20 copied into a story's paragraphs, past which the
default stops apply with a warning. The fuzz test feeds hostile paragraph
attributes: alignments, auto leading, hyphenation options and tab stops.
2026-11-07 18:49:20 +01:00
M Balazs PC a4e315796b Type: right-aligned area type sets the text after a line's last tab against the edge
In right-aligned area type, the text before a line's last tab sits at its
stops, measured from the left edge, and the text after it (none when the
tab ends the line) against the right edge. The line was laid out from the
left and aligned as a whole, which moved its start off the left edge and
its tabs' text off their stops. Illustrator's own layout in a user's .ai
sets its price lists so. Centred and justified lines are aligned as a
whole as before.
2026-11-07 18:49:19 +01:00
dotCooCoo db61a47435 Docs: the region-building line gives the latest Divide timings and more of the commands that use it
The line names trapping, Intertwine and the Pathfinder effects next to
Divide, Hard Mix, Soft Mix, Shape Builder and Flatten Transparency, and
gives six alternating runs of each build of Divide on 3,000 overlapping
rectangles, timed on this branch's final code.
2026-11-07 09:16:05 -08:00
dotCooCoo 3fcd157f17 Path ops: region building lists the shapes covering each region instead of a flag per shape
Finding the distinct regions of an arrangement built a flag for every
input shape at each edge and kept them in a sorted set, so it cost edges
times shapes in time and memory. Each coverage is now the sorted list of
the shapes that cover it, deduplicated in a hash set and sorted into the
order the flag masks had, so regions, their order and the output of
Divide, Hard Mix, Soft Mix, Shape Builder and the flattener are the same.
The face lookup and Pathfinder merging take the same lists.

Tests compare the lists and the regions with the flag masks for
overlapping, nested, touching and disjoint shapes and for 72 shapes.
2026-11-07 08:44:50 -08:00
M Balazs PC f2c1df1ec3 .ai/EPS import: the parity note says what still differs in the file it was checked on 2026-11-07 17:43:42 +01:00