Changing Preferences › Hyphenation › Exceptions bumped each open
document's revision, but the caches of laid-out type outside the text
crate were keyed on the font generation alone. The renderer kept the
glyph geometry, raster-effect pixels, live-effect and envelope art,
pattern tiles and placed symbol art of unchanged type objects, so
hyphenated area type kept its old line breaks on the canvas. The
hit-test art of blends and envelopes, the Fit to Artwork Bounds answer,
the layout caches of the Type and Touch Type tools and the out port's
overflow mark were keyed the same way.
vectorcraft_text::layout_inputs() returns a number that changes with
the fonts and with the hyphenation exceptions. Every one of those
caches now keys on it instead of FontDb::generation(), and envelope ink
uses it in place of the private envelope_ink_inputs(). The hit-test key
hashes it together with the plug-in revision.
Tests: a renderer that drew hyphenated area type, alone, with a drop
shadow, in a group with a Transform effect, in a symbol instance and in
an envelope, draws it as a new renderer does after the exceptions
change; the out port of selected area type shows the overflow that the
new exceptions cause. The render test helpers that run a step again
when the fonts change during it now also run it again when the
exceptions change.
With repeated names numbered when a brush library is read, a stroke that
names a repeated brush draws the first brush of that name, and a later
brush of the name is read as "Name 2". Three tests built a library with a
repeated name and expected the later brush:
- Document Info lists a name two stored brushes share with the first
brush's type (art), not the last one's.
- The two render memory tests add their own `Dots` scatter brush beside
the default library's `Dots`. They now remove the default `Dots` first,
so the stroke draws their brush.
- The .ai writer test that leaves out a Pattern brush "X" gets the
Calligraphic brush after it back as "X 2", the name it had in the
document.
A group's or layer's geometry effects now run after its members' own:
the geometry effects of each visible path and compound path in it and
of their fills and strokes, and a nested group's geometry and
Pathfinder effects, are applied first, at any depth, and the group's
effects reshape the result. A symbol instance's geometry effects run
after those of its symbol's members in the same way. Before, the group
reshaped the members' outlines and their own effects ran afterwards:
a 100 pt square with its own 10 pt Offset Path in a group with a 50%
Transform drew 70 pt wide, and it now draws 60 pt wide. Existing
documents with such groups draw differently.
The canvas, export (including groups that keep their type), Expand
Appearance and the art that Pathfinder operations and compound shapes
take from such a group use the same order. The reply of
effect.expandAppearance names such a group and no longer names the
members whose effects the group's art already holds.
The renderer now drops the art it keeps for a group when a plug-in is
installed or removed and a member of the group has a plug-in effect.
Docs: docs/target-app-parity.md. Not yet: the own geometry effects of
images, symbol instances, paths with a linked opacity mask or a 3D
effect, and nested groups with a 3D effect in a group still run after
the group's.
Each of the fifteen Warp styles now bends the bounds as one Bézier patch.
The style sets the patch's control points from the bend and the size of
the bounds, the horizontal distortion scales each column of control
points about its middle, and the vertical distortion scales each row.
The Warp effects and warp envelopes share the map (`WarpNet`). Content
with no width or no height takes the middle of the patch along that
side.
A warp carries the map it draws with as `version`. New warps, the
built-in graphic styles' Warps and warps opened from .ai files get 1.
Warps in .vectorcraft documents saved before the version existed read
as 0 and keep the earlier map, so those documents keep their look.
Edits keep a warp's version, and Warp Options editing several objects
keeps each one's own. effect.apply, effect.setParams and the warp
envelope commands take `version` 0 or 1 (`1.0` counts as 1) and refuse
any other value. An .ai file holds a warp's settings and not its
version, so a version 0 warp saved to .ai opens again with version 1.
The .ai writer compares a style's settings without the version, so
saved warps still export as editable effects.
Docs: docs/mcp.md (Envelopes), docs/effects-parity.md (Warp),
docs/target-app-parity.md.
The canvas key did not change when a plug-in was installed, replaced or
removed, so the canvas kept showing the frame drawn with the old plug-in,
and a pan by whole pixels copied that frame's pixels next to strips drawn
with the new one.
The key now carries the plug-in revision of the last install or removal
after which the document draws a plug-in effect, in its layers, in a
symbol's or pattern's art, or in a brush's art. The canvas looks through a
document once after each install or removal; a document without a plug-in
effect keeps its key.
From about 50% zoom on the file of #4155, the pixels drawn are the full 141-megapixel photo,
and in a CMYK document they were separated into ink planes (or colorized, or proofed) whole
for every view: 8 to 9 s of white canvas a zoom step.
When the pixels drawn are larger than a 1,024-pixel tile, their colours are made again for the
frame and part of them is out of view, only the tiles in view are made, each kept under its own
key (`ImageKey::tile`), and drawn together as one pixmap so their edges don't show. The colours
are made pixel by pixel, so the result is the same as for the whole image. CMYK images painting
their own inks are still made whole.
Zooming in to 50%, 100% and 200% on that file went from 9.0, 8.6 and 8.7 s to 0.78, 0.05 and
0.05 s (M3 Pro, one run each), with the same pixels on screen.
With image mips on (the canvas, navigator and layer thumbnails), an image was colorized,
separated into the frame's ink plane and shown through Separations Preview's plates at its
full size, and only then shrunk to the mip drawn. The 141-megapixel image of #4155 made
1.6 GB of planes a frame, more than the image store holds, so every frame made them again.
The mip is now picked first and everything else is made from it, under the keys `kept_mip`
and `nearest_kept` already look up. A CMYK image's own inks are halved with its pixels
(`ink::key_inks`, `images::half_inks`), so it still paints them rather than inks separated
from its displayed colours. Colour bitmap glyphs follow the same order.
On that file the app's first frame went from 9.2 s to 1.6 s and the sharp frame after a pan
from 3.9 s to 8 ms (M3 Pro, one run each). Fine detail now shows its true average: 1-pixel
black and white lines show mid grey, where separating first showed them 44 levels darker.
A compound path was assembled from its members in every frame it was
drawn, and Node::stroke_path grew its buffer by doubling, copying the
path into ever larger buffers for a compound path of many anchors. The
renderer's geometry cache was swept only once it held more than 1,024
entries, so while an object was dragged (a new node, and layer, in
every frame) the old copies stayed alive with all their members.
Now:
- a compound path is drawn from the path the renderer keeps for it in
its geometry cache, as a plain path already was, and is assembled
only when the node changes;
- Node::stroke_path sizes a compound path's buffer up front from its
members' segment counts (the same elements, in the same order);
- unused geometry entries are dropped after a few frames however few
entries there are.
Tests:
- crates/render/src/tests/memory.rs: the second frame draws the kept
path and the same pixels as the first and as a new renderer; after a
five-frame move the renderer no longer holds the compound path drawn
before it. The test fails without the renderer change.
- crates/doc/src/node/tests.rs: a compound path's path is its members'
paths in order (open, closed, empty and single-anchor members).
Not timed; vectorcraft-cli perf was not rerun.