The new General preference Show Bounding Box While Moving and Drawing
(`boundingBoxWhileMovingAndDrawing`, off by default) keeps the bounding
box and its handles visible during two kinds of drag, with View › Show
Bounding Box on. While a drag moves the selection (a Selection tool
move, an Alt-drag copy, or a shape tool's move by the center point),
the box is drawn where the drag has moved the selection. The box is
measured once when the drag starts and offset by each step's move.
While the Rectangle, Rounded Rectangle, Ellipse, Polygon and Star tools
draw a shape, the box is drawn around the shape. A rotation and a
widget drag still hide the box until the release. The Line Segment
tool, the Pen, the Pencil and the Paintbrush draw no box.
With the preference off, the box hides during a move (#737, for #712)
and while a shape is drawn (#5839), as before. A Selection tool move
with Real-time Drawing off still moves the box with the pointer, and a
shape tool's move by the center point hides it in both modes.
With Real-time Drawing off, the box of a shape being drawn is measured
from the pending preview, in the color of the layer the shape goes on.
A shape being drawn shows no box until a preview step has succeeded,
so a failed preview does not show the box of the selection from before
the drag. The preference's label has a row in every catalog.
Session::deferred_move() is replaced by Session::move_drag_box(), which
returns the moved box, and Session::deferred_transform_box() now also
returns the layer color of the box.
Docs: docs/mcp.md, docs/target-app-parity.md.
file.new refused a side over 163,830 pt, while artboard.new took larger
artboards. Both now take each side more than 0 and at most 3,999,856 pt:
the 4,000,000 pt the canvas reaches from the origin, less a 72 pt bleed
on both sides. A side outside that range is refused with an error that
names the limit in points and, when the document's units are not points,
in those units, rounded down so the value shown is accepted.
artboard.new now refuses a supplied width or height of 0 or less instead
of making a 1 pt side, and refuses a size taken from a larger artboard.
Saved and Recent presets are read with sides up to the new limit.
Follows #6643.
The Width menu now offers Tilt, Bearing and Rotation beside Fixed and
Pressure, each with the second width. Tilt goes from Width with the pen
lying flat to the second width upright; Bearing and Rotation go from
Width at -180 degrees to the second width at 180 degrees, as Scatter
Brush Options' modes do. A stroke drawn without that input is half way
between the two widths. brush.options takes width_mode tilt, bearing
or rotation.
Gujarati text from a PDF came in jumbled even with its fonts installed:
- A glyph with no advance (a vowel sign or anusvara set over its letter)
was taken for vertical type and opened as an object of its own, which
type then drew on a dotted circle. In a font the file writes
horizontally it now stays on its line.
- A line read glyph by glyph is not always the text that was set: the
file draws a vowel sign before the consonant it follows, and may not
name a conjunct. A line with characters of U+0900 to U+0DFF is now set
again and its glyphs compared with the ink the file drew; when they
differ the line keeps the file's glyphs as outlines, with a note.
Tests: crates/pdf/src/tests/reshaped.rs (two fail without the change).
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.
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.
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.
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.