paint_pattern draws the tile content as a tree of its own on a fresh tile, so the
plain-clip state inherited from an enclosing group must not apply there: an inner
clip that blends against the tile was drawn as a plain clip and lost its backdrop.
Save and clear SurfaceBudget::plain around the tile draw, as apply_soft_mask does.
Upstream gained region-limited coverage, clip regions, a group nesting cap
in the PDF builder and a render budget. The clipping fast paths (canvas-covering
clips drawn without a surface, plain clip groups on region-sized surfaces) are
ported onto those; the crop-based shape/image/paint changes and the PDF
builder depth cap are superseded by upstream's.
* fix(svg): support static SVG patterns
* fix(svg): cache patterns per viewport
* fix(svg): share cached pattern content
* fix(svg): harden pattern cache keys
* fix(svg): harden pattern inheritance and caching
* Preserve SVG pattern fallback paint
* Format SVG pattern fallback conversion
* Harden SVG pattern resource bounds
* Fix SVG pattern test formatting
* fix(svg): bound hostile path and raster work
* Bound SVG ellipse expansion
* fix(ui-egui): suppress clippy warnings on wasm target
Rename unused `frame` parameter to `_frame` in draw_inner since
pointer_wrap::finish_native is cfg'd out on wasm32. Guard State::disabled
field with #[cfg(any(not(target_arch = "wasm32"), test))] so it only
exists where it's read (finish_frame on native + tests).
* fix: resolve clippy warnings blocking CI
- Rename unused `frame` parameter to `_frame` in draw_inner (wasm target)
- Guard State::disabled field with cfg(native + test) (wasm target)
- Replace chunks_exact(2) with as_chunks::<2>() in SVG polyline/polygon parsing
* fix(svg): budget raster work by affected region and report refusals
Address review on #2732: the finite-work guards charged the whole canvas,
dropping valid sparse art (8x8 image scaled to 1px on 2049x2049, 2x2 rect
under a 1,028-element clip on 512x512, one of six 2x2 rects sharing a 1x1
pattern on 3840x2160).
- Build fill/stroke/image/clip coverage over the device region only and
charge that region; remaining whole-canvas passes are charged to a
render-wide pixel budget (caps are not raised).
- Add try_rasterize/try_rasterize_with returning RasterError; rasterize
keeps its signature. media layered decode now surfaces refusals.
- Pattern content reached through href inherits styles from the owning
pattern; device_region falls back to the full canvas on non-finite input.
- Document new items and the limits in the svg README; regression tests.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
* SVG: bound tessellation, kept geometry, attributes, entity expansion and re-rendering
Circles and rounded rects flattened at a fixed 0.01 tolerance, so a huge
radius made unbounded curves; the tolerance now grows with the radius as
arcs already did. Every path a <use> copies and every gradient reference's
stops were parsed and kept without a document-wide limit; both now share a
budget of 8 million items. An element with thousands of attributes made
the XML parser's duplicate check quadratic, and repeated entity references
could expand attribute text to gigabytes below the node limit; a preflight
refuses more than 1,024 attributes per element and entity references that
expand past 64 MiB. Nested knockout and non-isolated groups re-rendered
their children several times per level; node draws are now held to 64 per
node of the tree.
* address review: entity_bytes takes the largest declaration of each name
* address review: drop tessellation-tolerance, attribute-count and entity-size refusals; keep retained and draw budgets, warn when the draw budget is hit
Continuously rasterised vector footage (an A4 PDF scaled 200-400 %) is a page of
millions of pixels, and the rasteriser did page-sized work per element:
- Every path, run of text and image computed and walked a coverage mask the size of
the whole page. Coverage and paint now run over the pixels the shape (fill, or stroke
outline) or image can reach. A generated A4 page of 720 text-run paths and 60 strokes
rasterises at 300 % in 0.18 s instead of 4.97 s (200 %: 0.13 s instead of 2.44 s), with
the same pixels.
- Every clipping group copied the whole backdrop and drew on a second page-size surface,
so deeply nested clips ran past the 512 MB surface budget and their artwork was dropped
(at 200 % from the eighth level, at 400 % from the second). A plain clipping group (no
soft mask, blend mode, group opacity or knockout, Normal content throughout) is now drawn
straight onto the page when every clip is an axis-aligned rectangle covering each pixel
the content can reach, and otherwise on a surface the size of its clip. Both give the
same pixels; groups with a blend mode or knockout inside keep the backdrop path.
Never crash: drawing stops below 256 levels of groups, and the PDF/EPS builder keeps groups
at most 200 deep (a crafted page nesting `q ... W n` twenty thousand deep overflowed the
stack when the document was drawn or dropped).
The 596 x 842 px import size of an A4 page is unchanged: the page in points at 72 dpi,
rounded up, as After Effects takes a point as a pixel.
Refs #2895
A few kilobytes of internal entities expanded to millions of nodes (each top-level
reference stays under roxmltree's per-reference cap), so a 1 MB file exhausted memory.
SVG keeps DTDs, which Illustrator's exports use for entities, but caps the expanded
document at 4 million nodes. Final Cut Pro XML and FCPXML, which FilmCraft parses
without a node limit, are refused when they declare an entity; real exports never do.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found while testing crates/svg/src/lib.rs:510-520 (parse_css)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The WGSL grammar test scanner indexed token characters directly, so a malformed shader could panic the test instead of failing it. Checked access turns that into a reported violation.
Every selector of a comma list cloned the whole declaration block, and every
element scanned every rule, so a sub-megabyte <style> could demand billions of
string pairs. Selectors now index one shared block, the sheets are capped at
20 000 selectors and 50 000 declarations, rules are bucketed by id/class/type
so an element checks only candidates, and matching work over all elements is
charged against a 50M-step budget that fails the import instead of doing it.
The PDF / Illustrator import dialog now offers Composition - Retain Layer
Sizes. Each file layer's footage is cropped to its artwork bounds (fills,
stroke outlines, images, clips) and positioned to keep its place on the
page. Decoding, continuous rasterisation, shape conversion and reload share
one crop (effectcraft_pdf::layer_doc_with_sizes), so they agree.
Also collapses a match guard in the STL reader for current stable clippy.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Depth-limited <use> expansion still let a few kilobytes of branching
references expand to 2^N elements. The parser now counts every element it
converts, <use> copies included, against a budget of max(500 000, twice the
file's own elements) and fails the import with Error::Xml once it is spent.
Targets currently being expanded are tracked, so mutual references stop at
the first repeat instead of nesting to the depth limit.
Fixes#1236
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N9kwMcw2pYQ5fSjKa3ZPnh
roxmltree recurses per element and overflowed a 2 MiB stack at a few thousand nested
elements (aborting the app). parse() now scans the element depth first and returns
Error::Xml beyond 256 levels.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Path data like "M0 0 L10 0 Z9" repeated Z implicitly for the stray number; Z consumes no
numbers, so the parser looped forever appending close-paths until memory ran out (a 1-byte
change to a valid SVG used 24 GB and was killed). A number after Z is a syntax error, so
parsing now stops there and keeps what was read, as the spec asks. Also denies the panic lints
in the crate (it had no panic sites).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Text with embedded TrueType, CFF (Type1C / CIDFontType0C / OpenType), Type 1 and Type 3 fonts,
standard-14 fallback to the bundled OFL fonts; Flate / DCT / inline / stencil images with SMask,
Indexed and ICC alternates; luminosity / alpha soft masks and the 16 blend modes in the SVG
render tree; tiling patterns; calculator functions; file.import page and Footage::page;
Create Shapes from Vector Layer keeps clips (page clips as layer masks, nested clips as Merge
Paths Intersect).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>