Commit Graph
9422 Commits
Author SHA1 Message Date
dotCooCoo a717e34f02 Merge main into fix/plugin-grant-module-hash 2026-11-08 12:55:59 -08:00
BFlat 74310c6737 Merge pull request #6250 from dotCooCoo/fix/placed-gradient-hidden-children-and-freeform
Effects: hidden layer children and edited freeform gradients follow the Transform and Free Distort effects
2026-11-09 04:31:53 +08:00
BFlat 2cdec30659 Merge pull request #6249 from dotCooCoo/fix/ai-editing-copy-paragraph-once
.ai import: the editing-copy paragraph in the file-format doc appears once again
2026-11-09 04:31:38 +08:00
BFlat 9150f88a83 Merge pull request #6247 from dotCooCoo/feat/ai-path-align-distance
Type: Align to Path moves each character by its own font's metrics
2026-11-09 04:31:23 +08:00
BFlat ba353a22af Merge pull request #6246 from dotCooCoo/feat/plugin-filter-shortcuts
Keyboard Shortcuts: each Object › Plug-ins filter has a row of its own
2026-11-09 04:31:08 +08:00
BFlat 156ccf4b6d Merge pull request #6245 from dotCooCoo/fix/generic-cmyk-swop
Color: Generic CMYK tints gain as CGATS TR 001 gives for SWOP printing
2026-11-09 04:30:52 +08:00
BFlat 85519d5970 Merge pull request #6244 from dotCooCoo/feat/composite-fonts
Type: Composite Fonts… sets each class of character in a font of its own
2026-11-09 04:30:38 +08:00
BFlat 358df585dc Merge pull request #6241 from dotCooCoo/fix/3d-export-triangle-budget
Asset Export: the 3D mesh triangle limit bounds memory across all exported objects
2026-11-09 04:30:20 +08:00
BFlat fddbbe023d Merge pull request #6231 from dotCooCoo/fix/missing-link-relative-path
Links: a missing linked file keeps its relative folder when a moved document is saved
2026-11-09 04:30:06 +08:00
BFlat 0b8fc3c89d Merge pull request #6228 from dotCooCoo/feat/plugin-storage
Plug-ins: a plug-in keeps settings and a cache of its own
2026-11-09 04:29:51 +08:00
BFlat 0b533ae5f8 Merge pull request #6179 from dotCooCoo/fix/ids-param-strict
Commands: an ids list with an entry that is not an id is refused instead of dropping the entry
2026-11-09 04:29:39 +08:00
BFlat 6d506dc9c8 Merge pull request #5143 from dotCooCoo/fix/ai-os7
.ai import: images past 2^25 pixels in the editing data keep the layers
2026-11-09 04:29:23 +08:00
dotCooCoo 4724475e1a Effects: hidden layer children and edited freeform gradients follow the Transform and Free Distort effects
A path that keeps its shape because the effect would pass the geometry
budget holds a group's own placed gradients in place. A hidden path in a
layer, which the layer's bounds leave out, no longer holds them, so the
layer's gradient moves with its visible art. The art's own gradients
follow the same rule.

A freeform gradient whose points were edited keeps its vector fitted to
the bounds, so it did not count as placed and its points stayed behind
under a Transform effect and Free Distort unless another placed gradient
was in the same appearance. Its points now move like a placed gradient.
2026-11-09 03:14:41 +07:00
dotCooCoo c4de0035b2 .ai import: the editing-copy paragraph in the file-format doc appears once again
docs/file-format-parity.md held 35 copies of the paragraph under
"Illustrator's private editing data" after #6202 left one, each copy
carrying a different set of the changes merged since. The section now
holds one copy with every clause from the others: placed PDF and .ai
pages as placed documents, Bas Relief among the single-effect art
styles, Bas Relief's settings block in type's art style, the fill a
clipping path keeps with its exceptions, paths with an Art brush, the
spot colors in brush art, symbols defined before the art styles
section, the Type on a Path options, and the artboards the type of a
PDF's later pages goes to.
2026-11-09 03:14:41 +07:00
dotCooCoo 11f1d228de Type: Align to Path moves each character by its own font's metrics
Align to Path moved the whole line by the largest ascent and descent
among its characters. Each character now moves by its own font, size
and vertical scale. Ascender runs the top of the font's em box along
the path: the ideographic em box that the font's BASE table gives, or
in a Chinese, Japanese or Korean font the one that its typographic or
hhea box, a one-em box-drawing cross or its ideographs give; else an
em box centered on the cap height. Descender runs the bottom of the font's
bounding box along the path, and Center runs a line at half the height
of the top of the font's H along it. In vertical type, Ascender and
Descender move the characters half an em, and Center leaves them on
the path.

