Commit Graph
9106 Commits
Author SHA1 Message Date
dotCooCoo 31dd69ff4e Reference point: the locator is one Tab stop, and the arrow keys move the point
Each of the locator's nine squares was a Tab stop of its own, so Tab from
the field before it in the Transform panel, the Properties panel, the
Control bar and the dialogs that show it stopped up to nine times before
it reached the next field. The locator is now one Tab stop. While it has
the focus it shows an outline, and the arrow keys move the reference
point one square, stopping at the edges. A click on a square works as
before.

Screen readers get a radio group holding the nine squares as radio
buttons, with the current point as its value. The group is named after
the label next to the locator: Reference Point, or Pivot, Alignment,
Registration or Placement where the locator sets one of those.
2026-11-08 13:17:20 +07:00
dotCooCoo 5a3de875fa 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-08 13:17:13 +07:00
dotCooCoo fe92583e13 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-08 13:17:13 +07:00
dotCooCoo e592e8277b 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-08 13:17:13 +07:00
BFlat b72dc56660 Merge pull request #6153 from dotCooCoo/feat/three-d-panel
3D and Materials: Window › 3D and Materials edits the selection's 3D effect in place
2026-11-08 14:15:56 +08:00
BFlat e77c410f71 Merge pull request #6151 from dotCooCoo/fix/tab-one-press
Fields: Tab moves from a field to the next past its spinner and preset chevron
2026-11-08 14:15:40 +08:00
BFlat d573b25d68 Merge pull request #6150 from dotCooCoo/feat/ai-editing-data-s6b
.ai save: the editing copy keeps live effects
2026-11-08 14:15:30 +08:00
BFlat a3c3164958 Merge pull request #6142 from dotCooCoo/fix/pdfimport-params
PDF import: cropTo, password, colorMode and textAs reject a value of the wrong type
2026-11-08 14:15:15 +08:00
BFlat 623164ad5b Merge pull request #6141 from dotCooCoo/feat/text-styles-load-from-document
Text styles: load character and paragraph styles from another document
2026-11-08 14:14:59 +08:00
BFlat a2a3c06f3c Merge pull request #6133 from dotCooCoo/fix/ai-warped-type-compare
.ai import: warped type that draws differently from the file opens as its drawn art
2026-11-08 14:14:43 +08:00
BFlat 8ae6f15903 Merge pull request #6130 from dotCooCoo/feat/smooth-color-step-count
Blend: Smooth Color counts a step per level of color change
2026-11-08 14:14:26 +08:00
BFlat 4e1d1ab8c6 Merge pull request #6129 from dotCooCoo/fix/colormgmt-params
Color management: commands reject a param of the wrong type
2026-11-08 14:14:10 +08:00
BFlat 8dab326d41 Merge pull request #6127 from dotCooCoo/fix/flatten-region-limit-early
Flattening: stop building a group's regions at the first one past the region limit
2026-11-08 14:13:55 +08:00
BFlat 1a28f998cc Merge pull request #6126 from dotCooCoo/fix/issue-6110
Fix #6110: pattern brush corner tiles line up with the side tiles
2026-11-08 14:13:44 +08:00
BFlat d7acf687e9 Merge pull request #6124 from dotCooCoo/fix/envelope-params
Envelopes: commands reject a style, orientation or preserveShape of the wrong type
2026-11-08 14:13:33 +08:00
BFlat 2c442f642c Merge pull request #6122 from dotCooCoo/feat/linesweeper-craft-libs
Build: linesweeper from craft-libs' vendored copy at 481f66d
2026-11-08 14:13:15 +08:00
BFlat 45d31fc197 Merge pull request #6120 from dotCooCoo/fix/relative-paths-nested-links
Links: links inside symbols, patterns and masks follow a moved folder and are updated like links in the layers
2026-11-08 14:13:00 +08:00
BFlat 9e8bfd87f9 Merge pull request #6119 from dotCooCoo/feat/trace-preset-buttons
Image Trace: buttons above the Preset menu choose the Auto Color, High Color, Low Color, Grayscale, Black and White and Outline presets
2026-11-08 14:12:45 +08:00
BFlat 0199dd10ca Merge pull request #6118 from dotCooCoo/feat/artboard-fade-outside
Artboard Options: Fade Region Outside Artboard darkens the area outside the artboards
2026-11-08 14:12:29 +08:00
BFlat b8884e40c4 Merge pull request #6116 from dotCooCoo/fix/type-find-params
Type: find and replace and Type menu commands reject a param of the wrong type
2026-11-08 14:12:13 +08:00
BFlat 5c4efaa515 Merge pull request #6114 from dotCooCoo/fix/ai-legacy-rksj-text
.ai import: legacy type in CJK fonts decodes by the font's CMap
2026-11-08 14:11:58 +08:00
BFlat e0f2c98e1f Merge pull request #6108 from dotCooCoo/feat/recent-colors-30
Color: Recent Colors keeps the last 30 colors used, across documents
2026-11-08 14:11:43 +08:00
BFlat 57c7fc24ee Merge pull request #6090 from dotCooCoo/feat/control-bar-dock
Control bar: the panel menu and the gripper dock it to the top or the bottom of the window
2026-11-08 14:11:27 +08:00
dotCooCoo 67339a68c7 3D and Materials: a mixed checkbox shows a dash and keeps each effect's value
With several objects selected, Shading, Revolve's Cap, Keep visible surfaces
only when expanding and the other checkboxes read a setting the effects hold
with different values as off. A mixed Shading also turned off the Lighting
tab's controls.

