Commit Graph
5423 Commits
Author SHA1 Message Date
dotCooCoo efb31aa51a PDF and EPS export: gradients name only the spot inks of stops that color something
A gradient's Separation or DeviceN space, and EPS's %%DocumentCustomColors,
named the spot ink of every linked stop. A stop out of order whose
neighboring stretches have no width, a stop at a tint of 0 without process
plates, and in PDF a stop whose stretches are fully transparent print no
ink, but their spot inks were still declared, so separations got an empty
plate.

- vectorcraft-color: Gradient::drawn_stops (the rule Document Info uses,
  moved here) and Gradient::reached_stops (every stop taken as opaque).
- PDF: Separation and DeviceN shadings, the Perceptual spot shadings and
  the spot-image warning name only inks of drawn stops at a tint above 0
  or with process plates; other stops are written with no ink, so their
  process inks and RGB or Lab colors no longer shape the space either.
- EPS: the same with reached stops, since EPS writes stops opaque; a
  transparent spot stop keeps its ink.

Output is unchanged when every stop colors part of the gradient and every
spot stop has a tint above 0 or process plates.
2026-11-14 04:11:40 -08:00
dotCooCoo 490c803080 SVG import: type on a closed path wraps around past the path's start
Text on a path of one closed subpath that is anchored to start before
the path's start point (text-anchor end or middle, right-to-left start,
or a negative startOffset) started at the start point, and text offset
past the path's end started at its end. It now wraps around the path,
as SVG 2's startOffset attribute describes for a single closed subpath
(https://www.w3.org/TR/SVG2/text.html#TextPathElementStartOffsetAttribute):
text-anchor end at startOffset 0 ends at the start point. Open paths
and paths of several subpaths still start the text at the path's start
or end.
2026-11-14 04:04:48 -08:00
dotCooCoo b3fd92ccdc PDF export: CMYK images that keep their numbers carry their ICC profile
A CMYK TIFF written again, a CMYK JPEG that the Compression settings
resample or compress again, and a CMYK image written with its mask as
its soft mask lost the CMYK profile the image embeds. Such an image is
now written in an ICCBased space holding that profile, byte for byte,
when output.profiles is all or taggedSource, and in PDF/A-2b, PDF/X-3
and PDF/X-4 unless profiles is destination. Pixels the Output settings
convert are never tagged with it.

A CMYK JPEG embedded as it is now follows the same rule instead of
always carrying its own ICC_PROFILE segments: with profiles none it is
DeviceCMYK, and PDF/X-1a export no longer refuses a CMYK JPEG that
carries a profile.

A profile tags an image only when it is at most 16 MiB and its declared
size, acsp signature, device class, CMYK color space and tag table are
well formed. Tagged CMYK documents blend transparency in the document's
CMYK profile space, not in an image's own; without that space they
blend in DeviceCMYK, or keep their RGB space in PDF/A.
2026-11-14 03:59:32 -08:00
dotCooCoo 4eb1b1cf99 SVG import: linked rasters inside a linked SVG file are read
An SVG file that an <image> links to was parsed with usvg's
from_data_nested, which drops every href to a file, so a PNG or JPEG
that the SVG file linked to disappeared without a placeholder or a
warning.

The files a linked SVG file's own <image> elements link to are now read
the way the imported SVG's links are, relative paths from that file's
folder: a raster stays linked, an SVG file imports as vector art, and
one that can't be read (missing, or refused by the reader) gets the
placeholder stretched to its box, its link and a warning. The same href
in SVG files of two folders names two files. A link that leads back to
an SVG file showing it gets the placeholder and a warning. Reading the
links of linked SVG files stops at the element depth cap and at 1,024
reads and 512 MB of text per import, the same limits decoded nested SVG
images have, counted separately from them. An SVG data URL still reads
no file links, having no folder of its own.

SVG 2 tells a viewer to ignore external references in an SVG shown by
<image>; reading them on import is VectorCraft's own rule.
2026-11-14 03:53:02 -08:00
dotCooCoo 10382a2f37 Export: symbol art dropped from the budget still counts toward it
An instance whose baked art passed the export's placed symbol art budget,
or drew too deep, gave its count back, so any number of instances could
each bake their art in full and be dropped without the work counting.

- Art baked and then dropped is now counted with the placed art against
  the budget, both before more art is baked and when baked art is checked.
- While an instance's art bakes, the art's objects before baking are held
  in the budget, so instances nested in it are placed only within what is
  left.

Documents whose placed art fits the budget export as before.
2026-11-14 03:51:14 -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 7e63d4ca0c Recovery: a recovery copy that finishes later keeps a newer status line
A recovery copy written in the background set "Saved recovery data for
<title>" (or its failure line) when it finished, over any message shown
since it started, such as Restore's count with its notes or the
"Saving…" line of a copy started after it.

The status bar now counts the messages VectorcraftApp::status sets. A
copy shows its result only while its own "Saving recovery data for …"
line is still the latest message, or right away when it was written
without the worker. A failure is still logged, and a failed folder is
still recorded for automation replies, when its line is not shown.
2026-11-14 03:48:25 -08:00
dotCooCoo fe82f68d6f TIFF: a 16-bit CMYK or gray TIFF with alpha converts at 16 bits
Place, Open and relink read a CMYK or grayscale TIFF with an alpha
channel through extra_samples_tiff_rgba, which cut every 16-bit sample
to its high byte before converting it. A faint ink or a low alpha was
lost: cyan 129 at full alpha showed as white, and an alpha of 129
became fully transparent.

The samples are now normalized at the depth the file stores them, and
only the resulting color and alpha are rounded to 8 bits (a 16-bit
alpha to the nearest 8-bit value). Associated alpha is divided out at
16 bits. A pixel whose associated alpha is zero now has no color,
instead of keeping its stored color. TIFF 6.0's Associated Alpha
Handling section states this arithmetic and the zero-alpha rule for
RGB data; applying them to CMYK and gray samples is VectorCraft's own
rule.
2026-11-14 03:44:41 -08:00
dotCooCoo 3c562254e8 Text wrap: Invert Wrap with an offset lets a line use all the room the grown shape holds
With Invert Wrap and a positive offset, a line's band was cut into at
most 64 pieces, and anchor cuts were dropped when a shape had more than
64 of them. Beside a notch the offset fills, a line could stop at the
notch instead of at the grown edge: 20 pt short beside a 0.5625 pt notch
with an offset of 1, and short beside sloped notch sides and tall bands.

The grown shape is now measured exactly: the shape near the band is cut
into trapezoids, each grown by the offset into a convex polygon, and the
line keeps the x at which those polygons hold every height of its band.
The work is capped; a shape that needs more steps than the cap, for
example one whose edges cross one another tens of thousands of times,
keeps the 64-piece measure, which keeps the line inside the grown shape.
A band of no height exactly the offset past a shape's tip now holds a
line too.
2026-11-14 03:44:29 -08:00
dotCooCoo 5803d2da4a Fix #7411: a selection grabbed by an anchor snaps it onto other paths
With Smart Guides on, a selection the Selection tool grabbed by one of
its anchors only landed that anchor on other anchors and centers, or
lined its bounds up. The anchor now also lands on the other objects'
paths ("path"), and where a path crosses another path or a ruler guide
("intersect"), in the order Direct Selection uses for a dragged anchor.
When the anchor lands on a path, the bounds do not also line up with
other objects, and a ruler guide nearby does not pull it off the path.
A selection grabbed anywhere else keeps lining its bounds up.

- Targets::for_move_by_anchor gathers the other art's path segments as
  well, and Targets::snap_onto_path lands a point on them or on their
  crossings with each other and with the ruler guides.
- MoveSnap::by_anchor uses those targets; the Selection tool picks it
  when the press grabbed an anchor.

Reported by pivot-al.

Docs: docs/target-app-parity.md.
2026-11-14 03:42:08 -08:00
dotCooCoo 848a5ee904 Zoom: Space moves a text-edit zoom marquee after Cmd is let go
While the Type tool edits text, a zoom marquee started with Cmd+Space
read Space as up once Cmd was let go. Space pressed again moved the
marquee only in the frame of the key press, and later frames sized it.
The marquee now reads the Space key itself, so it moves and sizes as it
does outside text editing.

A space typed or committed by an input method during a Zoom tool drag
(the marquee or an animated zoom) is no longer typed into the text.
With no zoom drag, Space types a space as before.
2026-11-14 03:41:39 -08:00
ncic bdaaff534c Merge remote-tracking branch 'upstream/main' into pencil-cursors
# Conflicts:
#	docs/ui-parity.md
2026-11-14 12:31:28 +01:00
dotCooCoo bbf3e5ca7e Merge main into fix/plugin-store-folder-lock 2026-11-14 03:22:06 -08:00
dotCooCoo 14076169fc Merge main into fix/svg-masked-shadow 2026-11-14 03:21:12 -08:00
dotCooCoo f2ba375478 Merge main into fix/inflate-lazy-puffs
# Conflicts:
#	crates/three-d/src/shadow.rs
#	crates/three-d/src/solid/inflate.rs
2026-11-14 03:15:53 -08:00
dotCooCoo e04fa72959 Docs: the automation-roots section names the app-folder commands that are confined
The Confining file access bullet said the app's own folders are not
confined. It now names the commands that check the roots for a file
there: the arrowheads edit, reload and list commands, the New Document
profile commands and file.new, and the Scripts folder listing and run,
each linked to its section.
2026-11-14 03:15:13 -08:00
dotCooCoo cdbd079ee9 Fix #7525: Extrude & Bevel cuts sharp corners square instead of spiking
An inset ring limited a corner's miter by moving the corner four times
the bevel width along its bisector. At a corner sharper than about 29°
that the bevel opens (a convex corner with the bevel outside, a notch
with it inside), the bevel still ran out to a spike up to four times
the width and no longer lined up with the art. With the bevel outside,
the wall behind it spiked the same way.

Such a corner is now given twice in the outline before the solid is
built, and each copy moves along its own edge's normal, so the bevel
(and, with the bevel outside, the wall) cuts the corner square, as a
bevel join cuts a stroke. Corners within the limit keep their miters,
and corners where the inset edges meet keep the four-times limit.

A cap's outline skips the straight segment of no length between the
two copies where they do not move apart.

Docs: docs/three-d.md, docs/target-app-parity.md.
2026-11-14 03:10:33 -08:00
dotCooCoo 347458aff7 Place: text files in UTF-16 without a byte-order mark place as UTF-16
File › Place of a text file with the Unicode character set read UTF-16
only after a byte-order mark. Without one, UTF-16 text was read as UTF-8
(or the 8-bit set): characters outside U+0001 to U+00FF came out as
other characters, and each CR LF placed as two paragraph breaks.

Place now reads a file without a byte-order mark as UTF-16 by the rule
Import Data Sets uses, through the shared byte-order helper: an even
length, at least half of the two-byte units holding a NUL byte, the
byte order that reads a line break (for one line, the order its NUL
bytes give), and valid UTF-16 with no NUL character in that order. Any
other file is read as before, as UTF-8 or else the platform's 8-bit set.

Docs: docs/mcp.md, file.place params text, docs/target-app-parity.md.
2026-11-14 03:05:40 -08:00
dotCooCoo fc562960ec Merge main into fix/dimension-second-point-guides 2026-11-14 03:02:44 -08:00
dotCooCoo 134b8b33a1 Export: placed symbol art keeps its instance's link
An instance whose symbol art has live effects is replaced in the export by a group holding the baked art. That group now takes the instance's attributes as well, so a PDF export keeps the instance's URL as a link annotation over the art where its effects draw it.
2026-11-14 02:59:02 -08:00
dotCooCoo 0397bfa47f Merge main into fix/ai-calligraphic-samples 2026-11-14 02:53:05 -08:00
dotCooCoo 80fa9015fd Merge main into fix/trace-flat-16-levels 2026-11-14 02:50:21 -08:00
dotCooCoo b1d364033e Artwork Cleanup: Combine and Join Point Text keep hidden and locked pieces apart
With ids, Combine Point Text and Join Point Text take locked and hidden
type. They kept the first piece's object and removed the others, so
naming a visible piece and a hidden one beside it hid the visible text
or showed the hidden text, and the same held for locked pieces and for
pieces in a locked or hidden group or layer.

A piece now joins only pieces that are as visible and as locked as it
is, counting their groups and layers. The selection route takes only
editable type, so it behaves as before.
2026-11-14 02:45:50 -08:00
dotCooCoo b59ec11b32 Export: symbol art placement skips instances the export leaves out
Hidden instances, instances in hidden groups, on template layers, and
on hidden layers or layers that do not print when the exporter leaves
those out are no longer placed for PDF, print, EPS and DXF. Their art
was baked and counted toward the 16,000,000-object limit for placed
symbol art, so it could leave a visible instance written without its
effects.

bake_document_placing_symbols takes a WrittenLayers value: PDF passes
the layers its settings write, EPS writes layers that do not print but
not hidden ones, and DXF writes both. Print removes the layers that do
not print before baking.
2026-11-14 02:45:49 -08:00
dotCooCoo 3824b15a77 .ai and EPS import: large canvas symbols come in at the file's size
VectorCraft reads the symbol definitions of a large canvas .ai or EPS,
and of a .ai whose page is in larger units, in the same units as its
layers. Opening such a file scaled the layers and graphic styles up to
full size but left the symbols' art as it was. Instances on the layers
drew at the right size, but each one's transform carried the factor N,
and a newly placed instance came in at 1/N of the size, where N is the
file's large canvas scale or its page's unit.

- Opening the file now scales each symbol's art, strokes and effects with
  the layers. Instances on the layers, in symbol art, in pattern tiles
  and in opacity masks keep their own scale and rotation and draw where
  they did.
- A symbol library without layers from such a file gets the same scale
  as its graphic styles.
- Opacity masks on the layers that do not move with their object are
  scaled with the layers too, as are those in symbol art.
- Editing data that VectorCraft wrote (its %%Creator line) keeps its
  symbols and those masks at their own size, as the .ai save writes
  them, so files saved by earlier versions open as before.
2026-11-14 02:43:50 -08:00
dotCooCoo 795fbf0148 i18n: Swedish translates 114 more status and error messages
The untranslated report listed these messages as missing from the
Swedish catalog. Among them are the image export encoders and size
limits, color profiles, color books, swatch exchange files, DXF import,
3D and Revolve errors, and the `index` check of document.activate. Each
now has an @msg row in sv.tsv, with its placeholders, backticked names,
format names and values kept as the English writes them. Messages that
open pull requests already translate into Swedish are left to them.

The Swedish row in docs/localization-parity.md is recounted, and
docs/target-app-parity.md gets a line for the Swedish catalog.
2026-11-14 02:42:29 -08:00
dotCooCoo 1c973dc141 SVG import: absolutely placed characters in right-to-left text land on their x
An absolutely placed character starts its own text chunk, anchored on its
own x (SVG 1.1 text chunks). In a right-to-left line the import kerned the
character before each placed one as if kerning moved the placed character
right, but a right-to-left glyph takes its kerning at its left, so the
correction moved the wrong glyph. In <text direction="rtl" font-size="20">,
<tspan x="100 160" y="80 80">אב</tspan> on a second line put the right
edge of א at 393.48 instead of 100.

The placement now works in drawing order: each kerning is a cut after its
character (before it when it runs right to left), each gap between two
placed neighbors takes one cut, and the line's left edge is measured again
every round. Corrections are divided by the character's horizontal scale,
so text stretched with lengthAdjust="spacingAndGlyphs" lands on its x too.

A left-to-right character drawn between two placed right-to-left ones has
no kerning slot before the next one, which then keeps its place in the
line; the import warns about it.
2026-11-14 02:41:16 -08:00
dotCooCoo 27e75cfce2 Merge main into fix/flat-logo-gray-between-black-and-white 2026-11-14 02:40:29 -08:00
dotCooCoo 7694627a39 Perspective: reapplying the current grid preset adds no undo step
perspective.grid.preset stored the preset's grid every time, so applying
the preset the document already holds recorded an undo step that changed
nothing. It now compares the new grid with the stored one, as
perspective.grid.set does through grid_kept, and records a step only when
the grid changes. When only whether the grid shows or its active plane
differs, the preset sets them without an undo step, as
perspective.grid.show and perspective.plane.set do.
2026-11-14 02:35:48 -08:00
ruchirguitar e0fe953258 docs: sync symbols area row inventory in target-app-parity 2026-11-14 16:05:47 +05:30
dotCooCoo a8c2a405ac Merge main into fix/dxf-ellipse-doc-line 2026-11-14 02:34:12 -08:00
dotCooCoo b391aeafe9 Merge main into fix/pt-br-missing-message-rows 2026-11-14 02:32:22 -08:00
dotCooCoo 110cf34f29 Merge main into feat/ai-import-kinsoku-settings 2026-11-14 02:32:17 -08:00
dotCooCoo 013cd6aa42 Merge main into fix/it-missing-message-rows 2026-11-14 02:30:48 -08:00
dotCooCoo 9834c58b66 Merge main into fix/links-stored-brush-art 2026-11-14 02:26:44 -08:00
dotCooCoo 9ebd467f8d Merge main into fix/type-dialogs-story-wide 2026-11-14 02:25:49 -08:00
dotCooCoo 5eb428f02f Merge main into fix/nl-message-rows 2026-11-14 02:25: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
dotCooCoo 9735e51473 Clipboard: files copied in a file manager paste as art on core Wayland
Where the clipboard goes through the compositor's core Wayland protocol
(the Flatpak on GNOME), Paste now reads the text/uri-list a file manager
offers, else GNOME Files' x-special/gnome-copied-files, and pastes the
first file that is art before the clipboard's other types, as on the
other platforms. The list is read on the read worker and the files on
the paste's background thread. Only file: URIs with no host or
localhost are taken (RFC 8089), percent escapes decoded once (RFC
3986); other URIs are skipped, and a list of more than 1,024 URIs, a
limit of VectorCraft's own, names no file. The Paste menu item is
enabled when a file list is offered.
2026-11-14 02:24:26 -08:00
dotCooCoo 897a0c7ba0 Merge main into fix/es-missing-message-rows 2026-11-14 02:22:43 -08:00
dotCooCoo ad31fe9527 Merge main into fix/reverse-path-profiles 2026-11-14 02:21:25 -08:00
dotCooCoo bf3a23d031 Merge main into fix/graph-label-paint-recolor 2026-11-14 02:19:54 -08:00
dotCooCoo 9965454983 Merge main into fix/eps-bitmap-glyph-rollback-test 2026-11-14 02:17:57 -08:00
dotCooCoo 0f135f8f09 Merge main into fix/single-line-composer-remeasure 2026-11-14 02:16:06 -08:00
dotCooCoo 35a9045612 Merge main into fix/text-inset-skips-seams 2026-11-14 02:15:45 -08:00
dotCooCoo 24d7df0372 Merge main into fix/shortcut-optional-typed-params 2026-11-14 02:15:43 -08:00
dotCooCoo cee68c525a Merge main into fix/reflected-dimension-line 2026-11-14 02:15:24 -08:00
dotCooCoo 66ae075f90 Merge main into fix/plugin-unlinked-stop-plates 2026-11-14 02:14:25 -08:00
dotCooCoo f21c9561c5 Merge main into fix/ai-warped-image-pieces-cropped 2026-11-14 02:14:20 -08:00