Commit Graph
1828 Commits
Author SHA1 Message Date
dotCooCoo 38bb213917 PDF export: a Perceptual gradient that mixes spot and process inks keeps its inks
A Perceptual linear or radial gradient that mixes spot colors with each
other or with CMYK or gray stops was written as an image in process
colors. It is now written as a DeviceN shading of its inks, with the
stops on its Perceptual curve: at each one, the inks of the two stops on
either side are mixed at the weight where the two colors mixed in
display RGB have the OKLab lightness of the color on the curve.

- Gradient::ink_mixes gives the curve's stops as weights between stops,
  under the same 4,096-stop limit as ink_tints.
- Perceptual gradients that mix a spot color with RGB or Lab stops,
  dithered fills and freeform gradients stay images, and the warning
  now names those cases.
2026-11-01 11:09:09 +07:00
dotCooCoo 7e5e099f8e Export for Screens: a second file with a taken name is numbered instead of skipped
Squashed from #5028 onto main.
2026-11-01 11:09:08 +07:00
dotCooCoo ff036557fb Symbols: Edit Symbol opens the symbol in its own editing mode, and every instance follows each edit
Squashed from #5064 onto main.
2026-11-01 11:09:03 +07:00
dotCooCoo 5716a996ab Type: Touch Type moves a character rotated near 90 degrees across its line
Baseline shift now moves a character in the line's frame, outside
Character Rotation, so a positive shift moves a character up from its
line at any rotation, and the character turns about its shifted pen
position. The Touch Type tool splits a drag into its part along the line
(kerning) and its part up from the line (baseline shift) at every
rotation; before, within about 6 degrees of a quarter turn it dropped
the cross-line part.

Characters that already combine a rotation with a baseline shift are
drawn in a new position. Their stored values do not change.

- text: glyph transform order, PositionedGlyph::pivot (the turning
  point), tab leaders in the same order
- tools: Touch Type splits drags against the line's up axis and measures
  rotate-handle turns about the shifted pen position
- engine: text.touchType description; dy is up from the line
- docs: mcp.md Touch Type paragraph, target-app-parity.md progress line
2026-11-01 11:08:57 +07:00
dotCooCoo 94ef9b87c2 Type: Character panel toggles show off for a mixed selection, and text.setFormat checks on/off values
The Character panel's All Caps, Underline and Strikethrough buttons, and
its menu's All Caps, Underline, Strikethrough, Proportional Metrics,
Tate-chu-yoko and No Break, read the first selected character's style.
With only some characters marked they could show on, and choosing one
turned the attribute off for every character. They now show on only
when every selected character has the attribute, and a click on a mixed
selection turns it on for all, as Small Caps and Standard Vertical Roman
Alignment do. type.underline (Cmd+Shift+U) underlines a mixed selection
the same way. The Character Alignment and Digits submenus check no item
while the selected characters differ.

text.setFormat ignored a value that was not true or false for underline,
strikethrough, allCaps, proportionalMetrics, tateChuYoko,
standardVerticalRoman, noBreak, hyphenate, hyphenateCapitalized and
romanHangingPunctuation. It now refuses it with "`<key>` must be true or
false" and changes nothing, as text.setRangeStyle does.
2026-11-01 11:08:56 +07: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
dotCooCoo af133b1ee4 .ai import: envelopes open as live envelopes
An envelope in a .ai's editing data opened as its distorted art, with
its mesh and contents dropped. It now opens as a live envelope of its
contents: a warp with its style, bend, distortions and orientation, a
mesh with its points and handles, or a top object with its outline,
with Envelope Options, Fidelity and Edit Contents.

The envelope replaces its drawn art only when VectorCraft draws it like
that art, with a budget so that live envelopes don't make the file open
from its PDF part. When the layers still differ too much from the page,
the drawn art is put back. An envelope that can't be read, or that
draws differently, keeps its drawn art with a note. Envelopes of type
keep their drawn art and hidden type as before.
2026-11-01 11:08:49 +07:00
dotCooCoo c027947362 .ai import: Objects on Path groups open live with their path, Pivot and Rotate
Squashed from #5059 onto main.
2026-11-01 11:08:47 +07:00
dotCooCoo 70651f585e .ai import: template layers and ruler guides open as they were set
The editing data's layer options set a template layer from the flag four
places after the colour index. The colour index of nine-operand options,
and the colour index and dimming percentage of eleven and twelve operand
options, are read from their own places (they were read one place later).

