Commit Graph
5870 Commits
Author SHA1 Message Date
BFlat 563f075764 Merge pull request #7707 from dotCooCoo/feat/opentype-hv-style-roman-italics
OpenType panel: H or V Style and Roman Italics set kana and Latin forms
2026-11-15 09:46:29 +07:00
BFlat 55c2bb5194 Merge pull request #7511 from dotCooCoo/fix/live-paint-make-drawn-rows
Live Paint: Make keeps every fill and stroke row that draws on the source
2026-11-15 09:46:20 +07:00
BFlat 3f90b8ff4c Merge pull request #7719 from dotCooCoo/fix/unit-parse-long-expression
Units: a very long expression reads as nothing instead of overflowing the stack
2026-11-15 09:46:13 +07:00
dotCooCoo f05d481247 Control bar: Select Similar Objects selects by the attribute its menu keeps
With something selected, the Control bar shows a Select Similar Objects
button and, beside it, the Select Similar Options menu. The button
selects the objects like the first selected one by the attribute kept
for the session; a menu item selects by its attribute and keeps it,
and the kept item is checked. The items are All, Fill Color, Fill &
Stroke, Stroke Color, Stroke Weight, Opacity, Blending Mode,
Appearance, Graphic Style, Shape and Symbol Instance.

- select.similar {by?} runs the select.same command of that name, or
  for "all" matches fill and stroke colors, stroke weight, opacity and
  blending mode together. An unknown by is an error that keeps the
  selection and the kept attribute. The journal records the attribute
  used, so a recorded action repeats it, and a failed script or plug-in
  call puts the kept attribute back.
- The button and menu belong to the Object Options group and sit at
  the right end of the bar, after the X, Y, W and H fields. They take
  only the room the other controls leave, so the bar leaves them out
  before any other control.
- The Paragraph tests' control_bar_node looks for a label before a
  value, so a link's text run listed first no longer stands in for
  the link.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-14 18:41:14 -08:00
dotCooCoo 1a4dd4f800 PDF export: limit the own-profile rule to destinations other than sRGB
An sRGB destination converts tagged gray and RGB images to sRGB even when the
document's own RGB profile is sRGB, so the statement that the document's own
profile as destination keeps tagged images applies only to other RGB profiles.
2026-11-14 18:39:38 -08:00
dotCooCoo 4887305f00 .ai import: files saved for version 11 take their type from the text document
Files saved for version 11 write the keys of their text document by name
(/DocumentResources, /FontSet, /StreamTag) and the kinds of its strikes
by their long names (/FrameStrike). The reader found no stories in them,
so their text objects were filled with the page's type in painting
order: type outside the artboards was lost, and type on them could land
in another text object.

The keys the reader uses now get their numbers from the dictionary they
sit in, from the root down, before the document is read. A run whose
style is written by name as a style's number takes that style. Files
saved for later versions that write a newer key by name among the
numbered ones (a font record's VersionString, a paragraph's
ParagraphDirection) have those keys read too.
2026-11-14 18:26:22 -08:00
dotCooCoo f55e42343e PDF export: state that the document's own RGB profile as destination keeps tagged images
With Convert to Destination and an RGB destination that is the document's
own RGB profile, RGB colors and RGB images keep their numbers, so an image
that carries an ICC profile keeps it. The export contract and progress line
now say so, and the test checks it.
2026-11-14 18:19:33 -08:00
dotCooCoo a20cf07fe3 Pattern Options: Move Tile with Art moves the tile with the pattern's art
Pattern Options gets the Move Tile with Art checkbox under Size Tile to
Art. With it on, a move of all of the tile art in pattern editing mode
moves the tile as far as the art moved, pixel-grid snapping included:
object.move, object.nudge, object.transform with a translation, and
drags with the Selection tool. A group counts as moved when each of its
members moved. A move of only
some of the art, a copy, a rotation, a scale and a move of
direct-selected anchors leave the tile where it is. The option is off
for a new pattern.

