Commit Graph
500 Commits
Author SHA1 Message Date
BFlat 45d98a5f82 Merge pull request #7443 from dotCooCoo/fix/wireframe-outline-stroke-width
3D: Expand as Wireframes outlines each face's own stroke under a later Outline Stroke
2026-11-14 21:55:03 +07:00
BFlat 8657b38b35 Merge pull request #7590 from dotCooCoo/perf/group-sublayer-guides-one-pass
Effects: a layer's effects gather its sublayers' ruler guides in one pass
2026-11-14 21:51:54 +07:00
BFlat d1aa073c42 Merge pull request #7585 from dotCooCoo/fix/clipping-type-fill-effects
Export: clipping type with geometry effects clips where the canvas does
2026-11-14 21:50:33 +07:00
BFlat 035d22b3e2 Merge pull request #7476 from dotCooCoo/fix/svg-clip-path-effects
Effects: a clipping path's geometry effects shape the clip on the canvas
2026-11-14 20:38:37 +07:00
BFlat 4bcb0026da Merge pull request #7569 from dotCooCoo/perf/3d-validation-builds-once
3D: effect validation builds each Extrude and Inflate solid once
2026-11-14 20:38:09 +07:00
dotCooCoo a8aea70be5 Merge main into perf/group-sublayer-guides-one-pass
# Conflicts:
#	crates/effects/src/group/tests.rs
2026-11-14 04:45:50 -08:00
dotCooCoo 59e4a6bfca Merge main into fix/wireframe-outline-stroke-width 2026-11-14 04:39:51 -08:00
dotCooCoo 65b221192e Effects: a layer's effects gather its sublayers' ruler guides in one pass
Evaluating a layer's Pathfinder or geometry effects asked each member
whether a sublayer below it held a ruler guide, then asked the members
of every selected sublayer or group the same question again on the way
down. A sublayer nested N deep was scanned once per layer or group above
it, so a chain of N sublayers cost N(N+1)/2 scans.

