Commit Graph
585 Commits
Author SHA1 Message Date
Dylan M. Taylor 2ad5fa1734 Preserve renderer source limits for streaming PNG reduction 2026-11-15 17:41:07 +00:00
FredApps c9cad8d017 Merge main into fix/restore-codec-cutover-ci
Port main's new variable-library parsing (variable kinds, image, visibility
and graph values) from roxmltree to craft-xml with the branch's strict
options and attribute validation. Keep both sides' variable tests.
Drop the stale docx::nesting doc link.
2026-11-15 15:43:44 +01:00
BFlat 8138a6e973 Merge pull request #7814 from dotCooCoo/feat/editing-one-anchor-copies-the-whole-anchor-list
Paths: editing one anchor of a long path keeps one chunk of anchors for undo
2026-11-15 17:31:01 +07:00
BFlat 63f5dcea9b Merge pull request #7800 from dotCooCoo/fix/a-rasterize-effect-before-a-scaling-transform
Effects: a Transform effect after Rasterize moves the image with its pixel grid
2026-11-15 16:40:20 +07:00
dotCooCoo 18fe65acd6 Type: composite fonts take custom character sets
Type > Composite Fonts... has Custom: named character sets, each setting
the characters it lists in its own font, style, size, baseline and
scales ahead of their class. The later of two sets that list a character
sets it. Characters are added by Direct Entry or by Unicode code and
deleted one at a time, and the parts table scrolls when it grows.

- type.compositeFonts.set takes `custom`; part keys left out take the
  Kanji part's values. Sets are saved with the document and in
  .vccomposite files, and Export refuses a file over 4 MB.
- VectorCraft's own limits: 64 sets per font, 8,192 characters per set,
  each character once per set, up to U+FFFF and no control characters.
- The font database caches each font's character lookup.

Docs: docs/mcp.md, docs/type-parity.md, docs/target-app-parity.md.
2026-11-14 22:16:08 -08:00
dotCooCoo 7104cd05f3 Merge main into feat/editing-one-anchor-copies-the-whole-anchor-list 2026-11-14 22:05:53 -08:00
dotCooCoo 9afd71bcb6 Merge main into fix/a-rasterize-effect-before-a-scaling-transform 2026-11-14 21:25:33 -08:00
dotCooCoo a5493a1cd0 Paths: editing one anchor of a long path keeps one chunk of anchors for undo
A subpath's anchors are now an `Anchors` list held in chunks of up to
256 anchors behind `Arc`s. Copying a path copies the chunk table and
shares the chunks, and editing one anchor copies only the chunk that
holds it, so the undo step of a one-anchor edit no longer keeps a copy
of every anchor of the path. Inserting or removing an anchor copies the
chunk it is in and rebuilds the table. Reads and edits follow the Vec
and slice methods the code used; files write and read each subpath's
anchors as one list, as before, within the same anchor read budget.

The undo memory estimate counts only the chunks the other version of
the path does not hold, and the renderer's kept paths compare only the
chunks an edit copied when they look for moved anchors.

Moving one anchor of an open path of 10,000 or 200,000 anchors
(path.moveAnchor, path.setHandle, path.moveAnchors, a nudge) keeps at
most 48 KiB in its undo and redo steps, where it kept 56 bytes per
anchor.
2026-11-14 21:25:15 -08:00
dotCooCoo 27553366ab Effects: a Transform effect after Rasterize moves the image with its pixel grid
On a path or compound path, a Transform effect listed after the
object's own Rasterize effect now moves the image that Rasterize makes.
The image is made of the art before the Transform effect, at the
Rasterize effect's resolution and with its room around the art, and the
Transform effect scales, turns, reflects and moves it. Before, the
Transform effect moved the art and Rasterize made a new image of the
moved art on a grid square to the page.

- effects: rasterize_stage finds the Transform effects that move the
  last Rasterize image; stage_map composes their maps about the
  reference point of the art each one takes.
- render: the canvas draws the node without those Transform effects
  through the map, and its drawn and painted bounds follow the map. A
  map that scales the image to nothing draws nothing.
- engine: Expand Appearance places Object > Rasterize's image of the
  art through the map, and PDF export makes those images before it
  bakes the geometry effects.