pattern.options takes moveTileWithArt and pattern.list reports it. A
pattern.options call that changes nothing no longer records an undo
step.
2026-11-14 18:19:17 -08:00
dotCooCoo 3cd57bca02 Merge feat/pdf-srgb-destination-converts-images into fix/pdf-image-profile-to-destination
# Conflicts:
#	crates/pdf/src/export/images.rs
#	crates/pdf/src/images.rs
#	docs/mcp.md
#	docs/target-app-parity.md
2026-11-14 18:11:47 -08:00
dotCooCoo 098e819a04 Place: Show Import Options asks for each file's import options or uses the last ones
The Place dialog gets a Show Import Options checkbox after Link, Template
and Replace. On (the default, saved with the preferences), each PDF, DXF
or text file asks for its import options before it is placed, also each
file of the place cursor when it is clicked or dragged. Off, each file is
placed with the options last confirmed for its format: the Text Import
Options, the DXF fit, lineweight, centering and layer choices, a PDF's
first page and crop box. An encrypted PDF still asks for its password.

file.place takes showImportOptions (true or false; anything else is an
error). Text Import Options now remembers its options and starts from
them.
2026-11-14 18:08:06 -08:00
ruchirguitar 61df62bdff Merge remote-tracking branch 'upstream/main' into feat/style-neon-glow
# Conflicts:
#	docs/gaps.md
#	docs/target-app-parity.md
2026-11-15 07:28:31 +05:30
dotCooCoo 18e5e393d2 PDF export: warn when a tagged image can't be decoded for sRGB conversion
With Convert to Destination and an sRGB destination, a gray or RGB image
with an ICC profile whose pixels can't be decoded (a header past the
decoding allowance) was kept with its profile and no warning. It now
reports that the image is not converted. When the image is left out of
the file as well, only the warning that it is missing is given.
2026-11-14 17:57:51 -08:00
dotCooCoo 3b788515d1 Import PDF: linked pages on their trim boxes keep the bleed between artboards
Linked pages on their trim boxes were spaced by the 36 pt gap alone, so
with a large bleed one page's bleed box reached into the next artboard
and a page export could show part of its neighbor. The artboards are
now laid out once the document's bleed is known, 36 pt apart plus the
bleed on both sides: the document's bleed, or a page's own bleed box
where it reaches farther.
2026-11-14 17:56:30 -08:00
dotCooCoo 4ec16519a4 Export: the HP-GL plot of the art's bounds places 9-slice and filtered symbol art before measuring
The art's bounds no longer clip art that 9-slice guides place, or refuse
art that an instance shows through a nested instance:

- An instance whose art goes through 9-slice guides, at any depth, is
  measured as its art placed through the guides, with the objects the
  plot leaves out hidden after placing. Leaving them out first changed
  the box the guides cut.
- Hidden art is not placed, so it does not use up the limit on placed
  objects that the visible instances share.
- The copy of a dynamic symbol that an instance's changes are measured
  on keeps the symbol's 9-slice guides and natural size.
- The changes of the instances in a dynamic symbol's art are collected
  from all of the art, also from objects at 0% opacity or without paint,
  which an instance of the symbol can change.
2026-11-14 17:52:29 -08:00
ruchirguitar 1ab2743f8e G5: resolve Tech Circuit documentation merge conflict
Merge current main and retain both the Pencil snapping documentation and Tech Circuit library evidence. Only docs/mcp.md required manual conflict resolution. Focused checks passed: no conflict markers or whitespace errors, all 28 catalogs retain four unique nonempty labels, and brush implementation/tests remain unchanged. No full local Cargo CI rerun.
2026-11-15 07:21:46 +05:30
dotCooCoo 5956076b9f PDF export: CMYK and other RGB destinations convert tagged images from their profile
With Output › Convert to Destination and a CMYK destination, or an RGB
destination other than sRGB that images are converted to, an RGB image
that carries an ICC profile had its numbers read as sRGB, so a Display
P3 image came out with the wrong colors. Such an image is now converted
from its profile to sRGB with the color settings' rendering intent, then
to the destination.

- An untagged image converts from sRGB as before.
- A gray image keeps its profile, as gray is not converted.
- A profile the color engine can't read leaves the numbers read as sRGB,
  with a warning.