- A mixed checkbox shows a dash with its reset dot filled; a click turns it on
  for every selected effect, and other changes leave it as each effect has it.
- A mixed Shading leaves the light settings available.
- A mixed menu choice shows its default; a mixed light color fills its reset dot.
- Add Light is unavailable while a setting of a single light is mixed.
2026-11-08 12:59:34 +07:00
dotCooCoo a71a6ca53d Fields: Tab moves from a field to the next past its spinner and preset chevron
A numeric field's up/down spinner and the chevron that opens its presets
were Tab stops, so Tab took three presses to get from one field to the
next in the Stroke, Character and Transform panels and two in a text
field with presets (Export for Screens' scale). The Transparency row's
opacity slider chevron was a Tab stop after the Opacity field too. All
three now sense clicks without taking the keyboard focus; clicking them
works as before, and Up/Down in the field still step it.

Without the chevron in the Tab order, Alt+Down (with no other modifier)
in a field with presets opens its preset list with the keyboard focus on
the chosen preset, or on the first one. Before, Alt+Down stepped such a
field down by one; Shift+Alt+Down still steps it by ten, and fields
without presets still step on Alt+Down. Enter on the focused preset picks
it and closes the list without also pressing a dialog's OK, as the combo
boxes do, and after a pick or Escape the field has the keyboard focus
again.
2026-11-08 12:59:34 +07:00
dotCooCoo 79dcf3b1ff .ai save: the editing copy keeps live effects
Squashed from #6150 onto main.
2026-11-08 12:59:34 +07:00
dotCooCoo 0723346135 PDF import: cropTo, password, colorMode and textAs reject a value of the wrong type
document.open, file.place and document.pdfInfo read cropTo (and its
older name crop), password, colorMode and textAs as strings and used
the default when a value was not a string, so "textAs": true or
"colorMode": 5 opened the file with the defaults. They now return an
error naming the param, and nothing opens or is placed. A wrong crop is
refused even when cropTo is given. document.pdfInfo also rejects a
thumbnailSize that is not a number, with or without a thumbnail.

Leaving a param out or giving null keeps its default, and an empty
password still means no password.
2026-11-08 12:59:34 +07:00
dotCooCoo cbe374df62 Text styles: loading imports once and reads the brush library once
charStyle.load, paraStyle.load and textStyle.loadAll imported the styles
into a copy of the document to see whether anything changed, then ran the
same import again inside the edit. The edit now takes the copy the first
import made. While a typing session is open the import still runs inside
the edit, because the edit ends the session first and that can change the
document.

Matching a loop of definitions parsed the document's brush library again
for every comparison, and placing brushes in use order parsed it again for
every brush. Each now reads it once.

The params text and docs/mcp.md now say that the symbols and brushes the
patterns use come along, that `skipped` lists names in the file, and that
charStyle.load and paraStyle.load list only the styles of their own kind.
2026-11-08 12:59:34 +07:00
dotCooCoo ba25415792 3D and Materials: Window › 3D and Materials edits the selection's 3D effect in place
The panel opens from Window › 3D and Materials (window.panel {panel:
"threeD"}). Its object types Plane, Extrude, Revolve and Inflate apply
Rotate, Extrude & Bevel, Revolve or Inflate to each selected object
without a 3D effect, and change the 3D effect of each other selected
object in place, all as one undo step. Below them are the effect
dialog's Object, Rotation and Lighting tabs with the same controls.
A changed setting goes to every selected 3D effect that takes it, as
one undo step; a drag previews and records one step on release, and a
change of selection during a drag commits it first, and so does closing
or hiding the panel. A setting the
selected effects hold with different values shows its default with its
reset dot filled. A light list edit reaches only the objects whose list
matches the first object's.

effect.setParams takes threeDType (plane, extrude, revolve, inflate):
the settings both effects take keep their values, rotation angles wrap
into -180..180 outside Revolve, and the rest start at the new effect's
defaults. Another value, or a non-3D effect at index, is refused; the
type an effect already has, with nothing else to change, records no
undo step.

Materials, shadows and ray-traced rendering are not part of this.

Docs: docs/three-d.md, docs/mcp.md, docs/effects-parity.md,
docs/target-app-parity.md.

Fixes #3672
2026-11-08 12:59:34 +07:00
dotCooCoo ea3fe16896 Text styles: loading uses a loop the document has under the names found for it
When the document has a loop of styles and patterns under one set of names, its styles
were still matched one by one, so a style could be matched to another copy with the same
attributes and the pattern then compared with the wrong style name. Each definition of
such a loop is now the document's under the name found for it.
2026-11-08 12:59:34 +07:00
dotCooCoo 127251f297 Keyboard Shortcuts: the text style loaders are listed only with a key of their own
charStyle.load, paraStyle.load and textStyle.loadAll need a file, which their panel menu
items ask for, so a key press without one reports a missing param. They join the library
loaders that Edit > Keyboard Shortcuts lists only when a key was saved for them.
2026-11-08 12:59:34 +07:00
dotCooCoo 63e8e765ac Text styles: loading places brushes in use order with styles and patterns
A brush whose art sets type in a style renamed on the way in was compared before the
rename was known, so loading the file again added the brush and what uses it again.
Loading now places brushes with the styles, symbols and patterns, each after what it uses.
Paste keeps its order.
2026-11-08 12:59:34 +07:00
dotCooCoo b31ad2c537 Text styles: loading adds every style and pattern of a loop the document lacks
A style that paints with a pattern whose type is set in that style could be matched to the
document's style of the same name and attributes while the pattern came in under a free
name, so the loaded style painted with the document's other pattern. When the document does
not have such a loop under one set of names, each of its styles, symbols and patterns is now
added.
2026-11-08 12:59:34 +07:00
dotCooCoo 089d6c3e74 .ai import: warped type in a file with artboards is compared on the first artboard
The page that warped type is compared with was read after the artboard
list had been moved into the document, so a file with an artboard list
fell back to its crop marks or its art's box. The page is now read
before the list is moved.
2026-11-08 12:59:33 +07:00
dotCooCoo 4abf9f4081 Text styles: loading matches a long loop of patterns that use each other
The names a loop of styles and patterns has in the document were searched by trying every
combination, up to 256, so a loop of nine with a numbered copy each was not matched and a
repeat load added it again. The names are now picked one definition at a time, comparing each
definition as soon as the names of those it uses are picked.
2026-11-08 12:59:33 +07:00
dotCooCoo 7036d44603 .ai import: warped type bound to a text variable stays type
Warped type that a text variable binds stays type with the effect live,
so it keeps its binding. Before, a failed comparison replaced it with
its drawn art and the binding was skipped.

When drawn art replaces warped type with a wrap setting, the wrap shapes
are checked against the file's limit on wrap work again, so a file whose
drawn art would go past it opens from its page, as one with too many
text objects does.
2026-11-08 12:59:33 +07:00
dotCooCoo 8f14e2f0ec Text styles: loading skips a style whose sizes or scales are out of range
A loaded character style kept a size, scale, leading, shift or stroke width that
charStyle.new refuses. Such a style is now skipped and listed in the reply's skipped names.
2026-11-08 12:59:33 +07:00
dotCooCoo dfb507b7b7 Text styles: a loaded style's pattern brings the styles of either kind its type uses
Load Character Styles and Load Paragraph Styles left out every style of the other kind,
so a pattern that a loaded style paints with kept a reference to a paragraph or character
style the document did not get. The styles of the kind not loaded now come along when such a
pattern or symbol sets type in them, renamed like any other.

The order in which styles, symbols and patterns are placed is worked out from one graph of
their uses instead of scanning every definition left in each round.
2026-11-08 12:59:33 +07:00
dotCooCoo c168302fec Text styles: match each loop of patterns that use each other on its own when loading styles
Loading styles placed every definition in a loop of uses, and everything that used one, in one group and tried the product of all their candidate names under one cap of 256. Separate loops multiplied: nine self-referencing patterns, each in the document under its name and as a numbered copy from an earlier load, gave 512 combinations, none were tried, and a repeat load added more numbered copies. One loop with no candidate stopped every other loop from matching.

The loops are now the strongly connected components of the uses among those definitions. Each loop is matched with its own search and cap, and a definition that only uses a loop is placed after it, with the loop's names known.
2026-11-08 12:59:33 +07:00
dotCooCoo d8187b4967 Text styles: load character and paragraph styles from another document
The Character Styles and Paragraph Styles panel menus get Load Character
Styles... or Load Paragraph Styles..., and Load All Styles..., which add the
styles of a document picked in an open dialog in one undo step
(charStyle.load, paraStyle.load, textStyle.loadAll). The swatches,
patterns and symbols the styles use come along as Paste brings them, in
use order, so a style or pattern renamed on the way in keeps its links.
A style the document already has, under its name or a numbered copy of
it, is not added again; another style whose name is taken is added under
a free name. The file's Normal styles, and styles with a blank name or
attributes that do not read, are not loaded.
2026-11-08 12:59:33 +07:00
dotCooCoo 888bf32f82 Blend: Smooth Color counts a step per level of color change
Smooth Color now counts the steps between each pair of keys from the
keys' colors and visible bounds, which changes the step count of most
Smooth Color blends. The counts are VectorCraft's own values:

- When the keys' solid fills or strokes differ (in groups, member by
  member; in text, run by run), the count is 255 times the largest
  change of one channel as a fraction of its range, a half step
  rounding down, from 1 to 254. An RGB channel's range is 256 values,
  CMYK and gray count in percent, and two tints of one swatch by their
  tints. It is at most eight per point of the largest of the keys'
  widths and heights and the distance between their centers. Black to
  white was 128 steps and is now 254.