A Transform effect that makes copies or moves at random, one followed
by another kind of effect, a fill's or stroke's own Rasterize effect,
and Rasterize on type, images, symbol instances and groups keep the
earlier behavior.
2026-11-14 20:45:07 -08:00
BFlat 26878d3d0e Merge pull request #7715 from dotCooCoo/fix/svg-open-path-type-before-start
Type on a path: type on an open path can start before the path
2026-11-15 10:46:42 +07:00
Dylan M. Taylor 28c8b12452 test(render): correct PNG row scratch thresholds 2026-11-15 01:42:22 +00:00
BFlat 2331fd44fa Merge pull request #7680 from dotCooCoo/feat/radial-blur-center
Effects: Radial Blur turns about a Blur Center set in its dialog
2026-11-15 08:24:28 +07:00
Dylan M. Taylor fb45e7ecb5 fix(render): validate dimensions in PNG header estimate 2026-11-15 00:37:40 +00:00
Dylan M. Taylor 118a9b627f fix(render): use integer divisibility helper 2026-11-15 00:35:33 +00:00
Dylan M. Taylor eb9c049af0 fix(render): estimate streaming for truncated PNG headers 2026-11-15 00:29:35 +00:00
dotCooCoo 094971e3ac Type on a path: type on an open path can start before the path
Type on an open path can now start before the path's start: its start
is stored below 0, the span runs from there, and the characters whose
middle falls before the path's start are not drawn, as SVG 2 lays out
text on a path (https://www.w3.org/TR/SVG2/text.html#TextLayoutPath).
The text keeps every character, and the start bracket stays at the
path's start. Past the path's end, text that does not fit is overflow,
as for other type on a path. Type that starts on the path draws every
glyph as before.

- SVG import keeps a <textPath> start before an open path's start
  (text-anchor end or middle, or a negative startOffset) instead of
  starting the text at the path's start, which drew every character.
- SVG export writes it as a negative startOffset.
- PDF export writes only the characters drawn on the path.
- The legacy .ai and .ai editing data writers write the type from the
  path's start with the type attributes warning.
- type.pathOptions takes a start below 0 for type on an open path; on a
  closed path it is the path's start, as before. A flip starts the type
  at its start bracket. Dragging the center bracket slides it from where
  it starts, and no further before the path.
- A click at the path's start places the caret by the first drawn
  character, and the caret in the hidden characters stands at the
  path's start. The highlight of substituted fonts and glyphs leaves
  them out.
- Release Type on a Path keeps the first drawn glyph where it was
  drawn, with the hidden characters before it.
- The Touch Type tool shows no box for a hidden character, and
  text.touchType returns an error for one. A character with a drawn
  glyph is changed by that glyph.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-14 15:44:12 -08:00
Dylan M. Taylor 5122a1f9d9 fix: preserve XML and raster import semantics after codec cutover 2026-11-14 23:25:19 +00:00
Dylan M. Taylor 1e1100a9ed fix(tiff): keep test directory alive while checking borrowed ICC bytes 2026-11-14 23:25:19 +00:00
Dylan M. Taylor db05483915 fix(codecs): adapt migrated regression tests to shared public APIs 2026-11-14 23:25:19 +00:00
Dylan M. Taylor d97cb31bb6 fix(render): use CodecError::Unsupported and cargo fmt 2026-11-14 23:25:19 +00:00
Dylan M. Taylor 00804c9ed3 fix(render): fix PNG streaming decode error type and u64 casts 2026-11-14 23:25:19 +00:00
Dylan M. Taylor 08305948cf style: cargo fmt 2026-11-14 23:25:19 +00:00
Dylan M. Taylor 1306afb5e8 Cut over roxmltree, png, tiff, psd, and trace codecs to craft-libs (#7638) 2026-11-14 23:25:19 +00:00
BFlat 4fffbce639 Merge pull request #7614 from dotCooCoo/fix/export-cull-brushed-path-art
PDF, EPS and print: a brushed path just off the page whose brush paints onto it is written
2026-11-15 06:17:15 +07:00
dotCooCoo a5868102ae Merge main into feat/radial-blur-center 2026-11-14 13:47:19 -08:00
dotCooCoo 5831b1d23a Effects: Radial Blur turns about a Blur Center set in its dialog
Effect > Blur > Radial Blur... has a Blur Center box. A press or a drag
in the box sets the point the spin or zoom starts from, the arrow keys
move it 1% (10% with Shift), and Horizontal and Vertical fields take the
same position in percent. Screen readers get the box with both values.

- blur.radial takes centerX and centerY, from 0 to 1 across and down the
  object's bounds (0.5 each by default), so the center moves and scales
  with the object. An effect saved without them draws as before.
- effect.apply and effect.setParams refuse a value outside 0 to 1, or
  one that is not a number; a saved one draws at the nearest edge.
- The raster's margin is measured from the center, and the center stays
  in the object's own bounds when a Rasterize splits the stack.
- Params text, docs/mcp.md, the evidence line in
  docs/target-app-parity.md and a Blur Center row in every catalog.
2026-11-14 13:39:57 -08:00
BFlat 88b83a8689 Merge pull request #7546 from dotCooCoo/fix/svg-raster-keeps-resolution
SVG import: a raster stored again as PNG keeps its resolution
2026-11-15 04:22:10 +07:00
dotCooCoo 4ee24a8bbe Merge main into fix/export-cull-brushed-path-art 2026-11-14 12:29:41 -08:00
BFlat 6970c4efec Merge pull request #7609 from dotCooCoo/fix/transform-copies-raster-effects
Effects: each copy of a Transform effect draws the raster effects listed before it
2026-11-15 03:21:43 +07:00
dotCooCoo df257c2d53 Merge main into fix/svg-raster-keeps-resolution 2026-11-14 12:12:06 -08:00
bflatastic 79572cbf6c Revert "Cut over roxmltree, png, tiff, psd, and trace codecs to craft-libs (#7638)"
This reverts commit bada8e1710. #7638 merged with its gate failing: besides six unformatted
files, render and trace don't compile against craft-libs e2dc681 (u64::from(usize) in
render/src/paint.rs, a private craft-libs function, and a call with one argument too many in
trace/src/opaque.rs), so main's CI fails. The tree is that of 0adbdce6cb, whose CI passed.
2026-11-15 02:26:07 +07:00
Dylan M. Taylor bada8e1710 Cut over roxmltree, png, tiff, psd, and trace codecs to craft-libs (#7638) 2026-11-14 13:49:50 -05:00
dotCooCoo c51d14262f Merge main into fix/composite-font-lent-document-only 2026-11-14 09:42:51 -08:00
BFlat 63129de08a Merge pull request #7595 from dotCooCoo/fix/image-scaling-alpha
Images: scaled-down images keep their color beside clear pixels
2026-11-15 00:41:27 +07:00
dotCooCoo 46c9f922c2 Type: a document draws only its own composite font definitions
While a document's composite fonts are lent, type naming a composite font
the document does not define is set as in a missing font, even when the
front document or the document a placed document sits in defines one of
that name. A document that defines no composite font gets an empty scope
too, so a document in the back, a tiled window, a thumbnail or an export
made while another document is in front no longer borrows the front
document's definitions. A temporary document drawn while a document draws
keeps that document's fonts, and type laid out with nothing lent still uses
the registered ones.

- FontDb::composite_font looks only in the latest loan of the database.
- lend_composite_fonts lends an empty set at the top level when the
  database holds composite fonts; lend_document_composite_fonts also lends
  one inside another loan, for placed documents, back-document measuring
  and threaded reflow on open.
- A loan that leaves out a registered font gets its own generation, so
  layouts made with that font are not reused under it.
2026-11-14 08:16:02 -08:00
dotCooCoo a40f00ece9 Merge main into fix/export-cull-brushed-path-art 2026-11-14 07:25:25 -08:00
dotCooCoo c410e3fbb5 Brushes: the renderer's brush cull room counts only painted brushed strokes
The doc comment on pad() now says a brushed stroke needs a paint to get room, as vectorcraft_brush::reach does.
2026-11-14 07:25:25 -08:00
dotCooCoo 96a8a0c6d6 Merge main into fix/svg-raster-keeps-resolution 2026-11-14 07:23:45 -08:00
BFlat 508a0b0180 Merge pull request #7597 from dotCooCoo/fix/separations-spot-stop-plates
Print: a spot gradient stop prints its process plates on the separations
2026-11-14 21:51:47 +07:00
BFlat 09f882b9d2 Merge pull request #7534 from dotCooCoo/fix/tiled-documents-own-profiles
Color management: documents behind the front one draw through their own profiles
2026-11-14 21:51:30 +07:00
dotCooCoo e086cf6d83 PDF, EPS and print: brush art painting onto the page keeps its path 2026-11-14 05:51:22 -08:00
dotCooCoo f00ddcbaa9 Effects: each copy of a Transform effect draws the raster effects listed before it
A path's Drop Shadow, glow, blur, Feather or pixel filter listed before a
Transform effect that makes copies was drawn once under all the copies, at
the object's own distances. Each copy now carries those raster effects,
scaled by the copy's mean scale, with a Drop Shadow's offset turned,
reflected and scaled with the copy. Raster effects listed after the
Transform effect still paint once around all the copies. Copies that stop
at the effect budget keep their effects, and a Transform effect without
copies draws as before.

The canvas, the object's bounds, export, baking and Expand Appearance use
the same art. Type, images, symbol instances, groups, a fill's or stroke's
own copying Transform effect, and paths with Rasterize or an SVG filter
before the copying effect keep one set of raster effects.
2026-11-14 05:32:43 -08:00
dotCooCoo 786dcc5581 Images: scaled-down images keep their color beside clear pixels
The image crate's filtered resize filters each channel on its own, which
is correct only for premultiplied pixels, and its thumbnail averages each
channel on its own too. Placed images, linked-image previews, MCP
captures and previews, metafile bitmaps, PDF downsampling and library
thumbnails passed straight RGBA to them, so the color under clear pixels
(usually black) bled into the opaque pixels beside them and darkened
cut-out edges.

vectorcraft_doc::resample scales such images with each pixel's color
weighted by its alpha: filtered resampling premultiplies the pixels in
place and divides them back after, and averaging takes the area-weighted
mean of the pixels each new one covers. Opaque and alpha-free images are
scaled as before. PDF export also multiplies the inks of a CMYK image
with alpha by that alpha before resampling them, and divides them by the
resampled alpha after.
2026-11-14 05:07:39 -08:00
dotCooCoo 0843e1e331 Merge main into fix/tiled-documents-own-profiles 2026-11-14 04:58:21 -08:00
dotCooCoo 6ab46b5fd8 Print: a spot gradient stop prints its process plates on the separations
A gradient stop linked to a spot ink that also carries process plates
(a DeviceN stop opened from a PDF) printed only its spot tint: print
separations and Separations Preview left its Cyan, Magenta, Yellow and
Black plates blank. They now print the stop's plates beside the tint.
With spots printed as process, each process plate prints the stop's
plate layered with the spot tint's process equivalent, as a separated
image's spot plates layer. Plates beside no spot link, or beside
Registration, still print nothing of their own.

The color visitor also skipped a freeform gradient's points, so print
plates kept their display colors and Document Color Mode left them
unconverted. The points are now visited as unlinked colors.
2026-11-14 04:46:10 -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 e7feeb311d SVG import: a raster stored again as PNG keeps its resolution
A raster that SVG import decodes and stores again (a TIFF, a BMP or any
other format that is not PNG, JPEG, GIF or WebP, or an image whose EXIF
or TIFF orientation turns or flips it) was written as a PNG with no pHYs
chunk, and a turned or planar CMYK TIFF was written without resolution
tags, so the image lost the resolution its file declares.

The converted PNG now carries the source's resolution in a pHYs chunk,
and the CMYK TIFF in its resolution tags, as Open and Place store them.
A quarter turn (orientations 5 to 8) swaps the horizontal and vertical
values. An image that declares no resolution is stored without one, and
an image stored unchanged keeps its own bytes.

The PNG, JPEG, TIFF, WebP and BMP resolution readers and the pHYs writer
move from the engine to vectorcraft-doc, so the SVG importer can use
them; the engine and renderer entry points forward to them unchanged.
2026-11-14 02:40:45 -08:00
dotCooCoo cd86168e34 Color management: documents behind the front one draw through their own profiles
With Window › Arrange › Tile or floating document windows, every document
other than the front one was drawn through the profiles the front document
is assigned, since the active color settings are process-wide.

- cms::with_active puts other settings in place of the active ones on one
  thread, fast paths included, and puts them back after (also on a panic).
  cms::for_document gives the context a document's assigned profiles make,
  the same one each time for the same profiles and working settings.
- Each pane renders its document's art through colormgmt::doc_cms, on the
  render worker and on the UI thread alike, and draws its paper, artboard
  colors and transparency grid through the same settings.
- Loading or removing a profile redraws the documents assigned it, the
  ones behind the front one included.
- The ink and separation tables keep the tables of up to four color
  settings, so documents with different CMYK profiles side by side do not
  rebuild them on each redraw.

Placed documents inside a document behind the front one still draw through
the front document's profiles.
2026-11-14 02:24:51 -08:00
dotCooCoo a9fbb7aa50 Merge main into fix/svg-clip-path-effects 2026-11-14 02:24:38 -08: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