- Preserve Numbers is unchanged.

docs/mcp.md, the document.exportPdf params text and the progress doc
describe the behavior.
2026-11-14 17:44:50 -08:00
dotCooCoo 0939157d12 3D and Materials: the Lighting tab's widget moves lights around the object
The panel's Lighting tab shows a sphere above the list of lights with
every light of the selected 3D effect at its Rotation and Height, filled
in front of the object and hollow behind it. Dragging a light moves it
on its side of the object, previewed while the pointer is down and one
undo step on release; a press selects it in the list. Move Light to Back
and Move Light to Front change the selected light's side. Each light
takes the keyboard focus, where the arrow keys move it (Shift steps
15 degrees), and screen readers name it with its settings. The widget
sends effect.setParams like the light settings below it.
2026-11-14 17:37:56 -08:00
BFlat 6016d6200f Merge pull request #7206 from dotCooCoo/fix/hindi-label-senses
i18n: Hindi labels use the interface sense of their English
2026-11-15 08:25:53 +07:00
BFlat 34ffc46cb5 Merge pull request #7687 from dotCooCoo/feat/links-copy-info
Links: Copy Info in the panel menu copies the selected links' file names
2026-11-15 08:25:44 +07:00
BFlat a53891b846 Merge pull request #7291 from dotCooCoo/feat/live-paint-bucket-multi-click
Live Paint: double-click floods across unstroked edges, triple-click paints the same paint
2026-11-15 08:25:35 +07:00
BFlat b63b99ba1a Merge pull request #7606 from dotCooCoo/fix/monitor-profile-after-blending
Canvas: translucent art blends with the paper before the monitor profile
2026-11-15 08:25:27 +07:00
BFlat d593b41961 Merge pull request #7691 from dotCooCoo/feat/variable-library-every-kind
Variables: Load and Save Variable Library hold visibility, image and graph variables
2026-11-15 08:24:45 +07:00
BFlat 61091515b3 Merge pull request #7624 from dotCooCoo/fix/cmyk-tiff-alpha-and-extra-sample
TIFF: alpha after another extra sample places and opens as transparency
2026-11-15 08:24:36 +07:00
BFlat 2331fd44fa Merge pull request #7680 from dotCooCoo/feat/radial-blur-center
Effects: Radial Blur turns about a Blur Center set in its dialog
2026-11-15 08:24:28 +07:00
BFlat 905eb30384 Merge pull request #7716 from dotCooCoo/fix/svg-import-budget-shared
SVG import: bound selector matching and share the limits with linked and embedded SVGs
2026-11-15 08:24:10 +07:00
BFlat 17dfe41a7e Merge pull request #7672 from dotCooCoo/fix/export-selection-doc-save-panel
MCP: docs say document.exportSelection with options and no path still asks for the file
2026-11-15 08:23:31 +07:00
BFlat 40d1fc913a Merge pull request #7702 from dotCooCoo/fix/reverse-compound-stroke-records
Paths: Reverse Path Direction turns a compound path's own stroke width profile and pen records
2026-11-15 08:23:22 +07:00
BFlat 410bb908ce Merge pull request #7695 from dotCooCoo/fix/issue-7275-rename
Fix #7275: Rename artboards in Export for Screens by double-clicking their names
2026-11-15 08:23:04 +07:00
dotCooCoo 6c585de940 Eraser: Angle, Roundness and Size vary with Random, Pressure, Tilt, Bearing or Rotation
Eraser Tool Options gives Angle, Roundness and Size each a variation menu
(Fixed, Random, Pressure, Tilt, Bearing, Rotation) and a Variation field.
path.eraseRegion takes angleMode, roundnessMode and sizeMode with their
variations, sweeps a varying tip as a Calligraphic nib with what the pen
read along the drag, and refuses an unknown mode or a variation out of
range. The Eraser records the pen's pressure, tilt and rotation when a
mode follows them, and its tip outline at the pointer takes the angle,
roundness and size the pen gives while it erases.
2026-11-14 17:08:14 -08:00
dotCooCoo a3ac628576 .ai import: symbol instances in older files are read, so art outside the artboard opens
Files saved for versions 10 to 13 place each symbol instance with a
TransformMatrix. On the page it takes the symbol's art to the canvas
(y down); in a symbol's art, it takes the art to that symbol's space. The
reader only knew the RTransformMatrix of newer files, so any such
instance made the editing data unreadable, and the file opened from its
PDF part alone, which holds only the art on the artboards.

