Commit Graph
10704 Commits
Author SHA1 Message Date
dotCooCoo 7436a38f44 JavaScript: Object, Function, Array, Error, Math and JSON built-ins
vectorcraft-js now provides the ECMAScript 5.1 built-ins: the Object
property-descriptor functions, create, keys, seal and freeze (15.2),
Function.prototype.bind (15.3.4.5), Array with every ES5 method (15.4),
the error types (15.11), Math (15.8), JSON with revivers, replacers and
indentation (15.12), and the global functions with Annex B's escape and
unescape (15.1, B.2). Prototype methods are writable and configurable.

The array methods work on array-like objects and visit only the indices
that exist, so a sparse array of length 2^32-1 costs as much as its
elements, and they see indices a callback adds. join writes a cycle back
to an array as an empty string; JSON.stringify throws a TypeError on a
cycle. JSON parsing, writing and the reviver walk use no native
recursion. Every loop takes fuel and every result is checked against
the heap limit, so new Array(4294967295).join("x") ends with the heap
limit and a huge sort or stringify ends with a limit.

cargo xtask test262 also runs the suite's ES5 built-in tests and fetches
json2.js at a pinned commit, checked against its SHA-256, to compare its
output with the built-in JSON once Date, String.prototype.replace and
RegExp exist.
2026-11-07 16:49:38 -08:00
dotCooCoo decb3321d1 Docs: the 3D effects summary counts Extrude & Bevel (Classic) 2026-11-07 16:27:43 -08:00
dotCooCoo 20accc5943 Docs: 3D remaining-work lists name what 3D (Classic) still lacks
Extrude & Bevel (Classic) ships, so the remaining-work lists in
effects-parity.md, gaps.md (G3), target-app-parity.md and three-d.md
name Revolve (Classic), Rotate (Classic) and Map Art instead of all of
3D Classic.
2026-11-07 16:00:09 -08:00
dotCooCoo 71ce0a3c1d Merge feat/ai-editing-data-s6b into feat/ai-editing-data-s6b2 2026-11-07 15:57:45 -08:00
dotCooCoo 7ca34c522d .ai save: the large-canvas warning names every effect the editing copy leaves out
On a large canvas no art style is written, so objects with live effects
keep only their geometry effects in the editing data for other apps:
blurs are left out as well as shadows, glows and feathers. The warning
now says that no art styles are written and that only geometry effects
are kept.

The comment on rgb_without_cmyk in art_styles_write_the_same_bytes_again
now gives the cause of the Windows difference: the Generic CMYK
separation of the default Pink swatch, at the edge of the press gamut,
lands on C0 M93.9 Y16.3 or C0 M93.2 Y15.3 when its RGB changes in the
last float bits, and the platform's float math decides which. The
comment also says that named and spot RGB colors are not blanked.
2026-11-07 15:49:34 -08:00
dotCooCoo 0b936bf60e JavaScript: the script a realm runs does not count against the re-entry limit
Limits::reentry bounds runs inside an operation (getters, setters, conversions, indirect eval). The top-level script took one of those slots, so a limit of 0 refused every script and a limit of 1 left no room for a getter. Only indirect eval now counts when it starts a global run.
2026-11-07 15:29:40 -08:00
dotCooCoo 5ebf32e973 JavaScript: shrinking an array takes fuel for each property
Assigning a smaller length to an array visits every property in one operation. It now takes fuel for each one before anything is removed, so a run with a small fuel limit or a set interrupt flag stops there and leaves the array unchanged.
2026-11-07 15:24:53 -08:00
dotCooCoo 1f352bc7c1 Plug-ins: manifests list permissions, the user grants them at install, and the host enforces the grant
A manifest may list `permissions` (doc.read, doc.write, state,
effect.render, export.write) and an `api` level. doc.read, doc.write
and state follow the capability model proposed in
storytold/photocraft#662; the other names are VectorCraft's own. An
unknown, reserved, duplicate or wrong-kind name is refused by name. A
manifest without the key gets the permissions its kind implies and
installs as before.

- Install Plug-in... and File > Open show the name, id, version, file
  SHA-256 and each permission in plain words, with control and
  bidirectional characters escaped and each string cut to 64
  characters. OK installs the module only if it still has the SHA-256
  shown; Cancel installs nothing. The heavy-budget prompt and the
  status line show the escaped name too, and OK keeps the `replace` it
  was given.
- `plugin.install` needs `grant` listing every permission, and
  `plugin.inspect` reports `needsApproval`. `hash` pins the module:
  one with another SHA-256 is refused. The grant is kept with the
  module's hash in the store's `grants.json`, and only that store's
  grants count while it is attached; the same set does not ask again,
  more permissions do, and `plugin.remove` forgets it.
- The Additional Plug-ins Folder and `plugin.reload` install only
  plug-ins the attached store has granted and report the others as
  needing approval. At startup the store skips an ungranted plug-in.
- A filter run without doc.read is given no objects; without state it
  neither reads nor writes `documentData`; without doc.write an output
  that changes the document is refused and the document is unchanged.

