Commit Graph
212 Commits
Author SHA1 Message Date
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
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
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
bflatastic e13c4bc9d0 Add-ons: Path Precision Tools — live path effects 2026-10-31 06:10:47 +07:00
bflatastic ebc5b7038c Add-ons: Color Effects — Duotone effect and Print Ink Fixes
Effect › Color Effects › Duotone… (addon.color.duotone, also in Object ›
Plug-ins › Color Effects) prints the grey-equivalent tone of each colour
with one to four inks, each with its own tone curve. It is a colour
adjustment like the add-on's others, so it stacks with them and works as
a filter through addon.color.filter.

- One tone of a swatch the document has gives a tint of that swatch,
  linked, so a spot tone separates onto its plate; several tones give
  the CMYK mix of their tints (the inks overprint, so they multiply).
- Colour adjustments now map paints with their swatch links
  (ColorMap::apply_link); the existing adjustments behave as before.
- Skip Objects with Spot Colors leaves spot-linked colours as they are.
- The dialog has a row per tone and the picked tone's curve (the Curves
  graph, reused), its points and Reset to Linear / Inverse.

Print Ink Fixes (addon.color.printFixes, Object › Plug-ins › Color
Effects › Print Ink Fixes…) scales CMYK colours over a total ink limit
down to it, removes white overprint and sets black overprint (Overprint
Black's logic) in a CMYK document, as one undo step, and reports what
changed. RGB documents are refused.

The panel opens both under Inks.

Deferred: an opaque undercoat, tones for type only, extra gradient stops
for smoother tints, curve flip and all-100 % buttons.
2026-10-31 00:26:18 +07:00
bflatastic f4be2b9006 3D Extrude & Bevel, Inflate and Rotate apply to type, which stays editable (#4715) 2026-10-30 23:03:51 +07:00
bflatastic f4c245286e Add-ons: Color Effects — live Vector Halftone effect
Effect › Color Effects › Vector Halftone… (addon.color.halftone, also in
Object › Plug-ins › Color Effects) draws its object as the halftone dots
Object › Vector Halftone makes, live: mono (one dot colour, or each dot in
the art's colour under it) or CMYK screens, the five dot shapes,
frequency, angle, invert and clip to the art's outline.

- The screens, dots and caps move to vectorcraft_effects::addons::halftone,
  shared by the command (its behaviour and tests unchanged) and the effect.
- The renderer samples the art (vectorcraft_render::addons::halftone) and
  keeps the dots by the object's content and what it reads from the
  document, so unchanged art isn't sampled again; past 100000 cells per
  screen the object draws as it is.
- Expand Appearance turns the object into its dots, and the SVG, PDF, EPS
  and AI exporters write them as paths.
- Its dialog reuses the command's fields, without Keep Original.

Deferred: stochastic and radial patterns, a dot-gain curve, per-screen
separation settings, type or symbols as dots.
2026-10-30 22:13:33 +07:00
bflatastic 427752ce65 Add-ons: Color Effects — live exposure, desaturate and invert, apply as filter, panel
A built-in add-on in Effect › Color Effects and Object › Plug-ins › Color Effects:
- Exposure (stops of linear light, offset and gamma), Desaturate and
  Invert Colors as live colour adjustments, evaluated in stack order with
  those of Effect › Color Adjustments.
- addon.color.filter applies any colour adjustment to the colours
  themselves, through the Edit Colors pass, as one undo step.
- A panel picks an adjustment and its values, then adds it as a live
  effect or applies it as a filter.

The add-on lives in its own modules (effects, engine and ui-egui addons
folders) and leaves the existing effects, commands and menus as they
were.
2026-10-30 14:14:33 +07:00
datatimp 6a80e43b68 Effect dialogs keep a typed distance within the effect's range (#4637) 2026-10-30 09:01:11 +07:00
bflatastic 5165b6eb1d Pathfinder: live compound shapes (Make, Shape Mode, Release, Expand Compound Shape)
Squashed from #4621 onto main.
2026-10-30 00:15:58 +07:00
el-j 82e4fc422c perf(effects): reorder pure-translation Transform copies after round-join terminal Offset Path (#4145)
Follow-up to #4345 / #4145 per maintainer guidance from @bflatastic.

- In `crates/effects/src/geometry.rs` & `crates/effects/src/reshape.rs`:
  - Implements `optimize_geometry_effects`: reorders pure-translation Transform effects
    with copies after a terminal round-join Offset Path effect when the effective style is safe
    (NonZero fill and no stroke).
  - Offsetting a union equals the union of offsets for round (Minkowski) offsets; moving
    pure-translation copies after the terminal offset evaluates Offset Path once on the base
    geometry rather than over dozens of multiplied copies, turning O(copies * segments) planar
    sweep explosion into a single fast offset plus lightweight affine copies.
  - Safely commutes across multiple consecutive pure-translation Transform effects.
  - Preserves exact visual geometry by leaving miter, bevel, EvenOdd, stroked, or non-terminal
    effect stacks in their original order.
- Added comprehensive unit and regression tests in `crates/effects/src/tests.rs`.
- Added contributor entry in `contributors/people.toml`.
2026-10-29 23:15:08 +07:00
Taha-Mahmoodi b41599f657 Fix #3089: a stroked line with an effect expands to a stroked line, then Expand outlines it
Squashed from #4169 onto main.
2026-10-29 18:54:59 +07:00
dotCooCoo dfa9f883c0 Fix Drop Shadow Darkness in source color space 2026-10-29 14:36:41 +07:00
Dylan M. Taylor e1bc6b235c Clarify effects dependencies and split parameter checks 2026-10-28 04:52:07 +00:00
nrq6993-a11y dfec712c2d G2: Scribble effect Settings presets
Squashed from #4274 onto main.
2026-10-27 14:36:12 +07:00
aiongg a8410bab4e refactor(effects): move lib.rs items to {catalog,geometry,params}.rs 2026-10-26 21:17:08 +00:00
aiongg f1d427762b style: cargo fmt on files moved without formatting 2026-10-26 19:32:10 +00:00
aiongg 0d282bad01 refactor(effects): move solids.rs tests to solids/tests.rs 2026-10-26 18:33:15 +00:00
aiongg 113c15c64f refactor(effects): move tests_*.rs to tests/<topic>.rs 2026-10-26 18:26:54 +00:00
aiongg e57586fdc2 refactor(effects): move group.rs tests to group/tests.rs 2026-10-26 18:18:18 +00:00
aiongg 18464c7007 refactor(effects): move bake.rs tests to bake/tests.rs 2026-10-26 18:18:17 +00:00
aiongg 6bbfb91d16 refactor(effects): move pixel/mod.rs to foo.rs files 2026-10-26 18:15:18 +00:00
Cursor Agentandnrq6993-a11y 988c958e3d ci: allow unknown_lints for manual_isolate_lowest_one on Rust 1.95
Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
2026-10-26 09:09:44 +07:00
Taha-Mahmoodi cab62cbb18 Fix #3964: Create Outlines, EPS, EMF/WMF and legacy .ai keep the ruby where the canvas draws it 2026-10-24 17:29:32 +07:00
Dylan M. TaylorandClaude Opus 5.5 e2a870e602 Security: bounded flattening, plug-in budgets and caches, loaded textures, Revolve paint copies, color book names and ICC names
CodeRabbit findings #4, #34, #46, #51, #77, #101, #170, #171, #188:

- `vectorcraft_geom::flatten`: kurbo's flatten with each curve's tolerance raised so it makes
  at most ~4096 segments (non-finite curves become a line); the canvas outline and
  variable-width strokes use it.
- Plug-ins: a heavy filter's budget is the host's `Limits::heavy_fuel`/`heavy_wall_time_ms`,
  never more; a start function runs on one fuel slice; the effect cache holds at most ~1M
  anchors of inputs and results, and doesn't keep a result past a quarter of that.
- Loaded textures are cached by their PNG (base64 spacing doesn't matter), and live textures
  hold at most 512 MB together.
- Revolve draws the source path when the faces' paint copies would pass 256 MB.
- Color books: names with prefix and suffix take at most 64 MB.
- ICC: localized-name (`mluc`) records over 1 MB together are refused before moxcms copies them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:19:54 +07:00
bflatastic 028cafa52e Scribble: the row loop's stop compares with partial_cmp (also stops on NaN; clippy) 2026-10-24 04:49:07 +07:00
Dylan M. Taylor b59235e762 Test: sliding-window maximum 2026-10-24 04:49:07 +07:00
Dylan M. Taylor e3223a419d Audit: Scribble rows counted, Outer Glow dilation in linear time, CSS export names in a set 2026-10-24 04:49:07 +07:00
bflatastic c2ad9f8bbb Type: emoji go with type that effects reshape and Expand Appearance
Squashed from #3879 onto main.
2026-10-24 04:49:06 +07:00
Taha-Mahmoodi 3b34ffb977 Pathfinder: Trap pairs only shapes within the trap's reach, not every two
Review follow-up (#3785, CodeRabbit): traps() tried every pair of visible solid paths on each redraw of the live effect and in the panel command, so many separated shapes cost quadratic work that neither the segment cap nor the overlap budget bounds. Each visible part's bounds are now computed once and a sort-and-sweep on x finds the pairs whose bounds come within the trap's reach (the clamped thickness across x, thickness × height/width across y, plus a hair for rounding); only those reach same_color, lighter and trap_band, which rejected the rest by the same bounds test, so the traps and their order are unchanged. Tests: 2,000 separated squares of two colours and one abutting pair give one candidate pair and one trap; the traps of a mixed scene match those of each pair alone, in order.
2026-10-24 03:09:08 +07:00
Taha-Mahmoodi fd345e0c56 Pathfinder: Trap spreads the lighter colour into the darker as an overprinting strip where solid colours meet
The Pathfinder panel menu's Trap… (object.pathfinder.trap) and Effect › Pathfinder › Trap… (pathfinder.trap, live on groups) share one geometry (vectorcraft_pathops::trap_band, vectorcraft_effects::trap): Thickness, Height/Width, Tint Reduction, Traps with Process Color and Reverse Traps, plus the effect's Precision and Remove Redundant Points. The panel's Trap is one undo step and groups the traps above the topmost selected object. Behaviour from https://helpx.adobe.com/illustrator/using/trapping.html and https://helpx.adobe.com/illustrator/using/pathfinder-panel-overview.html.
2026-10-24 03:09:08 +07:00
bflatastic 2e572c7805 Count Repeats inside symbol art toward the Repeat instance budget
Squashed from #3788 onto main.
2026-10-24 02:06:39 +07:00
Jürg Lehni c8fe9193d9 Type: colour glyphs go with type that effects reshape and Expand Appearance
COLR and SVG glyphs, which have no outlines, were left out wherever type was taken as its outlines: geometry effects, Expand Appearance, EMF/WMF export.
2026-10-24 02:06:11 +07:00
bflatastic c27ff0d96b Live Pathfinder budget: allow the manual lowest-bit form clippy flags, for rust-version 1.95 2026-10-23 11:08:06 +07:00
bflatastic d50afbcc1d Live Pathfinder budget: lowest set bit without the unstable isolate_lowest_one (rust-version 1.95) 2026-10-23 11:08:06 +07:00
NetterSilverandClaude Opus 5.5 c770e900e3 Cap the input of live Pathfinder effects
Fixes #3591

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 11:08:06 +07:00
Angelo Bernardini 3f16fabd89 G11 #885: Transform effect options (Transform Objects, Transform Patterns, Scale Strokes & Effects)
Squashed from #3358 onto main.
2026-10-23 06:07:37 +07:00
Brian TorresandClaude Opus 5.5 54c8a7f2bd Effects: stacked geometry effects keep to an anchor and line budget (#3578)
A chain of geometry effects makes at most 2 million anchors of a path (of a
type, symbol or image art's paths together) and about 8 million lines for the
renderer to draw at 1 px/pt, or what the path costs when that is more.
Roughen spaces its points further apart, Zig Zag makes fewer ridges a
segment, Free Distort, Twist and the warps split segments into longer pieces
(map_nonlinear_within) and Transform makes fewer copies where they would pass
it; a result drawn with too many lines is built again with fewer points, and
an effect that still doesn't fit is left out.

Three Roughens of a rectangle in a 25 KB file needed gigabytes of geometry,
and 2 million anchors of them flattened into 141 million lines (7 GB, past
vello's 2^27 lines a path); the file now opens in 0.4 s at about 450 MB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 02:44:52 +07:00
Taha-Mahmoodi 2bad646821 Gradients: a Perceptual gradient mixes its colours in OKLab, and SVG and PDF write it as an image
Illustrator 30.0's gradient Method, from the public documentation
(https://helpx.adobe.com/illustrator/desktop/paint-and-fill/create-and-edit-gradients/control-perceptual-interpolation-in-gradients.html):
Classic or Perceptual; perceptual interpolation matches colour transitions to
how the eye perceives differences between colours, and perceptual gradients
are rasterised when saved as PDF or SVG.

- Gradient gains `method` (Classic | Perceptual; serde default Classic,
  written only when Perceptual, so older files open as Classic and Classic
  files are written as before). The colour crate's OKLab helpers open up for it.
- Perceptual mixes neighbouring stop colours in OKLab (sample, and
  sample_keep_model for the stroke meshes, Expand and blends); opacity stays
  linear. Renderers that mix linearly get stops on the perceptual curve,
  placed by halving each half segment where a straight line strays more than
  0.4 of a colour level (a nearly straight segment needs none). Classic
  gradients expand exactly as before.
- draws_as_pixels includes Perceptual gradients, so SVG and PDF write a
  Perceptual fill or stroke as an image at the document's raster effects
  resolution, clipped to what it paints. A gradient along or across a stroke
  stays slices (PDF no longer draws it as a within-stroke image).
- With Dither: a dithered Perceptual fill is the perceptual mix with dither's
  noise (the canvas's dithered grids are keyed by method too); SVG and PDF
  write it as an image with the noise, and a dithered Perceptual stroke as an
  image without it, as the canvas draws it (GradientPaint::pixels, SVG's
  raster_paint and PDF's area are told whether they paint a fill).
2026-10-23 01:53:29 +07:00