Commit Graph
9906 Commits
Author SHA1 Message Date
dotCooCoo ab0ae9f880 Type: area type insets stop at the frame's edges, not at an edge its contours share
An edge that two contours of an area type frame share lies inside the
frame, and lines already run across it. Inset Spacing still kept text
clear of it, so a frame of contours that meet along an edge left a gap
of twice the inset at the seam. The inset now applies only beside the
stretches of edges that bound the frame, counted by parity as the line
spans are. A negative text wrap offset no longer shrinks a wrap object
beside an edge two of its contours share.
2026-11-13 21:00:03 -08:00
ruchirguitar 7929c95ce9 #6613: guard web Gujarati selection and address local review 2026-11-14 10:29:25 +05:30
ruchirguitar ea2deffde1 style(svg): format craft-svg delegation in text_within 2026-11-14 10:28:44 +05:30
dotCooCoo 15bf65f014 Merge main into fix/issue-6784 2026-11-13 20:54:25 -08:00
dotCooCoo 4416640bf4 3D: Expand as Wireframes outlines each face's own stroke under a later Outline Stroke
Expand as Wireframes reshaped the faces of a 3D effect with the geometry
effects after it, but the faces it built carried no stroke. An Outline
Stroke after the 3D effect then outlined a plain 1 pt stroke with miter
joins, while the canvas outlines the round-joined stroke each face is
drawn with: the seam stroke (half the facet's thickness, 0.05 to 0.75 pt;
0.75 pt on Revolve) or the 0.5 pt wire edge of the Classic Wireframe
surface. The wireframe's faces now carry that stroke, so the expanded
edges lie where the drawn outlines lie.
2026-11-13 20:53:22 -08:00
dotCooCoo 5750843d73 Links: placed images in stored brush art get Links rows
Linked images and placed documents in the art of the stored brushes (a
scatter or art brush's art, a pattern brush's tiles) are listed in the
Links panel after the other stored art, one row per linked or placed
object in each brush tile, with the brush as owner
(`{kind: brush, name, index, tile?}`). Check Links, the missing and
modified files reported on open, the link watch, Find in Folder, Relink
(including Relink All Instances), Update, Embed, Placement Options, Link
Info and Go To act on them, and their tooltip names the brush.

- vectorcraft-doc: `Document::mounted_art` holds art kept outside the
  document's trees while a command looks it up by id; the stored-art
  lookups, link visitors and `art_roots` include it, and
  `number_mounted_art` gives its objects ids of their own.
- vectorcraft-brush: `stored_art::StoredArt` mounts the art of the
  brushes that hold images or placed documents and writes back only the
  entries whose art changed. Entries that do not read as a brush are left
  as stored. `brush::store` keeps ids of their own in that art, so a row
  keeps its id between commands.
- vectorcraft-engine: the links commands, opening a document, saving a
  placed document's source, output of linked files and placed documents,
  color masks after Update or Relink, and Package relinking go through
  the mounted art.

