A pattern's definition (in either form) and a brush's art were read
without the file's art styles, so an object there with a style came in
as the look it draws, with a "drawn look" note, while the same object on
a layer or in a symbol came in as itself with its effects live. The
three definition readers now take the art styles as the symbol reader
does, and an object in a pattern's art with a style in the file's style
list keeps that graphic style's id.
An art styles section inside a symbol's, a pattern's or a brush's art
is now skipped, so it no longer replaces the file's own art styles.
The editing-data writer wrote a run's key 35 only for Tate-chu-yoko (3).
Type with Standard Vertical Roman Alignment, on or off, was saved with no
key, so the setting was lost from the editing data. Every run now carries
key 35 in the form the reader reads it (crates/eps/src/import/ate.rs,
Texts::style, lines 669-670): 1 when the setting is on, 2 when it is off
and 3 for Tate-chu-yoko. The document's defaults and the normal character
style carry 1.
Key 35 holds one value, so a run with both Tate-chu-yoko and the setting
is written as Tate-chu-yoko, and the save reports the type attributes
warning for it.
- writer/texts.rs: baseline_direction() gives each run's value;
normal_char() writes 1; loses() and TYPE_ATTRIBUTES name the setting.
- tests.rs: a vertical and a horizontal object with the setting on, off
and Tate-chu-yoko come back the same through the reader, lay out as
before, and carry the expected keys; a run with both is reported.
- docs/file-format-parity.md: the .ai save section lists the written
values.
swatch.new stored a gradient or pattern as it was given. A gradient
swatch made from a gradient swatch by name, from a fill linked to one,
or from a gradient that names one (the Gradient panel's add to
swatches) kept the link to that swatch, so copying art that uses the
new swatch brought the other swatch along too. A pattern swatch made
from a current fill picked up from art with transformed tiles kept
that transform, and art the swatch was applied to took it in place of
its own.
The new swatch now drops the gradient's link and stores the pattern
untransformed. A gradient swatch keeps its aspect as before.
The editing-data reader set the paint of each gradient swatch in the
palette to link to the swatch's own name. The default gradient swatches
and a gradient swatch given a new gradient with swatch.edit hold their
gradient without a link, so a document saved as .ai and opened again
had swatches that differed from the ones it was saved with. The swatch
now holds the gradient alone. Art filled with the gradient is not
changed: it still links to a swatch by the gradient's name.
The fix also applies to a .ai whose layers are not read, such as a
gradient library, where only the palette comes in.
Three tests cover a hand-written palette with a gradient swatch named
by its gradient and one with a name of its own, a new document's four
gradient swatches written by the editing-data writer and read back, and
a gradient library without layers.
dialogs::tests::workspace_and_toolbar_dialogs_end_at_their_buttons now
requires the gap between OK and the bottom of the window to be 0 to 40 pt,
so an OK drawn past the window's bottom edge fails. It requires exactly one
OK inside the window, and in New Workspace and New Toolbar exactly one
Cancel on OK's row to its left; the two Manage dialogs have no Cancel. It
also requires the gap between OK and the nearest shape drawn above it to be
under 40 pt.
The modern type reader read key 35 of a character style only for
Tate-chu-yoko (3). A run whose key 35 is 1 (Standard), in the run, its
character style or the document's defaults, now opens with Standard
Vertical Roman Alignment on, so its half-width characters stand upright
in vertical type. Horizontal type keeps the mark with no change to its
layout. A value of 2 (rotated), 3, any other value and no key at all
leave it off, VectorCraft's default.
- ate.rs: Style reads the flag and passes it to CharStyle, with a unit
test over defaults, character styles, run overrides and bad values.
- tests_native.rs: a vertical and a horizontal story with Standard,
rotated and unset runs; the test of values the reader ignores also
checks the flag.
- import_fuzz.rs: the vertical fixture also checks the flag.
- docs/file-format-parity.md: one line on the mapping.
Escape and Cmd+Enter (Ctrl+Enter on Windows and Linux) end text editing
and switch back to the tool that double-clicked into the type, or to the
Selection tool when there was none (`TypeTool::end_editing`). The
evidence lines in docs/type-parity.md, docs/ui-parity.md and
docs/target-app-parity.md, and the doc comments on `prev_tool` and
`claims_key`, said they always switch to the Selection tool.
The legacy .ai writer gives the type attributes warning when a text
object loses something it cannot hold. It did not give it for several
attributes that it does not write:
- Align to Path set to Ascender, Descender or Center.
- An end bracket before the end of an open path, or short of once
around a closed path. A legacy text path holds the path and the start
point only (AI7 File Format Specification, section 15).
- Manual kerning other than 0, which is written as kerning off, and
optical kerning.
- Optical Margin Alignment, System Layout and fractional widths off.
- A second subpath in an area type frame or a type path. The writer
writes the first subpath only.
The warning now names each of these.
SVG viewers center each <textPath> glyph on its midpoint on the path and
turn it to follow the path, which is how the Rainbow effect draws. Type on
a path with any other effect and no spacing was written as a plain
<textPath>, so a viewer drew it as Rainbow. It is now written as outlines
with a warning, as type with an end bracket, Align to Path or Spacing
already is.
Docs: docs/mcp.md, docs/target-app-parity.md.
The drawer opens and closes before the strip and the toolbar, so the
test fails when the palette windows were already hidden, and opens again
at the end. The test checks the floating strip is the Pen group's and
the custom toolbar is Mine, shown.
The hidden-toolbar test now expects exactly one show command when the
flyout stops drawing, and the comment at palette_window_levels names
the All Tools drawer.
The baked Transform and Free Distort tests now compare each placed
gradient's start, end, aspect and focal point with the expected values
within a tolerance, and the Transform test adds a turn with a scale.
A gradient placed with the Gradient tool stayed where it was when the
object's Transform or Free Distort effect moved, turned or scaled the
outline, so the shape slid across its own gradient.
The Transform effect now maps placed gradients by its own transform,
and each of its copies takes them as many times as it takes the
transform. Under Free Distort, each path's placed gradients move and
scale from the path's bounds before the effect to its bounds after it.
This change does not alter gradients fitted to the object.
The canvas, Expand Appearance and export, Pathfinder and compound
shapes, groups, a fill's or stroke's own effects, and Object › Expand
of a gradient fill apply the same rule. In a group, the own fills and
strokes of the group, of the groups inside it and of a symbol's art
follow it too, and images and symbol instances that a group's
Transform effect moves take the placed gradients of their own fills
and strokes along. A group whose path keeps its shape because the
effect would pass the geometry budget keeps its own gradients in
place.
This changes how existing documents draw: a gradient placed on a path,
or on an image's or symbol instance's own fill, inside a group with a
Transform effect now moves with it. Before, only the gradients of type
moved (#2214).
How gradients follow each effect is VectorCraft's own rule. The
Distort & Transform help page describes what the effects do to the
object:
https://helpx.adobe.com/illustrator/desktop/manage-objects/reshape-transform-objects/distort-and-transform-effects-in-illustrator.html
Moves the bulk memory case types, strategies and their test after arb_paint, so they no longer share the lines after output where other fuzz generators are added.
plugin_fuzz now builds plug-ins whose run executes memory.fill,
memory.copy (overlapping ranges included), memory.init followed by
data.drop, and data.drop followed by memory.init. Lengths and offsets
are sampled at zero, small, page and mebibyte sizes, at an exact end,
one before and one past it, with copy sources and destinations and init
memory and segment offsets chosen separately. Fill and copy can repeat
up to about one fuel slice of copying.
Each case runs directly under the default budget, a small fixed budget
or one near its estimated cost. A run must trap exactly when a range
leaves memory or the data segment (empty once dropped), and must finish
when it is in bounds and has ample fuel; otherwise it may hit the
instruction budget. The same plug-in then runs through plugin.run: a
failed run leaves the document unchanged and the document still renders
and exports.
bulk_memory_cases_reach_their_instruction checks that each operation's
module contains its instruction and traps on a small out-of-bounds case.
A top object's corner test treats a straight segment as having its
handles a third of the way along it, so an anchor between two straight
segments is a corner only when it turns out of the outline. docs/mcp.md
and the doc comment now say so, and a new test covers an inward anchor
between straight segments. The bulging-curve corner test checks against
a fixed point instead of the same nearest-point routine the code uses.
Saved corners from an .ai file stay on the same anchors when the
envelope is reflected, as they already did when it was moved or
rotated. A reflected outline runs counter-clockwise; the corners were
then mapped as if the outline had been drawn the other way round, no
longer fit it, and were found again from the outline.
On a tie between two corner anchors, or two nearest outline points,
the one met first along the outline in the order it was drawn wins,
for outlines drawn counter-clockwise too.
The docs state the corner rule in full: a handle 0.01 pt long or
shorter makes an anchor a corner whichever way it turns; otherwise its
tangent unit vectors must differ by 0.01 or more in x or y and turn
out of the outline. Content spreads evenly along a segment without
handles.
A top-object envelope splits its outline into four sides at four corners
and maps the content onto the Coons patch of those sides. The sides
shared out the content by length, and the corners were the anchors or
curve points nearest the bounding box corners.
Each piece of a side between anchors and corners now takes a share of the
content's width or height in proportion to the length of its control
polygon, spread along the piece by its curve parameter. A straight
segment spreads it evenly by length. A rounded rectangle stays close to
the identity, and the content follows the curves of a side whose segments
differ in size.
Each corner is now the nearest anchor to its bounding box corner among
the sharp anchors that point out of the outline and lie within 47.5% of
the box's width and height from that corner. A handle shorter than
0.01 pt, or tangent unit vectors that differ by 0.01 or more in x or y,
makes an anchor sharp, and the first one along the outline wins a tie.
Without such an anchor, the corner is the outline's nearest point to the
box corner, moved onto the end anchor of its segment within 0.5% of the
segment's parameter. Envelopes opened from .ai files keep the corners the
file saves.
These are VectorCraft's own rules. Existing top-object envelopes redraw by
them. Gradient meshes made from a path keep their sides measured by length.
- crates/doc/src/live/mesh.rs: Coons::from_top_object and the corner
search, used for top-object envelopes.
- EnvelopeKind::TopObject gains an optional `corners` field (anchor
indices); the .ai importer fills it from the mesh's corners.
- Params text of object.envelope.makeWithTopObject, docs/mcp.md
(Envelopes) and a progress line in docs/target-app-parity.md.
Closing a document told the worker to forget every row whose document was
not open at that moment. The worker keeps that test until it is idle, so
while a job still ran, a document opened afterward had its rows dropped
and they stayed without thumbnails. The worker now forgets only the
documents that closed.
Proportional Metrics changes an upright glyph's cell on a vertical path, and its width runs along that changed cell. Its font ligature carets were still divided by the unchanged cell, so the caret, a click and the selection missed the drawn stop. They now divide the same length the width uses.
In vertical type on a path, every glyph was turned a quarter turn with
its top toward the path's end. An upright glyph's characters then read
backwards along the path, so a ligature's font caret other than its
middle did not line up with the glyph as drawn.
An upright glyph whose top faces the path's end now turns half a turn
about the centre of its cell, so its top faces the path's start. It
keeps the same stretch of the path. Glyphs lying on their side, and
upright glyphs that the Skew, 3D Ribbon and Stair Step effects already
turn this way on a path running to the left, are unchanged. The ligature
stops follow the top of the cell, so the caret, a click and the
selection meet the drawn caret line.
File › Open and File › Place read HEIC and HEIF still images (.heic,
.heif) through heic-rs 0.1.4, the pure-Rust decoder photocraft-heif
uses, and store the pixels as PNG. Single pictures and grids of tiles,
8 to 10 bits, with or without an alpha image, are read with the
container's rotation, mirror and crop applied. A grid without a color
box of its own takes its tiles'. When neither the image nor its tiles
have an nclx box, the HEVC stream's video signal type gives the
samples' matrix and range. An RGB ICC profile, or Display P3 with the
sRGB curve named by an nclx box or, without a color box, by the
stream, is converted to sRGB. The EXIF resolution tags size the image;
without them it is 72 ppi. When the container's rotations turn the
image an odd number of quarter turns, the resolution's axes swap with
the pixels'.
Image sequences, images that aren't HEVC-coded, grids of cropped tiles
and images past the pixel allowance are refused with a message before
the pixels are decoded. The allowance counts each coded picture at the
size its sequence parameter sets give it.
The decoder is in the engine's `heif` feature, which is on by default
and listed by the desktop, CLI and web apps. A build without it still
recognizes the files and refuses them with a message.
window.toolsBesideCanvas reads on with opt_bool, which treats null like an omitted value. docs/mcp.md and the params text now say that an omitted or null on toggles the setting and that any other non-boolean value is an error.
Docked Tools stays at the window's left edge again, outside any panels
docked on the left. Window › Toolbars › Keep Tools Beside the Canvas
(`window.toolsBesideCanvas {on?}`) docks it between those panels and the
canvas instead.
- The setting is its own field in the UI state and in workspaces, and a
missing field reads as off, so saved state and workspaces keep Tools at
the window's edge. Built-in workspaces have it off.
- Off, app.rs draws docked Tools before the docking layout, the canvas
reserves no width for it, and only the full-height window-edge strip
docks a floating Tools panel. On, the canvas panel draws it, the canvas
keeps room for it, and both the window edge and the canvas edge dock it
beside the canvas.
- Turning the setting off forgets the canvas-edge strip, so a strip laid
out while it was on does not dock Tools. A floating Tools panel stays
floating when the setting changes.
- `window.panel.dock {panel: "tools"}` docks Tools where the setting says.
- The menu label has a row in every catalog.
Docs: docs/mcp.md, docs/control-protocol.md, the ROADMAP progress log and
docs/target-app-parity.md. The headline-numbers row and the paragraphs
under the status lines are gone, and scores are unchanged.