Preferences > User Interface > UI Scaling sets egui's zoom factor, and the
canvas mapped one document point to one of the interface's points at
100%. A document point then covered UI Scaling times as many device pixels,
so the art grew and shrank with the interface.
The canvas now maps the document at the view's zoom divided by the UI
zoom (View::screen_zoom, Xf::at). The rendered frame, the pointer, rulers,
grids, Fit and Actual Size, pan, scroll, zoom and turn about a point, the
Zoom tool's marquee, Pixel Preview's check, tiled panes, the Navigator's
view box and the tools' tolerances use that mapping. The zoom value means
the same at every UI Scaling, and the interface still follows UI Scaling.
fit_zoom, zoom_about, rotate_about, pan_pixels and scroll_by take the UI
zoom, and Xf::new is now test-only.
Found while looking into a report by bortek about the art's size at 100%.
In a gradient or a shaded area the palette colors on either side of a band
border differ by more than the image changes across it, so pixel noise
decided where the border ran, and it was smoothed over 0.5 px like a real
edge: borders wobbled, kept stair steps and took many anchors.
Each crack between two colors now records how much of the step between
them the image makes next to it and a few pixels further out, how much the
image changes there along the line between the two colors and in any
direction, and how much it changes within each side (RGB distances, 0 to
255 a channel). A piece of outline is the contour of a smooth area when its
cracks show less than half of the step; either more of it further out, a
change along the line under 12, or no opaque pixels further out; some change
within the sides, at least 1/32 of the change along the line; and a whole change
under twice the change along the line, or under 24. Such a piece is
smoothed over 4 px (a closed one over at most an eighth of its smaller
width or height), keeps no corners, is fitted to at least 0.5 px and is
checked against its smoothed points. The values are the same from either
side of the crack.
Grayscale reads each pixel as its gray, for this rule and for every edge's
sub-pixel shift, which compared the pixels' colors with gray palette
entries.
Color traces of clean flat-color art and Black and White traces are
unchanged. Specks rise by up to 0.8 per image on gradient and photo
inputs, and Auto Color with Shapes leaves a 0.3 px gap there.
Docs: docs/target-app-parity.md, docs/image-trace-quality.md.
Load Actions refuses an action set file over 8 MiB, with more than 1,000
actions, or with an action of more than 10,000 steps. Several ways of
changing a set could pass those limits, leaving a set that Save Actions
refuses to write.
- While an action records, a command (a batch and Find Objects that
selects included) whose step would give the action more than 10,000
steps or its set's file more than 8 MiB does not run, and the recording
goes on. A stop that playback reaches is left out then. A command whose
step grows past a limit only as it runs keeps its edit; the status bar
names the limit and Stop leaves the step out. Stop also leaves out any
recorded step still past a limit. Steps recorded after an exclusion
past an action's last step are included.
- An exclusion that would make the set's file larger than 8 MiB changes
no checkmark; one that keeps the size or shrinks it always works.
- Begin Recording, New Action, Duplicate, renaming an action, Action
Options, Set Options and New Set refuse a change that would give a set
more than 1,000 actions or a file larger than 8 MiB. A change that
leaves a set no further past a limit than it is now is allowed.
- Load Actions refuses a set, .aia sets included, that Save Actions would
write larger than 8 MiB (a file with less white space, or a set name
that gets a number added).
The limits are the existing ones from files.rs, and the errors reuse the
existing messages. docs/mcp.md and the commands' params text describe the
new errors.
With one object that Start Global Edit accepts selected with the Selection
tool, the canvas now highlights the other objects a start would take with the
current Global Edit Options, before Global Edit starts. The outlines are kept
per document revision and options, and none are shown during a drag.
Docs: docs/mcp.md (Global Edit), docs/gaps.md (G5).
The AppKit cursor delivery's evidence in docs/ui-parity.md and
docs/target-app-parity.md says the host sets its cursor again on every
pass while it owns it, so the tool's cursor stays when the pointer moves
(#6362). Status lines and history updated; scores and estimates
unchanged.
The AppKit cursor adapter set its cursor again only when
NSCursor.currentCursor differed from it. But that is the app's last set
cursor, not the one on screen: when the pointer moves, AppKit can put
the system arrow back while currentCursor still reads as ours, so the
adapter kept the arrow. Pressing V over the canvas showed the Selection
tool's arrow, and the first move replaced it with the system pointer.
While it owns the cursor, the adapter now sets it on every pass. That
costs nothing when it is already showing.
With Transform Objects off, a group's Transform effect scales the
strokes and moves the patterns of a member's linked mask as it does
the member's, instead of leaving the mask as it was.
- `charpath` in a CIDFont only named, over a predefined CMap, adds the
outlines of the characters its codes stand for, placed as `show` sets
them, and moves the point as `show` does. It added no outlines.
- `cshow` gives its procedure each code of such type, two bytes for a
two-byte code, with the code's width. It split two-byte codes into
single bytes.
- `glyphshow` sets the named character itself. It set the character's
UTF-8 bytes as Latin-1 letters.
- `kshow` runs its procedure between each two codes of such type, with
the two codes' values. It didn't run it. The procedure sees the font
the file set as current, and a font it sets stays current.
- A name that ends in the row-and-cell CMap `H` or `V` splits off the
CMap only when the file defines the CIDFont of that name (as a
resource or with `definefont`), or the name has a hyphen and an
installed face that covers Japanese has it. `Foo-Bold-H` stays a font
of the whole name.
- In a CMap that can't be read (`GBT-H`), each code moves the point one
em, along the line or down the column; a tab or carriage return byte
is a code of its own.
- One parser reads the names of the predefined Unicode CMaps, for EPS
and legacy `.ai` type.
- Outlines added to a path by `charpath` stop at the path's point limit.
- docs/file-format-parity.md, docs/gaps.md and docs/mcp.md describe type
in named CIDFonts over the predefined CMaps.
Single Word Justification's Full Justify counted and placed a gap after
every drawn glyph, so a combining mark or the vowel sign of a Devanagari
syllable moved away from its letter. Desired Letter Spacing and the
letter spacing range of a justified line did the same between two glyphs
of one cluster.
- The Full Justify gap count and placement share one check that skips
glyphs with the same cluster byte as the glyph drawn after them.
- Letter spacing goes after the last glyph of a cluster only.
- Letter spacing, Full Justify and CJK inter-character gaps pass over
every default-ignorable character drawn with no width (soft hyphens,
bidi marks, embeddings, overrides and isolates, joiners, word joiners,
variation selectors, tags, the byte order mark) and put the space
between the visible characters on either side. The Hangul fillers stay
letters.
- A zero-width space takes no word-space room on a justified line and
stays a line break opportunity. Letter spacing before it is set after
it, so a line broken there ends at its last letter.
- A single word that Full Justify spreads and that breaks at a hyphen
has the same gap before the drawn hyphen as between its letters.
- Kinsoku push-in counts the gaps it can close past format controls, as
the layout closes them.
Tests cover horizontal, right-to-left and vertical type, Desired and
fitted letter spacing, format controls, zero-width spaces, the drawn
hyphen, push-in, and a Devanagari syllable when a Devanagari face is
installed.
A linear, radial, conic or diamond gradient has a spread: Pad (the
default, as before), Repeat or Reflect, with a count of 1 to 100
(VectorCraft's own limit). Repeat and Reflect run the stops that many
times along the vector (around the turn for a conic) and keep going past
both ends, Reflect running every other run backwards, as SVG's
spreadMethod does.
The Gradient panel has a Spread menu and a Repeats field, and the
Gradient tool marks where the runs meet. paint.setFill and
paint.editGradient take `spread` and `repeats`; bad values are errors.
Presets, swatches, blends, strokes along or across a path, Outline
Stroke and Object › Expand follow the spread; Expand gives each run the
same whole number of objects, and Outline Stroke's mesh keeps the color
on each side of a sharp step between two stops at one offset.
SVG writes and reads spreadMethod: SVG import now reads a repeating or
reflecting gradient as one that repeats or reflects once, instead of
expanding its stops over the shape. CSS writes repeating gradients.
PDF writes a conic's sweep shading over one run. PDF, EPS, legacy .ai
and the .ai editing data write the other kinds with their stops
repeated across the shape: at most 256 runs and 16,384 stops (256 stops
in .ai files), and for a radial or diamond no farther than 65,536 runs
from its center, with a warning past those. PDF import now finds sharp
steps in any axial or radial shading instead of blurring them.
Docs: docs/mcp.md (Spread), docs/target-app-parity.md, docs/gaps.md.
The editing copy of a PDF-compatible .ai now holds the Brushes panel's
Calligraphic, Scatter and Art brushes in the panel's order, with the art
of Scatter and Art brushes. A path or compound path with a Calligraphic
brush, or with an Art brush in Tints whose art bends along the path,
keeps the brush on its stroke. Other brushed strokes are still written
as their brush's art.
The writer reads each brush back with the reader's code before writing
it. Brushes that would not come back with their settings, brushes past
the reader's limits and every brush on a large canvas are left out with
a warning. A brush that has the name of an earlier brush that was left
out is written, and no path is written with it on its stroke.
An object linked to a graphic style that is left out at the object
limit now also raises the warning about links left out.
Brushes and their options:
https://web.archive.org/web/20241230205225/https://helpx.adobe.com/illustrator/using/brushes.html
Docs: docs/file-format-parity.md.
egui spreads a wheel notch over the next frames. When a number field took
a notch and the pointer then left the field, the rest of that notch
scrolled the panel under the pointer, or a panel drawn before the field.
- A begin-pass plugin (`WheelTailPlugin`) keeps, per viewport, how much of
the notches number fields took egui has not let out yet, and takes what
egui lets out of them out of each pass's scrolling before any panel
scrolls.
- It reads each pass's wheel events in order with egui's touch rules
(start, end, cancel, and the timeout of a touch that never ends), so a
turn inside a touch, or one ended in the same pass, leaves nothing owed.
- A turn the other way on the panel while the rest runs out scrolls the
panel by its whole size.
The sweeps in command_sweep.rs kept their own list of file and folder
keys (path, diffPath, folder, destinationFolder) in testkit's
safe_value and again in the temp-folder test, so a command whose file
key was not on the list was sent raw junk strings, and a key written as
`{path | name ...}` (document.open) was never swept.
- The engine exports the plug-in call rules' file keys as
`cmd::key_location`, `cmd::location_in` and `cmd::location_keys`,
which read every key a params description names, the keys of the
commands its `...` entries name, and the schema. `diffPath` is a file
key, so a plug-in call that carries it is refused; Slice Options'
`url` and Export for Screens' `folders` name part of the document, so
a call to object.slice.options with a top-level `url` is accepted.
- testkit's `param_keys` reads the keys the engine reads, and
`junk_params_for_command` and `safe_value_for_command` send every
string under a file or folder key, in arrays and in objects inside
them, as a location in the sweep's temp folder. Each such key also
gets a list of paths and a list of `{ids, path}` objects.
- Every catalog sweep, the serializability sweep included, uses them,
and the temp-folder test checks every key the catalog names, at any
depth.
Type and live objects in the art of a linked opacity mask are outlined
and evaluated before a group's or layer's geometry effects run over it,
so the mask moves and bends with the art it masks. Before, the effects
reached only the paths in a mask's art.
- With Scale Strokes & Effects on, a Transform effect scales the strokes
of an image's or symbol instance's linked mask as it scales those of a
path's mask.
- A mask's art takes Transform copies in the form it had before the
first effect, as the art it masks does.
- A linked mask whose art is one image or symbol instance takes a
Transform effect's move and copies with the art it masks. Under any
other geometry effect, which images and symbol instances do not take,
art whose masks hold one keeps its shape.
- A symbol instance in perspective projects the linked masks in its art
with that art.
- A live-effect plug-in that paints its pieces leaves art with linked
masks as it is, since a mask can't take the pieces.
Docs: the docs/target-app-parity.md line moves next to the Transparency
entry and lists the cases where existing documents draw differently.
The merge of main kept main's calls to write_plan, which plan the save
with acknowledgeLoss set, so a save in the app no longer refused to
replace the file the document was read from when that file was one
written beside the path (an EPS artboard file). The save is planned
again without it before it is written, as before the merge.
The files a save writes beside the path still ask before replacing a
file that is there, except those the document's last save wrote. A new
test covers an EPS save with Use Artboards meeting artboard files from
another document: it asks, Cancel writes nothing, OK writes every file,
and the next Save does not ask.
The continuous-tone test asked whether 8 colors leave more than a tenth
of the error of one color. A gray picture's tones lie along one line,
where 8 colors come nearer to them, so some gray photos scored 0.078 to
0.093 and were traced as flat art, without the smoothing color photos
get. Their noise then mixed neighboring tones (a 16 Colors trace could
keep 10 or 12 colors) and stepped the edges.
A picture with at least 95% of its opaque pixels within 8 levels across
their channels now also counts as continuous tone when 8 colors leave
more than 0.065 of the error of one color, unless 16 colors leave at
most a fifth of the error of 8. These are VectorCraft's own values. The
exception keeps gray flat art of up to 16 clean levels on its old
route. Pictures with more than 5% of their opaque pixels outside that
8-level range are unchanged.
Anti-aliased or noisy gray flat art can now take the smoothed route as
well. Very noisy gray scans of flat art get fewer specks and staircase
edges; some gray illustrations and sketches get more anchors and
staircase edges at 16 Colors and High Fidelity Photo. Some 16 Colors
and High Fidelity Photo palettes of gray photos grow toward the
requested count, with more anchors and regions, and some 6 Colors
traces get more staircase edges.
The menu items that a pick or a shortcut reads are read once. Rows that
show a name that is user data (a custom toolbar under Window › Toolbars,
a script under File › Scripts, a recent file, a saved selection) are now
left out of them, as rows that list a plug-in already are, so a pick of
Show Toolbar no longer runs with the name of a toolbar that existed when
the items were read.
While a menu item is dimmed and the engine gives no reason (a UI
command, or an Appearance command with nothing targeted), a pick or a
shortcut now opens no dialog and shows "command `<id>` is not available
right now". The message has a row in every catalog that has the
engine's longer "not available right now" message.
Review feedback: with no tolerance, pen or trackpad jitter turned a tap
into a drag and the value was no longer selected. A release within 1 pt
of the press is a tap; anything further keeps the caret.
Regression test: a_tap_with_a_pixel_of_jitter_still_selects_all_on_release.
A shortcut given to Set Corners… (`addon.pathtools.cornerSet`) ran nothing,
on a single key or a chord. The keymap is built from the list in Edit ›
Keyboard Shortcuts, and that list left the command out. An engine command
without a menu path of its own was listed only when it had a default key,
or when it was an undoable command, not an alias, whose params doc ends
each field with `?`. A UI command was listed only when it had a default
key or a params doc of `{}` or `{path…}`, or was Rename. Set Corners…
needs a radius, so it was left out. The same rules left out other
commands that items of the menu bar run:
- View › Perspective Grid's Lock Grid, Lock Station Point, Show Rulers and
Snap to Grid, and Object › Perspective's Attach to Active Plane, Move
Plane to Match Object and Edit Text.
- Edit › Edit Custom Dictionary…, a query.
- UI commands: Recolor Artwork…, the Edit menu's four preset dialogs,
Apply SVG Filter…, Export As…, Export Selection…, Edit Original, Apply
Bullets, Apply Numbers, the four library saves, and the Window menu's
New Toolbar…, Double Column, Keep Tools Beside the Canvas, New
Workspace…, Float in Window and Consolidate All Windows.
Such a command is now listed when an item of the menu bar runs it as a key
press would: with no params, or with the one set of params all its items
give. `needs_a_value` already used this check, and it moves into
`a_menu_bar_item_runs` so that both use it. The command is listed in the
group named by the first part of its id, next to the commands of its
family that were listed before (Set Corners… under Addon with Corner
Tool, the grid toggles under Perspective).
File › Export Selection… was the row of `document.exportSelection`, which
no item of the menu bar runs. That row now runs `file.exportSelection`, as
the menu item does, and `document.exportSelection` is listed as Document ›
Export Selection…. A shortcut already given to it keeps running it. The
Window menu's Learn item gets no row, because the Learn panel's row
already has its name.
Tests: on F and on a chord, Set Corners…, Edit Custom Dictionary…, Recolor
Artwork…, the four preset dialogs and Apply SVG Filter… open the dialog a
click on their menu item opens. Snap to Grid turns off and on from F, and
Export Selection… on F opens Export for Screens. Every command the menu
bar runs this way is listed, none of them shares its group and label with
another entry, and a shortcut on four of them is kept through a saved
set's export and import. The other Object › Plug-ins dialogs, Select by
Link Status… and Composite Fonts… already opened from a shortcut and are
checked the same way.