A straight (N) * guide path directly on a layer that runs across the
whole canvas, or from edge to edge of one artboard, opens as a ruler
guide on that layer (an artboard guide of that artboard); other guide
paths stay guide paths. Guides scale with the document when its editing
data is in the units of a UserUnit page, and an EPS that keeps only its
first artboard keeps only that artboard's guides.

Fixes #779
2026-11-01 11:08:18 +07:00
Don Omondi 1e8ac2434c Fix #4920: Document Tools exports every open document
addon.document.exportAllOpen {folder, format?} writes a copy of every
open document to one folder as Save a Copy does, each named after its
document with taken names numbered so no file is replaced. Documents
keep their paths and modified state, the active one stays active, and a
document that can't be written is reported while the others are still
written. Object > Plug-ins > Document Tools gets Export All Open
Documents as PDF and as SVG, which ask for the folder.
2026-11-01 09:24:25 +07:00
dotCooCoo 18b9c6113e .ai import: one object the reader can't read comes in as the page's art, and the layers stay
Squashed from #5050 onto main.
2026-11-01 09:24:23 +07:00
dotCooCoo 8362b7532c Eyedropper: Shift-click samples a blend's steps and an envelope's distorted art
Squashed from #4949 onto main.
2026-11-01 09:24:18 +07:00
dotCooCoo c38607a5ae Tests: .doc import fuzzing also damages the compound-file container
A new text_import_fuzz case builds a valid Word 97-2003 document (version
3 or 4 compound file, its streams in the mini stream or in FAT sectors),
checks that it places, and then damages the container itself: header
fields, the sector and mini sector shifts, FAT and mini FAT entries,
directory entry fields and stream sizes, single bytes, and truncation.

Session::execute turns a panic into EngineError::Internal, so the cases
in this file did not fail when an import panicked. They now go through
no_panic, as import_fuzz.rs does.
2026-11-01 09:24:09 +07:00
bflatastic 84336967aa Fix #4922: Expand Dashes into Paths 2026-11-01 09:08:07 +07:00
dotCooCoo d72022daf5 Grid tools: F, V, X and C change the divider skews by 10 while a grid is dragged out
Squashed from #5019 onto main.
2026-11-01 08:33:02 +07:00
dotCooCoo ece78f052f Type: Standard Vertical Roman Alignment stands half-width characters upright in vertical type
Character panel menu > Standard Vertical Roman Alignment, with Show East
Asian Options, is now a check item. It sets a new character attribute,
`standardVerticalRoman` (text.setFormat, text.setRangeStyle), off by
default and saved only when on. In vertical type the marked Latin
letters, digits and other characters that would lie on their side stand
upright one below the other, each in its upright cell. Spaces keep their
width and tate-chu-yoko blocks stay across the column. Horizontal type
keeps the mark and does not change. A combining mark shaped as its own
glyph turns with its letter, in Latin and CJK upright type alike.

Character Style Options labels the Character Alignment row "Character
Alignment" and gives Standard Vertical Roman Alignment its own checkbox.
Reset Panel turns the attribute off. PDF and SVG export place the glyphs
from the layout and need no change.
2026-11-01 08:32:55 +07:00
dotCooCoo ac896cfe3d PDF export: a Perceptual gradient of one spot ink's tints keeps its ink
A Perceptual linear or radial gradient was always written as an image,
so a gradient of spot ink tints lost its plate, and no warning named the
spot ink.

PDF export now writes a Perceptual gradient whose stops are tints of one
spot color (and paper white) as a Separation shading in that ink. Its
tints follow the gradient's curve: at each stop the renderer places on
the curve, the tint with the OKLab lightness of the color there.

