Asset.data becomes AssetData (embedded bytes or a linked length, each
under a process-unique SourceKey), with the link_relative, link_hash,
storage and proxy fields. AlphaOutline names its source by SourceKey.
Dedup in assets.rs compares embedded bytes as before.
- A request turned away as recently decoded schedules its wake only for the
first decode of that image, level and epoch: a view larger than the cache
(or more failed images than are remembered) no longer decodes every 2 s.
- A worker that takes a job while a wake is scheduled hands the timed wait on.
- A full decode drawn at level 0 from the cache leaves the zoom-in list.
- Pixels decoded under colour settings changed since are not cached.
- Shadows and glows drawn while an image in them decodes are not kept.
The content-grabber ghost and the place-gun thumbnail take their proxy
with mip_now: a level not cached yet decodes in the background and they
draw another cached level, or the outline, meanwhile. A stand-in texture
is drawn again when the image generation advances.
Pages panel thumbnails render with defer_images, so they no longer run
warm on the UI thread or wait at the decode gate. A thumbnail that drew
images still decoding renders again once more have finished, at most
every 250 ms.
- A panic anywhere in a background job, sizing and the wait at the gate
included, marks the image bad. A guard takes the job off the busy
list however it ends, and a thread that ends is counted out so
another starts.
- Background decodes reserve their bytes where mip chooses the decode:
the reduced JPEG estimate before a reduced decode (a JPEG without one
goes to the full decode), the full peak before a full decode, nothing
when a cached level is halved.
- A request turned away as recently decoded schedules one generation
advance for when its window has passed, so its stand-in doesn't stay
until the view changes. Emptying the cache (new colour settings,
clear) starts a new epoch, and decodes into the old cache no longer
count as recent.
- At most two full decodes are kept for zooming in; a newer one evicts
the oldest.
- warm's planning runs under catch_unwind; a panic skips warming.
- Renderer::images_pending says whether the last render drew an image
still decoding.
Regression tests use a test-only fault hook that panics inside the job
and inside warm's planning.
The canvas renders with RenderOptions::defer_images and keeps the image
generation each texture was rendered at. Finished background decodes
are taken up at most every 250 ms and not while a render is in flight,
so a page of photos decoding one after another re-renders a few times
instead of once per photo, and a newer request doesn't drop the render
in flight before it is shown. The eyedropper still decodes the image it
samples.
Based on #2051 by texjer.
The image cache kept the full-resolution level 0 of every TIFF, PNG,
PSD and CMYK JPEG, and of any image shown at High Quality: about 48 MB
for a 12 MP photo, so after a dozen photos every edit evicted and
decoded them again on the render thread.
- mip keeps only the level drawn. It remembers each asset's full size
(from its header, then from a decode), builds a coarser level from a
finer cached one, and tries the reduced JPEG decode before a full one.
When an image is zoomed into (a finer level asked for while a coarser
one is cached) it keeps the full decode too, up to 96 MB, so the
following steps halve it instead of decoding again.
- With RenderOptions::defer_images (the canvas) the image draw uses
mip_now: a level that isn't cached is decoded on one of three
background threads, newest request first, and a coarser cached level
or a light box is drawn meanwhile. images::generation advances and
the waker runs when a decode finishes. A decoder panic marks the
image bad. Background decodes reserve their peak bytes at the same
gate as warm, so they wait while decodes in flight hold half the
budget.
- An image asked for again within 2 s of its decode (evicted at once:
the view holds more than the cache) isn't decoded again until then,
in place or in the background, so the canvas never decodes on its
own thread.
- warm counts an asset as cached when the level each drawing takes, or
a finer one, is cached, and sizes a job by the levels it keeps. It
leaves a decode larger than the whole budget to the render, and the
canvas skips it.
- A render that deferred an image isn't kept as the CMYK view snapshot.
Based on #2051 by texjer.
The image cache keys decodes by the bytes' address, so a variant rebuilt
as a new Arc misses the decodes it already has. With decodes in the
background, more variants on screen than the variant cache kept would
decode and re-render without end. Variants are now looked up weakly,
with the 64 most recent held strongly.
Based on #2051 by texjer.
The IDML story writer skipped the endnote reference character, so an
exported body story lost every endnote's place: "an endnote here. End."
with nothing between "here" and the full stop. The endnote frame's
story was written with its numbers as text, so nothing linked the
listed endnote back to where it was referenced.
Each reference is now written as its own superscript character range
holding the endnote's number, formatted by Endnote Options (start,
style, prefix and suffix) as the endnote frame lists it. IDML's
Endnote / EndnoteRange elements are not written yet.
The Text Frame Options dialog filled its fields from the document's
ruler unit but never set the dialog's own unit, so it stayed at picas.
The spinner fields (Top, Bottom, Left, Right, a non-rectangular frame's
Inset, the column width and gutter, Paragraph Spacing Limit) showed
their values in picas whatever Preferences > Units & Increments said,
and a bare number typed in any measure field, Min under First Baseline
included, was read as picas.
The dialog now takes the document's horizontal ruler unit when it opens
and keeps it while open, as the Rectangle dialog does (#1964).
Fixes#2742.
Make UiState::hidden_panels session-only (#[serde(skip)]) and clear hidden_panels when opening or revealing panels, toggling the Control bar while hidden, or loading/resetting workspaces. Treat hidden panels and flyouts as not visible in checked/toggle checks so Window commands unhide them instead of toggling them off invisibly.
* Tools: snap Gap tool drags to active snapping settings (#2637)
* Tools: reject unreachable Gap tool snap targets beyond resize clamp
* Tools: preserve raw Gap tool delta when no reachable snap matches
* Text Frame Options: every dropdown and field has an accessible name
The Columns and Align dropdowns on the General tab, and the dropdowns and
text fields on the Column Rules, Baseline Options and Auto-Size tabs, had
no accessible name, so a screen reader announced them without a caption
and kittest's accessibility check failed on the dialog. Each one now takes
the caption shown next to it. The non-rectangular frame test runs with the
check on and opens every tab.
* Text Frame Options: numeric fields take their captions as names
The Number, Width, Gutter, Maximum, inset and Paragraph Spacing Limit
fields on the General tab were named by their internal ids, so a screen
reader announced tfo_columnWidth and its spinner read as Increase
tfo_columnWidth. Each field and its spinner buttons now take the caption
shown beside it.
* Text Frame Options: test the numeric editors' accessible names
The test checked only the spinner buttons' names. It now also finds each
numeric editor of the General tab (Number, Width, Gutter, Maximum, Paragraph
Spacing Limit, the four sides and Inset) by the text-input role and its
caption.