Commit Graph
2938 Commits
Author SHA1 Message Date
EricKuckandClaude Opus 5.5 0a4e9ea8c8 SVG export: a chosen artboard's file leaves out the art of other artboards inside a shared group
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 02:21:47 +07:00
dotCooCoo e22b6a5d45 Render: a knockout group drawn over its backdrop counts an element's partial coverage once
A knockout group that is not isolated, and whose elements blend, is
drawn over a copy of the art below it when the renderer has no layer
open around it. Each element was drawn over the whole copy in a layer,
and the layer was cut to the element's knockout shape with DestIn.
Where the shape covers part of a pixel, the cut counted the element's
coverage a second time. With Page Knockout Group on and Page Isolated
Blending off, the page is drawn this way as soon as an object on it
outside an isolated group has a blend mode other than Normal, on itself
or on a fill or stroke. On a test page, adding a Multiply square
changed the half-covered edge of a blue square over orange from
[115, 115, 141] to [172, 159, 147] on white.

Each element is now drawn over the copy offscreen, over its own
bounds. With the DestOut pass before it, each pixel gets (1 - shape)
times what was below plus shape times the element composited with the
copy at a shape of 1, as ISO 32000-1 section 11.4.6 describes. Pixels
that the shape covers fully or not at all are drawn as before.
2026-10-16 02:21:47 +07:00
dotCooCoo 5473e3a5c5 Effects: type in a group with a geometry effect keeps its transparency, mask, effects and visibility
Geometry effects on a group or layer, and effects on a symbol instance,
blend or repeat, outline the type inside it. outline_nested_text
replaced each type object with a plain group of its outlines, so the
type lost its opacity, blend mode, opacity mask, knockout shape
option, own effects and perspective, and hidden type was drawn,
exported and made visible by Expand Appearance.

outline_nested_text now replaces type with the art that as_art makes
for it, which is also what reshape makes for type with geometry
effects of its own. That art has the type's own geometry effects and
perspective applied and keeps its name, transparency, opacity mask
and other effects. as_art also keeps the object's visibility and
knockout shape option, so hidden type with a geometry effect of its
own is left out of exports. Type in a clip group's clipping path still
becomes its plain outlines and now keeps its visibility.
2026-10-16 02:21:47 +07:00
MarekSpodBiedry 8e58b9a23f Menus: keep scroll bar clear of shortcuts and stop above the status bar (#2086) 2026-10-16 02:21:47 +07:00
dotCooCoo 0c3a5929c7 Type: area type opens and lays out with at most 100 rows and 100 columns
In a dev build, opening a native file whose area type has 2^60 rows
or 2^60 columns failed with an internal error ("capacity overflow"),
and opening one with 2^32 rows and 2^32 columns failed with "attempt
to multiply with overflow". Text layout reserved room for rows times
columns frame cells. `text.areaOptions` keeps both counts within 1 to
100, but reading a document kept the counts the file gave.

Reading a document now clamps each count to 1 to 100
(`AreaOptions::MAX_ROWS_COLUMNS`): a larger count reads as 100, and 0
reads as 1, as layout already treated it. Text layout clamps both
counts the same way. Area type with 1 to 100 rows and columns lays out
as before.

The cells of a frame now share one copy of the frame's flattened
polygons and one copy of the flattened text wrap shapes. Each cell held
its own copy: in a dev build, a test process that laid out text in 100
rows and 100 columns of a circle frame of radius 1,000,000 pt peaked at
1.33 GB of memory, and now peaks at 100 MB.
2026-10-16 02:21:47 +07:00
dotCooCoo 7960fa722f Fix #1770: Shape Builder merges leave no spur or split outline when shared edges differ by rounding
The Shape Builder merges faces by uniting their contours, and the edges
two faces share cancel out. The sweep can give two faces copies of a
shared edge whose ends lie a few times its tolerance apart, with the
difference left as pieces shorter than the tolerance. The union could
then keep the space between the copies: a hairline that joined a hole
as a spur, or a seam that cut a petal tip off the ring's outer outline
as an outline of its own. On Apple Silicon, turning one petal of the
rosette test by -180 degrees instead of 180 leaves a spur.

A Shape Builder action unites the picked faces first, and then what is
left of each shape. When two copies of a shared edge differ in the
first of these unions that unites the faces' contours, each point of
the faces' contours that lies within 16 times the sweep's tolerance of
a point kept before it now moves onto that point before that union and
each later one, with the handles next to it. A piece left within that
distance of one point is dropped. The planar map joins the ends of
copies of an edge within the same distance. Copies that share their
ends leave at most a hairline contour, which the merge drops as a
sliver. When the copies in that union all match exactly, the unions
take the contours unchanged. Only the Shape Builder's merges and
deletions unite faces this way, so Pathfinder output does not change.
2026-10-16 02:21:46 +07:00
dotCooCoo ac4d69032c Artboards: copied artboards take a free id and keep their own guides
Duplicate Artboards, the Artboard tool's Alt-drag (artboard.move with
copy) and Paste of a copied artboard gave the new artboard the largest
artboard id plus one, saturating. In a document with an artboard id
of 4,294,967,295 (u32::MAX), which only a hand-made file has, the copy
got that same id. Artboard guides record the id of their artboard.
Deleting either of the two artboards with that id then deleted the
guides of both, and guide.list reported the copy's guides on the
other one.

