Emit clipped `<image href>` for fills with a registered media URL instead
of Skia base64 embeds. Register URLs from the frontend and exporter via
store_image_url. Cover rect, path, frame, and text (glyph clip) cases in
SVG export tests.
Closes#11383
* ✨ Export solid inner and outer strokes to WASM SVG
SkSVGDevice drops save_layer+Clear used for path Outer strokes, so
solid Inner/Outer strokes on closed shapes are expanded to filled
outlines via stroke_to_path. Center and open paths stay on the shared
stroke path.
Closes#11381
* ✨ Export dotted, dashed, and mixed strokes to WASM SVG
PathEffects do not survive SkSVGDevice, so dotted/dashed/mixed strokes
expand via stroke_to_path with the effect kept, producing filled
outline geometry for all alignments including Center.
Closes#11382
* 🐛 Fix WASM SVG stroke export edge cases
Keep expanded stroke outlines in local space under the leaf CTM so
rotated rects/paths are not double-transformed; overlay open-path caps
after dotted expansion; draw frame strokes outside the content clip;
and route per-side rect/frame strokes through the evenodd band path.
* ♻️ 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.
Shapes and text with stacked solid fills were exported without fill
attributes because merge_fills builds a Skia shader that SkSVGDevice
does not serialize. Draw each fill layer separately for SVG export,
bottom to top, matching the classic exporter.
Closes#11466
* ✨ Add text and @font-face to WASM SVG export
Emit selectable <text> elements and inject @font-face rules that
reference the font URLs registered at load time. Text fill bypasses
save_layer wrappers that SkSVGDevice drops. Text strokes are deferred
to a follow-up PR.
* 🐛 Strip trailing commas from Skia SVG text positions
Skia's SVG backend appends a trailing comma to per-glyph x/y lists.
Firefox rejects the malformed attribute and drops glyph positioning,
making exported text vanish or mis-render.
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.
HQ tiles are 512px and the atlas stays at 4096² (64 full-size
slots). Browser zoom plus a forced ?dpr= can need more visible
tiles than that, and a framebuffer larger than the GPU allows.
Pack interest tiles into smaller atlas cells, blit at 512 then
scale, and inset Linear samples so seams do not bleed. Clamp the
canvas backing store and DPR together, wrap Skia at the real
drawingBuffer size, and wait one frame after DPR changes so CSS
client size and overlays stay aligned.
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.
Release packs far more cheap Current draws (e.g. fills_none paths)
into one Partial than debug; a single end-of-Partial
flush_and_submit then stalls the browser. Soft-flush every N walker
nodes (and on Partial yield) keeps ops buffers bounded while Full
still submits via present_frame.
* ✨ Add headless wasm render backend to the exporter
* ♻️ Move render-wasm bridge to common and split wasm builds
* 🔧 Upload builtin font variants in the wasm exporter
* ♻️ Move shared font and resources utils out of render_wasm
* ⚡ Fetch only the exported roots in the wasm exporter
* ⚡ Bound save_layer rects in the vector export path
* ⚡ Skip drop shadows that are imperceptible at current scale
Filter drop shadows by on-screen footprint (stricter for recursive
shapes) so overview HQ avoids expensive blur passes that barely show.
* ⚡ Simplify Path and Bool strokes at low scale
At overview zooms, Inner/Outer strokes fall back to Center and
dash/dotted styles become solid when the pattern is subpixel.
Strokes are never skipped so stroke-only icons stay visible.
* ⚡ Drain GPU work on partial render frames
Partial frames only flushed the Backbuffer, so tile GPU commands
queued until present_frame's flush_and_submit and stalled the
browser on large files. Submit the context each partial frame
without presenting Target or re-composing the tile atlas.
* ⚡ Prefer direct painting when effects are imperceptible
Skip the Fills/Strokes layered path when drop/inner shadows would
not paint at the current scale, and allow stroke-only shapes
(fills_none) on the direct path. Apply the same footprint LOD to
inner-shadow painting.
Marking intermediate surfaces dirty after clearing them on tile
context switch made the first stack composite blit empty
Fills/Strokes/shadows into Current. Dirty means content to
composite, so clear the flags after the clear instead.
Copy Current into DocAtlas and the tile atlas with Surface::draw
instead of image_snapshot_with_bounds, matching the interactive
path and removing a GPU sync stall on every completed tile.
* 🔧 Support background blur on PDF render for strokes and text shapes
* ✨ Add LRU eviction to the wasm image store
* ✨ Add RasterFormat to encode png, jpeg and webp from wasm
* 🐛 Fix client-side wasm export encoding jpeg and webp as png
* ✨ Remove guides from svg overlay
* 🎉 Draw guides in wasm
* 🎉 Serialize guides to wasm
* ✨ Store separate and sorted horizontal and vertical guides
* 🎉 Implement collision detection with guides
* 🎉 Right click on guides to change color or remove
* ✨ Implement dragging guides
* 🎉 Edit wasm guides by double clicking them
* 🎉 Implement changing mouse cursor on hovering a guide
* ✨ Show guide pill on hover
* 🎉 Implement removing guide on hovering + Del
* 🔧 Fix lint + fmt errors
* 🎉 Clip out outer board guide lines
* ♻️ Extract common code into guide-pill* component
* 🎉 Draw dotted lines on hovering board guides
* 🐛 Fix board rotation when it has guides
* 🎉 Make foreign guides not visible in focus mode