A glass layer's coverage, distance field and normals depend only on its
outline and the zoom. A shape asked for again in a later render (the
next frame of a drag, a slider drag, a canvas patch, an export of the
same view) is now worked out whole, in its own pixel frame (translation
reduced to its fraction, in 1/65536 px with carry), and kept: renders
reuse it instead of redoing the distance transform and normals for
their crop.
A shape asked for only once (each step of a zoom, a pane dragged by
fractions of a pixel, a resize) is still worked out for just the part
shown, so those don't get slower: working out the whole pane when only
a corner is in view cost 1.8x before this rule.
The cache is bounded in bytes (128 MB, 32 MB on the web), keeps the
least recently used last, skips shapes over 4M px (1M on the web), and
parallel bands share one computation (OnceLock slot). Renders count
once per render_view / render_view_single; bands don't.
Output: digests of 30 renders (5 looks, square and rounded, scales 1,
1.37, 2) are identical to main; a cut through a rounded pane now equals
the whole render exactly.
Release timings (glass_render_timings, 2400 × 1600 px, min of 5):
canvas drag under the glass 49.5 → 26.5 ms, glass slider drag
104.8 → 61.6 ms, same view again 94.8 → 54.0 ms; zoom 105.0 → 93.7 ms
(no reuse: each zoom is new).
Refs #256
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
page.duplicate copies every layer with duplicate_all_into (navigation between
copied frames points at the copies) and builds the old-to-new list for flows
from that copy, instead of copying each layer separately.
Main's case-insensitive replace loop (from an earlier PR) took the place of the
loop this change edited, so the replacement text is normalised once, where
the parameter is read.
Czech counts take three integer forms: one (1), few (2-4) and other
(0 and 5+). Since #257 catalogs can supply `few`, so `plural()` gets a
Czech rule and the 38 plural entries in cs.toml now read naturally
("1 vrstva", "3 vrstvy", "5 vrstev") instead of the count-neutral
"Vrstvy: {n}" that #469 used for everything but 1.
Test czech_integer_plurals covers the rule (1; 2-4; 0, 5, 11, 12, 21,
22, 100, 1 000 000), a real key through counted(), and that every Czech
plural entry has one and few. Docs no longer say Czech has only one/other.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The control server answered a line that wasn't JSON with an error and read
on. A web page can make the browser send an HTTP request to the loopback
port; its request and header lines were skipped that way and the JSON lines
of its body ran as commands. The first line that isn't JSON now closes the
connection before anything after it is read. Clients that send JSON lines
(MCP --attach, scripts) are unaffected.