Commit Graph
293 Commits
Author SHA1 Message Date
BFlat c86c535389 Merge pull request #6402 from dotCooCoo/feat/text-glyph-bounds
Type: an optional setting measures point type by its glyph outlines
2026-11-10 14:14:00 +07:00
dotCooCoo 860149a981 Merge main into feat/text-glyph-bounds 2026-11-09 22:03:17 -08:00
dotCooCoo 156613941a Type: glyph bounds take in underline and strikethrough bars
With Measure Type by Glyph Bounds on, point type is measured by its
glyph outlines and its underline and strikethrough bars, as the canvas
draws them. A typed W or H gives what is drawn that size, and underlined
or struck-through spaces are measured by their bars instead of the em
box.

The texts now say that each point type object selected as an object
(not inside a selected group) is measured this way, that moved type
snaps by its ink box, and which Arrange Tools commands follow the
option: Swap Objects, Replace with Top Object, Set Size of Each and
Sort Objects. Arrange in Grid and Group Overlapping Objects keep
measuring visual bounds.
2026-11-09 21:53:22 -08:00
dotCooCoo c703cc5650 Revolve: a face drawn on its own keeps its fill or stroke's opacity and blending mode
A face of a group member that paints nothing (its fill or stroke at 0% opacity) was drawn without a group, so its zero opacity was lost and the member drew fully opaque. Such a face now keeps a group with the opacity and blending mode of its fill or stroke.
2026-11-09 21:37:27 -08:00
BFlat 04edd114b1 Merge pull request #6395 from dotCooCoo/fix/revolve-group-depth-order
Revolve: a group's faces keep one back-to-front order when a member is transparent
2026-11-10 12:27:32 +07:00
dotCooCoo a1949095c6 Type: an option fits a text object's bounds to its glyph outlines
Measure Type by Glyph Bounds (`typeGlyphBounds`, off by default) is in
Preferences > Type > Glyph Bounds and the Transform panel menu. With it
on, the bounding box, the Transform, Control bar and Properties X, Y, W
and H, `object.setBounds`, the transform tools' reference point and the
Arrange commands measure point type selected on its own by the ink of
its glyphs instead of its em box. A typed W or H scales the live type
until its ink has that size.

- The engine caches each type object's ink in text space with its
  layout bounds; the cache is not saved.
- Use Preview Bounds adds the characters' strokes, and type with
  geometry effects is measured as drawn. Skewed type is measured by its
  outlines.
- Type that draws nothing, area type, type on a path and type inside a
  selected group are measured as before. Align and Distribute keep
  following Align to Glyph Bounds.

Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md,
object.setBounds params text.
2026-11-09 21:07:55 -08:00
dotCooCoo af2ee68bf3 Revolve: a group's faces keep one back-to-front order when a member is transparent
When any member of a revolved group had an opacity below 100% or a
blending mode, every member's surface was drawn whole in member order,
so the opaque members lost their shared depth sort and a transparent
member drew entirely over or under the others.

Every member's faces are now sorted into one order. Opaque faces go in
that order on their own. A transparent member's faces share one group
with its opacity and blending mode, and its scopes group them further,
unless a face of another member that overlaps them on the page lies
between them in the order; only there is the member split. Faces
overlap when the convex hulls of their outlines come within the 0.75 pt
seam stroke of each other. Faces that paint nothing never split a
member. Past 4,194,304 overlap tests on one group, each further face
of such a member is drawn as a part of its own.