Existing documents with Align to Path set to Ascender, Descender or
Center lay their type out at a new distance from the path.
2026-11-09 03:14:41 +07:00
dotCooCoo 85a933ad4f Keyboard Shortcuts: each Object › Plug-ins filter has a row of its own
Squashed from #6246 onto main.
2026-11-09 03:14:41 +07:00
dotCooCoo 25ecee0c40 Color: Generic CMYK tints gain as CGATS TR 001 gives for SWOP printing
Generic CMYK's tone curves now pass through the CGATS TR 001 tone value
increase of each ink at 40% and 50% (C 20.0, M 17.6, Y 16.8, K 21.6 at
50%), and its 16 Neugebauer primaries mix linearly, so a single ink's
tints gain as TR 001 gives. The 300% ink limit stays. The primaries, the
black-generation curve and the black point are VectorCraft's own values.

- The black point is 90% black under neutral CMY that fills the ink
  limit: sRGB black separates to C75 M68 Y67 K90 instead of C67 M67 Y67
  K100.
- Black follows a curve over the gray component of the black-free
  solve, raised by how far that solve stays lighter than the target.
  Grays from sRGB 177 up carry no black, and sRGB 128 gray separates to
  C50.5 M42.2 Y42.0 K7.5 instead of C38.8 M26.3 Y29.9 K24.4.
- Display of CMYK fills, swatches and imported CMYK values and the
  separation of RGB and Lab colors use the same model.

Paper white still separates to C0 M0 Y0 K0, but other separations
change, and so does the display of CMYK colors with ink. Tests that held
numbers of the old model are updated.
2026-11-09 03:14:41 +07:00
bflatastic c2f2c8ae9b Find Font: a composite font's row is listed by its name alone 2026-11-09 03:14:41 +07:00
dotCooCoo b9d999fe26 Asset Export: the 3D mesh triangle limit bounds memory across objects
The 2,000,000-triangle limit on a 3D object's meshes is now checked as
each mesh is built, so an object past it is refused before the rest of
its meshes are built:

- Revolve counts each fill's and stroke's mesh as it builds it, instead
  of building every one first.
- Inflate still solves every shape's membrane at once (the eye depends
  on the highest puff), but builds each solid only when its mesh is
  reached (inflate_meshes), so a refused object leaves the later
  solids unbuilt.
- All the objects of one 3D asset share one budget
  (three_d_meshes_of), so assets.export3D refuses an asset whose
  objects pass the limit together.
2026-11-09 03:08:23 +07:00
bflatastic faec1f4290 Links: the moved-document tests compare the found path as a path, so Windows separators match 2026-11-09 03:08:23 +07:00
dotCooCoo c94269ff72 Type: Composite Fonts… sets each class of character in a font of its own
Squashed from #6244 onto main.
2026-11-09 03:08:23 +07:00
dotCooCoo faa7b8ef6a Links: a missing linked file keeps its relative folder when a moved document is saved
Squashed from #6231 onto main.
2026-11-09 03:08:23 +07:00
bflatastic d4f2cf5394 Plug-ins: the fuzz tests install each case's module in place of the one before 2026-11-09 03:08:22 +07:00
dotCooCoo 9f23044b87 Merge main into fix/plugin-grant-module-hash 2026-11-08 12:04:11 -08:00
dotCooCoo a224331554 Plug-ins: a failed store write keeps the stored module and its grant together
plugin.install wrote the grant and the module as two separate writes,
and either could fail with only a log record. With a grant tied to the
module's hash, the stored pair then no longer matched and the plug-in
was skipped at the next start.