push_artboard_copy now takes the id from Document::next_artboard_id,
as artboard.new and Convert to Artboards do. Since the #1718 fix, that
function returns the smallest free id when the largest is u32::MAX.
In a document whose artboard ids are all below u32::MAX, a copy gets
the same id as before.

Docs: docs/target-app-parity.md.
2026-10-16 02:21:46 +07:00
dotCooCoo 83759c0e94 Render tests: two moved raster tests no longer run alongside the tests that add fonts
The key of a raster made for content that shows a symbol includes the
font generation, and since c348b384 (#1723) the key for content
painted with a pattern includes it too. FontDb::add_font increases
that generation, and the six tests in tests_fontchange.rs call it. Two
tests in fx.rs draw such content and count the rasters moved between
frames: moved_rasters_need_the_same_content_and_effects and
a_moved_group_draws_the_shadow_of_the_instance_art_in_it_while_interacting.
Neither held fonts_steady(). When a font test added a font between
their frames, the renderer made the raster again and the test counted
0 rasters moved instead of 1. Under CPU load on Windows, with the font
tests in the same process, the first test failed in 12 of 100 runs and
the second failed in 36 of 70.

Both tests now hold fonts_steady().
translucent_blended_and_shadowed_type_redraws_when_its_font_becomes_available
added its font without the font lock that fonts_steady() holds shared,
and it now takes adding_fonts(), as the other five font tests do. With
the change, the first test passed in all 200 runs and the second
passed in all 120 runs under the same load.
2026-10-16 02:21:46 +07:00
dotCooCoo 37c3eb0d01 Tests: the Alt-drag tests no longer fail when their documents are made in different seconds
file.new stamps metadata.created from the clock in whole seconds. Four
Alt-drag tests in tests_xform.rs compare the document under test with
one that a second session builds, and both sessions start from
session()'s file.new. When the clock reached a new second between the
two calls, the documents differed in created, and the test failed.
With a temporary change that made each clock read on a thread at least
one second later than the one before, all four failed.

session() in tests_xform.rs and persp_session() in
tests_persp_select.rs now pass "created": null to file.new, as #1894
did for doc_with_rect() in tests_ids_without_selection.rs. Two new
tests in #2067 compare two documents built on persp_session().
2026-10-16 02:21:46 +07:00
bflatastic f5fcb30745 Type: Option and AltGr still type while Cmd/Ctrl chords don't (#2094) 2026-10-16 02:21:46 +07:00
Fabio William ConceiçãoandCursor 2ebc607ed2 Fix #2094: Cmd+Shift+O Create Outlines while typing
Keep Type tool from inserting Text when Cmd/Ctrl/Alt is held so the
chord outlines instead of typing, and cover Selection and Type-tool
paths so File › Open and the Artboard tool cannot steal it.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-16 02:21:46 +07:00
bflatastic 53eb76f001 Properties: the catalogs drop the flip labels the panel no longer shows 2026-10-16 02:21:46 +07:00
Fabio William ConceiçãoandCursor c53e161e37 fix(G11): Reflect X/Y flip the correct axes (#1910)
Transform Each had Reflect X and Reflect Y swapped relative to Effect › Distort ›
Transform and the Transform panel. Properties flip buttons also used inverted
tooltips. Align them so Horizontal is left-right and Vertical is top-bottom.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-16 02:21:27 +07:00
NetterSilverandClaude Haiku 5.5 a8e9b9d86e Make New Document preset cards follow the chosen units
Fixes #2078

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 02:21:27 +07:00
NetterSilverandClaude Haiku 5.5 5162f830d0 Fix New Document orientation on category tabs and preset cards
Fixes #2084

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 02:21:27 +07:00
NetterSilverandClaude Haiku 5.5 62ab3bd797 Make SVG export of type with control characters well-formed
Found while testing crates/svg/src/export.rs:1908

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 02:21:27 +07:00
NetterSilverandClaude Haiku 5.5 18c1bb0d55 Apply the sign of a picas+points value to the whole value
Found while testing crates/doc/src/lib.rs:~298 (parse_measure, picas+points branch)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 02:21:27 +07:00
NetterSilverandClaude Haiku 5.5 1524ceae09 Evaluate * and / left to right in field arithmetic
Found while testing crates/doc/src/lib.rs:269-297 (parse_measure, used by Unit::parse and parse_number)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 02:21:27 +07:00
NetterSilverandClaude Haiku 5.5 a59621fa78 Accept a negative operand after an operator in field arithmetic
Found while testing crates/doc/src/lib.rs:272

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 02:21:27 +07:00
BFlat 8b22b07e09 Merge pull request #1909 from cecobald/feat/bg-catalog
i18n: add the Bulgarian (bg) catalog
2026-10-16 02:17:32 +07:00
BFlat 8a8b21385b Merge pull request #1761 from euisuh/fix/mcp-protocol-validation
fix(mcp): discard malformed JSON replies before reusing connections
2026-10-16 02:17:08 +07:00
BFlat ccc8a246ae Merge pull request #1886 from marcoarnulfo/fix/text-edit-commit-before-transform
Type: a Transform panel edit or a dialog preview while typing keeps what was typed
2026-10-16 02:16:45 +07:00
BFlat fda8434d93 Merge pull request #1885 from dotCooCoo/feat/distribute-follows-align-to-artboard
Align: Distribute follows Align to Artboard
2026-10-16 02:16:24 +07:00
BFlat 62089aa333 Merge pull request #1923 from marcoarnulfo/fix/move-angle-distance
Move dialog: Distance and Angle, linked to Horizontal and Vertical
2026-10-16 02:15:59 +07:00
BFlat 0a09706453 Merge pull request #2041 from giang17/fix/title-bar-wm-keeps-release
Title bar: a move or resize the window manager finished no longer blocks the next one
2026-10-16 02:15:37 +07:00
BFlat d939e46542 Merge pull request #1472 from LloydNicholson/fix/svg-use-artboards-clip
Place keeps a clipped group's clip
2026-10-16 02:15:17 +07:00
BFlat 47f826b16f Merge pull request #1884 from marcoarnulfo/fix/text-scale-font-size
Info panel: scaled type shows its scaled size, as the Character panel does
2026-10-16 02:14:55 +07:00
BFlat 0ccc501ef9 Merge pull request #1887 from dotCooCoo/fix/issue-1770-pinned-stars
Part of #1770: the pinned Pathfinder test builds its stars from fixed unit vectors
2026-10-16 02:14:32 +07:00
BFlat bdff89b5c1 Merge pull request #2044 from midasmatterhorn/fix/issue-2031-large-canvas-scale
eps: a Large Canvas editing copy is read at the page's scale (#2031)
2026-10-16 02:14:00 +07:00
BFlat d47e5cf461 Merge pull request #2043 from midasmatterhorn/fix/issue-1732-transform-again-after-transform-each
transform: Transform Again repeats a Transform Each (#1732)
2026-10-16 02:13:38 +07:00
BFlat 18186dbeb7 Merge pull request #2042 from midasmatterhorn/fix/issue-2023-transformed-group-images
effects: a Transform effect moves and copies a group's images too (#2023)
2026-10-16 02:13:16 +07:00
BFlat 45922c40ef Merge pull request #2203 from Messhias/fix/2131-clippy-pdf-collapsible-match
fix(pdf): collapse Shading match for clippy 1.95
2026-10-16 02:12:43 +07:00
bflatastic f6b9ab905e i18n(bg): the strings main added since the catalog was written (legacy .ai options, Dimension tool, Revolve cap) 2026-10-16 02:04:36 +07:00
euisuh e9fc3c57ae fix(mcp): discard malformed JSON replies before reusing connections 2026-10-16 02:02:48 +07:00
Marco Arnulfo 256b052981 Type: a Transform panel edit or a dialog preview while typing keeps what was typed (refs #1881)
The Cmd-drag part of #1881 landed in #1897. This covers the two other
paths: an edit from outside the typing session (the Transform panel) and
a new interaction such as a dialog's preview now end the typing first.
2026-10-16 02:02:48 +07:00
dotCooCoo 93742621bc Align: Distribute follows Align to Artboard
With Align to Artboard chosen, the Align panel's six Distribute Objects
buttons and its two Distribute Spacing buttons acted on the selection.
object.distribute and object.distributeSpacing took no to or artboard
param. Distribute Objects kept the outermost objects where they were
and did nothing with two objects, and Distribute Spacing kept the first
object's left or top edge and the last object's right or bottom edge
where they were.

Both commands now take to ("selection", "artboard" or "key") and
artboard, and the panel sends its Align To choice as to. When to is
"artboard", the first object's left or top edge goes to the artboard's
left or top edge, and the last object's right or bottom edge goes to
the artboard's right or bottom edge. Distribute Objects spaces the
other objects evenly by its button's line, and two objects are enough.
Distribute Spacing without a spacing value makes the gaps between the
objects equal. Both commands use the same artboard as object.align.
The app passes the active artboard to both commands, and recorded
actions leave it out, so an action plays on the artboard that is
active when it plays. With "selection" or "key", or without to, both
commands work as before. Distribute Spacing with a spacing value still
keeps the key object in place with each of the three to values. With
anchor points selected, both commands still space the points among
themselves and do not use to.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 02:02:48 +07:00
bflatastic 8d4a814c81 Move dialog: an angle past 180° reads as its negative one (#1915) 2026-10-16 02:02:48 +07:00
bflatastic f53e7a4c52 i18n(bg): English keeps its own name in the Language menu, as in the other catalogs 2026-10-16 02:02:48 +07:00
cecobald 10b35a4218 i18n(bg): apply terminology (Gradient=Градиент, Bleed=изтичане, Spot Colors=спот цветове) 2026-10-16 02:02:48 +07:00
cecobald ceb69c20d1 i18n(bg): fix typos, artifacts and leaked [@msg] tags (native review) 2026-10-16 02:02:48 +07:00
cecobald 5bcf040659 i18n: add the Bulgarian (bg) catalog
The catalog holds the 4,789 rows the other complete catalogs hold: the whole
interface (every menu string and `tl!` literal) and the status and error
messages, in the Bulgarian vocabulary of vector illustration, following
Adobe Illustrator's Bulgarian conventions; one/other plural forms.

Clean-room from VectorCraft's English meaning, drafted with AI assistance
(Gemini); a native speaker has not reviewed it yet. `bg-BG` and every other
`bg-*` locale resolve here.

`cargo test -p vectorcraft-ui-egui i18n::tests` passes (46 tests, including
complete menu, literal, message and font coverage).
2026-10-16 02:02:48 +07:00
Marco Arnulfo 8e72916a69 Move dialog: Distance and Angle, linked to Horizontal and Vertical (fixes #1915) 2026-10-16 02:02:47 +07:00
Giang Nguyen 07b45e8dd3 contributors: credit giang17 as Giang Nguyen 2026-10-16 02:02:09 +07:00
lloydandClaude Opus 5.5 8d288337f5 Place keeps a clipped group's clip
Place flattened every top-level layer into its objects, so an SVG's clipped top-level group lost
its clip and its clipping path came in as a loose, invisible path; sublayers lost their clips the
same way. A clipping layer is now placed as one clip group, for SVG/DXF and for the art placed from
an artboard (PDF, EPS, placed documents) alike.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 02:01:50 +07:00
Marco Arnulfo d0c302c1a3 Info panel: scaled type shows its scaled size, as the Character panel does (part of #1882) 2026-10-16 02:01:50 +07:00
dotCooCoo d425aede37 Part of #1770: the pinned Pathfinder test builds its stars from fixed unit vectors
every_pathfinder_operation_is_pinned built its stars with shapes::star,
which calls the platform's cos and sin. At the star angle
2.204350845268838, cos on macOS x86_64 (measured under Rosetta on
macOS 27.0.1) returns 0xbfe2f1c59f37cbf4, where the correctly rounded
value, which macOS aarch64 returns, is 0xbfe2f1c59f37cbf5. In the set
of five shapes with seed 7, this moves one star vertex by one ulp, and
the set's Unite hashes to 60181664961792917, where PINNED has
9388160212451732406. Under Rosetta, 21 of the 40 hashes differ.

The test now builds each star from a table of the correctly rounded
cosine and sine of the star's ten angles, written as f64 bit patterns,
with the arithmetic of shapes::star. PINNED is unchanged. With these
inputs, all 40 hashes equal PINNED on aarch64 and under Rosetta.
2026-10-16 02:01:50 +07:00
bflatastic 7beebfabb9 eps: apply the Large Canvas scale to EPS files only; a .ai keeps its art space (#2031) 2026-10-16 02:01:50 +07:00
midasmatterhorn 3af1976d19 transform: Transform Again repeats a Transform Each (#1732) 2026-10-16 02:01:50 +07:00
midasmatterhorn d5abc71677 effects: a Transform effect's image copies stay within a node budget (#2042) 2026-10-16 02:01:50 +07:00
Giang Nguyen 6986d87771 Title bar: a move or resize the window manager finished no longer blocks the next one (fixes #2040) 2026-10-16 02:01:50 +07:00