The reader now converts a TransformMatrix with the canvas point of art
space's origin that the template box gives. A file whose symbol
instances were the only part it could not read now opens from its
layers, with the art outside its artboards.

The symbols fuzz test also damages the same data in the older form.

Docs: docs/target-app-parity.md, docs/file-format-parity.md.
2026-11-14 17:03:22 -08:00
dotCooCoo 7d205368e8 PDF export: Convert to Destination converts tagged images to sRGB
With Output > Convert to Destination and an sRGB destination, a gray or
RGB image that carries an ICC profile (a Display P3 TIFF, a PNG or JPEG
with an embedded profile) is converted from that profile to sRGB with
the color settings' rendering intent and written without the profile.
Before, it kept its own numbers and profile.

- A 16-bit image that is not resampled or recompressed stays at 16 bits
  a sample from PDF 1.5 on.
- A JPEG kept as JPEG whose samples the conversion leaves unchanged (an
  sRGB profile) keeps its JPEG data; other JPEGs are encoded again.
- A black-and-white image whose converted levels are gray is compressed
  as grayscale.
- A profile the color engine can't read is kept, with a warning.
- Without conversion, and with Preserve Numbers, images keep their
  profile as before.

IccProfile::to_srgb_pixels converts a run of pixels in one pass.
Docs: docs/mcp.md, document.exportPdf params, target-app-parity.
2026-11-14 16:59:18 -08:00
dotCooCoo e6bfe40d30 Import PDF: linked .ai pages open on their trim boxes with the bleed
With linkPages and cropTo: crop, a PDF-compatible .ai opened on its crop
boxes, while opening it as art uses its trim boxes. It now uses the trim
boxes too. A page on its trim box shows its bleed box round the
artboard, and the pages' bleed (the widest on each side) becomes the
document's bleed, as the importer sets it.
2026-11-14 16:42:06 -08:00
dotCooCoo cc7d081198 Import PDF: linked pages read the file once and keep blank pages
linkPages read and checked the whole PDF again for every page it
linked. The pages are now read from the file opened once. With
cropTo: bounding, a blank page stopped the open with "has no art to
place"; it now gets its crop box, as opening the page as art does.
2026-11-14 16:42:05 -08:00
dotCooCoo 0f8b20c489 Type: glyph forms and width forms follow the OpenType rules
- A form other than the default, set with text.setRangeStyle or
  text.setFormat, takes away the characters' glyph choice, which would
  otherwise keep drawing its own glyph. "default" keeps it.
- With a width form (fwid, hwid, twid, qwid), shaping leaves out palt and
  turns kern and apkn off, and SVG output writes font-kerning: none and no
  palt, as the OpenType feature list asks. proportionalMetrics and kerning
  keep their values.
- The Glyphs panel menu counts a width form as available when a face has
  the feature in GSUB or GPOS.
- At a caret, the menu's check marks and its no-op check read all the
  text of the object, which is what the command formats. Choosing the
  current form again is not skipped when a character has a glyph choice.
2026-11-14 16:39:01 -08:00
dotCooCoo 8cba5fae0c Merge main into fix/live-paint-make-drawn-rows 2026-11-14 16:37:54 -08:00
dotCooCoo c7aa27ec12 Transform: saved Scale and Reflect steps without a basis keep the page's axes
An action or journal entry recorded before Scale and Reflect followed the
turned bounding box has no basis value. Replayed, such a step now acts along
the page's axes, as it did when it was recorded; steps recorded now carry
basis "box" and replay along the box. The built-in Reflect Horizontal action
names basis "box", so it keeps reflecting across the box's own axis.

