Commit Graph
3078 Commits
Author SHA1 Message Date
bflatastic 166afce360 SVG export: type with small capitals, superscript, subscript or tab leaders is written as outlines (#3869) 2026-10-24 04:49:08 +07:00
aiongg 88884bcd01 EPS tests: budget tests wait 120 s for the program to stop
search_in_a_loop_runs_out_of_the_budget searches about 3 GB before the operation budget runs
out: 14 s on a fast desktop, over the 20 s limit on the FreeBSD runner. The 20 s limit stays
for the tests that use it as a speed bound.
2026-10-24 04:49:08 +07:00
Gabriel Luís da Silva 60764fb65b Fix #3724: Window > New Window is greyed out until it opens a window
New Window was enabled in the menus and in the control channel's menu
listing, but choosing it opened nothing and answered with the internal
note "multiple windows land with M11.5". It is now disabled, as Window >
Arrange's unimplemented items already are, and a direct call fails with
a message meant for the user, translated in every catalog.
2026-10-24 04:49:07 +07:00
Jürg Lehni 181aeef44c Renderer: colour caches key colours with Color::key
The freeform and dithered gradient grids and the separated inks each built the same exact colour key by hand; they now take the one Color::key gives.
2026-10-24 04:49:07 +07:00
Dylan M. Taylor 5020dc0585 PDF export: past the retry cap, one last run leaves out every image instead of failing 2026-10-24 04:49:07 +07:00
bflatastic 2e71ab5476 PDF import and export: rustfmt 2026-10-24 04:49:07 +07:00
Dylan M. Taylor 4b8e69981e Audit: PDF import and export bounds 2026-10-24 04:49:07 +07:00
bflatastic 9c8afb09ba Image encoders: rustfmt 2026-10-24 04:49:07 +07:00
Dylan M. Taylor 52ceefe906 Audit: Targa and palette encoders check pixel buffer sizes 2026-10-24 04:49:07 +07:00
Dylan M. Taylor 9843d5f1ab Audit: export names, linked-file ids and MCP prompt arguments in one pass 2026-10-24 04:49:07 +07:00
bflatastic 028cafa52e Scribble: the row loop's stop compares with partial_cmp (also stops on NaN; clippy) 2026-10-24 04:49:07 +07:00
Dylan M. Taylor b59235e762 Test: sliding-window maximum 2026-10-24 04:49:07 +07:00
Dylan M. Taylor e3223a419d Audit: Scribble rows counted, Outer Glow dilation in linear time, CSS export names in a set 2026-10-24 04:49:07 +07:00
bflatastic a82bcfe7a5 DXF export: format the far-coordinate check 2026-10-24 04:49:07 +07:00
bflatastic 62333a2128 DXF export: the far-coordinate check compares with partial_cmp (also refuses NaN; clippy) 2026-10-24 04:49:07 +07:00
bflatastic 711b10ca59 Security: DXF export bounds (layer and style names, flattening, entity count, image size) and import dash patterns
Squashed from #3886 onto main.
2026-10-24 04:49:07 +07:00
Gabriel Luís da Silva f0ec1c8506 Fix #3716: a click near an anchor selects without moving the object
A Selection tool press within reach of an anchor or the centre grabs the
object by that point, but the drag threshold was measured from that point
instead of from the press. A press 3-6 px from it was already past the
threshold, so the first pointer wobble started a move and jumped the
object by the offset. The threshold now counts from where the pointer
went down; a real drag still moves the object by the grabbed point.
2026-10-24 04:49:07 +07:00
bflatastic c2ad9f8bbb Type: emoji go with type that effects reshape and Expand Appearance
Squashed from #3879 onto main.
2026-10-24 04:49:06 +07:00
bflatastic 0ecef703ef Security: cap the perspective grid's line-loop bounds at 121 a way 2026-10-24 04:34:18 +07:00
Dylan M. Taylor 1bb904c147 Audit: Perspective Grid lines counted not summed; Liquify subdivision stays under its anchor ceiling 2026-10-24 04:13:37 +07:00
Dylan M. Taylor aa160b969b Audit: path edit work bounds (redundant points in one pass, simplify and join budgets) 2026-10-24 04:13:36 +07:00
Dylan M. Taylor f4a30c1a94 Audit: geometry length measurement refuses coordinates the integrator cannot handle 2026-10-24 04:13:36 +07:00
bflatastic 9827bfbcbb SVG import: the shared appearance needs no conversion (clippy) 2026-10-24 03:52:24 +07:00
bflatastic d9e524df30 SVG entity scan: look for a reference's ';' no further than the longest name 2026-10-24 03:52:24 +07:00
Dylan M. Taylor 98d11ad66b Audit: cap SVG entity expansion, filter layer stacks and export id/companion probing; share compound-path appearances; escape-proof font feature tags 2026-10-24 03:52:24 +07:00
bflatastic 8e8aaa8683 SVG: a Preserve Editing SVG reopened from disk saves as the full document again (#3867) 2026-10-24 03:52:24 +07:00
Jürg Lehni e372d00cb7 Type: tests pin colour glyphs in variable fonts, on paths and on the canvas
A variable font's COLR layers follow its instance, a colour glyph turns with type on a path, and the canvas draws an SVG glyph's art in its own colours and the type's fill.
2026-10-24 03:52:23 +07:00
bflatastic 9f1a001a2b Export for Screens: a per-artboard EPS takes the artboard as its page, so an empty artboard still writes 2026-10-24 03:52:22 +07:00
bflatastic d81145aee3 Artboard documents keep objects without measurable bounds (type in a missing font) 2026-10-24 03:52:22 +07:00
bflatastic 60107cd33a Export for Screens: a document row for an artboard keeps only that artboard's art (#3868) 2026-10-24 03:52:22 +07:00
Zaxaerith 9985d587f7 fix(stroke): preserve extended dash patterns (#3497) 2026-10-24 03:52:22 +07:00
ham9zah 1653790965 Import: an Illustrator gradient mesh comes in as one connected mesh
The editing data writes a gradient mesh as its patches, each with its
place in the grid (`/P`) and the grid's size (`/Size`); the importer
read each patch as a mesh of its own, in a group, so moving a mesh
point tore a patch away and left a hole, and a patch with anchors on
its edges was cut into cells on its own.

The patches are now placed by `/P` in the `/Size` grid and joined at
the corners they share into one GradientMesh. Which index of `/P` runs
along the columns is taken from the one under which the shared corners
meet. Where an edge bends through anchors, a mesh line runs through the
whole row or column of patches there, each patch cut at the same place,
so every cell keeps single-cubic edges. A mesh whose patches don't say
where they are reads as before; one whose patches fill the grid but
don't join up reads as before with a warning. Sizes and lines are
capped; non-finite values fall back.

Hand-written tests: a 2 x 2 grid as one mesh with the old patches'
colours, a moved inner point shared by its four cells, an anchor on a
shared edge adding a line through the mesh, a collapsed patch with
finite values, and unplaced or unjoined patches staying separate.
2026-10-24 03:52:21 +07:00
Marco Arnulfo d0919ad0df Actions: Create New Set and Set Options… name action sets, and a recording goes into the current set (#3712) 2026-10-24 03:52:20 +07:00
Jürg Lehni 7efd8f941a Type: colour glyphs keep each fill's own colour, also between colours that look alike
The colour glyph cache keyed the text's colours by their 8-bit RGB look, so a fill that only looked like an earlier one (a grey and the same RGB grey, a spot colour and its process match) took that one's colour, and its separations. It now keys them exactly.
2026-10-24 03:52:15 +07:00
FractalEncrypt 25abd1f472 text: recheck concurrently loaded fallback faces
A system fallback search can add no new face because another lookup loaded it
first. Re-read the loaded faces regardless of the search's return value, so
concurrent first use does not produce a missing glyph and different advances.

Add an isolated generated-font regression with simultaneous cold lookups.
The original code missed 14 of 16 lookups; the fixed regression passed twenty
runs. Both previously failing Ruby tests pass unchanged.

Validation: Rust 1.98.1 cargo xtask ci, all 10 gates passed; workspace tests
9,635 passed, 0 failed, 14 ignored. Default Rust toolchain unchanged.
2026-10-24 03:52:15 +07:00
NetterSilverandClaude Haiku 5.5 add5e1e7dd Reject signed hex digits in XML-ID _xHH_ escapes
Found while testing crates/doc/src/xml_id.rs:80 (escaped)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 03:52:14 +07:00
bflatastic 0066447eac Global Edit: cache the highlight outlines per document revision 2026-10-24 03:09:12 +07:00
bflatastic 6e3ecc3adf Select: Start Global Edit edits the objects of the same shape together, each in proportion
Squashed from #3781 onto main.
2026-10-24 03:09:12 +07:00
dotCooCoo 2a2e63856c Type: the Paragraph panel's Bullets button turns paragraphs into a bulleted list
VectorCraft had no lists. A bullet could only be typed as a character,
and the tab after it did not stop at the left indent. The reference app
turns paragraphs into a bulleted list from the Paragraph panel, the
context menu and Type › Bullets and Numbering › Apply Bullets.

text.setFormat takes list ("none" or "bullet") and bullet ("none",
"dot", "dash", "circle" or "square"). The layout draws the bullet before
the first line of each list paragraph that has text, in the font, size
and color of its first character, and starts the text at the next tab
stop, with the left indent counted as a stop. Wrapped lines start at
the left indent, and type on a path draws the bullet too. In a
horizontal right-to-left list paragraph the indents are mirrored: the
bullet hangs at the right, and the wrapped lines start at the right
where the first line's text starts after the bullet. The bullet is not
a character of the text. A paragraph whose left and first-line indents
are both 0 gets 18 pt and -18 pt when it joins a list. Return continues
the list, paragraph styles carry it, Reset Panel turns it off, and the
native file saves it only when it is set.

The Paragraph panel has a Bullets button with a list of the five
presets, and Type › Bullets and Numbering › Apply Bullets and the
context menu run type.applyBullets. Live SVG text writes the bullet's
character, and SVG writes type on a path with bullets as outlines. DXF
writes the bullet as a TEXT entity of its own, and legacy .ai export
warns that bulleted lists are left out. The caret, selections, Touch
Type and Show Hidden Characters skip the bullet.

Live SVG text of horizontally scaled type now writes each tab in a
tspan of its own. Before, the characters before a tab shared its tspan,
and its textLength made a viewer stretch them across the tab's gap.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-24 03:09:11 +07:00
Taha-Mahmoodi 5c8e440ab5 Symbols: thumbnails work out the document's resource key once per panel frame, not per tile
Review follow-up (CodeRabbit): each thumbnail hashed every symbol's and pattern's art before its
texture cache lookup, so a panel frame cost visible tiles × (symbols + patterns) even when every
thumbnail was cached. The Symbols panel works the key out once per frame, a symbol library panel
once per library it shows, and the dragged chip once; thumbnails take it as given.
2026-10-24 03:09:11 +07:00
Taha-Mahmoodi f6715487c0 Symbols: the thumbnail test reads pixels as four-byte chunks, as clippy asks 2026-10-24 03:09:11 +07:00
Taha-Mahmoodi ee5c262154 Canvas: a test drops a library symbol on the canvas and finds it added and placed there in one step
Review follow-up (CodeRabbit): the library panel test only checked the drag payload. The new
canvas test drops PanelDrag::LibrarySymbol over art and checks that the symbol joins the
document's Symbols, an instance is placed with its centre at the drop point in document
coordinates and at its natural size, as one Add to Symbols undo step that undo takes back.
2026-10-24 03:09:11 +07:00
Taha-Mahmoodi 89abc2c9d2 Symbols: a symbol's thumbnail draws the symbols it nests and the patterns and images it uses
Review follow-up (CodeRabbit): thumbnails rendered the symbol alone in an empty document, so a
symbol nesting another one, or painting with a pattern or showing an image, lost that art in the
Symbols panel and in symbol library panels. The preview now renders an instance alone on a copy of
the document (or library) the symbol comes from, which keeps its resources but none of its art,
and the thumbnail cache also follows the art of the document's symbols and patterns.
2026-10-24 03:09:10 +07:00
Taha-Mahmoodi 7da5e3062d Symbols: Window › Symbol Libraries opens symbol libraries whose symbols click into the document's Symbols
Window › Symbol Libraries and the Symbols panel's Symbol Libraries Menu open each symbol library
in a library panel of its own, on the shared library panel code the swatch and graphic style
libraries use (https://helpx.adobe.com/illustrator/desktop/manage-objects/traces-mockups-symbols/create-or-import-symbol-libraries.html,
.../symbols-panel-options.html, .../create-and-place-symbols.html).

- Basic Shapes: one original library generated in code (circle, squares, triangle, diamond,
  hexagon, star, burst, arrow); no other app's libraries.
- A click adds a library symbol to the document's Symbols as one undo step, with its Symbol
  Options and the resources it uses (nested symbols, patterns, swatches, brushes, graphic styles,
  images), and makes it the current symbol; one already there isn't added again, a clash of
  names numbers the library's. Shift/Cmd-clicks select for Add to Symbols. Dragging a library
  symbol onto the canvas adds it and places an instance there, in the same step.
- Save Symbols… (library menu, Window menu) and Save Symbol Library… (Symbols panel menu) write
  the document's symbols as a .vectorcraft document holding only them, into the user library
  folder (User Defined, window.userSymbolLibrary1-10) or a file; Other Library… reads the symbols
  of any document VectorCraft opens, and a file it can't read is an error.

Commands: symbol.libraries, symbol.library, symbol.addFromLibrary (place, x, y),
symbol.saveLibrary, symbol.loadLibrary; UI: window.symbolLibrary (.other), ui.saveSymbolLibrary
(dialog saveSymbolLibrary). i18n rows in every complete catalog; docs updated.
2026-10-24 03:09:10 +07:00
bflatastic f247772042 Type: selected type shows its in and out ports, and the in port threads backwards
Squashed from #3817 onto main.
2026-10-24 03:09:10 +07:00
Taha-Mahmoodi b321a77d38 Smart Guides: a tool switched to under a still pointer is hovered at once
The hover's context now includes the active tool (PR review follow-up):
switching to the Selection tool with Alt held and the pointer still
showed no Distance Guides until the pointer moved, since the new tool
had never hovered. A tool switch re-hovers at the pointer whatever the
tool; the rest of the context (canvas, view, document and revision)
re-hovers tools that ask (Tool::wants_rehover).

canvas::tests::distance_guides_follow_what_lies_under_a_still_pointer
adds a tool switch (fails without the rule), a modal dialog with its
backdrop over the pointer, and another document opened under it.
2026-10-24 03:09:10 +07:00
Taha-Mahmoodi dbe4b84915 Smart Guides: the still-pointer Distance Guides test passes clippy's unused-mut lint 2026-10-24 03:09:10 +07:00
Taha-Mahmoodi 7693aeb508 Smart Guides: Distance Guides follow what lies under a still pointer
One rule for the hover's context (PR review follow-ups): the target is
recomputed where the pointer is, or cleared, whenever what lies under it
can change while Alt is held.

- The tool hovers only where the pointer is on the canvas itself
  (`on_canvas`): under a floating panel, a menu, a popup or a dialog
  its hover ends (Tool::hover_ended), as when the pointer leaves the
  canvas or a pan, zoom or view-rotation press starts.
- The canvas keeps the hover's context: its rect, the view's centre,
  zoom and rotation, and the active document's id and revision (which
  moves with every edit, undo and selection change). When it changes
  under a still pointer, a tool that asks (Tool::wants_rehover; the
  Selection tool after an Alt hover) is hovered again at the pointer,
  so wheel, gesture, key or command scrolling and zooming, tab
  switches, edits and undos re-measure.
- Coming back onto the canvas re-hovers the tool.

canvas::tests::distance_guides_follow_what_lies_under_a_still_pointer:
a floating window over the pointer (fails without the on_canvas filter),
a 150 pt scroll that leaves empty artboard under it (fails without the
re-hover), a square made under it. select::tests::distance_guides_need_
alt_a_selection_and_smart_guides checks wants_rehover.
2026-10-24 03:09:09 +07:00
Taha-Mahmoodi 26bf324c81 Smart Guides: a pan, zoom or view-rotation press ends the Distance Guides hover
An Alt+Space pan press went to Drag::Pan and never reached the tool, so the Distance Guides stayed through the pan until the pointer left the canvas (PR review follow-up). One rule now covers all three cases: the tool's hover ends (Tool::hover_ended, renamed from pointer_left; Session::tool_hover_ended) when the pointer leaves the canvas with no press the tool holds, and when a press starts any drag that doesn't reach the tool (pan, middle-button pan, zoom box or scrub, view rotation, touch gesture). canvas::tests::distance_guides_go_when_the_hover_ends asserts they go at an Alt+Space press and stay gone panning out over a panel.
2026-10-24 03:09:09 +07:00
Taha-Mahmoodi 16b66e5f4b Smart Guides: Distance Guides also go when a pan, zoom or view-rotation drag leaves the canvas
The pointer-left check skipped every drag, so Alt+Space panning out over a panel kept the measurements (PR review follow-up). Only a press the tool holds (Drag::Tool, Drag::Art) keeps its state now; pan, zoom box, zoom scrub, view rotation, gesture and presentation drags never reach the tool. canvas::tests::distance_guides_go_when_the_pointer_leaves_the_canvas pans out with Alt+Space; it fails with the old drag.is_none() check.
2026-10-24 03:09:09 +07:00