The module is now written first and its grant only once it is there.
When the grant can't be written, the store gets its old module back, or
loses the new one on a first install, and a disabled plug-in stays
disabled. A stored module that can't be read back is not replaced by
one that needs a grant.
2026-11-08 12:04:03 -08:00
dotCooCoo 218c711181 Plug-ins: a plug-in keeps settings and a cache of its own
Squashed from #6228 onto main.
2026-11-09 02:54:33 +07:00
dotCooCoo 1f38a16329 Commands: an ids list with an entry that is not an id is refused instead of dropping the entry
Squashed from #6179 onto main.
2026-11-09 02:54:32 +07:00
bflatastic 02d877d043 .ai import: the unread-PDF-part test expects the cut-short note for its large image 2026-11-09 02:54:32 +07:00
dotCooCoo b5adb679e4 .ai import: images past 2^25 pixels in the editing data keep the layers
Squashed from #5143 onto main.
2026-11-09 02:43:13 +07:00
BFlat c0893584d4 Merge pull request #5999 from mockydevs/fix/eps-composite-fonts
EPS import: composite fonts draw their Type 42 glyphs (pdftops EPS shows its type)
2026-11-09 03:40:23 +08:00
BFlat 2d40a56047 Merge pull request #6240 from Silvertree2010/fix/h11739-type-insert-unicode-parameter-ac
Reject a plus sign in type.insert unicode hex digits
2026-11-09 03:40:05 +08:00
BFlat 5aca0d70b5 Merge pull request #6229 from addibble/solid-overlaps
3D effects: resolve overlapping contours before building a solid
2026-11-09 03:39:50 +08:00
Don Omondi 21e6464e6f EPS import: scaling a named descendant counts its dictionary's size; test Type 3 descendants and that unreadable Type 42 data is read once 2026-11-09 02:24:54 +07:00
Don Omondi 70353f003e EPS import: reading sfnts data is charged before the copy, whatever its result
Joining a Type 42 font's strings is charged per byte (as other bulk
copies are) before it runs, so data that turns out unreadable, read
again after leaving the cache, no longer copies for free.
2026-11-09 02:24:54 +07:00
Don Omondi e61f0940d0 EPS import: composite fonts' Type 42 review fixes
widthshow matches a composite character by font number times 256 plus
its code; measuring Type 42 glyphs counts against the operation budget;
the Type 42 data cache keeps the least recently used order, remembers
fonts whose data can't be read and counts each font's data against the
memory budget once; composite font arrays are borrowed, not copied.
2026-11-09 02:24:54 +07:00
Don Omondi 3bb43b2fe6 EPS import: composite fonts draw their Type 42 descendants' glyphs
A composite (Type 0) font with the 8/8 mapping picks a descendant font
and a code in it with each pair of bytes (PLRM 3rd ed., 5.10). The reader
set its strings as type in a font of the composite font's name, the
bytes read as Latin-1 and at a thousand times the size, so EPS from
pdftops of a PDF with embedded TrueType fonts showed nothing, or one
black shape, where its type was.

Characters now go to their descendants: a Type 42 font's glyphs are drawn
from the TrueType outlines its sfnts strings carry (Adobe Technical Note
5012), by the glyph index CharStrings gives their names, spaced by their
own widths or the show operator's numbers; charpath and stringwidth read
them too. A Type 3 descendant runs its procedures, and a descendant found
by name sets its character as type at the composite font's size.
2026-11-09 02:24:54 +07:00
NetterSilverandClaude Haiku 5.5 b142814bbd Reject a plus sign in type.insert unicode hex digits
Found while testing crates/engine/src/cmd/typemenu.rs:614 (unicode_char)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 02:24:50 +07:00
Drew Dibble bc87fd1b7e 3D effects: merged contours keep their parts, and edge cases are consistent
The boolean's answer went through orient(), which judges each ring's
side from its first point. The boolean often starts a contour where it
touches another, so a triangle whose tip rests on a square's edge was
dropped, and an even-odd hole touching its outline was filled. The
boolean already runs holes against their outlines, so its rings are now
only turned as a whole.

Other fixes:
- A bowtie drawn as one contour has no area of its own. It was dropped
  before the meet check and built nothing, although it fills both lobes.
  Sampling now keeps rings with no area, and orient() drops them after
  the check. Flat rings, every point on one line, fill nothing and are
  still dropped, so a stray flat contour doesn't send separate art
  through the boolean.
- An open subpath was closed along its end handles when the profile went
  through the boolean, but straight otherwise, as the renderer fills it.
  It is now closed straight before the boolean too.
- An empty union was taken as a refusal. Contours that cancel (a square
  drawn twice under even-odd) built a square. They now build nothing.
- Contours meet within twice the boolean's own sweep tolerance,
  computed by its rule from every anchor and handle of the path it is
  given. pathops snaps anchors onto nearby heights before the sweep
  joins edges within that tolerance, so contours up to about 1.4 times
  it apart can come out as one; within twice it, every contour it
  might join goes through it, even far from the origin, and the few it
  leaves apart cost a boolean that builds the same shape.
- A one-anchor subpath draws nothing, so it is skipped, as the renderer
  and the boolean skip it.
- A profile the boolean refuses reuses the rings already sampled.

Tests:
- touching parts and holes;
- an open subpath with handles, alone and beside crossing bars;
- a flat contour beside separate squares;
- contours joined far from the origin, including by handles alone,
  and contours a few millionths apart near it kept apart;
- triangles snapped together and joined at 1.4 times the tolerance,
  the same triangles left apart and kept whole, and the factor pinned
  between 1.9 and 2.2 times, with the worst case just past twice the
  tolerance left apart by pathops;
- a 24-bar grid: too complex for Extrude and Inflate, whole under Rotate;
- the merged rings turned as a whole;
- a one-anchor loop;
- the bowtie and the cancelling squares under all three effects;
- a 3,001-point star that the boolean refuses (TooComplex), built as
  drawn.