One read walk now looks at each member once at most and records which
members hold or lead to a sublayer's guides, and the move visits and
copies only those. As before, the groups inside a sublayer that holds no
guide are not looked into. The guides taken, their order, their hidden
and locked state, the art left behind and the sharing of untouched
members are the same as before.
2026-11-14 04:39:29 -08:00
BFlat 67f432c965 Merge pull request #7502 from dotCooCoo/fix/revolve-local-depth-order
Revolve: overlapping faces draw in the order of their depths where they overlap
2026-11-14 19:37:37 +07:00
BFlat 9a8b7bc3db Merge pull request #7517 from jayzed80/fix/offset-path-clip-silhouette-7289
Appearance: a group's own fills and strokes follow a clip group's clipping path, not the art it hides (#7289)
2026-11-14 19:37:29 +07:00
dotCooCoo 0e6151011d Export: clipping type with geometry effects clips where the canvas does
Type used as a clip group's clipping path, with a geometry effect on the
object, on one of its fills or strokes, or a perspective, was baked into
its outlined pieces with the effects applied, so SVG, PDF and the other
exports clipped by all of them while the canvas clips by the plain glyph
outlines. The baked clipping path was also a group, so the type's fills
and strokes were not painted.

bake_node now bakes such a clip group as the canvas draws it: the
clipping path is a path of the region effects::clip_outline gives, the
type's fills (effects baked) paint behind the clipped art inside the
clip, and its strokes paint over it outside the clip, in a group that
keeps the clip group's id and transparency.
2026-11-14 04:30:45 -08:00
dotCooCoo fb8cf27b9a Effects: clip regions follow fill effects and compound paths in every case
Three cases still clipped differently from what the clipping path draws:

- A clip group with an appearance of its own (a Drop Shadow, a geometry
  effect) was measured for culling by its plain clipping path, so a view
  showing only the part of the clip that an effect moved drew nothing.
  The renderer now grows that measure by the clip region in this case
  too.
- The geometry effects on the fills and strokes of an unpainted clipping
  path applied after the effects of a group around it. They now apply
  first, as for other members. A clipping path that paints keeps them
  live, so its fill and stroke still draw.
- Export baked a compound clipping path with an effect of its own from
  its raw paths, dropping the effects on those paths. It now bakes the
  clipping path as the canvas clips by it, and the pieces it bakes into
  get ids of their own.
2026-11-14 03:52:45 -08:00
dotCooCoo 25e35ee5b1 3D: effect validation builds each Extrude and Inflate solid once
Checking an Extrude & Bevel (both kinds) or Inflate effect built every
shape's profile about the profiles' bounds, then built the fill and
stroke solids again about the bounds of the regions they paint. A
filled shape's profile is its fill's solid, so that solid was built
twice. When a stroke reaches past the shape, the first build also used
bounds the effect does not draw it about.

The check now builds the profile on its own only where no drawn solid
is built from it: every shape for Rotate, and for Extrude & Bevel and
Inflate a shape with no fill (strokes only, or no paint). A filled
shape's solid is built once, about the bounds the effect draws it
about. The shadow check is unchanged.

Tests count the solids the check builds: an object with a fill and a
stroke, a group of two such members, an effect on the fill and the
shadow on; a shape with no fill still has its profile built.
2026-11-14 03:51:00 -08:00
dotCooCoo a9fbb7aa50 Merge main into fix/svg-clip-path-effects 2026-11-14 02:24:38 -08:00
dotCooCoo 21267a4b1f Merge main into fix/wireframe-outline-stroke-width 2026-11-14 02:24:25 -08:00
BFlat c3df647cd7 Merge pull request #7408 from dotCooCoo/fix/3d-export-builds-once
3D: Export 3D Object builds each Extrude and Inflate solid once
2026-11-14 16:53:56 +07:00
BFlat 4c86cb97d3 Merge pull request #7489 from dotCooCoo/fix/instance-row-raster-effects
Effects: raster effects on a symbol instance's fill or stroke are drawn
2026-11-14 16:52:35 +07:00
jayzed80 f4f90d3e99 Appearance: a group's own fills and strokes follow a clip group's clipping path, not the art it hides (#7289)
A Fill + Offset Path below a group's Contents painted every clipped member
of a clip group among its members, so art hidden outside the clipping path
bulged the offset outline. A clip group (or clipping layer) now adds the
region its clipping path clips to.
2026-11-14 07:14:51 +00:00
dotCooCoo 68b0365355 Merge main into fix/wireframe-outline-stroke-width 2026-11-13 23:08:57 -08:00
BFlat 0ca2952093 Merge pull request #7363 from dotCooCoo/fix/stained-instance-export
Symbols: a stained instance keeps its stain in SVG, PDF and the other exports
2026-11-14 13:42:39 +07:00
dotCooCoo 96d5cd78a9 Revolve: overlapping faces draw in the order of their depths where they overlap
Revolve sorted its faces by the depth of each face's middle only, so a
tilted profile with long edges, or a profile of several contours, could
draw a nearer face under a farther one where the two overlap.

- A revolved face carries its view-space plane (none when its corners lie
  off one plane or reach the eye), and Revolve (Classic)'s facets keep it.
- Revolve and Revolve (Classic) put each surface's faces through the local
  depth order Extrude & Bevel uses for its fill and strokes: when two
  overlapping faces are drawn the wrong way round, every pair of
  overlapping faces goes in the order of their depths at the middle of the
  overlap, within the same 4,000,000-comparison limit. A surface already
  in the right order keeps it.
- A group's members, sorted together by depth, go through the same order
  across members.

Docs: docs/revolve.md, docs/effects-parity.md, docs/target-app-parity.md.
2026-11-13 22:32:34 -08:00
dotCooCoo d3e520b14b Effects: raster effects on a symbol instance's fill or stroke are drawn
A raster effect (Drop Shadow, Outer Glow, Gaussian Blur and the other
effects that paint pixels) on a symbol instance's topmost fill now draws
on each filled shape of the symbol's art, and one on its topmost stroke
draws on each stroked shape, after any geometry effects listed before
it. The same rules as for geometry effects apply: only a visible fill or
stroke with an opacity above 0 counts, a group's own fills and strokes
in the art take the effect, and an instance inside the art passes it on.

The canvas, Use Preview Bounds and the drawn bounds, SVG and PDF export
draw it, and Object > Expand Appearance is enabled for such an instance:
a shadow or glow becomes an image under the instance, and a blur,
feather or inner glow replaces it with the image, in one undo step.

Existing documents with a raster effect on a symbol instance's fill or
stroke draw differently: before, the effect drew nothing.
2026-11-13 21:53:15 -08:00
dotCooCoo 6bd6755283 Effects: a clipping path's geometry effects shape the clip on the canvas
A clipping path with Roughen, Transform or another effect that reshapes
a path drew its own fill and stroke reshaped, but the canvas and raster
export still clipped the art by the plain path. SVG and PDF export bake
the effect into the path before writing the clip path, so the screen
and a saved SVG showed different art.

effects::clip_outline now applies the live geometry effects in the
clipping path before taking its region: the path's or compound path's
own effects, the effects of its fills and strokes (the region is then
the union of the paths they give, as an export bakes them), the effects
of a compound path's paths, of a group's visible members and of a
nested clip group's clipping path, shown or hidden, and a group's own
effects as an export evaluates them. Raster effects such as Gaussian
Blur leave the region as it is. The renderer, the engine commands that
measure a clip region (flatten, arrowheads, cutting) and the writers use
it; the writers receive the baked document, so their output for a path
with effects does not change.

The renderer measures a clip group by the region its clipping path's
effects give it, so a view or tile that shows only the moved part of
the clip still draws the clipped art, and it drops cached clip regions
that hold a plug-in effect when plug-ins change.

Two rules change in every export as well as on the canvas:

- When the clip group, or a group around it, has a geometry effect of
  its own, the clipping path's effects apply first and its gradients
  move with them. #7114 left the clipping path's effects live under the
  group's effect, so they applied after it.
- Type used as a clipping path keeps its own effects when a group's
  effect outlines it. #2073 and #2290 outlined it without them, to
  match the plain clip the canvas drew.
2026-11-13 21:18:18 -08:00
dotCooCoo 4416640bf4 3D: Expand as Wireframes outlines each face's own stroke under a later Outline Stroke
Expand as Wireframes reshaped the faces of a 3D effect with the geometry
effects after it, but the faces it built carried no stroke. An Outline
Stroke after the 3D effect then outlined a plain 1 pt stroke with miter
joins, while the canvas outlines the round-joined stroke each face is
drawn with: the seam stroke (half the facet's thickness, 0.05 to 0.75 pt;
0.75 pt on Revolve) or the 0.5 pt wire edge of the Classic Wireframe
surface. The wireframe's faces now carry that stroke, so the expanded
edges lie where the drawn outlines lie.
2026-11-13 20:53:22 -08:00
dotCooCoo 3d9a461be5 3D: Export 3D Object builds each Extrude and Inflate solid once
Export 3D Object built every Extrude & Bevel (both kinds) and Inflate
solid twice: once for the facets that decide whether the art draws it and
count toward the object's face limit, and again for its mesh.

The solid builder now keeps the projected facets and the faces before
projection from one pass (`extrude_meshed`, `inflate_meshed`), and the
export decides and meshes each part from that one build. Where a mesh
built alone cuts Inflate's twisted sides differently (it has less room
left after keeping the faces turned away), the mesh's sides are cut with
its own room. Strokes past their limits are still left out, a fill's
error and the object's face limit still stop the export at the same
part, and the triangle budget is unchanged.

Tests compare the facets and meshes with separately built ones bit for
bit, and count one build per solid.
2026-11-13 18:35:48 -08:00
dotCooCoo 20fc6a0225 Symbols: Break Link and Expand keep an instance's bounding box
After Reset Bounding Box on a turned symbol instance, Break Link to
Symbol and Object > Expand gave the art a box turned with the instance's
transform again. The art's boxes now turn with the instance's own box,
so they stand square when the instance's box did, and the angles the
art has inside the symbol are kept relative to it. The group that an
instance's opacity, blending mode or opacity mask adds around the art
takes the instance's box angle instead of standing square to the page.

A reflected instance can hold a box 180 degrees from the box its
transform gives in one step; the art now takes the instance's box
there too, the same rectangle with its handles where the instance had
them.

Compound shapes and Pathfinder receive an instance's art through the
same rule.

The clip groups and clip paths that 9-slice guides make for gradient
and pattern art take the angle of the cell that places them, and the
outer group keeps the object's angle turned by the instance, instead
of standing square to the page. This also changes the result for an
instance that was never reset: a 20 degree sliced instance gave clip
groups at 0 degrees and now gives them at 20.

Docs: params text, docs/mcp.md, docs/target-app-parity.md.
2026-11-13 18:26:00 -08:00
dotCooCoo de8ac51502 Symbols: a stained instance keeps its stain in SVG, PDF and the other exports
A symbol instance colored with the Symbol Stainer lost its stain in
export whenever the canvas's stained art was not used:

- An instance with geometry effects was reshaped for export from the
  symbol's art with only its dynamic changes, so SVG, PDF, EPS, .ai,
  DXF, EMF/WMF and HPGL wrote the unstained colors. A color adjustment
  on an instance recolored the unstained art the same way.
- PDF, EPS, legacy .ai, DXF and EMF/WMF wrote an instance without
  effects from the unstained art.

tint_node, stain and instance_art now live in
vectorcraft_doc::symbol_overrides, which both the effects and the
exporters can use; vectorcraft_brush re-exports them. Baking, color
adjustments and the writers above now use instance_art: dynamic changes
first, then the stain.
2026-11-13 17:24:06 -08:00
dotCooCoo 9d3717b0c0 Merge main into fix/colored-solid-faces-one-order-limit 2026-11-13 15:16:25 -08:00
dotCooCoo c8177dc7e8 Effects: a plug-in before a fill's or stroke's own 3D effect is told its fill or stroke
A 3D effect on a fill or stroke worked on copies of the object's fills
and strokes, and the copies were looked up among the object's items by
identity, so a live-effect plug-in before that 3D effect was given
`_context.item` "object" and a deferred stage there was listed with no
item. The drawn art, the 3D meshes and Expand as Wireframes now pass the
original item, so the plug-in is given `{"fill": i}` or `{"stroke": i}`
as docs/plugins.md describes. The paints of a type's first run still have
no item.
2026-11-13 13:33:01 -08:00
dotCooCoo 1fa71e2ab1 3D: solid-color fills and strokes under colored lights draw their faces in one depth order
Under a light that is not white, an opaque Inflate fill or stroke in a
solid color was drawn as one composite of all its facets, so the
object's solids were drawn whole, one after another: the stroke's faces
covered every face of the fill, nearer or not.

When an object's solids share one order (all opaque with Normal
blending, or one member's under its opacity mask), each facet of such a
solid is now drawn on its own, with the composite's paint, channel
light ramps and seam width, and takes its place in that order as the
faces of a gradient already do. A lone solid, and the solids of an
object with a translucent or blended fill or stroke, keep the one
composite.

A face drawn on its own is about 16 nodes, against about 6 per facet
in the composite of a whole surface. These faces go in one order while
they number at most 30,720 together, counted again after the cuts.
Past that, each such solid is drawn as one composite.

Docs: docs/three-d.md, docs/target-app-parity.md.
2026-11-13 12:34:42 -08:00
BFlat 9107dad274 Merge pull request #7194 from dotCooCoo/fix/item-3829
Envelopes: a partly transparent image keeps its alpha where its warp pieces overlap
2026-11-14 03:23:28 +07:00
BFlat cf6c666d25 Merge pull request #6980 from addibble/seam-round-joins
3D effects: every facet's seam has round joins
2026-11-14 03:21:49 +07:00
Drew Dibble 09d5522785 Merge remote-tracking branch 'upstream/main' into seam-round-joins
# Conflicts:
#	docs/effects-parity.md
#	docs/gaps.md
#	docs/target-app-parity.md
2026-11-13 12:29:58 -07:00
dotCooCoo 4d4d7ee1a7 Envelopes: opaque pixels of a warped image stay opaque where its pieces overlap
In SVG and PDF output, each piece of a warped image whose pieces can show
through was drawn through a mask of every later piece that reaches it. On a
later piece's antialiased edge the viewer multiplies the earlier piece's
coverage by the mask and draws the later piece over it, so an image with
both opaque and partly transparent pixels came out lighter at its opaque
pixels along the triangles' edges (alpha 184 of 255 in the new SVG test).

A later piece now goes into an earlier piece's mask only when a pixel of
either piece's image within 2 pixels of their overlap is less than opaque
(vectorcraft_effects::WarpSeams). Where two pieces overlap over opaque
pixels, the later one is drawn over the earlier one without a mask.
2026-11-13 10:36:16 -08:00
dotCooCoo b54f357ced Merge main into fix/raster-effects-skipped-transform-budget 2026-11-13 10:06:29 -08:00
BFlat 4f58b83c75 Merge pull request #7118 from dotCooCoo/fix/painted-effect-every-item
Effects: a later painted effect runs on every fill and stroke a piece returns
2026-11-14 00:49:38 +07:00
BFlat 3904a7396c Merge pull request #7120 from dotCooCoo/feat/revolve-graphics
3D and Materials: wrap graphics around the side of Revolve objects
2026-11-14 00:49:21 +07:00
Drew Dibble 0654aef75b Merge remote-tracking branch 'upstream/main' into seam-round-joins
# Conflicts:
#	crates/effects/src/solids.rs
#	docs/target-app-parity.md
2026-11-13 10:18:23 -07:00
dotCooCoo 25a99d7c07 Effects: raster effects before a Transform effect past the budget stay with the art
A Transform effect whose result would pass the geometry budget (2 million
anchors or 8 million lines drawn) is left out and the art stays where it
was, but the raster effects listed before it still scaled and moved with
it: before a Transform effect that scales the art 1000 times, a Drop
Shadow's offset grew 1000 times and its blur went to the 1000 pt limit
around art that had not moved, and Expand kept those values.

The geometry pass now notes each Transform effect that moves the art once
and that it leaves out, in the Carry it already returns, and
Carry::hide_skipped hides those effects in the list the raster effects
are read from. The canvas (a path's own effects and its fills' and
strokes'), its bounds, bake (SVG and PDF export), shape art, Expand,
Expand Appearance and Outline Stroke use it, and a fill's Transform
effect inside a piece no longer scales the effects before it when the
budget leaves it out. The budget itself is unchanged.

A path drawn as its own art inside a group whose geometry effects run
after its members' own read its object effects whole. The reshaping pass
now notes a Transform effect that no path in the art took past the
budget, and the member's art hides it before its raster effects are read.

The bounds skip the extra geometry pass when no raster effect could
follow a Transform effect, and painted_reach runs it once for both
measurements.
2026-11-13 09:16:26 -08:00
dotCooCoo 0663c76be1 Envelopes: a partly transparent image keeps its alpha where its warp pieces overlap
An envelope or the Warp effect cuts an image into triangle pieces that
reach a little past their edges, so neighbors overlap and no seams show.
On an image with alpha, the overlap drew that alpha twice: a 50% image
came out about 75% opaque along every cell edge and diagonal.

- The pieces now form a knockout group, and each piece is marked as a
  warp piece (`warp_piece`) whose knockout shape is its whole triangle,
  so where pieces overlap only the top one draws.
- The canvas knocks each piece out by its triangle at full coverage.
- SVG and PDF draw the pieces of a partly transparent image (its pixels,
  opacity, color mask or colorize paint) through one mask each, of the
  later triangles that reach it; pixels on a triangle's antialiased edge
  come out slightly lighter there. Pieces of an opaque image are drawn
  one over another as before.
- SVG writes one copy of the image for pieces cut by opacity masks
  (Preserve Shape Using Transparency) too.
- A cell count past the generated-object budget makes an empty group
  instead of overflowing.

Docs: docs/target-app-parity.md.
2026-11-13 08:38:48 -08:00
BFlat d3bb35ff61 Merge pull request #7154 from dotCooCoo/fix/3d-walls-depth-sort
3D: fill walls and dashed or profiled strokes draw in depth order where they overlap
2026-11-13 23:31:09 +07:00
dotCooCoo 4b695aafb1 Merge main into fix/painted-effect-every-item 2026-11-13 08:12:58 -08:00
Drew Dibble 26af1c7aa4 Merge remote-tracking branch 'upstream/main' into seam-round-joins
# Conflicts:
#	docs/target-app-parity.md
2026-11-13 09:09:32 -07:00
dotCooCoo 2361d2cb1b 3D: caps stay last when overlapping faces form a depth cycle
- When the faces that overlap form a cycle of depth orders, the order
  broke the cycle only after drawing every face with nothing to wait
  for, so a cap could be drawn before the walls and they painted over
  it. A face drawn last now keeps its place: no face moves across it.
- A face with a corner at or past the eye, which the perspective
  projection holds just in front of the eye, no longer gets a plane,
  so its depth is not measured on a plane its drawing does not match.
- docs/three-d.md states the masked member rule in Groups as the
  Fills and strokes section does, and docs/target-app-parity.md cites
  the Inflate test by its name.
2026-11-13 07:23:56 -08:00
dotCooCoo a0e0f09d79 3D and Materials: bound Revolve graphics' work and paint copies, and close the gap at the back
- Each contour of a graphic is cut only at the faces its own bounds reach,
  and the points cut at the faces count toward a limit of 64,000,000.
- The paint copies of a graphic's parts count toward a budget of their own,
  one copy for a part's fill and one for its seam stroke when it takes one.
- A part filled with a pattern, or whose gradient has a transparent stop or
  point, takes no seam stroke.
- Under several lights an opaque solid part also covers its seams, with its
  lit art clipped to a band of the seam stroke's width.
- A line of a graphic that reaches farther than any surface is refused, as a
  curve already was.
- A full turn places each segment by its own middle, so the cut at the back
  falls on the segment edge nearest half a turn from the middle.
- A group's members are measured for graphics only when it has some.
- docs/three-d.md: Revolve shows no Face control, and the new limits.
2026-11-13 07:06:38 -08:00
dotCooCoo 57d37a6dae 3D: fill walls and gapped strokes draw in depth order where they overlap
Extrude & Bevel, Extrude & Bevel (Classic) and Inflate sorted the fill
walls and the faces of a stroke that leaves gaps (dashed, profiled,
brushed) by one depth each, so a far stroke face could draw over a near
fill wall and the reverse. Two such strokes on one shape drew over each
other the same way, and Inflate drew a plain stroke as if it covered
the fill's edge, which an inflated fill can rise in front of.

- Each flat facet now carries its plane, so its depth can be measured
  at any point under it, with orthographic and perspective views.
- Where faces of one shape's fill and strokes overlap in the wrong
  order, the overlapping faces are ordered by their depths where they
  overlap. A fill wall and its covering stroke keep their order.
- A face of a stroke that leaves gaps that passes through a fill wall,
  a covering stroke's face or an earlier such stroke's face is cut
  along the line where their depths meet, keeping its curved outline,
  within the face limit and the paint allowance.
- Under Inflate, no stroke counts as covering the fill's edge.
- The faces go in one order when the fill and strokes are at full
  opacity with Normal blending. A member of a 3D group with an opacity
  mask or a blending mode of its own orders its faces inside it when
  its own paints qualify. A gradient with transparent stops keeps the
  one order with graphics on its cap, and so does Inflate in gradients
  under a colored light. A solid color under a colored light, drawn as
  one composite per surface, still draws each surface whole.
2026-11-13 06:45:13 -08:00
Drew Dibble 00c0e7a7fd Merge remote-tracking branch 'upstream/main' into seam-round-joins
# Conflicts:
#	docs/target-app-parity.md
2026-11-13 07:25:46 -07:00
dotCooCoo 1517c81262 3D and Materials: wrap graphics around the side of Revolve objects
The Materials tab and threeD.mapGraphic now map graphics onto
Revolve's swept side, unrolled flat: x runs around the axis (the
angle times the profile's distance from the axis at that point) and
y along the profile. A graphic keeps its size at every distance from
the axis, so it reaches farther around where the profile comes nearer
the axis. Each face of the side draws the part that falls on it: a
graphic narrows toward the silhouette, follows the profile along its
length, is shaded with the surface (several lights included) and is
hidden where the side faces away. A part that runs past the end of
the profile reaches the curved rim and stops there. The middle of the
side faces the viewer with the axis on either edge. On a compound
profile or a group the graphics go on the longest contour.

- three-d: with Revolve::map_surface set, side faces carry a
  SurfaceCell (corners on the page and on the unrolled side, whether
  the outside faces the viewer) and a closed profile off the axis
  takes an anchor where its side is cut; without it the faces are as
  before. revolve_surface_size gives the side's size for a new
  graphic's fit.
- effects: Revolve takes `graphics` (front only); surface_parts cuts
  and maps them per face; curves are cut into straight pieces one at
  a time, and commands refuse graphics past the point limits;
  switching between Extrude, Plane and Revolve keeps the front's
  graphics.
- The Materials tab hides Face for Revolve; params text, docs/mcp.md,
  docs/three-d.md and the progress docs describe the change.
- i18n: the complete-message catalogs translate the three new
  refusals in place of the planar-faces refusal they replace, and ja,
  es, zh-hans and zh-hant translate the Materials tab's label.
2026-11-13 05:06:03 -08:00
dotCooCoo 39f66f3870 Effects: a later painted effect runs on every fill and stroke a piece returns
When a painted live effect on a fill or stroke returned several fills or
strokes, the next effect in that stack ran only on the first of them and
the others took its geometry. A later live-effect plug-in, and a later
geometry effect on strokes, now runs once on each of them in paint order,
given the piece's fills and strokes and its own `_context.item`. Each
run's pieces replace only that fill or stroke; a run that fails, is
refused, is deferred or would pass the effects' budget leaves only its own
fill or stroke as it was. Fills and strokes that keep the same path stay
on one path, and a deferred run is listed at the source fill's or
stroke's place.

The results that are kept share the effects' budget, and each run's
result is kept or left out whole. They are first placed with all the
room the art leaves, and placed again with room kept for the piece's path
when a fill or stroke left on that path finds no room. A result on the
path before it costs nothing and is taken whatever room is left; a
built-in effect that finds no room is built again with all the room the
art leaves, and that result is taken only when it is on the path before
it. A plug-in result is held only while it is placed: one that does not
fit, or that moves onto the path before it, is let go at once, so the
results held at one time stay within the budget however many fills and
strokes the piece has. A result kept in the first placing is reused in
the second without running the plug-in again. A painted piece's share of
the budget is counted once at each later effect.
2026-11-13 04:44:11 -08:00
dotCooCoo e8c3dace32 Effects: a group's geometry effects reshape what its members draw
A group's or layer's geometry effects now run after its members' own:
the geometry effects of each visible path and compound path in it and
of their fills and strokes, and a nested group's geometry and
Pathfinder effects, are applied first, at any depth, and the group's
effects reshape the result. A symbol instance's geometry effects run
after those of its symbol's members in the same way. Before, the group
reshaped the members' outlines and their own effects ran afterwards:
a 100 pt square with its own 10 pt Offset Path in a group with a 50%
Transform drew 70 pt wide, and it now draws 60 pt wide. Existing
documents with such groups draw differently.

The canvas, export (including groups that keep their type), Expand
Appearance and the art that Pathfinder operations and compound shapes
take from such a group use the same order. The reply of
effect.expandAppearance names such a group and no longer names the
members whose effects the group's art already holds.

The renderer now drops the art it keeps for a group when a plug-in is
installed or removed and a member of the group has a plug-in effect.

Docs: docs/target-app-parity.md. Not yet: the own geometry effects of
images, symbol instances, paths with a linked opacity mask or a 3D
effect, and nested groups with a 3D effect in a group still run after
the group's.
2026-11-13 04:41:58 -08:00