Brush art rows follow the general Links rule as VectorCraft's own
application of it.
2026-11-13 20:51:54 -08:00
dotCooCoo 3a62659028 Type: a taller line in a further span beside a wrap object no longer reaches into the line above
When a wrap object splits a line band, the lines in the spans after the
first shared the first line's baseline even when they held taller type.
Their ascent then ran into the line above the band. A further span now
goes only to a line whose own leading sets it no higher than the span's
baseline; a taller line leaves the span empty and goes on in the next
span or on the next baseline. Both composers follow the same rule.
2026-11-13 20:48:23 -08:00
dotCooCoo edee68e3d1 EPS import: Ryumin-Light-H and GothicBBB-Medium-V read as Japanese type without their CIDFont
A name ending in the row-and-cell CMap H or V split only when the file
defined the CIDFont or a face of that name was installed, so
/Ryumin-Light-H findfont in a file that only names it read its strings
byte by byte as a plain font: <467c> came in as "F|" instead of 日.
Ryumin-Light and GothicBBB-Medium, the Japanese CIDFonts a printer
carries (Adobe Technical Note #5014, appendix A.2), now split at H or V
as well. Latin names such as Foo-Bold-H still stay whole.
2026-11-13 20:48:18 -08:00
dotCooCoo 5b24c0a55e Actions: Batch errors name the step by its place in the commands sent
action.batch drops Open steps before it plays each file or data set, and
returned the per-file error of command.batch unchanged, so `batch step N`
counted from 0 within the filtered steps. A failed step is now named
``action step N (`id`) failed: reason``, N being its place in the
`commands` the caller sent, from 1, with skipped Open steps counted.
The batch's own open, data set choice and destination steps keep their
unnumbered errors, and command.batch messages are unchanged.

A prefs.import step, which command.batch refuses when it reaches that
step, rolling the batch back, is now refused before any file opens
instead of failing each file or data set the batch plays.

Docs: action.batch params text, docs/mcp.md, docs/target-app-parity.md.
2026-11-13 20:47:50 -08:00
dotCooCoo 774ffbbc21 EPS import: KSC-Johab type reads one-byte ASCII codes
The KSC-Johab CMaps had no code space listed, so type in a font over
KSC-Johab-H or KSC-Johab-V read every code as two bytes, so two ASCII
characters moved the point one em instead of two. The code
space now follows Adobe's KSC-Johab-H CMap: <00>-<80>, <8441>-<D3FE>,
<D831>-<DEFE> and <E031>-<F9FE>
(https://github.com/adobe-type-tools/cmap-resources/blob/master/Adobe-Korea1-2/CMap/KSC-Johab-H).
2026-11-13 20:47:32 -08:00
dotCooCoo cf7a72e21b Type: the Single-line Composer measures a line's room across its tallest character
In area type of a shape other than a rectangle, or with text wrap, the
Single-line Composer placed each line at the metrics of its first
character and broke it in the room there. When a later character on the
line was taller, the baseline moved down by the difference without
measuring the room again, so the line could reach into a narrower part
of the frame or into a wrap object.

- A line that turns out taller than it was placed is placed again at
  metrics that hold both and broken again in the room there.
- When that leaves the taller character for the next line, the line is
  set at its own metrics where the room there is no narrower, and takes
  the words before that character that fit there. Otherwise it stays
  where it was placed.

Tests: crates/text/src/tests/combos.rs (a stepped frame and text wrap;
the two mixed-size tests now expect the Single-line Composer to break
as the Every-line Composer does there).

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 20:46:39 -08:00
datatimp 2610d97cd4 Layers: a plain click on another row lets go of the selected guide (#7340) 2026-11-13 23:44:33 -05:00
dotCooCoo 0263b4af13 Merge main into fix/smooth-keeps-closed-start 2026-11-13 20:38:29 -08:00
dotCooCoo 702b863306 .ai import: reads Kinsoku, Kinsoku Shori Type, Burasagari and Bunri-Kinshi
Paragraphs in a modern .ai text document now keep their East Asian line
breaking settings: the Kinsoku set (None, Hard or Soft), Kinsoku Shori
Type, Burasagari and Bunri-Kinshi. Each comes from the paragraph, else
its paragraph style or a style that one is based on, else the document's
defaults, as the other paragraph settings do. A value that cannot be read
takes the paragraph style's value.

A paragraph whose Kinsoku set is a custom set takes its paragraph
style's set, and the import warns that custom Kinsoku sets were left out.
.ai export does not write these settings.
2026-11-13 20:36:17 -08:00
dotCooCoo 0a68935bf2 .ai import: Art brush guides match as fractions of the art too
A path's guide lengths matched the brush's within 0.001, so on very short art guides at 30% and 35% of the art matched. The guides now also match as fractions of the art's length.
2026-11-13 20:35:50 -08:00
dotCooCoo dd6ab903e7 3D: Expand as Wireframes measures later effects with the cast shadow
A geometry effect after an object's 3D effect, such as a Transform that
scales or rotates about the center, measures the drawn art, cast shadow
included. Expand as Wireframes measured the faces alone, so with a
shadow on, the expanded edges landed away from the surfaces on the
canvas. The faces are now reshaped together with the shadow the canvas
draws behind them (Extrude & Bevel, Inflate, Rotate and Revolve, on an
object, group or layer), and only the faces are kept.
2026-11-13 20:32:36 -08:00
dotCooCoo 3ea1524618 Image Trace: Flat Logo traces a gray between black and white as one shape
With a gray among the colors, an anti-aliased edge pixel of black on
white is also a mix of black and gray, or of gray and white, and the
unmixing took the mix with the smallest error, which often held the
gray. A black disc and a gray square on white traced the gray as the
square plus 8 to 24 slivers around the disc, with the colors found or
named exactly.

When another mix of two classes also reproduces an edge pixel, the pixel
now takes it if that mix's classes lie nearer in the flat areas around
the pixel and the pixel has a neighbor on each side of the left-out
class, along the line between the other two. Pixels within a few levels
of a class outside a flat area are checked the same way, and they now
count toward the number of pixel values that decides when a busy image
is averaged down further. A flat area that stands for no class, as with
colors named some levels off, counts as holding the classes of its mix,
and so do the pixels of exactly its color joined to it. Whether a
hard-edged image is softened is still judged from each pixel's best mix.

The slivers are removed around sharp edges and edges blurred by up to
about half a pixel; an edge blurred by a pixel or more, or pixel noise
of a level or more, can still leave some. Gray strokes two and three
pixels wide beside black stay gray, and so does a one-pixel gray line
between black and white of at least 13 joined pixels. These trace as
black and white: a shorter one-pixel line, or one that falls between
pixels or is blurred; a soft-edged gray stroke about two pixels wide
touching black; and most or all of a soft-edged stroke about three
pixels wide touching black, 12 pixels long or less.

Docs: docs/image-trace-adjustments.md, docs/target-app-parity.md.
2026-11-13 20:32:14 -08:00
dotCooCoo 395ddae55a Merge main into fix/file-folder-param-classification 2026-11-13 20:30:48 -08:00
ruchirguitar f965fd6f4a Merge branch 'upstream/main' into feat/layers-row-context-menu 2026-11-14 09:58:09 +05:30
dotCooCoo f9b1c2504f Smooth tool: measure twice the reach along a curve that leaves without a handle
Near an anchor whose handle does not reach out, the curve starts more slowly than its control polygon, so the finely cut stretch could end before twice the reach and the turn there was measured along a long chord. The stretches past it are now cut as finely until the pieces reach three times the reach. docs/mcp.md says the one-eighth cap applies to a closed path the drag reaches all the way round.
2026-11-13 20:28:08 -08:00
dotCooCoo e93b672b3b Keyboard Shortcuts: panel menu commands with typed optional params can take a shortcut
An undoable command without a menu path or a default key was listed only
when every field of its params doc ended with `?`. A typed optional field
such as `on?: bool`, `ids?: [id…]` or `artboard?: index=0` counted as
required, so Fractional Widths, System Layout, Align to Pixel Grid, Embed
Image, Update Links, Delete Slices, Switch Orientation, Distribute Spacing
for artboards, Target Contents, Invert and other panel menu commands that
act on the selection could not be given a shortcut.

`runs_without_params` now reads the params doc with
`names_a_required_field`, the parser the editor already uses for menu
commands. The commands the new rule would list that set nothing, fail or
only give data back when a key runs them with no params (the panel
setters such as Fill and Character, the exports and saves without a path,
the undo group's begin and end, Create Dimension) join `NEEDS_A_PARAM`,
so they stay out of the list until the user gives one a key. New Symbol
joins it too, since the Symbols panel runs it through Symbol Options.

docs/mcp.md describes the rule and the full `NEEDS_A_PARAM` list.
2026-11-13 20:24:04 -08:00
dotCooCoo 1fbbb0a4e7 SVG export: shadows in a masked group show in readers that bound it by its shapes
Some SVG readers draw a masked group only inside the bounding box of its
shapes. A drop shadow, glow, blur or feather inside the group paints past
those shapes, so these readers left it out, while others drew it.

A masked group now starts with a rectangle over the mask's region,
unpainted (fill="none") and hidden (visibility="hidden"), when what it
holds has a visible raster effect: on a member at any depth, on a fill or
stroke, in a symbol's art, or in the art a blend or other live object is
written as. The rectangle widens the group's bounding box without drawing
anything, and import leaves it out. The masked groups of a knockout group
get the same rectangle when an element inside them has such an effect.
Other masked art, brushed strokes included, is written as before, and so
is an object whose own effects are written outside its mask.

Tests: a_masked_group_spans_its_region_when_its_art_paints_past_its_shapes
and a_knockout_group_spans_its_masks_when_an_element_paints_past_its_shapes
in crates/svg/tests/it/blend_export.rs.
2026-11-13 20:23:15 -08:00
ruchirguitar 05aef1f2c2 Merge remote-tracking branch 'origin/main' into pr-6613 2026-11-14 09:52:17 +05:30
dotCooCoo 90b053f480 i18n: Italian translates the messages no catalog had a row for
The untranslated report listed 167 status and error messages with no
row in any complete-message catalog, and 13 more that other catalogs
translate but Italian did not, so with the interface in Italian these
messages showed in English.

- it.tsv gains 114 `@msg` rows for the listed messages: image export
  and encoding errors, color profiles, color books and swatch exchange
  files, binary DXF and DWG import, 3D and Revolve limits, and script,
  zip and file errors.
- it.tsv gains 12 `@msg` rows for the Banner Hems and Grommets errors,
  three parameter checks and the failed recovery save.
- The rows sit in two commented blocks after the existing message rows.
- The 53 listed messages that open #7211, #7378 and #7405 translate
  (composite fonts, SVG filters, read roots and graph designs), and the
  justification order error that open #7116 translates, are left out,
  so no row is added twice.
- Placeholders, parameter names, command ids and literal values stay as
  the English writes them. The translations use the catalog's existing
  terms.
- docs/localization-parity.md and docs/target-app-parity.md give the
  Italian counts: 3,560 `@msg` and 48 `@msgplural` rows, 54 messages
  still listed.
2026-11-13 20:21:20 -08:00
dotCooCoo fb9d7208d5 Merge main into fix/ko-message-rows 2026-11-13 20:20:23 -08:00
dotCooCoo ea2391cbee Merge main into fix/hu-message-rows 2026-11-13 20:19:51 -08:00
dotCooCoo 6027126a1f Merge main into feat/trace-preset-defaults 2026-11-13 20:19:30 -08:00
dotCooCoo 155c2f722b Place: Placement Options clip a DCS image inside its file's clipping path
When links.update or links.relink re-read a DCS file and Placement
Options also clipped the image (Fill with Clip, or an aspect change
that overflows), the placement rectangle replaced the file's clipping
path, so plate art outside that path showed and printed.

The file's clip group now stays around the image and the placement's
clip goes in a clip group around it. The clip group holding just the
file's group takes that clip, as one holding just an image does today,
else a new one does, so later updates reuse the same two groups. A
file that loses its clipping path leaves its group as a plain group
inside the placement's clip. The same applies in symbols, graph
designs, patterns and opacity masks.
2026-11-13 20:18:35 -08:00
ruchirguitar 0ff98d0380 feat(layers): implement row context menu and actions
- Add right-click context menu on layer, group, and object rows:
  - Options... / Layer Options... / Options for Selection...
  - Duplicate <name> / Duplicate Selection
  - Delete <name> / Delete Selection
  - Lock Others / Unlock All Layers
  - Hide Others / Show All Layers
  - Locate Object
  - Collect for Export
- Select unselected row on right-click; preserve multiselection if already highlighted
- Dispatch actions via registered engine commands with Undo/Redo tracking
- Add headless egui tests covering selection, dispatch, and state integrity
- Update gaps and ui-parity documentation for G12
2026-11-14 09:47:46 +05:30
dotCooCoo f61c55876a Merge main into fix/ja-message-rows 2026-11-13 20:16:38 -08:00
dotCooCoo 5375b6e446 .ai save: images with a Warp count against the envelope limit
Opening an .ai file compares at most 256 envelopes and embedded images
with a Warp with their drawn art, from one budget. Saving the editing
data counted only envelopes, so a file with more than 256 of them in all
was saved with images past the budget written live and no warning, and
it opened with those images as their drawn look.

- The writer's budget now counts every image written with its Warp as
  well as every envelope, in the order they are written. An image past
  it is saved as its drawn look with a warning, and an envelope past it
  as its distorted art, as before.
- An image whose pixels can't be read is written as its gray outline,
  which the reader does not check, so it takes no part of the budget
  and keeps the warning about its pixels.
- The envelope warning names the shared budget.
2026-11-13 20:15:26 -08:00
dotCooCoo 9b2e21f6ca Live Paint: Merge keeps the visibility, opacity and blending of the parts it carries
Merge copied a face's or edge's appearance to the part it rebuilds in its
place, but not its visibility, opacity or blending mode. A half-transparent
face drawn by its stroke became opaque, and a hidden edge was shown again.
2026-11-13 20:14:37 -08:00
ruchirguitar 6f6746bd72 #6613: reconcile Gujarati catalog and complete current interface coverage 2026-11-14 09:44:24 +05:30
dotCooCoo b1cf6f810b PDF import: a knockout group in a form of its own opacity reads back as one group
PDF export writes a translucent knockout group as a form with its opacity around the /K group. PDF import now reads that pair back as one knockout group with the opacity, blend mode and isolation, instead of a translucent group holding a knockout group.
2026-11-13 20:13:02 -08:00
dotCooCoo 00de304ab0 Live Shapes: saved object.setLiveShape steps with a negative radius or out-of-range sides replay again
Since #7294, object.setLiveShape refuses a negative `radius` and a
`sides` that is not a whole number from 3 to 1000. Session::replay
applied the same checks, so a journal entry or action step recorded
before that change with such a value stopped with a parameter error.

On replay, a negative radius now counts as 0, which is how it drew
before. A whole side count below 3 or above 1000 is brought into that
range, and a fractional or negative one is ignored. Direct calls still
refuse these values.
2026-11-13 20:12:05 -08:00
dotCooCoo f0175cbdcb i18n: French leaves the read-root and graph design messages to their own pull request 2026-11-13 20:09:54 -08:00
dotCooCoo ec31808bf2 i18n: Spanish translates 114 messages that no catalog had a row for
The untranslated report lists 167 status and error messages that none
of the 23 complete-message catalogs translates. Spanish now has an @msg
row for 114 of them: the errors of the image encoders, color profiles,
swatch exchange files and color books, 3D and Revolve, path operations,
DXF import, the script engine and the parameter checks. Open #7211 and
#7378 add Spanish rows for 51 of the others, and 2 stay in English.

The rows keep their placeholders, backticked names, accepted values
(smallThumb, RGB, CMYK, Lab, Gray) and limits as the English writes
them. A test checks the Spanish shown for messages of each group.
2026-11-13 20:09:43 -08:00
dotCooCoo 877eb84f6d Graphs: an unchanged paint write keeps a series' kept gradient
A paint write that leaves a series mark's gradient as the graph drew it
now keeps the series' stored gradient and its unit-box flag in two more
cases:

- a mark with no width or no height, such as a column for a value of 0,
  where the stored gradient was replaced by the mark's gradient in
  document coordinates and no mark took it on the next redraw;
- a gradient kept in document coordinates (a file saved before the unit
  box), which a stroke weight written as it was moved to the unit box,
  so the next redraw placed it on each mark's own box.
2026-11-13 20:09:25 -08:00
dotCooCoo d47cbe5f77 3D: colored-light faces keep unplaced gradients fitted to the face
The color cover of a composed face grew past the underlay's seam, and a
source gradient without a placement fitted itself to that larger
rectangle. The face now pins such a gradient to its bounds grown by
1 pt, as before the cover grew. docs/three-d.md states the measured
limits of the 1:1 comparison.
2026-11-13 20:06:12 -08:00
dotCooCoo 991c36458a .ai import: an Art brushed path opens live only when its own settings would
A path's Art brush settings matched the brush's within a small tolerance, and only the brush's were checked. A path with a Spacing of 0.0005, or guides that leave no art between them, opened live with the brush's settings. The path's settings now pass the same checks as the brush's, and such a path keeps its drawn look.
2026-11-13 20:03:35 -08:00
dotCooCoo 85e0d59bfa Brushes: Scale Proportionately art grows with the stroke weight
An Art brush set to Scale Proportionately drew its art at the same size
on every stroke weight: the art was scaled across only by how much the
path stretched it along and by the brush's Width. Stretch to Fit Stroke
Length and Stretch Between Guides already multiply by the stroke weight.
Proportional art now does too, so a 3 pt stroke draws it three times as
wide as a 1 pt stroke, still as long as the path. The same applies to
each run with Overlap on and to a Width that follows the pen.

Existing Scale Proportionately art brush strokes at weights other than
1 pt draw scaled by the stroke weight. Strokes at 1 pt draw as before.
2026-11-13 20:00:01 -08:00
dotCooCoo be8fafde78 Type: justification spaces a right-to-left warichu block, and the caret keeps to its block line
A justified line opened no gap before a right-to-left warichu block: the
glyph drawn first after the text before it is not the block's first
glyph, and it was taken as continuing the block. The block now starts at
the first of its glyphs the line draws, and blocks the bidi order
interleaves keep their starts.

The caret next to a character of a block spanned the whole line. It now
spans the band of the character's block line, as the selection does.
2026-11-13 19:58:57 -08:00
dotCooCoo 1a01d591f3 Shapes: addon.shapes params text parses, and configure keeps omitted values
The ranges in the addon.shapes params text are in parentheses, so each
description reads as a params object. The configure description and
docs/mcp.md say that an omitted or null value keeps each shape's setting;
the defaults apply to the drawing commands only.
2026-11-13 19:56:50 -08:00
dotCooCoo 7c40cd2df2 Plug-ins: unlinking a gradient stop's spot swatch also clears its plates
A filter or importer that changes a gradient paint unlinks each stop from
its swatch and resets its tint, but left the stop's process plates. The
PDF and EPS writers read plates only with a spot swatch, so the stop kept
a plates array with no ink, saved with the document and compared in later
edits. Unlinking now clears the plates too, in fills and strokes; a paint
returned unchanged keeps its link, tint and plates.

The plate clamping test now checks the decoded output, before admission.
2026-11-13 19:56:38 -08:00
dotCooCoo 621f9b6287 Control bar: a bar too narrow for Document Setup still shows Preferences
With nothing selected, the Preferences button was drawn only after
Document Setup, so a bar with 90 to 111 points left showed neither,
although Preferences is 90 points wide and fits. The two buttons now
check the room left for each of them on their own.
2026-11-13 19:51:02 -08:00
dotCooCoo 6b54622e72 Type: a tabbed line that steps back ends at the latest break that fits as drawn
A glyph with a negative advance can draw a later break narrower than an
earlier one, so bisecting the breaks past the 256 measured one by one
could end a tabbed right-to-left line at an earlier break than the
latest that fits. Such a line now measures up to 1,024 breaks, or
hyphenation points, one by one before bisecting the rest.
2026-11-13 19:50:50 -08:00
dotCooCoo e9ae8b9661 Merge main into fix/ai-calligraphic-samples 2026-11-13 19:50:31 -08:00
dotCooCoo f643cddec4 Dimension tool: a reflected aligned dimension has its line on the reflected side
An unlinked aligned dimension that was reflected on its own kept its
offset, which is measured along the left normal of a to b. A reflection
turns that normal to the other side, so a line 30 pt above two level
points stayed 30 pt above them after a flip top to bottom instead of
going below them. The offset now changes sign when the transform
reverses orientation, as a reflection or a scale by a negative factor
does. Other transforms leave it as before, and linked, horizontal and
vertical dimensions keep their own rules.

Docs: docs/dimensions.md.
2026-11-13 19:48:30 -08:00
dotCooCoo 5f196fdfff Type: right-to-left tabbed lines are measured with their line-end trim where it is drawn
A right-to-left line draws its last character before its tabs. When that
character loses its Japanese-Latin space at the line's end, the layout drew
it narrower before placing the tabs, but measured the line with the full
advance and took the trim off afterwards. The measured line was narrower
than the drawn one by the trim: a right-aligned line ended past the
frame's right edge (305 pt in a 300 pt frame), and a line that did not fit
as drawn was kept whole.

drawn_width now takes the end trim off the glyph it belongs to, so the tabs
drawn after it take their stops from where it ends, both where lines break
and where a line is measured for alignment.
2026-11-13 19:47:46 -08:00
dotCooCoo 8f905c56be Merge main into fix/type-dialogs-story-wide 2026-11-13 19:45:37 -08:00