Docs: the pathops README's Limits section now says only the try_
functions refuse, lists OpenPath and the caught panic, and describes
unite_all's answers, and which calls take a precision. three-d.md and effects-parity.md (the 3D row, its
history and status line) describe the merge and its limits.
2026-11-09 02:24:47 +07:00
Drew Dibble 62a01689f0 3D effects: resolve a profile only when its contours meet
The boolean that merges crossing contours cost about as much as the rest
of a plain extrusion, and it ran on every profile. Most art has no
contours that meet, so the profile is now sampled first (its point limit
checked there, before any boolean) and resolved only when two edges
cross, touch, run along each other or fold back, in one contour or
across two. Edges are swept by their left ends, within a pair budget past
which the boolean decides. Touching counts: squares sharing an edge
inflate as one puff, not two with a seam.

On a release build, Extrude of 120 separate contours takes 0.31 ms
instead of 4.18 ms; profiles that do cross cost what they did.

Tests: the meeting cases, squares sharing an edge, the fallback for a
profile the boolean refuses, Inflate's extent and area for the crossing
k, and the coincident circles' area. The hairline test now holds a
crossing pair so that its profile still goes through the boolean.

Docs: the merge is described once for all three effects, linking to a new
Limits section in the pathops README instead of repeating its limits,
and the point limit notes that a merged outline can have more points.
2026-11-09 02:24:47 +07:00
Drew Dibble e1108210f8 3D effects: keep narrow contours when resolving overlaps
try_normalize refits its result at Pathfinder's default precision and
drops every contour thinner than 0.01 pt on average as a sliver. A
hairline beside a larger shape is art, not debris, and resolved() only
fell back to the input when nothing at all was left, so the hairline lost
its cap, walls and surface.

Resolve with try_unite_all_with at a precision far below any art, which
still drops the debris a boolean leaves where curves coincide: a circle
drawn twice, exactly or 1e-7 pt off, stays one outline.
2026-11-09 02:24:47 +07:00
Drew Dibble 5bd046ef64 Docs: 3D solids merge crossing contours before building 2026-11-09 02:24:47 +07:00
Drew Dibble 9bd8b69613 3D effects: resolve overlapping contours before building a solid
Extrude & Bevel, Inflate and Rotate broke on shapes whose contours cross.
Type often draws a glyph that way: Roboto Slab's "k" has its arm and leg
as one contour that crosses both the stem and the leg's foot serif.

rings() decided each contour's role (outline, hole, or no edge at all
under nonzero) from the contour's first point only. A contour that starts
inside another was dropped or flipped into a hole, cutting part of the
glyph away. A contour that starts outside was kept whole, so its walls and
bevels ran through the overlap and the overlapping parts drew as separate
boxes.

The profile now goes through vectorcraft_pathops::try_normalize first, so
rings() only ever sees simple contours that do not cross. A path the
boolean refuses is used as it was.
2026-11-09 02:24:47 +07:00
BFlat 90d5692d80 Merge pull request #6225 from slafebre/fix/6135-ai-open-without-import-dialog
Fix #6135: opening a .ai with editing data skips the Import PDF dialog
2026-11-09 03:21:34 +08:00
BFlat f2768165e6 Merge pull request #6214 from el-j/fix/ai-import-registration-style-6205
Fix #6205: support Registration and named swatches in AI art styles
2026-11-09 03:21:24 +08:00
BFlat 93944d19e9 Merge pull request #6213 from Silvertree2010/fix/h11183-pattern-library-import-treats-a
Don't treat a pattern named "Name +N" as a numbered copy on import
2026-11-09 03:21:08 +08:00
BFlat 875b04b5d8 Merge pull request #6197 from Silvertree2010/fix/h10042-windows-gpu-pci-id-parser-accept
Reject a plus sign in Windows GPU PCI id hex digits
2026-11-09 03:20:54 +08:00
BFlat 4283dfd68b Merge pull request #6196 from KaboomFox/fix/opening-fit-settles
Canvas: a document opens at the zoom of the settled window
2026-11-09 03:20:38 +08:00
BFlat 54d3c58c01 Merge pull request #6180 from SBaksa/export-screens-dots
Export for Screens: an artboard name keeps its dots (fixes #6143)
2026-11-09 03:20:21 +08:00
BFlat 18f772ef06 Merge pull request #6175 from alosslessdev/fix/delete-after-layers-rows-5870
Layers: Delete clears the selection after the last row is deleted (#5870)
2026-11-09 03:20:04 +08:00
BFlat 600ef57710 Merge pull request #6171 from sadkotheguest/fix/char-style-options
Text styles: double-click opens Character/Paragraph Style Options, and the dialog scrolls in a fixed width
2026-11-09 03:19:46 +08:00