* Vector: bound flattening memory, keep over-budget dashes, cheaper edge build (#5195)
- flatten: a path's flattened points are capped at 1 << 20; past it every
curve keeps a proportional share of its pieces (at least one), so hostile
handles from files (vmsk, SVG, effect outlines) cannot exhaust memory.
fill_rasterizer flattens the whole path under one budget.
- stroke: past the dash step budget (or below coordinate precision),
dash_polyline keeps the dashes made so far and draws the rest solid
instead of dropping the stroke. Open polylines are no longer copied.
- raster: coordinates are clamped to +-1e15 and edges with a non-finite
slope (vanishingly short) are skipped, so huge finite coordinates no
longer produce NaN coverage. fill_rasterizer sorts edges once instead of
after every component (stable sort, identical order).
- Cleanups: dead miter `half`, dead loop-length check in trace_mask,
shared mask render body, map_knots helper, shared straight-segment test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Vector: bound stroke outline points (#5211)
- stroke_polygons dashes all lines first, then counts round caps and
joins. When their full-resolution tessellation would exceed 1 << 20
outline points, every round cap and join gets the same smaller segment
count (down to 4 per circle, 1 per join; area-exact radius kept).
Strokes under the budget are unchanged; no piece is dropped.
- The dash step budget (100000) is now shared by all lines of a stroke
instead of per polyline, so many subpaths cannot multiply the dash
(and cap) count. Past it the rest is drawn solid, as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Curvature Pen: drag an anchor of the active path without a modifier
As in Photoshop, the Curvature Pen with no path being drawn shows the active
path's anchors (work path, active shape layer or targeted vector mask), and a
press-drag on one moves it with no Ctrl/Cmd. The curve reflows: every smooth
knot of that subpath gets its handles recomputed with the Curvature Pen's own
curvature_knots, so it keeps flowing through all its anchors; corners keep
their handles. The drag previews live and commits one history step.
- vector: edit::move_anchors_curvature
- engine: path.moveAnchors takes "curvature": bool=false
- ui-egui: direct_select routes the idle Curvature Pen press (Edit::Curvature)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Curvature Pen: add anchors, toggle smooth/corner and adapt the cursor on finished paths
As in Photoshop, with no path being drawn the Curvature Pen also:
- adds an anchor where a segment of the active path is clicked
(path.addAnchor), and a drag pulls it like any anchor; adding and dragging
are one history step;
- toggles an anchor between smooth and corner on a double-click
(path.convertPoint with the new "curvature" param, vector
edit::toggle_curvature_point): a Pen-drawn corner rounds off and the
segments around it curve through it; a second double-click makes it a
corner again;
- shows what a press does in its cursor: + over a segment, four arrows over
an anchor (also an anchor of the path being drawn).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* rustfmt
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
The Pen flyout (P / Shift+P) now holds Pen, Freeform Pen and Curvature Pen.
Freeform Pen: a drag draws freehand; on release the trace is fitted with
cubic Beziers within the options bar's Curve Fit (default 2 px) by
photocraft_vector::trace::fit_trace (Schneider, "An Algorithm for
Automatically Fitting Digitized Curves", Graphics Gems 1990, the fitting
Make Work Path already uses), keeping turns sharper than 60 degrees as
corners. Releasing on the start point closes the path.
Curvature Pen: each click adds a smooth point and the path runs through
every point (Catmull-Rom style handles from
photocraft_vector::edit::curvature_knots); dragging a point moves it,
double-clicking toggles corner/smooth, clicking the first point closes,
Enter/Esc finish and Backspace removes the last point, as with the Pen.
Both commit through the Pen's path: a shape layer in Shape mode, else the
targeted vector mask, else the work path, as one History step.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Paths could be reshaped after drawing since #865, but the number of
anchors could not change. Two new engine commands do that, and two tools
in the Pen flyout drive them on the canvas.
- photocraft_vector::edit::add_anchor splits the segment at t with de
Casteljau, so a curve keeps its shape and gets a smooth anchor; a
straight segment gets a corner on the line. delete_anchor joins the
neighbours keeping their handles, drops an emptied subpath and refuses
to remove a path's only anchor.
- path.addAnchor / path.deleteAnchor take the same targets as the other
point edits (work path, saved path by name, shape layer path, vector
mask) and record one history step each.
- Tool::AddAnchorPoint / DeleteAnchorPoint join the P group after the Pen.
They act on Direct Selection's paths, highlight the segment or anchor
under the pointer, show a +/- cursor badge, swap with Alt and turn into
Direct Selection with Cmd/Ctrl. An edit clears a Direct Selection on the
same path so it never points at a shifted anchor.
- Icons derived from Lucide pen-tool (ATTRIBUTION.md), hints and tool
names in all 16 catalogs, README tool list, roadmap.
Co-authored-by: Fabio Lussi <198260595+itrycodinganditsbad@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Direct Selection tool: reshape paths after they're drawn (#790)
Adds Photoshop's Direct Selection tool (A, in the Path Selection flyout) and
the Pen's Cmd/Ctrl (Direct Selection) and Alt (Convert Point) modifiers. It
selects and drags anchors, direction handles and segments of the work path,
the active shape layer's path and a targeted vector mask.
The geometry lives in photocraft_vector::edit; new engine commands
path.moveAnchors, path.moveHandle, path.bendSegment and path.convertPoint
apply it (one history step per drag, drivable over MCP and the control
channel), and the canvas previews a drag with the same code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Tool::ALL holds 49 tools now that Direct Selection and Magnetic Lasso both landed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>