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.
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).
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.
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.
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 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 client confined by --automation-read-root saw paths outside its read
roots that the person or an earlier request had put in the session:
- plugin.list: the plug-in folder last loaded and its failed files;
plugin.list and plugin.info: a plug-in's source file; plugin.list,
plugin.safeMode and plugin.setEnabled: the file of a plug-in turned
off for the next launch.
- file.recovery.list and file.recovery.restore: a document's original
file; file.recovery.list and file.recovery.save: the recovery folder.
- ui.inspect's scriptReport: the files a run wrote and the included
file a failed run stopped in.
A folder outside the read roots is now null, and a file outside them is
named by its file name. plugin.setEnabled {file} takes that name. The
restored documents keep their files, and unconfined clients and the
app's own UI see the same replies as before.
object.objectsOnPath.selectMember and object.objectsOnPath.moveMember
change only the document and its selection, as the other Objects on
Path commands do, so both join the commands a plug-in may call when its
manifest lists them.