Commit Graph
249 Commits
Author SHA1 Message Date
BFlat 64280c64d3 Merge pull request #6152 from dotCooCoo/perf/contours-cover-lists
Path ops: boolean contour passes test the shapes covering each face instead of a flag per shape
2026-11-09 08:03:59 +08:00
BFlat 8fc4464542 Merge pull request #6236 from dotCooCoo/fix/placed-gradient-follows-warp
Effects: placed gradients move and scale with the Warp effects
2026-11-09 07:47:08 +08:00
dotCooCoo 0945eaf2b3 Merge main into perf/contours-cover-lists 2026-11-08 15:00:56 -08:00
dotCooCoo 5c17cfd038 Tests: warped placed gradients check each warp's bounds and movement
The Warp gradient test now compares the baked bounds with the square's
outline mapped through warp_point, for every style and parameter set. It
requires the gradient to move exactly when those bounds move, and pins
39 of the 45 cases as moving the bounds.
2026-11-08 14:20:47 -08:00
dotCooCoo 83248b9bb4 SVG Filters: export writes a filter live only when import can read it back
SVG export wrote an SVG filter as a live <filter> when its SVG 1.1 form
was at most 64 KB, without counting the region and id it writes into
it. A filter close to the limit came back over it, SVG import dropped
it, and the reopened object had no filter.