- When the colors match, a solid paint meets no paint, or a key holds
  a gradient or a pattern, the count is the largest distance between
  corresponding visible bounding-box edges divided by the keys' mean
  width or height, rounded, less one, from 1 to 1000. Two 20 pt
  squares 200 pt apart were 100 steps and are now 9.

Keys without bounds make the color count when their colors differ,
and 1 step otherwise.

A blend nested in another blend's keys counts toward the step limit
by its color steps when its colors differ, and as up to 1000 steps
when they match (256 before). An outer blend of 200 steps between two
such same-color Smooth Color blends now draws 99 steps.

A Smooth Color blend in an .ai file whose drawn steps follow this rule
now opens as a live blend.

Blend Options: https://web.archive.org/web/20241217212108/https://helpx.adobe.com/illustrator/using/blending-objects.html
Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-08 12:59:32 +07:00
bflatastic 612682970f i18n: keep one Turkish row for each message 6129 touches 2026-11-08 12:59:32 +07:00
dotCooCoo d54d4657b9 .ai import: warped type that draws differently from the file opens as its drawn art
A Warp on type, on the object or on one of its fills or strokes, opened
as a live effect with no check. Where the live warp draws a different
shape from the art saved in the file, the type moved and changed size.

Warped type is now compared with its saved art once it is laid out,
with the comparison and the per-file budget that envelopes use. Type
that draws as its saved art stays editable with the effect live. Other
warped type opens as that art, not as editable type, with one note that
counts them, and saving over the file asks first. The art's box goes
back into the comparison with the page. Type stays live without a
comparison when its saved art paints nothing or draws type of its own,
and in frames of threaded type.
2026-11-08 12:59:32 +07:00
dotCooCoo badda0a16e Color management: color.gamutCheck names colors when it is not a list
A non-null `colors` that is not an array now gives "`colors` must be an array of colors, not ..." instead of the generic "bad color ...", with a row in every catalog. The loadProfile and removeProfile refusal tests also check that no profile is loaded or removed and the settings are unchanged.
2026-11-08 12:48:01 +07:00
dotCooCoo 56ad84266d Color management: color.gamutCheck rejects a colors param that is not a list
A colors value that is not an array, such as "#fff" or 5, was ignored and the command checked the selection or the whole document instead. It is now an error. A null colors still checks the selection or document, as an omitted one does.
2026-11-08 12:48:00 +07:00
dotCooCoo 8901877e40 Color management: commands reject a param of the wrong type
The color management commands read their params with helpers that fell
back to the default for a value of the wrong type, so "bpc": "no" kept
the old setting, "on": "true" toggled the view and "convert": "no"
converted the colors. They now go through switch_or and text_param:
such a value is an error and nothing changes. Omitting a param or
giving null keeps its default.