Docs: docs/revolve.md.
2026-11-09 20:49:13 -08:00
dotCooCoo 55e6c0a5b1 Revolve: a hidden Revolve's profile is measured before the effects after it
effect.setParams checks a Revolve before the edit, so turning a hidden Revolve back on measured
its profile after every geometry effect on the object, those after the Revolve included, and could
refuse a profile that draws. The check now measures the profile after only the geometry effects
before the Revolve, hidden or shown, as drawing does. An object holds at most one Revolve, hidden
ones included, so the check finds the same one that draws.
2026-11-09 19:47:40 -08:00
BFlat 4dbaa10e0a Merge pull request #6365 from dotCooCoo/fix/issue-3617
Revolve: type, groups and layers revolve, and the profile and face limits are higher
2026-11-10 10:23:52 +07:00
BFlat 695721f9df Merge pull request #6380 from dotCooCoo/fix/preview-bounds-butt-line
Transform: butt-capped lines measure to their end points with Use Preview Bounds
2026-11-10 09:59:06 +07:00
dotCooCoo 2e81086c38 Revolve: a nested group's opacity applies once to its members together
The opacity of a group inside a revolved group was multiplied into each member's surface, so where members overlap they drew darker than the group does without the effect. A member or group with opacity below 100% or a blending mode other than Normal now holds its members' surfaces in one group with that opacity and mode.
2026-11-09 18:30:41 -08:00
dotCooCoo bed632cc65 Transform: butt-capped lines measure to their end points with Use Preview Bounds
With Use Preview Bounds on, the visual box of a butt-capped stroke on an
open path grew by half the stroke weight past each end of the path, where
a butt cap paints nothing. A 2 pt vertical line set to H: 10 mm in the
Transform panel drew about 9.3 mm long.

The box of an open subpath with butt caps no longer reaches past its
ends. A straight segment's box comes from the four corners of its stroked
rectangle, and a curve's box comes from the stroke at its ends and where
its tangent is square to an axis. Bevel joins, and miter joins the limit
bevels, are measured by the stroked corners, and round joins by the arc
they paint outside the turn, instead of half the weight all round. Round
and projecting caps, arrowheads, closed paths and miter tips measure as
before. Two cases can still measure larger than the stroke paints: a
curve that bends more tightly than half the weight, and a butt-dashed
path whose first or last dash is a gap, which is measured to the path's
ends.

A horizontal or vertical butt line now measures one stroke weight less
along its length in W or H, and Align places it by its end points. A
slanted line's box shrinks by less: the stroke's corners still reach
past the end points across the line. object.setBounds measures as drawn,
after each scale it tries, a butt-capped open path with a segment at a
slant, symbol instances' art included.
2026-11-09 18:16:48 -08:00
dotCooCoo d8d73495bb Revolve: a group member's blending mode applies to its surface
A member of a group with Revolve drew its surface in Normal mode whatever its own blending mode or that of a group it is in. Each mode now applies once, to the member's surface or to the surfaces of the group that has it, nested as the groups are. Expand Appearance keeps every face of a blended member.
2026-11-09 18:05:17 -08:00
dotCooCoo cddebdf7f6 3D: a group's fill or stroke takes no 3D effect
Revolve, Extrude & Bevel, Inflate and Rotate on a group or layer draw only as the group's own effect. On the group's fill or stroke they drew nothing, yet effect.apply and effect.setParams accepted them. Both now refuse that placement.
2026-11-09 17:51:22 -08:00
dotCooCoo bb142cc063 Revolve: the fills and strokes of one object share the paint-copy budget
Each fill or stroke with its own Revolve counted the copies of its paint from zero, so an object with several of them could draw past the 256 MiB budget. They now share one count, and past it the source path draws, as for the members of a group.

effect.apply and effect.setParams on a fill or stroke now check the Revolve in that item's paint, after the item's geometry effects before it, together with the object's other items that carry a Revolve. Before, they checked the object's top fill.

docs/revolve.md marks the axis position, type handling and member paint as VectorCraft's own rules, and docs/mcp.md says how the budget is counted.
2026-11-09 17:19:13 -08:00
dotCooCoo 35db931810 Fix #6316: a group copies each member in place when a member makes more art
A group with a visible member that carries a geometry, Pathfinder or 3D effect, also in an opacity mask, keeps its previous copies. Copies stop at the budget with what each copy's own effects make, and a group's copies count the art of opacity masks.

The PDF and SVG tests for a group's image copies now expect the original on top.
2026-11-09 16:24:13 -08:00
dotCooCoo b07c808093 Revolve: type, groups and layers revolve, and the profile and face limits are higher
Type sweeps as its glyph outlines and stays editable. On a group or layer every visible member sweeps about one axis on the edge of the members' bounds together, each in its own paint.

A surface now takes up to 16,384 profile points and 163,840 faces. Curves take fewer samples, down to 4, when a surface passes those limits, and the command reports the failure below that, after the geometry effects before the Revolve and with the cumulative size of its paint copies counted. Mesh export turns the walls of holes toward them. Expand Appearance works on type with Extrude as well as Revolve.