Dithered fills, freeform gradients and Perceptual gradients that mix a
spot color with other colors are still images, and the export now warns
when such a gradient has stops linked to a spot swatch that its spot
colors are written in process colors.
2026-11-01 08:32:54 +07:00
dotCooCoo 482c011233 Transparency: a layer's art on a locked artboard or in a hidden or locked parent is not taken for an opacity mask
Make Opacity Mask expands a layer among its targets to the art that can
be edited: an object in a sublayer of a hidden or locked layer, or on a
locked artboard, is neither the mask nor masked, so it stays where it is.
2026-11-01 08:32:54 +07:00
dotCooCoo d0834e6834 Transparency: a layer on top gives its topmost object as the opacity mask
Make Opacity Mask took the topmost target as the mask. When that target was
a layer (a targeted layer above the art, or `ids` ending in a layer id), the
whole layer was removed from the layer tree and became the mask art. A layer
on top now stands for its visible, unlocked art, as a layer below the mask
already does: its topmost object is the mask and the rest of its art is
masked with the art below. A top layer with no such art is refused and the
document is left unchanged.
2026-11-01 08:32:54 +07:00
bflatastic cd277d5d84 Fix #4917: Sort Objects sorts the selection by one attribute and applies that order to another
Squashed from #5017 onto main.
2026-11-01 08:11:17 +07:00
bflatastic ef80709e16 Fix #4925: Randomize Opacity gives each selected object a random opacity in a range 2026-11-01 08:07:33 +07:00
Don Omondi 961694cba6 Fix #4918: delete nested picks safely, keep picks per document
symbol.delete {names} expands every instance of the named symbols,
round by round, before it removes any definition, so a symbol and the
one placed inside it delete alike in either order. The Symbols panel's
picks belong to the document they were made in, and a single picked
symbol is deleted only while symbol.unused still lists it.
2026-11-01 07:38:01 +07:00
Don Omondi 5b639169cd Fix #4918: Symbols panel Select All Unused
symbol.unused lists the symbols nothing places: instances in the art
(opacity masks included), graph designs, pattern tiles and brush art
count, and so do instances in a used symbol's art. The Symbols panel
menu's Select All Unused shows them selected, and Delete Symbol asks
once and deletes those still unused in one undo step
(symbol.delete {names}).
2026-11-01 07:38:01 +07:00
dotCooCoo 8805fa8214 Place: Word .doc text with a broken surrogate pair is refused, and fields without a result warn
A 16-bit piece holding half of a UTF-16 surrogate pair was placed with
U+FFFD in its place; the document is now refused. A pair split between
two pieces is decoded as one character.

A field with no result (no separator, never ended, or nested past 64)
is left out with its own warning, and the warning about fields placed
as their results is given only for fields that have one.
2026-11-01 07:16:30 +07:00
dotCooCoo 5fdccdf602 Place: Word 97-2003 .doc files place as area type with their formatting
File > Place reads a Word 97-2003 document (a compound file named .doc,
or one that holds a WordDocument stream) and sets its main text as area
type, as it does for .rtf and .docx files. The text comes from the
piece table, in 16-bit Unicode or compressed 8-bit pieces. Formatting
is resolved from the style sheet's default font, the paragraph style,
the character style and the direct character and paragraph properties,
and keeps the same properties the .docx reader maps.

Table cells are separated by tabs and each row is a paragraph, and a
field places as its result. Hidden and deleted text, pictures, headers,
footers, notes, comments and text boxes are left out, and the reply's
warnings name each kind of content left out or changed once. Word 6.0
and Word 95 documents, encrypted documents and documents last saved
with fast save are refused, and so are structures that lie outside
their streams.

The compound file is read with the cfb crate (MIT), which adds one
package to Cargo.lock.
2026-11-01 07:16:29 +07:00
bflatastic 859b3732c1 Fix #4977: Blob Brush and Eraser show their tip's outline at the pointer 2026-11-01 07:16:29 +07:00
bflatastic 7d8f1d4e06 Fix #4978: Area Type Options › Text Flow by rows or by columns 2026-11-01 06:11:11 +07:00
bflatastic 8704c15c6d Fix #4980: Pen with Cmd/Ctrl drags the path, not hidden bounding-box handles
Cmd/Ctrl held with the Pen lends the last-used selection tool (Direct
Selection until one is chosen), which already moved anchors, straight
segments and curves of the path being drawn, one undo step each, and
handed the path back to the Pen.

With the Selection tool used last, the lent tool hit-tested the
bounding box even though the canvas hides it while anchors are selected
on their own, as the end anchor of a path being drawn is. Over the
path it showed a resize pointer, and the drag scaled the path by a
handle nobody could see: a flat path did nothing at all.

The Selection tool's handles now take the pointer only while the box is
shown (View > Show Bounding Box, no anchors selected on their own), so
the lent Selection tool moves the path being drawn.