- edit.colorSettings: rgb, cmyk, intent, bpc
- file.documentColorMode (and its alias): convert, intent, grays,
  checked before the early return for the current mode; PDF import's
  grays reads the same way
- color.convert: to, intent
- color.loadProfile: path; color.removeProfile: name
- view.proofSetup: target, intent, simulatePaper, proof
- view.proofColors and view.overprintPreview: on
- view.separationsPreview: on, only, toggle, and plates, which must be
  an array of plate names
- swatch.setSpot: name, spot
2026-11-08 12:48:00 +07:00
dotCooCoo 96252edb74 Flattening: stop building a group's regions at the first one past the region limit
With an unclipped raster/vector balance between 0 and 100, a group that
splits into more than 10^(balance/20) regions is rasterized whole and
none of its regions are used. The region build now stops at the first
region past that limit (pathops `regions_within`) instead of building
every region and then discarding them. Groups at or under the limit,
and every group with Clip Complex Regions on, still build every region.

Flatten Transparency, the flattened document and EPS export come out
the same as with every region built, for groups under the limit, at it,
just over it and far over it.
2026-11-08 12:47:59 +07:00
dotCooCoo 5ccb73c6bb Fix #6110: pattern brush corner tiles line up with the side tiles
A corner tile was turned so that its x axis followed the mean of the
directions the path arrives and leaves in. A tile drawn as a right-angle
corner then came out turned 45° at every corner, so a rectangle drew its
corners as diagonal chevrons.