Docs: docs/plugins.md, docs/mcp.md, docs/target-app-parity.md.
2026-11-07 15:20:07 -08:00
dotCooCoo 44c17c4e9a JavaScript: the test262 runner reports a failed assertion's message
The harness's assert.js formats failure messages with the global String, which the interpreter does not provide yet, so the four failing runs reported "ReferenceError: String is not defined". The runner now defines a stand-in that converts with +, and the failures name the assertion (the completion value tests expect undefined where ECMA-262 5.1 section 12.6.3 gives 4).
2026-11-07 15:18:55 -08:00
dotCooCoo cf1162cf95 Merge feat/js-parser into feat/js-interpreter 2026-11-07 15:04:39 -08:00
dotCooCoo 5a4c3e12a5 3D (Classic): Extrude & Bevel (Classic) extrudes art with Wireframe, No Shading, Diffuse and Plastic surfaces
Effect > 3D and Materials > 3D (Classic) > Extrude & Bevel (Classic)... applies
`threeD.classicExtrude`, a live effect built on the Extrude & Bevel solid. It
takes Extrude Depth, Cap, a bevel with Height and Bevel Extent In or Out, the
Position presets, rotation and Perspective, and draws the faces with the
Wireframe, No Shading, Diffuse or Plastic surface: one to ten lights, Ambient
Light, Highlight Intensity and Size, Blend Steps, a Black, Custom or no Shading
Color, and Draw Hidden Faces. Invalid parameters are refused with an error.
2026-11-07 15:02:39 -08:00
dotCooCoo 4d8bee277c JavaScript: for-in takes fuel for each property and reserves heap for its names
Listing the names for a for-in loop now takes a unit of fuel for each
property it visits and reserves heap for the name list before it is
kept, so a run with small limits stops on an object built under larger
ones.
2026-11-07 14:59:24 -08:00
dotCooCoo 2b8cefe728 Merge feat/ai-editing-data-s6b into feat/ai-editing-data-s6b2 2026-11-07 14:55:16 -08:00
dotCooCoo a1842028da Tests: compare the RGB values of colors in the art-style round trip
art_styles_write_the_same_bytes_again failed on Windows (MSVC) on the
Pink swatch: the first save wrote its CMYK equivalent as 0 0.9317
0.1527 0 and the save of the reopened file as 0 0.9389 0.1629 0. The
writer computes the CMYK equivalent of an RGB color from its RGB values,
and the save of the reopened file computes it from the RGB values read
back at four decimals; for this out-of-gamut color the Generic CMYK
conversion moves by more than the test's 0.002 there. On macOS the two
saves of this document differ by at most 0.0016 in these numbers.

The test now blanks the CMYK equivalents of RGB colors (the first four
numbers of `c m y k r g b Xa` and of an RGB gradient stop's
`c m y k r g b 2 ... Bs`) and compares every other number, the RGB
values included. With them blanked, the two saves are identical on
macOS. The large-canvas test's comment also says what such objects are
written as.
2026-11-07 14:52:43 -08:00
dotCooCoo 66b4c171d4 .ai save: the large-canvas warning says what the editing copy keeps
On a large canvas no art style is written, so objects with live effects
are written as their vector art with their geometry effects applied, and
their shadows, glows and feathers are left out. The warning now says
that, as file-format-parity.md does, instead of "written as their drawn
look".
2026-11-07 14:52:43 -08:00
dotCooCoo 70cfdcb43d JavaScript: kept code and function source text count toward the heap
A collection counts each piece of code a closure or frame keeps: its instructions, tables,
names, nested functions and its source text, each shared buffer once. Code that eval and the
Function constructor compile at run time is charged when it is made, after a heap reservation.
Function.prototype.toString reserves and charges the text it copies.
2026-11-07 14:39:21 -08:00
ruchirguitar 2dc6991cf3 M2.1: retain gradient placement when deletion splits paths (#3380) 2026-11-08 03:51:00 +05:30
dotCooCoo dcccbad29c JavaScript: hexadecimal and octal numbers round once to the nearest value
ToNumber on a hexadecimal string folded its digits into a double one at a
time, so a string past 2^53 could come out one unit off the literal with
the same digits. The lexer kept digits exactly in a u128 but rounded per
digit once the value passed 128 bits. Both now call one helper that keeps
the digits exactly while they fit, records whether any later digit is
set, and rounds once.
2026-11-07 14:18:23 -08:00
dotCooCoo ea319ebcda JavaScript: identifiers follow the Unicode categories of section 7.6, and label and parameter checks are linear
is_id_start accepts the letter categories (Lu, Ll, Lt, Lm, Lo, Nl) and
is_id_part adds Mn, Mc, Nd and Pc, read with unicode-general-category.
A superscript digit (No) inside an identifier and a mark such as U+09BE
at its start are now SyntaxErrors, and identifiers with marks outside
the old list, such as the Bengali and Tamil viramas, now parse.

Labels in scope are kept in a map, and duplicate labels in a chain and
duplicate parameters of a strict function are found with a hash set, so
long chains, many labeled statements and long parameter lists are
checked in linear time.
2026-11-07 14:09:25 -08:00
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