Commit Graph
8 Commits
Author SHA1 Message Date
dotCooCoo c513114674 Gradients: Expand reports a capped gradient as unavailable
- object.expand.info reports no gradient or fill to expand for a
  gradient that repeats in more runs across its box than are written,
  matching object.expand, which leaves it a gradient. For a path that a
  painting live effect draws, it measures each piece the effect returns.
- CSS writes a repeating gradient's stop positions, and a repeating
  radial gradient's radius, with enough decimals that their rounding
  adds up to at most a hundredth of a period across the box (at least
  four for positions and three for the radius).
- docs/mcp.md says that sharp steps and swatch-linked stops are the last
  to be left out rather than always kept, and that the CSS conic limit
  counts stops before midpoints and Perceptual curves add more.
2026-11-12 12:55:54 -08:00
dotCooCoo 0691e1acbe Gradients: keep every run of a repeated gradient with many stops
When a repeated or reflected gradient needs more stops than a limit
allows, each run now leaves out the stops that change its colors
least, so every run is still written, instead of writing fewer runs
and padding the rest with the last color. Each run keeps its ends,
sharp steps, swatch-linked stops, tint and CMYK ink changes and spans
shaped by an off-center midpoint, and the colors are compared as the
gradient's method mixes them. This applies to gradients along or across
a stroke, CSS conic gradients, and PDF, EPS and .ai export.

- Outline Stroke's mesh fits the gradient to at most 1,024 stops, and
  splits a stroke into several meshes when one would hold more than
  2^20 points.
- Object > Expand leaves a gradient as it is when the box needs more
  than 256 runs, instead of expanding only the first runs.
- CSS writes the stop positions of repeating gradients with four
  decimals, so the period stays in place across the box.
- A swatch chip of a gradient that repeats gets at least four grid
  cells a run along each side (at most one a point, and 128), so it
  does not show one color when the count matches the chip's cells.