Export now leaves room for the id and the measured region, checks the
SVG 1.1 form the way import does, and counts each character past U+00FF
as the character reference Latin-1 output writes. A filter that does not
fit is exported as the other pixel effects are. The SVG 1.1 form and its
check are kept for the filters seen last, as checked filters already
are, so export does not check one filter again for each object.
2026-11-09 04:19:44 +07:00
dotCooCoo 1e21154e4d Symbols: symbol.instance.setAppearance refuses a fill or stroke an object does not draw
Squashed from #6232 onto main.
2026-11-09 04:19:25 +07:00
dotCooCoo 5aec304ef1 Merge main into fix/placed-gradient-follows-warp
# Conflicts:
#	crates/effects/src/reshape.rs
2026-11-08 13:11:12 -08:00
dotCooCoo c63f634e0c Merge main into fix/placed-gradient-follows-warp 2026-11-08 12:22:54 -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 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
Sven Lafebre b2acf71764 Fix #5960: find how far gradient ribs reach in one pass along the path
Each rib of a dashed stroke with a width profile looked up to 256 points
either way along the path, asking the profile at every step, and reached
as wide as the stroke gets anywhere past that. A sliding maximum over the
points' precomputed cover now gives every rib's reach in time in
proportion to the points, with no bound and no fallback to the widest
width (review on #6093).
2026-11-09 02:03:03 +07:00
Sven Lafebre 8f975aa0c5 Fix #5960: a narrow part of a variable-width stroke paints over a wide part only where they overlap
With a width profile, every slice of a stroke gradient (along or across)
reached as far as the stroke is wide anywhere. Where the stroke crosses
or runs close by itself, the later, narrower part painted a square of
its colour over the wider part beside it, clipped only to the whole
outline. Each rib now reaches as far as the stroke is wide there and on
its way to the next points (each side of a profile stays between its
widths at a span's points); for a dashed stroke, as wide as it gets
within a cap's reach, since caps and dots reach along the path.
2026-11-09 02:03:02 +07:00
dotCooCoo cca9a42c6c Effects: Effect › SVG Filters applies the document's SVG filters as live effects
Squashed from #6200 onto main.
2026-11-09 00:34:23 +07:00
dotCooCoo b9aacded51 Tests: placed gradient tests check the whole gradient after Transform and Free Distort
The baked Transform and Free Distort tests now compare each placed
gradient's start, end, aspect and focal point with the expected values
within a tolerance, and the Transform test adds a turn with a scale.
2026-11-09 00:34:12 +07:00
dotCooCoo 732434b4e5 Effects: placed gradients move with Transform and Free Distort effects
A gradient placed with the Gradient tool stayed where it was when the
object's Transform or Free Distort effect moved, turned or scaled the
outline, so the shape slid across its own gradient.

The Transform effect now maps placed gradients by its own transform,
and each of its copies takes them as many times as it takes the
transform. Under Free Distort, each path's placed gradients move and
scale from the path's bounds before the effect to its bounds after it.
This change does not alter gradients fitted to the object.

The canvas, Expand Appearance and export, Pathfinder and compound
shapes, groups, a fill's or stroke's own effects, and Object › Expand
of a gradient fill apply the same rule. In a group, the own fills and
strokes of the group, of the groups inside it and of a symbol's art
follow it too, and images and symbol instances that a group's
Transform effect moves take the placed gradients of their own fills
and strokes along. A group whose path keeps its shape because the
effect would pass the geometry budget keeps its own gradients in
place.

This changes how existing documents draw: a gradient placed on a path,
or on an image's or symbol instance's own fill, inside a group with a
Transform effect now moves with it. Before, only the gradients of type
moved (#2214).

How gradients follow each effect is VectorCraft's own rule. The
Distort & Transform help page describes what the effects do to the
object:
https://helpx.adobe.com/illustrator/desktop/manage-objects/reshape-transform-objects/distort-and-transform-effects-in-illustrator.html
2026-11-09 00:34:12 +07:00
dotCooCoo 00ac0ac5ae Tests: placed gradients under Warp on strokes, symbol art and compound shapes
Covers the other places a Warp now moves placed gradients: a group's
and a nested group's own strokes and a compound path's stroke (with the
stroke-inflated bounds), the art of a symbol instance and the area of a
compound shape with a Warp, and a stroke's own Warp on the canvas. A
new test checks that Arc's no-bend threshold for gradients matches the
one the warp uses, and the no-bend test now covers all fifteen styles.
The render test's Fisheye case, which left the square's bounds as they
were, is replaced by a vertical Bulge, and each style there is checked
to move the outline's left or right edge. The Object > Expand test
checks that it measures the ramp and not an edge of the outline.

The params text and docs/mcp.md now state which bounds each gradient
follows, and that a warp moves them with a bend or a distortion.
2026-11-08 09:29:57 -08:00
dotCooCoo b568977af4 Asset Export: 3D objects export as USDA, USDZ, glTF or OBJ meshes
Squashed from #6168 onto main.
2026-11-09 00:29:05 +07:00
dotCooCoo 394bbb37c0 Effects: placed gradients move and scale with the Warp effects
A gradient placed with the Gradient tool stayed where it was when the
object's Warp effect changed the outline, so the warped shape no longer
matched its gradient.

Under each Warp style the placed gradients of a path now move and scale
from the path's bounds before the warp to its bounds after it, as they
do under Free Distort. This applies to an object's own Warp and to a
fill's or stroke's own (a stroke uses its stroke-inflated bounds), on
the canvas and in Object > Expand of the fill. In a group with a Warp
effect, each path's and compound path's gradient follows its own
bounds, and the own fills of the group and of the groups inside it
follow those groups' bounds. A warp with no bend and no distortion
leaves gradients exactly where they are, and gradients fitted to the
object are unchanged.

This changes how existing documents draw: a placed gradient on art with
a Warp effect now follows the warped outline instead of staying in
place.

How gradients follow the warp is VectorCraft's own rule. What the Warp
effects do to the object is described in
https://helpx.adobe.com/illustrator/using/reshaping-objects-effects.html
2026-11-08 08:43:27 -08:00
dotCooCoo 9f629418e9 Merge main into perf/contours-cover-lists 2026-11-08 00:21:42 -08:00
dotCooCoo c43e4a388e Tests: placed gradient tests check the whole gradient after Transform and Free Distort
The baked Transform and Free Distort tests now compare each placed
gradient's start, end, aspect and focal point with the expected values
within a tolerance, and the Transform test adds a turn with a scale.
2026-11-07 23:24:09 -08:00
dotCooCoo c94aec3fff Envelopes: type maps from its glyph outline bounds
An envelope mapped type from its laid-out box: ascent to descent for
point type, the frame for area type. The distorted glyphs then filled
less of the envelope than other art does, with room above the capitals
and below the baseline.

The envelope now maps type from the bounds of its glyph outlines,
underlines and strikethroughs when the type is on its own, in groups
and layers, or used as a clipping path. Inline graphics count by their
boxes. Rotated type and type in perspective map from their outlines as
they are drawn. Make with Mesh,
Make with Top Object and Reset with Mesh without Maintain Shape use
those bounds. Type that draws nothing keeps its laid-out box, and so
does type inside any other object, such as a blend, a repeat or a
symbol instance. Shrink Text to Fit type is measured as it is laid out
on the page.

vectorcraft-text's envelope_ink measures the type, and
register_envelope_ink registers it with the document crate. The engine
session, Renderer::new, live evaluation in vectorcraft-effects and the
.ai reader register it. The document crate keeps the measured boxes per
thread, by object and by a hash of the content, and measures again when
the type, the fonts, the hyphenation exceptions or the transform's
scale or rotation change.

This is VectorCraft's own rule. Envelopes of type made in VectorCraft
and in saved files map from the glyph outline bounds instead of the
type's laid-out box, so they redraw differently.
2026-11-08 13:20:19 +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 142366d9ee Effects: placed gradients move with Transform and Free Distort effects
A gradient placed with the Gradient tool stayed where it was when the
object's Transform or Free Distort effect moved, turned or scaled the
outline, so the shape slid across its own gradient.

The Transform effect now maps placed gradients by its own transform,
and each of its copies takes them as many times as it takes the
transform. Under Free Distort, each path's placed gradients move and
scale from the path's bounds before the effect to its bounds after it.
This change does not alter gradients fitted to the object.

The canvas, Expand Appearance and export, Pathfinder and compound
shapes, groups, a fill's or stroke's own effects, and Object › Expand
of a gradient fill apply the same rule. In a group, the own fills and
strokes of the group, of the groups inside it and of a symbol's art
follow it too, and images and symbol instances that a group's
Transform effect moves take the placed gradients of their own fills
and strokes along. A group whose path keeps its shape because the
effect would pass the geometry budget keeps its own gradients in
place.

This changes how existing documents draw: a gradient placed on a path,
or on an image's or symbol instance's own fill, inside a group with a
Transform effect now moves with it. Before, only the gradients of type
moved (#2214).

How gradients follow each effect is VectorCraft's own rule. The
Distort & Transform help page describes what the effects do to the
object:
https://helpx.adobe.com/illustrator/desktop/manage-objects/reshape-transform-objects/distort-and-transform-effects-in-illustrator.html
2026-11-07 21:11:07 -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
Sven Lafebre a83a0054ea Part of #5964: stroke gradients cover an arrowhead to the end of its reach
With ribs only at the path's corners (an Along gradient), the ribs that reach
across an arrowhead stopped at the last corner inside its reach, so the slice
narrowed from the head's tip towards the next corner and left the corners of
a Triangle head's base outside every slice. Where each arrowhead's reach ends
now gets a rib of its own.
2026-11-07 05:15:12 +07:00
Sven Lafebre 1b62f86b8c Fix #5714: doc comments on the width profile tests 2026-11-07 05:15:10 +07:00
Sven Lafebre 9da56717a0 Fix #5714: widths run smoothly between width points
The width between two width points was a straight line, so a variable-width
stroke turned a corner at every width point.

- Each side of a width profile now follows a monotone cubic (Fritsch-Carlson)
  through its points: no kink at a point, flat at a point wider or narrower
  than both neighbours, never past either point of a span. Points on one line
  stay on it and two-point tapers are unchanged; stacked points still step.
- widest() counts each span's wider left and wider right, since the two sides
  needn't peak together.
- The outliner samples straight runs between width points closely enough to
  follow the curve to the drawing tolerance (at most 64 samples per span and
  4,096 per piece); straight spans get none.
- Tests that expected straight-line widths now expect the curve. The stroke
  gradient coverage test uses Teardrop instead of Wave until #5964 is fixed.
2026-11-07 05:15:09 +07:00
Don Omondi 3f7f743ddb 3D effects: Extrude & Bevel, Inflate and Rotate apply to groups
A 3D effect on a group or layer builds a solid from every path,
compound path and type in it, all turned about one shared axis, as the
public docs describe for groups. Fixes #4506.
2026-11-07 00:17:14 +07:00
Don Omondi 6537396ee0 Effects: a Transform effect's copies of a filled and stroked path stack one above another (#5920)
A path whose fills and strokes stack (a fill and a stroke, several of
either, an even-odd fill, or a partly transparent or blended one) drew
its Transform effect's copies as one path, so every copy's stroke lay on
top of every copy's fill. It now draws each copy as an object of its own
above the one before, as Expand Appearance makes them.

Fixes #5920
2026-11-06 23:04:56 +07:00
Don Omondi 41ceaadc7e SVG import: Gaussian blurs keep color-interpolation-filters; Gaussian Blur can blur in linear light (#5877) 2026-11-06 16:05:55 +07:00
dotCooCoo e6819a86f0 Rendering: open width-profile strokes outline only near the view 2026-11-06 12:42:33 +07:00
FractalEncrypt e0ad7ccf16 Preserve raster coverage of thin curved strokes
Squashed from #3273 onto main.
2026-11-05 20:00:21 +07:00
Don Omondi 231e43a490 Effects: Expand Appearance makes each copy of a path's Transform effect an object of its own (#5612)
A path or compound path whose Transform effect made copies expanded to
one compound path of every copy. It now expands to a group of one object
per copy, each painted as the path, as gradient copies already did; a
second Transform effect's copies nest in a group per copy of the first.
Drawing is unchanged.

# Conflicts:
#	docs/effects-parity.md
2026-11-05 10:25:44 +07:00
FredApps ed78763866 Merge pull request #4784 from datatimp/fix/3260-halftone-radius-pixels
Color Halftone: Max Radius in pixels of the raster effects resolution
2026-11-05 04:09:48 +01:00
dotCooCoo ed3efcbd7d Render: a long dashed stroke is outlined only near the view after an edit
A dashed stroke of a path with more than 1,024 path elements was outlined
whole in every frame after an edit. It is now outlined in and around the
view like a solid stroke. dash_kept runs the pattern along every segment
and keeps only the dashes and dots on the segments near the view, so they
sit where dashing the whole path puts them and the pixels are the same.
A pattern too fine to draw is still drawn solid, and that solid stroke is
cropped too.

At 1600 x 1200 the frame after one anchor moves takes 14 ms instead of
102 ms on a filled closed path of 50,000 anchors with 6 pt dashes and
4 pt gaps. anchor_bench now includes that document.
2026-11-05 03:55:48 +07:00
datatimp 1a1285fecd Merge remote-tracking branch 'upstream/main' into fix/3260-halftone-radius-pixels
# Conflicts:
#	crates/doc/src/limits.rs
#	crates/engine/src/cmd/fileio/tests_pdfedit.rs
#	crates/format/src/lib.rs
#	docs/target-app-parity.md
2026-11-04 12:30:23 -05:00
dotCooCoo f0f19077df Document Color Mode: convert reusable paints and restore them with Undo
Squashed from #4517 onto main.
2026-11-04 16:55:43 +07:00
Dylan M. Taylor 13b0bbe639 Linear-time scans: Add Anchor Points, swatch library adds, placed-document export, width profiles, symbolism previews
Add Anchor Points builds the new anchor list in one pass, Swatch Library add looks names up in sets, full_documents dedups placed keys with a set, width profile lookups and mark insertion use binary search, and the symbolism tools cap and thin the previews of a long drag as Liquify does.
2026-11-04 08:13:18 +07:00
datatimp c02b62dacb Merge remote-tracking branch 'upstream/main' into fix/3260-halftone-radius-pixels 2026-11-03 14:27:49 -05:00
Dylan M. Taylor 4aea3cc95c fix(effects): a dash pattern whose period overflows draws solid 2026-11-03 22:16:55 +07:00
dotCooCoo a870da6c7d .ai import: Effect › Pathfinder on a group opens as a live effect
Squashed from #5150 onto main.
2026-11-03 16:38:47 +07:00
dotCooCoo b664216a2a .ai import: type keeps its Distort & Transform effects live
Squashed from #5139 onto main.
2026-11-02 16:19:59 +07:00
dotCooCoo 9aac3ca888 Envelope: Distort Appearance keeps a Transform effect's Scale Strokes & Effects and Transform Patterns
With Envelope Options > Distort Appearance on, a path whose Transform
effect has Scale Strokes & Effects or Transform Patterns on, or copies it
with a gradient, was baked with the effect as geometry only: every copy
kept the original's stroke weight, dashes and pattern placement before
the envelope bent it. bake_appearance now makes such a path into the
per-copy art that drawing, export and Expand Appearance already use, and
bakes each copy's strokes into filled outlines from there.
2026-11-02 16:18:15 +07:00
dotCooCoo d324440afb Pathfinder: blends, envelopes and warped objects can be compound shape members
Squashed from #5226 onto main.
2026-11-02 15:22:32 +07:00
dotCooCoo 83f2bfe9d6 Symbols: a scaled instance of a symbol with 9-slice guides keeps its corners and edges unstretched
Squashed from #5079 onto main.
2026-11-02 15:22:07 +07:00
dotCooCoo ae23859002 Effects: later effects on a fill's or stroke's own Transform apply to all its copies as one piece
The geometry effects after a fill's or stroke's own Transform effect with
Scale Strokes & Effects or Transform Patterns now take the bounds of the
transformed path and all its copies as their reference box, as an
object's own effects do. A later Rotate turns the copies about their
combined center instead of turning each copy about its own, and a later
Offset Path or plain Transform applies to the paths themselves. Each copy
keeps its own scaled distances.

Part of #885
2026-11-02 15:22:00 +07:00
dotCooCoo eb92a1e53a Effects: a fill's or stroke's own Transform copies leave room in the effect budget for the pieces painted after them
transform_item_leaf now holds back the leaf's geometry for each plain or transformed piece that follows a transformed fill or stroke, so the copies of an earlier item no longer use up the budget that a later fill or stroke still needs. The nested pass over a transformed piece keeps to the same reduced limit.
2026-11-02 15:22:00 +07:00
dotCooCoo a1b8da43de Effects: plain fills and strokes beside a fill's or stroke's own Transform count toward the effect budget
Each fill or stroke without such a Transform effect is drawn on the object's geometry again, so its cost now counts toward the budget that limits the Transform effect's copies. The object's own geometry is no longer counted a second time next to the pieces that replace it. The Transform effect options entry in docs/target-app-parity.md links the current help pages.

Part of #885
2026-11-02 15:22:00 +07:00
dotCooCoo 3e77f65c7f Effects: a Transform effect on a fill or stroke honors Scale Strokes & Effects and Transform Patterns
A Transform effect in a fill's or stroke's own effect list now applies its
Scale Strokes & Effects and Transform Patterns options as the same effect on
the object does: the stroke's weight and dashes, the distances of the fill's
or stroke's later effects and its pattern follow the transformation, each
copy once more than the last, and with Transform Objects off the geometry
stays and the options apply once. The fill or stroke becomes an object of
its own in the art the canvas, export and Expand Appearance draw, and Use
Preview Bounds measures that art too (also for the object-level options).

Part of #885
2026-11-02 15:22:00 +07:00
bflatastic f22caa6108 Fix #4938: Dynamic symbols keep per-instance appearance linked to the symbol 2026-11-01 04:53:38 +07:00