* security: budget the rendering pipeline against DoS geometry (CWE-400/407/789)
Several render paths let crafted drawing data spin the rendering thread or
allocate without bound:
- Hatch dash sweeping reset its per-span step counter and used emitted geometry
as its only limit, so gap-only families (which emit nothing) could multiply
CPU work. Skip families that cannot draw and charge every dash step against a
shared per-hatch work budget (row 10).
- Hatch polygon deduplication compared loops with an O(n²) cyclic match and
every loop against every kept one. Charge vertex comparisons against a shared
budget and stop deduplicating when spent (row 12).
- Table coverage marked every merge rectangle, so overlapping merges re-marked
covered cells quadratically. Bound marking to a small multiple of the cell
count (row 11).
- Broken-table part layout expanded sparse rows to full width before checking
whether detailed layout is allowed. Only expand when within the cell limit;
otherwise leave cells sparse and let layout draw an outline (row 17).
- Dimension text substitution copied the base for every `<>` placeholder with no
size bound. Estimate the expansion and cap it at a fixed text budget (row 32).
- Linetype range generation cycled all-gap patterns forever (nothing emitted, so
the emit limit never tripped). Return continuous for all-gap patterns and
bound visited pattern elements (row 38).
- Viewport contents built with a fresh expansion counter, so a layout could far
exceed the documented block-expansion limit. Share one budget across the whole
build, seeded with what the enclosing list already spent (row 22).
New tests for the all-gap linetype path; all render tests pass, clippy clean.
Addresses findings rows 10, 11, 12, 17, 22, 32, 38.
* fix: preserve bounded render fallbacks and text output
---------
Co-authored-by: skylartaylor <26588250+skylartaylor@users.noreply.github.com>