The symbol test that reflects a turned instance names basis "page", which
is the reflection it was written for.
2026-11-14 16:30:56 -08:00
dotCooCoo eff1500bd2 Object: a Distribute submenu runs the Align panel's distribute buttons
Object › Distribute follows Object › Align and lists Horizontal
Distribute Left, Center and Right, Vertical Distribute Top, Center and
Bottom, Horizontal Distribute Space and Vertical Distribute Space. Each
item runs the button's `align.distribute*` command, so it uses Align To,
the key object and the Distribute Spacing value, and with the Artboard
tool chosen it spaces the selected artboards.
2026-11-14 16:28:19 -08:00
dotCooCoo 8dfbe54db6 Units: a very long expression reads as nothing instead of overflowing the stack
Unit::parse took one level of recursion per + - * / sign, so a text such
as "1+1+...+1" with 200,000 terms overflowed the stack and aborted the
process. Every number field, parse_number and every command parameter read
as a length went through it.

Text with more than 128 + - * / signs now reads as nothing; text with 128
or fewer reads as before. docs/mcp.md states the limit for length strings.
The test a_very_long_expression_reads_as_nothing aborted with a stack
overflow before the change.
2026-11-14 16:26:09 -08:00
dotCooCoo 2d790aab20 Merge main into fix/graph-design-art-aligned-rows 2026-11-14 16:21:34 -08:00
dotCooCoo d0f1346f87 Docs: record the PSD clipping path in the PSB row and the evidence list
The PSB row of docs/file-format-parity.md says the merged image comes in
clipped by the file's clipping path, as the PSD row does, and
docs/target-app-parity.md's evidence list gets a line for it.
2026-11-14 16:20:16 -08:00
dotCooCoo 89f20c45c4 SVG import: bound selector matching and share the limits with linked and embedded SVGs
The measurement that runs before the style cascade and usvg now covers
the inputs that still got past it:

- usvg matches a selector without keeping what it found, so one whose
  leftmost part matches nothing tests every set of ancestors in turn.
  The measurement counts those tests for each copy and stops at
  50,000,000; past that the SVG is refused with "the SVG's style sheets
  take too long to match". An SVG image's matching stops at what the
  SVG showing it left.
- A test counts one more for every 16 attributes a lookup scans and
  every 16 bytes of the value it compares, so many classes against a
  long class list count the work they do, in usvg's matching and in
  the import's own cascade.
- The declarations the import's own cascade keeps, once per element,
  count toward the 64 MB, including those of `:not()` rules, which usvg
  drops. Each `:not()` alternative counts as a test.
- A linked SVG file is measured before its cascade runs. The linked SVG
  files share one measurement: once they pass the limits together, the
  files after that are shown without their links. The tests a file past
  the limits made still count.
- SVG images share the element limit and the selector tests with the
  SVG showing them, as they already shared the 64 MB.

The svg_filters reader measures its SVG before the cascade too.
2026-11-14 16:10:10 -08:00
dotCooCoo af010b6dec PSD: a file's clipping path clips its merged image on Open and Place
A PSD or PSB file can name one of its saved paths (image resources 2000
to 2997) as its clipping path in resource 2999. psdread::clipping_path
reads that path in the image's pixel space, under the even-odd rule the
file format specification gives, with a subpath around the whole image
first when the initial fill record says the fill starts with all
pixels.

File > Place of such a file, and File > Open of its merged image, put
the image in a clip group of that path with no paint. file.place answers
the image's id as `image`, as for a DCS file. Replacing an image alone
in a clip group with such a file keeps the image's scale and rotation.
links.update and links.relink leave the clip group as it is. Files that
name no clipping path come in as before.
2026-11-14 15:55:34 -08:00
dotCooCoo 67fd1cd127 Merge main into feat/live-paint-bucket-multi-click 2026-11-14 15:48:45 -08:00
dotCooCoo 403023f834 Effects: Rough Pastels loads its texture from an image file
The Rough Pastels dialog has a Load Texture… button, as Glass and
Texturizer have. The image's gray levels become the paper surface,
stored with the effect as `textureImage` and listed as Loaded Texture
in the Texture menu; Scaling, Relief, Light Direction and Invert act on
it as on the built-in surfaces. The dialog's Texture and Light
Direction controls are now menus instead of text fields.