Tests: select::tests::hidden_box_handles_take_no_press_while_anchors_are_selected,
tests::draw2::pen_cmd_drag_edits_anchors_and_segments_and_goes_on_drawing.
2026-11-01 06:11:09 +07:00
bflatastic ffc9b71a2b Tests: artboard fill in EPS and PostScript print matches the red by hue, not one platform's CMYK values 2026-11-01 06:11:07 +07:00
bflatastic 51dcb94661 Fix #4967: a drawing tablet's pen draws on a Wayland session by default
On a Wayland session Linux Display Server's default, Automatic, opened
the window on native Wayland. winit 0.30 doesn't bind the Wayland tablet
protocol, and KWin (since Plasma 6.3) and Mutter turn no tablet input
into pointer input, so the pen moved only the compositor's cursor and
the app got no motion or presses. Only X11 (XWayland) When a Pen Is
Attached, which users had to find and choose, sent the window through
XWayland, where the pen works as a mouse with its pressure.

Automatic now opens the window through XWayland when a pen is attached
as the app starts, as PhotoCraft does by default.
VECTORCRAFT_NATIVE_WAYLAND=1 keeps the window on Wayland, like
PhotoCraft's PHOTOCRAFT_NATIVE_WAYLAND. The X11 choice is unchanged.
2026-11-01 05:32:30 +07:00
dotCooCoo f66b583b5b Tests: mixed spot gradients export as DeviceN shadings when radial or in a Lab ink
- A radial gradient from a spot swatch to a CMYK color is written as a
  DeviceN shading (ShadingType 3) of Yellow and the spot ink.
- A Lab spot color used as a flat fill and in a mixed gradient is
  written as one Separation space with the Lab alternate, which the
  DeviceN space names under /Colorants.
- docs/roadmap.md lists the gradients that still export without the
  spot ink: mixed spot/process gradients in SVG and PDF gradients with
  RGB or Lab stops. docs/target-app-parity.md also notes that a
  Perceptual gradient is written to PDF as an image.
2026-11-01 04:55:11 +07:00
dotCooCoo ba16468710 PDF export: a gradient that mixes a spot color with process colors keeps the spot ink
A linear or radial gradient whose stops mix a spot color with process
colors, or two spot colors, was written in process colors with a
warning. It is now written as a DeviceN shading of the process inks
its stops use and its spot inks, so each spot ink separates onto its
own plate. An off-center midpoint becomes a stop with the inks halfway
between its two stops. A gradient that mixes a spot color with RGB or
Lab colors is still written without the spot ink, with a warning that
says so.
2026-11-01 04:55:11 +07:00
dotCooCoo bbcb886a40 Perspective: a stored projection whose determinant overflows reads back at a w row of 1
A stored projection whose determinant is not finite is read back as the
same map divided by the largest magnitude in its w row, the scale the
overflow branch of conjugated already uses, so points that overflowed at
the stored scale draw: the identity with every entry 1e308 maps (2, 2)
to (2, 2). The overflow branch of inverse scales the map so that the
largest of the products its determinant sums is near 1, so a map with
large entries and a small w row, such as a scale by 1e305 with a move
by -3.9e307, is still inverted and read back.

