* ♻️ Share text layout paragraphs across modifier clones
Store Skia paragraphs in Rc so TextContentLayout::clone keeps the
cached layout for rotate/pan modifiers. Add layout.clear() and treat
needs_update as paragraphs-empty only.
* ⚡ Reuse cached Skia paragraphs when painting text
Add try_paint_from_layout_cache to paint from TextContent.layout when
versions match, skipping ParagraphBuilder rebuild and layout on each
frame. Wire into the layered text path for plain fills without strokes
or effects.
* ⚡ Paint plain text directly onto Current
Extend can_render_directly for stroke-free text and skip the empty
save_layer in draw_text when no stroke-group opacity is set. Plain text
paints into Current without the Fills/Strokes blit.
those textures across zoom for progressive previews, and invalidate
by old∪new document coverage so rotate/move edits do not leave
stale fragments on zoom-out.
Present visible tiles via ViewportReady so zoom settle turns sharp
without waiting on the interest ring, and paint at atlas slot size so
DPR 2 does not rasterize 1024 only to downscale into 512 slots.
Add a direct container-geometry path for eligible frames: inline blur
when the kernel fits the tile margin, otherwise a cached filter-surface
pass reused across tiles via DropShadowFilterCache on both the direct
and slow render_shape paths.
Move frame shadow logic into shadows.rs. Fix nested/clipped frame
shadows by deferring parent clip to composite time, apply negative
spread via inset, and allow rotated/transformed frames on the direct
path. Skip descendant extrect walks for clipped frames when only
nested drop shadows matter, and skip child silhouettes when the
container fill already covers shadow descendants.
Avoid an offscreen buffer per Fill::Image during tile walks: only use
save_layer when a shape image filter is present; axis-aligned rects and
frames without corner radii also skip the redundant container clip.