effect.apply and effect.setParams read `textureImage` from a file or
take the stored string and refuse anything else, and a plug-in filter
cannot have the host read a file for it.

In the Effect Gallery's Settings, a file dialog that answers later
(the macOS sheet, the Linux dialog) now gives the texture to the values
that asked: the filter being browsed, or the stack row that asked,
found by a number each row now carries. An answer for a removed row, a
filter no longer browsed or a gallery that closed is dropped.

Params text, docs/mcp.md, docs/control-protocol.md, docs/gaps.md and
the evidence line are updated.
2026-11-14 15:45:59 -08:00
dotCooCoo 094971e3ac Type on a path: type on an open path can start before the path
Type on an open path can now start before the path's start: its start
is stored below 0, the span runs from there, and the characters whose
middle falls before the path's start are not drawn, as SVG 2 lays out
text on a path (https://www.w3.org/TR/SVG2/text.html#TextLayoutPath).
The text keeps every character, and the start bracket stays at the
path's start. Past the path's end, text that does not fit is overflow,
as for other type on a path. Type that starts on the path draws every
glyph as before.

- SVG import keeps a <textPath> start before an open path's start
  (text-anchor end or middle, or a negative startOffset) instead of
  starting the text at the path's start, which drew every character.
- SVG export writes it as a negative startOffset.
- PDF export writes only the characters drawn on the path.
- The legacy .ai and .ai editing data writers write the type from the
  path's start with the type attributes warning.
- type.pathOptions takes a start below 0 for type on an open path; on a
  closed path it is the path's start, as before. A flip starts the type
  at its start bracket. Dragging the center bracket slides it from where
  it starts, and no further before the path.
- A click at the path's start places the caret by the first drawn
  character, and the caret in the hidden characters stands at the
  path's start. The highlight of substituted fonts and glyphs leaves
  them out.
- Release Type on a Path keeps the first drawn glyph where it was
  drawn, with the hidden characters before it.
- The Touch Type tool shows no box for a hidden character, and
  text.touchType returns an error for one. A character with a drawn
  glyph is changed by that glyph.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-14 15:44:12 -08:00
dotCooCoo 828817c4b2 Scripts: File › Scripts runs the text its check read, with includes from the checked folder
The menu item checked a listed script and then ran script.run by its path,
which opened the file again; a link put in place of the file or a folder on
its path in between could make it run a file the check never saw, and the
include folder was looked up from the path again as well.

script.run takes installed: true. With a path it reads the file once through
script::folder::read, runs that text, and reads #include and $.evalFile in the
Scripts folder's real path followed by the names that read found. The menu
item runs script.run {path, installed: true}.
2026-11-14 15:37:18 -08:00
dotCooCoo d91e6a8565 Merge main into feat/opentype-hv-style-roman-italics 2026-11-14 15:24:42 -08:00
dotCooCoo 0431809643 OpenType panel: H or V Style and Roman Italics set kana and Latin forms
With Show East Asian Options on, the OpenType panel menu has H or V
Style and Roman Italics. H or V Style is the character feature tag
`hkna`: kana take the forms the font draws for horizontal type, and in
vertical type the shaper applies `vkna` in its place. Roman Italics is
`ital`, the font's italic half-width alphanumerics. Both are on or off
only (`hkna=2` is refused), set through `features` and
`featureChanges`, cleared by Reset OpenType Features, and are switches
in Character Style Options > OpenType Features.

Docs: docs/mcp.md, docs/type-parity.md, docs/target-app-parity.md.
2026-11-14 15:22:36 -08:00
dotCooCoo 2b9325b9e0 Merge main into feat/links-copy-info 2026-11-14 15:21:36 -08:00
dotCooCoo dba42af495 Merge main into feat/ai-save-graph-records 2026-11-14 15:21:09 -08:00