The two overflow tests in persp_text.rs build their stored projections
with a w row of 1, so they still overflow after the read-back.
2026-11-01 04:55:11 +07:00
dotCooCoo 18510b77af Appearance: effect.apply reports the new effect's index in the object whose row it names
The reply's index came from the last object the effect was added to, while
its item came from the first selected object (or the first target for an
explicit item). When those objects held different numbers of effects on the
row, the reply named no effect of that object. The index is now read from
that object's effect list.
2026-11-01 04:55:10 +07:00
dotCooCoo 9ba55b3c03 Objects on Path: the tool's Rotate stays within -360 to 360
tool.setOption kept any finite rotate, while the Objects on Path Tool
Options dialog shows Rotate clamped to -360 to 360 and saves the value
it was given, so a rotate of 450 showed as 360 and the next attach used
450. The tool now clamps rotate to -360 to 360, and attach clamps the
saved rotate it falls back to the same way.
2026-11-01 04:53:41 +07:00
dotCooCoo af86b2c833 Objects on Path: double-clicking the tool opens its options
Double-clicking the Objects on Path tool opens Objects on Path Tool
Options: a nine-point Pivot grid, a Rotate field, Reset (the center and
0) and Save. Save sets the tool's options, which last across tool
switches and are saved with the preferences. The tool sends them with
each attach, and object.objectsOnPath.attach without pivot or rotate
uses them, so they apply to the objects attached next; groups attached
before keep theirs.
2026-11-01 04:53:41 +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 9c17301c46 Fix #4937: artboards can have a background fill, included in exports and print 2026-11-01 04:13:57 +07:00
bflatastic 8c35bacfb3 Global Edit: the menu checks a selected group's kind only; its contents are checked on start 2026-11-01 03:36:43 +07:00
bflatastic 3146ca513b Fix #4939: Global Edit finds and edits groups like the selected one 2026-11-01 03:36:43 +07:00
bflatastic b8365d6197 Fix #4942: native Indic digits in the Digits menu 2026-11-01 03:36:40 +07:00
bflatastic 68391bdde4 Fix #4926: New Symbols from Layers 2026-11-01 02:44:16 +07:00
bflatastic 916b60898a Fix #4927: Save a Timestamped Copy 2026-11-01 02:44:16 +07:00
bflatastic 9e3f8dccec Fix #4950: Path Precision Tools: Divide into Dashes
addon.pathtools.divideDashes cuts the selected paths (or only their
direct-selected segments) into separate open paths of a dash length
measured along the curve, with an optional gap (gap pieces dropped
unless removeGaps is false) and Fit to Corners and Ends; pieces keep
the path's appearance, one undo step, at most 100000 pieces. Geometry
in vectorcraft-pathops; dialog with unit fields and Preview; tests,
sweep cases, catalog rows and docs.
2026-11-01 02:44:16 +07:00
bflatastic 69985f4998 Fix #4928: Arrange Tools: Group Overlapping Objects
addon.arrange.groupOverlapping groups the selected top-level objects
whose visual bounds overlap or touch, chains included (union-find over a
sweep along x, at most 20000 objects), only within one layer or group.
Each group takes its frontmost member's stacking place; one undo step,
all groups made in one pass over the tree. Menu item, tests, sweep case,
catalog rows and docs.
2026-11-01 02:44:15 +07:00
dotCooCoo dfd07552c8 Cursors: Caps Lock gives the drawing tools the crosshair
While Caps Lock is on, the tools whose pointer General > Use Precise
Cursors changes show the crosshair, and the saved preference does not
change. The desktop app reads the lock state on macOS, Windows and
Linux X11 and passes each change to the new view.capsLock command. A
change to view.capsLock or usePreciseCursors through app.run refreshes
the canvas pointer. The view.preciseCursors command is labeled Use
Precise Cursors, so command search finds it by the preference's name.
2026-11-01 01:59:54 +07:00
bflatastic 214fca7ca7 Character: apply() sets the font in a helper of its own 2026-11-01 01:39:16 +07:00
bflatastic 2bdaaa8981 Fix #4946: a Language setting per text, with Indian languages (#4943)
Character panel > Language sets the selected characters' language;
text.setFormat and text.setRangeStyle take `language` by name or tag
(unknown: an error), and character styles carry it. Document Setup's
language list gains Hindi, Marathi, Gujarati, Bengali, Punjabi, Tamil,
Telugu, Kannada, Malayalam, Odia and Urdu, with catalog rows; the
Digits menu's numeral names move to a digits context, as Hindi is now
also a language name.
2026-11-01 01:39:16 +07:00
bflatastic a85487ad39 Fix #4940: text is shaped in its language
Characters get a language (CharStyle::language, a BCP 47 tag of one of
Document Setup's languages; none for the default, English: USA, saved
only when set). The shaper sets it on the HarfRust buffer, so fonts use
their language forms (OpenType locl): Turkish keeps fi apart and the dot
on its i. Runs in different languages are shaped apart. New type takes
the document's language.
2026-11-01 01:39:11 +07:00
dotCooCoo db6c5ea9df Fix #2678: Ungroup no longer multiplies the group's opacity into its members
Ungroup multiplied each member's opacity by the group's, so a member of a
50% group stayed at 50% after the group was gone, and members that
overlapped showed through each other. Each member now keeps its own
opacity, and the group's opacity is removed with the group.
2026-11-01 01:22:08 +07:00