Fixes #3617
2026-11-09 16:09:03 -08:00
dotCooCoo 59304f9964 Fix #6316: a Transform effect's copies of a group are whole groups below the original
A Transform effect with copies on a group copied each member on its own,
so one member's copies lay over the fills of the next member. Each copy
is now a whole group, the original on top and each copy below the one
before. A path's copies follow the same order. Guides are not copied,
and the copies stop at the node limit. A group with its own fill or
stroke, a clipping group and live type keep their previous copies.
2026-11-09 14:27:25 -08:00
dotCooCoo bd5ea2a1bf Merge main into feat/plugin-effect-paint 2026-11-08 17:59:33 -08:00
dotCooCoo d6a91b6142 Merge main into feat/plugin-effect-paint 2026-11-08 17:26:35 -08:00
BFlat 44a37b0729 Merge pull request #6233 from dotCooCoo/fix/fitted-gradient-turns-with-transform
Effects: fitted gradients turn with the Transform effect
2026-11-09 08:58:30 +08:00
BFlat e8dbb22d4c Merge pull request #6174 from dotCooCoo/feat/3d-classic-extrude-bevel
3D (Classic): Extrude & Bevel (Classic) extrudes art with Wireframe, No Shading, Diffuse and Plastic surfaces
2026-11-09 08:53:49 +08:00
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
dotCooCoo e2bac253f1 Merge main into fix/fitted-gradient-turns-with-transform 2026-11-08 15:56:12 -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 83f1333d1c Effects: a Transform effect that flattens the object leaves a fitted gradient fitted with its options on
With Scale Strokes & Effects or Transform Patterns on, the path and each copy are moved by Node::transform, which fixed a fitted gradient to its fit before a scale of 0 flattened it to one color. Scaling::keep_fit_when_flat keeps the gradient fitted under a map that flattens the object (node::flattens, the gate fixes_fit already used), and the Transform effect's path transforms set it.

docs/target-app-parity.md also says that the Gradient tool still shows a fitted gradient's vector at its unturned fit.
2026-11-08 15:38:07 -08:00
dotCooCoo a7fc513a0c Merge main into feat/3d-classic-extrude-bevel 2026-11-08 15:34:06 -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 e4d7e588ab Merge main into feat/plugin-effect-paint 2026-11-08 13:48:07 -08:00
dotCooCoo e4e6e0d382 Plug-ins: a painted piece linked to a global swatch follows its color
A piece linked to a global swatch is drawn in the swatch's current color at its own tint, and kept art and rasters follow a color or spot edit and its Undo. A value of `paintOutput` other than true is refused by a translated error. Tests in the effects crate pass the new document argument.
2026-11-08 13:45:17 -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 9d0b2b0c1c Merge main into fix/fitted-gradient-turns-with-transform 2026-11-08 13:07:04 -08:00
dotCooCoo 11703bd350 Merge main into feat/plugin-effect-paint 2026-11-08 12:56:42 -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 4b5f89e903 Merge main into fix/fitted-gradient-turns-with-transform 2026-11-08 12:09:50 -08: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
dotCooCoo 81c5b047bc Merge main into feat/plugin-effect-paint 2026-11-08 11:36:48 -08:00
dotCooCoo aee3a76e2a Merge main into fix/fitted-gradient-turns-with-transform 2026-11-08 11:16:42 -08:00
dotCooCoo 2f72a998b9 Plug-ins: a painted fill or stroke effect keeps a placed gradient on its moved shape
A Transform or Free Distort before a painted effect on a fill or stroke moved the shape but left the placed gradient at its old position, both on pieces that keep the fill or stroke and on the geometry drawn after a refused result. The inherited fill or stroke now takes the same gradient move as the Transform branch.
2026-11-08 11:05:27 -08: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 64817c2e8c Merge main into feat/plugin-effect-paint 2026-11-08 10:46:47 -08:00
dotCooCoo 21db71b9a6 Plug-ins: Expand works on each painted piece and stacked painted fills keep the others
Object > Expand of gradient and pattern fills now expands the pieces a
painted live effect draws one by one, so a piece keeps its own paints.
A later painted effect on a fill replaces only the first fill of a piece
and leaves the piece's other fills in place.

Document Info passes the document when it reads an image's painted fills.
2026-11-08 10:11:18 -08: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