Moves the flatten projection fns and command helpers into modules/draw/modify/flatten.rs (behavior unchanged) and adds flatten_plan / flatten_scene_apply to the COMMANDS suite.
Follow-up to 0bfd5dcc:
- A clipped block hatch kept its unclipped plane-local outline, which the
viewport plot projection prefers, so fills bled past the XCLIP boundary
on layouts. Rebuild it from the clipped outline.
- insert_spatial_filter / filter_handle run for every INSERT in each
render walk; resolve the xdictionary through the entity link or the
document index only, and leave the whole-object scan to set_insert_clip.
Fixes#1508
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Paste (and WBLOCK, which shares the kernel) kept the source boundary
handles, so the pasted hatch stayed tied to the original outline or to
unrelated handles in another drawing. The COPY remap now lives at the
document level and runs for both.
Refs #1370
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A V2 plugin passed the version gate and then failed silently while
registering its ribbon, since the ribbon wire types have moved on. The
host now loads V3 and newer, so V2 plugins are rejected up front with a
version message. The V2 compatibility fixture crate goes too.
Fixes#1085Fixes#987
Co-Authored-By: Claude Opus 5.5 <[email protected]>
It moved the text a fixed drawing unit off the line and then another unit
up, wrong at any real scale. It now sets DIMTAD = Above on the dimension
and lets the automatic layout place the text.
Fixes#543
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The bundled DRAINAGE / DRAINAGE2 definitions use the RIGHT_ARROW shape
from qcadshp.shx, which had no substitute, so they drew as continuous
lines. Add it to the bundled shape set alongside BAT, ZIG and the rest.
Fixes#665
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A running command only knew the entities that existed when it started;
committed results are now handed back to it, and OFFSET adds them to its
pick set.
Fixes#673
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A fan only covers convex faces; architectural n-gons filled well outside
their outline (the sample's faces covered 63% extra area).
Fixes#680
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Only the displayed annotation context followed a transform, so other
scales reappeared at the old place, and a copied annotative entity other
than a LEADER/MTEXT pair shared the source's context tree.
Fixes#700
Co-Authored-By: Claude Opus 5.5 <[email protected]>
EXPLODE left MTEXT untouched. Each laid-out run becomes a TEXT at its own
baseline origin, height, rotation and width, keeping inline colours.
Fixes#760
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The STEP header timestamp used SystemTime, which panics on wasm, and the
exports wrote through std::fs, which the browser does not have.
Fixes#761
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Middle (72 = 4) carries a Baseline vertical code, so the baseline landed on
the alignment point and the text sat half a height too high.
Fixes#767
Co-Authored-By: Claude Opus 5.5 <[email protected]>
COPY added the entity without its derived image model, so only the frame
appeared at the copy.
Fixes#829
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The synthesised dimension text copied the dimension's ByLayer colour, and
its glyphs take their colour from that entity, so the layer colour showed.
Fixes#898
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The mask is filled with the canvas colour; plotting carried that dark
colour (or the light-to-black rule) onto the sheet.
Fixes#1072
Co-Authored-By: Claude Opus 5.5 <[email protected]>
WBLOCK copied only the entities and their layers, so INSERTs pointed at
missing blocks and the file opened almost empty or needed recovery. It
now goes through the cross-drawing paste kernels, which bring layers,
linetypes, styles, block definitions and baked dimension blocks along.
Fixes#1111
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The width of a wide polyline lives on the wire as a GPU band, which the
custom-arrow extraction dropped, so the arrow drew as a hairline.
Fixes#1130
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Windows reports AltGr as Ctrl+Alt, so '@' and similar layout glyphs were
treated as shortcuts and dropped; polar input like @10<45 failed.
Fixes#1236
Co-Authored-By: Claude Opus 5.5 <[email protected]>
MOVE shifted the *D block contents but left the block cache on the old
epoch, so reopened drawings showed dimensions in place until REGEN.
Fixes#1342
Co-Authored-By: Claude Opus 5.5 <[email protected]>
They went out at depth 0 while lines kept theirs, so some fills
covered lines that DRAWORDER had put on top.
Fixes#1345
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The copy kept the source boundary handles, so editing the source
regenerated the copy onto the source outline and it seemed to vanish.
Fixes#1370
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The reference direction, base point and locked point went through f32,
so the drawn line drifted off true parallel.
Fixes#1387
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The dot-named temp file is stored Hidden by Samba and the attribute
followed it through the replace. Clear it unless the drawing was
already hidden.
Fixes#1414
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The definition took a peeked handle that the image then also received;
the DWG writer dropped the shared-handle definition and reopened images
lost their file.
Fixes#1421
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Resolve the SPATIAL filter through extension-dictionary fallbacks
(missing xdictionary handle, DictionaryWithDefault, case/whitespace
tolerant keys) so clipped INSERTs no longer plot unclipped. The
inverse-block matrix is used as stored; the codec decodes the on-disk
column-major layout (fixed upstream).
#1521 inserted crash_log between web_diag's doc comment and its module, so the comment documented crash_log instead. #1519 wrote the survived marker with a literal line break inside the string.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The DWF package reader, the DGN stream inflater and the new DGN
ExtendedColors scan each read a zlib/zip payload to its end, so a
crafted or corrupt file could inflate until memory ran out. Cap them:
1 GiB for a whole DWF package, 512 MiB per DGN stream, 4 MiB per
ExtendedColors record candidate - far above real files.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A release build hides the console and is stripped, so a panic ended the
process with nothing on screen, nothing on stderr and nothing on disk.
The window simply disappeared. That is all a reporter has ever had to
work from, which is why #635 and #845 ask for crash logs and why a
crash like #830 can be reported for months with no detail beyond the
steps to reach it.
Every panic now writes one file to <config>/crash_logs naming the
version, the OS, the graphics backend that was live, the thread, the
panic message, the source location and a backtrace. The hook chains
onto whatever was installed before it, so a debug build still prints to
stderr as well, and it is installed after the child-process handoffs:
a GPU probe aborting is how an unusable backend gets detected, not a
crash worth filing.
The report is written by a plain function taking the message and
location, so the layout is covered by tests without installing a panic
hook -- a test that asserts inside a hook fires on every other test's
panic and aborts the whole binary, which is how the first version of
these tests failed.
Backtraces use `force_capture`, not `capture`: a report that says
"disabled backtrace" because the user never set RUST_BACKTRACE is
exactly the report that helps nobody.
The text is deliberately English and does not go through `t!`. It is
read by whoever receives the bug report, and a panic handler that calls
into the localisation machinery risks a second panic while handling the
first.
Confirmed on Windows 11 by reproducing a real crash: opening either of
two large drawings on an Intel Iris Xe dies inside wgpu, and the report
names it -- "Buffer with '(wgpu internal) StagingBelt staging buffer'
label is invalid", backend dx12, with the full frame list.
Co-Authored-By: Claude Opus 5 <[email protected]>
- Insert > Reference: the PDF Attach button becomes an Attach Underlay menu
(PDF / DWF / DGN); its face runs the last one chosen.
- DWFATTACH, DGNATTACH and ATTACH on a .dwf/.dwfx/.dgn open the Attach
dialog for that kind: sheets or models with thumbnails (one chosen),
placement, path type, file details with the sheet / model size, and for
DGN the conversion units (sub units offer 1 / sub units per master as the
scale).
- DGN V8 true colours come from the ExtendedColors record packed in the
non-model attributes stream; the colour word's high part numbers them.
- A DGN model's extent includes each text's box (its length along the
baseline and 1.5 x its height), as the reference sizes a model.
- DWFx text uses the family named in its embedded (deobfuscated) font.
- DWF contrast pivots at 0.73 once colours are turned over for a dark
background.
- Hairline strokes are drawn solid one pixel wide, and underlay rasters are
made at or below their size on screen so those lines stay unbroken.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Drops the Google Play banner and its image from the Start page sponsors; the OpenAEC sponsor stays.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- W2D: a stream cut off right after an extended opcode's '(' sliced its
body backwards and panicked.
- DGN V8: the compound-file header was indexed before its length was
known (a short file with the signature panicked), the sector shift was
taken on trust (0 or 1 underflowed `sector / 4 - 1` into an endless
loop), and the DIFAT chain count was unbounded. The header must now be
complete, the shift 9 or 12, and the chain no longer than the file.
Found fuzzing the #1514 readers with truncated and random input.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The crash sentinel is armed before the event loop and disarmed after it
returns, so anything that stops the process without unwinding leaves the
file behind and the next launch skips that backend. A real GPU failure
does that — and so does the user closing the app from Task Manager, an
OOM kill, a power cut, or a panic with nothing to do with graphics.
The cost is not a one-off: the skip is permanent, and each later
abnormal end takes the next backend with it, walking a machine down
dx12 -> vulkan -> gl -> software rasterizer. The user is told their
driver is at fault the whole way.
Seen on this machine: a debug build died once while opening a large
drawing, and every launch afterwards reported "dx12 is not usable on
this GPU" on an Intel Iris Xe. Probing the backends directly showed
dx12 not merely usable but the best of the three
(max_storage_buffers_per_shader_stage 262144, against 59 for Vulkan
and 16 for GL). Clearing the stale sentinel brought dx12 straight back.
The failures this guard was built for kill the process at GPU init or
on the first drawing viewport, which is why arming it at all works. A
run that keeps drawing well past that has already shown the backend is
fine, so it now marks the sentinel `survived=1` after
SENTINEL_PROOF_DELAY, and a sentinel carrying that marker accuses
nobody. An early death still blacklists exactly as before.
Verified both ways on Windows 11 with an Intel Iris Xe: killed after
40s, the next launch still chose dx12; killed after 8s, the next launch
skipped dx12 and fell back to Vulkan.
Co-Authored-By: Claude Opus 5 <[email protected]>
`with_printer_devmode` sized the driver's DEVMODE with a
`DocumentPropertiesW` call that passed `DM_OUT_BUFFER` and no output
buffer to write into. That combination is not a size query: drivers
answer it with -1, the `needed <= 0` guard returned early, and the
function handed back `None` for every printer on every machine.
Measured here on Windows 11 x86-64, both an installed virtual printer
and a physical one:
fMode = 0 -> 5428 / 2684 bytes (the real size)
fMode = DM_OUT_BUFFER, NULL out -> -1
Two things were broken by it, both silently:
- `oriented_printer_devmode` builds the DEVMODE a print job is spooled
with. Getting `None` back, the direct GDI path fell through to
"CreateDC then falls back to the driver default", so the plot's
orientation and sheet never reached the job. A landscape plot came
out however the driver happened to be set. This is the route users
without a PDF application take.
- `PRINTERS <name>` could never name the driver's default sheet,
because the id it matches on comes from that same DEVMODE.
With the size query asking for a size, both work: the report now says
"Default sheet: ISO A4 (210 x 297 mm)" for both printers here, and a
landscape plot leaves `dmOrientation = DMORIENT_LANDSCAPE` set in the
job's DEVMODE.
The two new tests both fail with the old flag and pass with it removed.
The existing GDI ink tests do not catch this: they accept the raster
rotation fallback as an equally good outcome, so the page looked right
while the DEVMODE was empty.
Co-Authored-By: Claude Opus 5 <[email protected]>