Commit Graph
3872 Commits
Author SHA1 Message Date
HassanKhan b3860bf7d0 Commands: every angle and rotation param says which way it turns (#6340)
The params docs now state the direction (and the zero) of each angle or
rotation a command takes; behaviour is unchanged. Shape creation, text.create,
the grids, add-on shapes, saved views, Liquify, Puppet Warp pins, Mirror and
Radial Repeat and Vector Halftone turn clockwise; text character rotation,
gradients, the eraser tip and print screen angles turn counter-clockwise.

view.saved.new's rotation note changes its schema, so the API level goes to 3.

A test walks every command's params doc and fails when a param named like an
angle or rotation doesn't say clockwise or counter-clockwise.
2026-11-11 21:40:27 +05:00
jmverges 352b488b12 Merge remote-tracking branch 'upstream/main' into fix/aligned-lines-trailing-tracking
# Conflicts:
#	docs/file-format-parity.md
2026-11-11 16:38:59 +00:00
dotCooCoo ced8c1bb39 Merge main into fix/scriptcheck-identifier-chars 2026-11-11 08:36:00 -08:00
dotCooCoo 289401343c Script checker: names follow Unicode ID_Start and ID_Continue
Check Script read names with Rust's alphabetic and alphanumeric tests, so it
split names at U+2118, U+203F, U+00B7 and the zero width non-joiner and joiner,
and took U+00B2 and U+2E2F into names. It now uses the Unicode 16.0 ID_Start
and ID_Continue rule that vectorcraft-js uses, with `$` and `_`
(https://www.unicode.org/reports/tr31/,
https://tc39.es/ecma262/#sec-names-and-keywords).

A `\uXXXX` escape is part of a name only when it stands for a character the
name may hold where it is: `\u0030abc` no longer becomes `0abc`, and malformed
escapes end the name.

The engine's lexer comparison test now checks that both crates take the same
characters into names, written out and as escapes.
2026-11-11 08:35:19 -08:00
BFlat caaf261e9f Merge pull request #6605 from dotCooCoo/fix/gradient-stop-symbol-part
Gradients: picking a part of a symbol instance leaves no gradient stop selected
2026-11-11 23:25:06 +07:00
jmvergesandClaude Opus 5.5 9f80b4daae Type: aligned lines leave the tracking after their last character out (#6610)
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>
2026-11-11 16:07:40 +00:00
dotCooCoo 8eb3788eba Plug-ins: setting the plug-ins folder again after clearing it installs its plug-ins
Clearing Preferences > Plug-ins & Scratch Disks > Additional Plug-ins Folder
left the folder recorded as the one last loaded. Setting the same folder
again then matched that record, and nothing in it was installed, so a
plug-in removed in the meantime stayed removed. Clearing the preference now
forgets the folder when it is the one last loaded.
2026-11-11 08:07:27 -08:00
dotCooCoo ba05554c64 Merge main into feat/script-file-folder 2026-11-11 07:47:42 -08:00
dotCooCoo b7a6196994 Scripts: File and Folder read files in the script's own folder
Scripts get the File and Folder classes as built-ins of the script
engine. A script run from a file can test whether files exist, read
their properties, list folders with getFiles (a mask or a function),
and open files to read them with read, readln, readch, seek and tell.

- Reads stay inside the script's folder and, when automation read
  roots are set, inside them too. A script given as text reads no
  files. Network and device paths, and paths outside the folder by
  their names, are refused before anything is looked up. Links and
  junctions that lead out are refused, and getFiles leaves them out.
- The encoding comes from the byte order mark, then the encoding the
  script set, then UTF-8 when the bytes are valid, then CP1252.
- Limits: 8 MiB a file, 32 MiB a run, 256 files open at once, 2,048
  getFiles entries and 65,536 names looked at, and paths of at most
  32,767 characters.
- Writing, the file dialogs and execute are not available yet: they
  return false or null and set error.

The report's hostCallCounts gains fileCalls and fileExecutes.
Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-11 07:46:33 -08:00
dotCooCoo b44cbdb048 Gradients: picking a part of a symbol instance leaves no gradient stop selected
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.
2026-11-11 07:39:47 -08:00
dotCooCoo ac8e39fa2e Effects: a pasted SVG filter also takes a free punctuation character when no letter or digit is free
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.
2026-11-11 07:26:02 -08:00
dotCooCoo f60da17d39 Effects: a pasted SVG filter also takes a free capital letter when no lowercase name is free
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.
2026-11-11 07:26:02 -08:00
Taha-Mahmoodi bf8312120e Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-11 19:42:22 +04:30
Taha-Mahmoodi b79aae034f Merge remote-tracking branch 'origin/main' into fix/import-document-title 2026-11-11 19:42:07 +04:30
BFlat 9fc43f2a35 Merge pull request #6598 from dotCooCoo/fix/pasted-svg-filter-brush-names
Effects: a pasted SVG filter avoids brush effect names and is refused with no free name
2026-11-11 22:10:15 +07:00
Taha-Mahmoodi 58a4dd2eca Merge remote-tracking branch 'origin/main' into fix/import-document-title
# Conflicts:
#	docs/file-format-parity.md
#	docs/gaps.md
#	docs/target-app-parity.md
2026-11-11 19:33:31 +04:30
Taha-Mahmoodi 54f9c03dff Normalize imported SVG titles without changing restored metadata 2026-11-11 19:32:15 +04:30
Taha-Mahmoodi 44dc6b1440 Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-11 19:31:27 +04:30
dotCooCoo e0e361a834 Effects: a pasted SVG filter avoids brush effect names and is refused with no free name
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.
2026-11-11 06:08:58 -08:00
dotCooCoo 48e342f03b Merge main into feat/script-dollar-object 2026-11-11 05:55:39 -08:00
Taha-Mahmoodi 4837aff454 Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-11 18:07:04 +04:30
BFlat 2d90cda199 Merge pull request #5493 from storytold/fix/sec-effects-paint-dash-budget
Effects: bound 3D paint copies, dash restarts and trap candidate pairs
2026-11-11 20:36:20 +07:00
BFlat 8353e8fdd3 Merge pull request #6562 from dotCooCoo/fix/script-console-report-text
Script Console: report lines match script.console, counts of one are singular, every run ends
2026-11-11 20:36:11 +07:00
Taha-Mahmoodi c8b3c860e7 Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-11 17:59:13 +04:30
BFlat c064ded1d1 Merge pull request #6592 from dotCooCoo/fix/pasted-svg-filter-free-name
Effects: a pasted SVG filter is not renamed to a name the document's effects use
2026-11-11 20:28:20 +07:00
Taha-Mahmoodi 4c61e767db Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-11 17:45:13 +04:30
BFlat 3f8b10afdf Merge pull request #6588 from dotCooCoo/fix/rasterize-side-rounding
Rasterize: art that rounds to 32,768 pixels a side is no longer refused
2026-11-11 20:13:57 +07:00
Taha-Mahmoodi a724fc37ec Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-11 17:39:26 +04:30
BFlat f242b0752f Merge pull request #6590 from dotCooCoo/fix/text-style-leading-strict
Type: text.setStyle refuses a leading with trailing text
2026-11-11 20:08:46 +07:00
dotCooCoo f77fe0423f Merge main into fix/script-console-report-text 2026-11-11 04:58:29 -08:00
Dylan M. Taylor a8f5549fd5 Merge branch 'main' into fix/sec-effects-paint-dash-budget 2026-11-11 12:55:22 +00:00
dotCooCoo ccf153dccc Merge main into feat/script-dollar-object 2026-11-11 04:52:37 -08:00
dotCooCoo c746841839 Scripts: $.error keeps the last error thrown, and $.sleep throws in callbacks on the web
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.
2026-11-11 04:48:13 -08:00
Taha-Mahmoodi e851a3f912 Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-11 17:15:03 +04:30
dotCooCoo 08efd91360 Effects: a pasted SVG filter is not renamed to a name the document's effects use
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.
2026-11-11 04:44:54 -08:00
BFlat a2e34903e9 Merge pull request #6577 from dotCooCoo/fix/script-rethrown-error-place
Scripts: an error $.evalFile could not run, caught and thrown again, is reported where it was thrown again
2026-11-11 19:44:23 +07:00
dotCooCoo 07664847bd Type: text.setStyle refuses a leading with trailing text
`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.
2026-11-11 04:24:11 -08:00
dotCooCoo af22ac8f50 Scripts: $.stack names a declared function after its declaring function returns
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.
2026-11-11 04:23:32 -08:00
Taha-Mahmoodi b9ccfdc072 Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-11 16:45:59 +04:30
BFlat 8ea341d57f Merge pull request #6579 from dotCooCoo/fix/legacy-ai-flatten-side-limit
Legacy .ai export: a long transparent image is flattened whole
2026-11-11 19:15:04 +07:00
Taha-Mahmoodi f72c2560e1 Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-11 16:36:45 +04:30
BFlat e8a570cb0e Merge pull request #6578 from dotCooCoo/fix/print-bitmap-side-limit
Print: Print as Bitmap prints all of a page longer than 32,768 pixels
2026-11-11 19:05:50 +07:00
Taha-Mahmoodi 83db0b8991 Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-11 16:31:04 +04:30
dotCooCoo 80b452ad6c Rasterize: art that is exactly 32,768 pixels a side at the resolution is accepted
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.
2026-11-11 04:00:39 -08:00
BFlat a5a42e45ac Merge pull request #6576 from dotCooCoo/fix/pasted-svg-filter-size-limit
Effects: a pasted SVG filter at the size limit still draws under its new name
2026-11-11 19:00:06 +07:00
dotCooCoo c8475771b9 Merge main into fix/script-rethrown-error-place 2026-11-11 03:59:08 -08:00
dotCooCoo d50ea29772 Merge main into feat/script-dollar-object 2026-11-11 03:58:05 -08:00
dotCooCoo 2b88f31a7d Merge main into fix/script-console-report-text 2026-11-11 03:56:06 -08:00
Taha-Mahmoodi 076d68663f Merge remote-tracking branch 'origin/main' into feat/glyph-alternates 2026-11-11 16:21:58 +04:30
BFlat 4fc8517215 Merge pull request #6574 from dotCooCoo/fix/graph-labels-empty-middle-line
Graphs: centered labels with an empty middle line stay centered
2026-11-11 18:51:23 +07:00