A filter run kept a second copy of every read-only object as JSON values.
The run now keeps where each object is in the input, and checks an output
entry against it by parsing that one object, unless the entry is `{"id": …}`
alone.
An image that reaches the decoder now counts toward the 16 MiB pixel total
even when decoding fails, so broken images use up the same total as images
that decode.
The plugin.run text, docs/mcp.md and the progress line state the paint
order and that rule, and docs/plugins.md states that a CMYK image's pixels
are sRGB. New tests cover the per-image 1 MiB, the 16 MiB pixel total and
the 16 MiB text total at and one past their values, memory-budget failures
before the plug-in starts, images that are not decoded, CMYK images
included, and leading per run.
The Tools panel docked only on the left (the window's edge, or beside the
canvas with Keep Tools Beside the Canvas). Dropped on the canvas's right
edge, just left of the panels, or anywhere along the window's right edge,
it now docks on the right, between the canvas and the panels: it is drawn
inside the canvas panel at its right edge, which reserves room for it, so it
follows the panels however they are arranged. Dragged back to the left it
docks there again; Escape puts it back on the side it came from.
- The side is kept with the preferences and in saved workspaces (built-in
workspaces and state saved without it dock it on the left).
- Tool flyouts and the Edit Toolbar drawer open toward the canvas from a
toolbar docked right (toolbar::room / toolbar::beside).
- window.panel.dock {panel: "tools", side?: left|right (or Start|End)},
default the side it docked at last; replies carry the side. The grip's tip
names both edges; translated in every catalog.
- Test: the_tools_panel_docks_on_the_right_left_of_the_panels.
When loading the plug-in store can't remove the grant of an id whose stored
module lists no permissions, or can't read grants.json, the entry stays on
disk and still approved the bytes it covers. plugin.install has the same case
when the grant can't be removed and no earlier module can be put back.
The session now keeps those ids and does not count their grants in
plugin.inspect, plugin.install, plugin.reload or a later load of the store. A
successful update of the grant for the id ends that, and so does attaching a
different store.
The fuzz test from #6223 passes grant to plugin.install, which a plain
session now refuses, so its cases stopped installing the module. The
docs line for a filter that lists inputs now says installing it needs a
person's approval.
Only a Stroke Style filter's widths written as one centered array come in as the drawn look. A Stroke Offset stroke and widths written for each side stay live with their profile.
Only a painted effect's references are checked, so a refusal recorded for a painted effect stayed in plugin.info after an effect that paints nothing replaced it under the same id.
The unread grants test replaces the plain module it installed earlier,
as plugin.install now asks. A grants file over 1 MiB approves nothing,
so the new module stays in the store.
plugin.install refuses grant from a request unless the session was started
to allow it, so the test from main that installs with grant turns that on.
The install dialog's comment names OK's Sense::click.