Outer and inner corner art are now both read as the corner that joins a
side tile on its right to one below it, as in the help's steps for
making corner tiles. Each corner tile is turned so that those two arms
meet the sides: on a rectangle the tile is square to the side tiles and
turns 90° from one corner to the next, and at other angles it is turned
halfway between the two sides. The arms follow Flip Along and Flip
Across, and a corner that takes the other kind's art turns it the same
way. Which art each corner takes is unchanged.

The PatternBrush field docs, the brush.options params text, docs/mcp.md
and the progress doc describe how corner art is drawn.
2026-11-08 12:47:59 +07:00
dotCooCoo 4fddf66d2c Envelopes: commands reject a style, orientation or preserveShape of the wrong type
object.envelope.makeWithWarp, resetWithWarp and options read `style`
and `orientation`, and options read `preserveShape`, as text and
ignored any other value, so `{"style": 5}` kept the default style and
`{"orientation": "diagonal"}` kept the current orientation. They now
return "`style` must be a string" or "`preserveShape` must be a
string" for a value other than text or null, and "`orientation` must
be one of horizontal, vertical" for any other orientation, through
the shared `choice` helper. object.envelope.options checks the warp
keys whatever is selected, so a call with no envelope or only mesh
envelopes selected gets the same errors, an unknown style name
included. Omitted and null values keep today's defaults.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-08 12:47:59 +07:00
dotCooCoo f416fc49ef Build: linesweeper from craft-libs' vendored copy at 481f66d
The workspace patches linesweeper to storytold/craft-libs at 481f66d, the
merge of craft-libs#633, which keeps the crates.io 0.5.0 package in
vendor/linesweeper. Fixes made to that copy reach VectorCraft when the
rev moves. Cargo.toml still asks for linesweeper 0.5.

The library is unchanged: Cargo.toml and every file under src/ in the
copy are byte-identical to the crates.io 0.5.0 package, whose sha256 is
a25df1b0c5432893f41bba817150e323703ee5f6d974f3a6808ac7fd7f046d18, the
checksum Cargo.lock carried. Cargo.lock changes only linesweeper's
source and checksum lines.

NOTICE no longer lists linesweeper among the crates fetched through
crates.io, and names the craft-libs revision it comes from.
2026-11-08 12:47:58 +07:00