- docs/mcp.md states the stop limits and the PDF import sample budget.
2026-11-12 11:30:44 -08:00
dotCooCoo 91d705e155 Gradients: repeat or reflect a gradient's stops a set number of times
A linear, radial, conic or diamond gradient has a spread: Pad (the
default, as before), Repeat or Reflect, with a count of 1 to 100
(VectorCraft's own limit). Repeat and Reflect run the stops that many
times along the vector (around the turn for a conic) and keep going past
both ends, Reflect running every other run backwards, as SVG's
spreadMethod does.

The Gradient panel has a Spread menu and a Repeats field, and the
Gradient tool marks where the runs meet. paint.setFill and
paint.editGradient take `spread` and `repeats`; bad values are errors.
Presets, swatches, blends, strokes along or across a path, Outline
Stroke and Object › Expand follow the spread; Expand gives each run the
same whole number of objects, and Outline Stroke's mesh keeps the color
on each side of a sharp step between two stops at one offset.

SVG writes and reads spreadMethod: SVG import now reads a repeating or
reflecting gradient as one that repeats or reflects once, instead of
expanding its stops over the shape. CSS writes repeating gradients.
PDF writes a conic's sweep shading over one run. PDF, EPS, legacy .ai
and the .ai editing data write the other kinds with their stops
repeated across the shape: at most 256 runs and 16,384 stops (256 stops
in .ai files), and for a radial or diamond no farther than 65,536 runs
from its center, with a warning past those. PDF import now finds sharp
steps in any axial or radial shading instead of blurring them.

Docs: docs/mcp.md (Spread), docs/target-app-parity.md, docs/gaps.md.
2026-11-12 06:52:38 -08:00
dotCooCoo 66d21471ae Gradients: diamond gradients run the stops from the center out to a square
A new gradient kind, `diamond`, runs its stops from the center (the
start) out to a square with a corner at the end of the vector; the
aspect stretches the square across the vector into a rhombus. The
Gradient panel's Type row has a Diamond button, the Gradient tool draws
the square with the aspect handle and center ring, and a gradient
fitted to an object covers its box.

- Model and canvas: the level is |x| + |y| in the square's frame; a
  square with no area (no vector, an aspect of 0, numbers out of range)
  paints the last stop. The canvas draws it as pixels, out to a
  stroke's miters, caps and arrowheads. Transforms keep the vector and
  take the mapped size across it as the aspect.
- Commands: `paint.setFill`, `paint.editGradient` and
  `paint.setGradientGeom` take `kind: "diamond"`; a negative aspect or
  a focal point is an error. A conic or diamond gradient that a plug-in
  returns with a focal point loses the focal point.
- Gradient tool: dragging the aspect handle of a radial or diamond
  gradient whose file gave it a negative aspect now sets a positive
  aspect; only a conic's negative aspect mirrors it.
- Export: PDF, SVG, EPS and legacy .ai write four linear gradients, one
  for each quarter of the square, clipped to the shape (PDF as axial
  shadings). PDF and SVG write an image for translucent stops, a
  dithered fill or a flat square, and for the Perceptual method unless
  PDF writes the stops as spot color shadings. SVG writes a diamond on
  type characters as a radial gradient through the corners, and so
  does CSS. A swatch library saved as CSS gets four corner layers, a
  value for the `background` property (a circle when the swatch is
  turned by an angle that is not a multiple of 90 degrees). The .ai
  editing data holds a radial gradient through the corners. The
  document exports give a warning.
- SVG export: a stroke drawn as an image, as conic wedges or as diamond
  quarters now covers the miters, caps and arrowheads that reach past
  its paint box.
- PDF import reads a function-based shading whose color is the same
  along each square about the origin of its space as a diamond.
- Object > Expand gives nested squares or a mesh of rings.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-11 20:27:48 -08:00
dotCooCooandGert Pellin 1b744eae52 Gradients: conic gradients sweep the stops once around the center
A fourth gradient kind, conic (also accepted as `angle` or `conical`),
sweeps the stops once around the center (the gradient's start),
clockwise on the page from the vector, with a seam where the last stop
meets the first. A negative aspect mirrors the sweep, and reflecting an
object turns its sweep the other way, also for a conic without a
vector or with a flat extent.

- Gradient panel: a Conic button in the Type row; the Aspect Ratio
  field works for conic gradients and keeps a mirrored sweep mirrored.
- Gradient tool: the extent ellipse, aspect handle and center ring of a
  radial gradient, without a focal point.
- Rendering, swatch chips, transforms, warps, plug-in round trips, and
  Object > Expand into wedges or a mesh of columns around the center.
- Commands: a negative `aspect` is an error for linear and radial
  gradients, and so is a `focal` point for a conic gradient.
- PDF export writes a function-based shading whose calculator function
  turns the angle into the ramp, and PDF import reads a function-based
  shading that turns around the origin of its space back as a conic
  gradient, also when that origin lies outside the painted area. A
  PDF/A file, or a conic with more than 97 stops, gets an image
  instead.
- SVG export writes 360 solid wedges clipped to the shape for opaque
  stops and an image otherwise, and a linear gradient on characters.
- CSS export writes `conic-gradient(from ...)`, with the stops mirrored
  for a mirrored sweep.
- EPS and legacy .ai export write 360 solid wedges; the .ai editing data
  holds a linear gradient along the vector with the same stops.
- .af files: conical gradients open as conic gradients.
- An export that writes the gradient in another form gives a warning.

Supersedes #2326 and includes switch87's code from it.

Co-authored-by: Gert Pellin <gert@pellin.be>
2026-11-11 15:51:11 -08:00
dotCooCoo 427bce12b0 Character: Font Size can measure the cap height, x-height or ICF box
Squashed from #5026 onto main.
2026-11-01 11:08:55 +07:00
Ridzzz0Alam e110c6c770 Fix #3209: SVG export writes type sizes and spacing in CSS with px
With Styling set to Internal CSS, Inline Style or Style Entities, font-size
and letter-spacing were written as bare numbers. Only presentation attributes
take a bare number; in CSS a browser drops them, so the type was drawn at its
default size. They are now written in px, SVG's user unit, and presentation
attributes keep bare numbers.
2026-10-29 22:12:07 +07:00
aiongg 8cc69ed45c CI: one test binary per crate, nextest, line tables only (#3855)
* CI: line tables only for workspace crates, no debug info for dependencies

* CI: one integration-test binary per crate

Each crate's tests/*.rs files become modules of tests/it/main.rs. Files that change
process-wide state (Color Settings, the font database, installed plug-ins, the working
directory), the fuzz sweeps and the test targets the Affinity corpus workflow names stay
their own binaries.

* Docs: name the integration tests' new paths

* CI: xtask test with nextest and doctests, one wasm check, clippy --keep-going

cargo xtask ci runs the tests with cargo nextest (cargo test when it is not installed),
builds them with --lib --bins --tests, runs the doctests as their own step, and checks
the wasm crates in one cargo check --keep-going call.
2026-10-23 21:36:10 -04:00