5ac8cc7c034a4319d8fd50aaf80672098f427f90
27
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
fb674fc45e |
fix: recovered_name must not smuggle path separators through the extension
recovered_name reduced only the head to its final path component, so a
stored name like "a.b/c" came back as "a (recovered).b/c". The whole
input is now sanitized first, and the empty-stem fallback uses the
sanitized component, which also restores idempotence for
separator-headed names ("/.dwg" used to alternate across crash cycles).
Ported from
|
||
|
|
1c0963b68d |
fix: close the adversarial findings on the save/paste wave
Ported from |
||
|
|
835e8d469f |
feat: in-place save (File System Access), image paste, print wiring, web capture
The last high-severity web gap plus a small integration bundle.
In-place save: with the File System Access API (Chromium/Edge), Save
now works like desktop. Plain Save on a tab with a retained handle
writes straight through — no picker, no download, no "(1)" copies.
First save or format change opens showSaveFilePicker AT the confirm
gesture (the worker serialization that follows can outlast the
transient-activation window; retained handles need no activation to
write). Picker cancel cancels the save like desktop; picker or write
failure falls back to the legacy download with a note; Firefox/Safari
keep the download flow untouched (feature-detected). Handles are
keyed by tab id in a thread-local registry (Message must be Send —
JsValue cannot ride in messages or App state); closing a tab drops
its handle; Save As re-picks. Dirty clears only on successful
persistence, same race guard as before.
Image paste: Ctrl+V of a screenshot inserts it as an image reference
— the clipboard reader falls back to image/* items when neither the
entity clipboard nor text has anything (precedence preserved), the
bytes enter the image source registry as pasted-<timestamp>.<ext>,
and attach reuses the IMAGE command's model-creation path verbatim.
Browser print: beforeprint snapshots the WebGL canvas into a print-
only <img> (the capture_canvas technique), so the browser's own print
menu produces the drawing instead of a blank page.
Automation capture on web: the capture op no longer calls the
synchronous GPU-map screenshot (dead on wasm); main's frame-parked
capture waits for a presented frame and reads via capture_canvas — the
same workaround the save-thumbnail path uses — delivering the PNG as a
download.
(cherry picked from commit
|
||
|
|
0459f20129 |
fix: close the review findings on the restore-all/deep-links/PWA wave
Two reviewers, no blockers, two majors — all fixed.
- The remembered-tab focus after a Restore-all batch fired at the
message boundary, but the LAST restore's tab inserts one async round
later (its OPFS recent-cache write precedes the insertion) and the
insertion's own activation overwrote the selection. The focus flag
now also consumes at the insertion point, so the batch focus holds
in the common all-success case.
- The service worker cached ANY successful in-scope navigation under
the shell key — a direct navigation to a font or JSON would be
served as the app shell for every offline navigation until the next
online visit. Only the scope root caches as the shell now.
Also: '/app/' gets its own web app manifest (the previous commit's
'installable' claim was true only of the marketing site, whose
start_url sits OUTSIDE the service worker's scope — an installed app
opened offline showed an error page). Its icon is the
existing assets/logo.svg, copied next to the page.
(cherry picked from commit
|
||
|
|
6af8d8ba8c |
feat: restore-all session recovery, ?file= deep links, offline PWA
Session recovery: more than one pending snapshot adds a 'Restore all'
button to the Recover Drawing modal — every snapshot goes through the
exact same guarded path as a single restore (deleted only after its
own open succeeds). The open-tab list and active tab persist to
localStorage on web (open/save/close) and the remembered tab is
re-selected once a restore batch settles; the modal notes how many
drawings the session had. Nothing is auto-opened.
Deep links: ?file=<url|name> opens a drawing at boot. http(s) URLs
must end in .dwg/.dxf and are fetched with the same streaming,
64 MB-capped, 8 s-deadline reader the remote images use, then go
through the guarded open queue; cross-origin opens announce the
origin first. Bare names resolve from the browser's recent storage,
with a hint when absent. Everything else (file:, javascript:, drive
letters, non-drawing tails) is refused with a console note.
Offline PWA: the app was installable (manifest) but downloaded its
55 MB bundle on every visit. A cache-first service worker now serves
the whole bundle from Cache Storage after one online visit —
navigations network-first so updates land, hashed assets
stale-while-revalidate, non-GET/cross-origin passthrough, old caches
cleaned on activate, and the waiting-worker update flow documented.
The Pages workflow stamps the cache version from the bundle hash and
fails if sw.js is missing or unstamped.
(cherry picked from commit
|
||
|
|
2d2444fcfa |
fix: close the review findings on the issue wave
Ported from |
||
|
|
db8db14006 |
feat: web automation wrapper (#1349), DATALINK table on web, System theme; honest decode accounting
Ported from |
||
|
|
f015c3b5fa |
fix: native-bpp decode accounting, GIF frame bombs, streaming remote bodies
A second adversarial round (with empirical reproduction against the
vendored image 0.25) found the budget contract still had holes:
- The probe billed 4 bytes/px, but 16-bit formats allocate their
native layout during decode (8/px for RGBA16 PNG; TIFF stacks ~3x
codec scratch on top). In-budget 16-bit images were falsely refused
with self-contradictory notes, and the decode transient could exceed
the budget the tiers claimed to enforce. The probe now reads the
color type alongside the dimensions and bills the real peak (native
layout + RGBA where they coexist, plus the TIFF codec factor), so
refusals are honest and per-platform-correct, and the TIFF allowance
follows the same accounting.
- GIF: the probe reads the LOGICAL SCREEN, but a crafted frame may
declare itself arbitrarily larger (empirically: a 10x10 probed
screen with an 8192x8192 frame — 320 MB and 29 s from a
probe-claimed-400-byte image). The GIF frame buffer is now capped
to the probed size plus slack; frame bombs refuse like any other
oversize.
- Remote bodies on web streamed incrementally with the 64 MB cap
enforced DURING the read (array_buffer() materialized a hostile
chunked reply in full before any check could fire), aborting and
cancelling the reader the moment the cap is crossed.
- Degenerate raster entities (zero/non-finite size or vectors) no
longer produce NaN placement math that aborted whole PDF exports —
they resolve to the broken-reference placeholder.
- Same-name resolution now has a deterministic winner (newest
registration, via insertion order) instead of HashMap iteration
order; URL query strings no longer break by-name matching; the
image pick matches its refusal note by the quoted file name
(substring collisions like a.tif/2011.tif attributed errors to the
wrong file); a dropped remote outcome at the queue cap triggers one
unconditional catch-up re-resolution instead of waiting for another
event; the unknown-size refusal says so instead of printing 0x0;
and the build script fails cleanly when there are no fonts to
verify.
(cherry picked from commit
|
||
|
|
a10d9c6f89 |
fix: trust the probe for over-budget images; TIFF allowance
Review of the image wave (with empirical reproduction against the
vendored image 0.25) found the budget contract did not hold across
formats: the decoder's Limits reserve checks NATIVE bytes-per-pixel,
so a grayscale/RGB JPEG/PNG/BMP over the RGBA budget decoded anyway
and into_rgba8() then ballooned to up to 4x it — the tab death the
budgets exist to prevent. The probed dimensions already prove an
OverBudget image cannot fit, so it is now refused without decoding,
removing all dependence on per-decoder limit fidelity.
Conversely, image's TIFF codec stacks ~3x scratch buffers on top of
the reserve, so an in-budget TIFF (the flagship GIS scenario) was
refused with a self-contradictory note ('400 MB, over the 512 MB
limit'); the decoder allowance for TIFF is now 3x while tier math
stays on the real budget.
Also: the refusal message saturates instead of overflowing on crafted
headers, the image pick only matches the refusal note naming ITS file
(peek, not drain — other references' notes survive for their own
drains), and the Georgian Supplement range ends at U+2D2F (U+2D30.. is
Tifinagh, which ships no font).
(cherry picked from commit
|
||
|
|
93e97bdf18 |
feat: bounded huge-image decoding, webp/gif, remote rasters, Georgian/Armenian fonts
Giant rasters (500 MB aerial/GIS TIFFs) decoded whole: multiple GB of
RGBA on a wasm heap is tab death, and even desktop silently failed
past the image crate's 512 MiB default allocation cap. Decoding now
probes the header for dimensions first and runs in tiers — full decode
under a per-target budget (512 MB wasm / 4 GB native, enforced through
the decoder's allocation limits so oversize fails fast instead of
ballooning), Lanczos3 downsample to a display cap (4096² wasm /
8192² native) when the decode fits but the buffer is oversized, and a
clear localized refusal naming the dimensions and the limit when it
cannot. The probed source dimensions stay the entity's sizing truth,
so a downsampled buffer never shrinks the on-paper footprint; PDF
export self-corrects (effective DPI derives from placement × stored
pixels). Refusals surface once per image through the pick, open, and
drop/re-resolve paths.
Decode coverage gains webp and gif (pure Rust in image 0.25 — no C,
no lockfile churn), with the attach picker and drop filters matching.
Remote http(s) raster references now fetch on web: CORS-classified
failures name CORS, HTTP errors name the status, bodies over 64 MB and
8 s deadlines are bounded, and fetched bytes join the session source
registry (so ARCHIVE can package them and re-resolution reads cache).
Georgian and Armenian Noto subsets ship (generation blocks included),
so those scripts render instead of skipping; scripts still without
subsets remain silently skipped, unchanged.
(cherry picked from commit
|
||
|
|
8a5d343927 |
fix: final pre-PR review sweep
The final holistic + quality audit (three reviewers) returned GO with
four majors; all fixed.
- Start-page recents were the last unguarded writer of the open slot
on web: clicking one under the open overlay clobbered the in-flight
open and silently lost its bytes. Refused with the same in-progress
notice the picker uses.
- The web quit-after-save continuation stalled: a Quit pending now
survives the tab-save AND continues — offering to save the next
dirty tab or finishing the quit, mirroring native.
- Data-extraction's multi-file pick is capped (16): every picked file
becomes a full parsed document held for the session, and one giant
pick could exhaust the wasm heap.
- The xref registry tests raced each other on the process-global
registry (reproduced 3/10 at high thread counts — CI roulette); they
now hold a module-level guard.
Minors: the collision warning is cataloged in all 21 locales; the
docs' parallelism detail header no longer contradicts its own table;
the drop-filter and name-hash helpers gained inline tests (their only
prior coverage was a verbatim copy in the red-team suites).
(cherry picked from commit
|
||
|
|
108ef045b8 |
web: worker-route WBLOCK/SAVEALL/ARCHIVE; close the follow-up review
WBLOCK, SAVEALL, and web ARCHIVE now serialize through the Web Worker
like SAVE/AUTOSAVE: prepare on the main thread, writer pass on the
worker, inline fallback on any worker failure. SAVEALL clears each
tab's dirty flag under the same unchanged-tab race guard the single
save uses; ARCHIVE assembles the ZIP in the completion handler so the
transmittal matches the snapshot taken at command time.
The review of the previous fix commit found the collision refusal
still REPLACED the registry bytes — the exact silent retargeting it
was meant to prevent. The refusal now keeps the old registration, the
extraction settings picker reports refused picks in the wizard's error
slot (previously silent, and the stale collision flag could surface as
a wrong-file warning on an unrelated browse), and the xref registry's
same-name ambiguity is documented as a browser fundamental (native
distinguishes by folder): newest registration wins consistently for
resolution, ARCHIVE, and XRELOAD — matching what the drawing displays.
Also: the Quit pending-close survives a successful web tab-save
(continue the quit instead of dropping it), the last ZIP64 sentinel
(central size) is rejected like the other four, and the new behaviors
gained regression tests (collision keeps old bytes, registry eviction,
including the deadlock fix for the guard-scoping that test exposed).
(cherry picked from commit
|
||
|
|
8968e79942 |
fix: close the review findings on the last web wave
Full verification of the XREF/data/ARCHIVE/worker wave (three
reviewers, one forensic) found no blockers and no crossfire damage;
five majors and several minors are fixed here.
- ARCHIVE now packages XREFs: the bytes registry added by the same
commit is consulted (the in-code 'no xref store exists' comment was
false within the commit), and the drawing is packaged only after
the full save preparation — without it kernel solids shipped
without their ACIS data.
- PendingClose stores the stable tab id instead of a vector index:
the web save now completes asynchronously, and closing a lower tab
during the serialization window shifted indices — closing the WRONG
tab, or panicking on a stale one. All producers and consumers
resolve the id at use.
- The xref bytes registry is capped (6 entries, oldest evicted): every
open, drop, and pick registered full drawing bytes with no bound —
an OOM waiting to happen. Reopened recents register too, so any
entry path can serve as another drawing's xref.
- A re-picked data-link source with the same name but different bytes
no longer silently replaces the first (the browser hands back bare
names, so two same-named files collided and every reference read
the newer pick): the pick is refused and the user is told why.
- The unresolved-xref warning lists file names (what to drop on the
page), not internal block names; the ZIP writer refused the ZIP64
sentinel values (0xFFFF counts, 0xFFFFFFFF sizes/offsets) instead
of emitting archives that send strict readers hunting for a ZIP64
EOCD that is absent; docs note the worker-side saves.
Known follow-ups documented, not fixed here: the serde-skipped
ExtendedEntity/CadDocument raw bytes still drop on worker crossings
(needs codec accessors — upstream), and WBLOCK/SAVEALL/ARCHIVE
still serialize inline (the worker route is a small follow-up).
(cherry picked from commit
|
||
|
|
61c32c7f74 |
web: XREFs, data links & extraction, ARCHIVE transmittals, worker-side saves
The last four big web-vs-desktop gaps.
XREFs: XATTACH reads the picked drawing's bytes and registers them
name-keyed (the image/PDF-underlay pattern), pre-parses on the web
worker, and the commit merge produces the same xref block flow as
native. Opened drawings resolve xrefs from the registry (trailing-name
match) before cache build; unresolved references produce ONE warning
listing the names and the fix — drop the referenced files on the page
(drops and picker opens now register their bytes) and reopen or
XRELOAD. XRELOAD works off the registry on unsaved drawings too.
Data Link & Extraction: spreadsheet links read picked xlsx/csv bytes
(calamine from slices / CSV from string) through a session registry,
so preview, refresh, and table-insert work on web; extraction takes
external drawings via a multi-file picker parsed on the worker, and
outputs CSV/TXT/.dxex via download_bytes. The disabled 'Add folder'
button explains why.
ARCHIVE/ETRANSMIT: assembles the drawing plus registered images, PDF
underlays, and session plot tables into a ZIP delivered as
{stem}_transmit.zip; skipped dependencies are reported by name.
Save/autosave off the UI thread: the parse worker gains a serialize
action (protocol v5) — the document is prepared once on the main
thread (clone, styles, dimension bake), then the DWG/DXF writer pass,
the dominant cost, runs on the worker; any worker failure falls back
to inline serialization with the identical shared implementation.
The save path also clears the dirty flag only when the tab didn't
change mid-write, and the runtime-fields sidecar now carries
graphic_data, fixing a pre-existing loss of raw DWG round-trip bytes
on web-opened documents.
(cherry picked from commit
|
||
|
|
9cd898a17a |
web: raster images, WBLOCK/SAVEALL/SCRIPT/CTB/LAYTRANS/INSERT, filled TTF text
A fresh web-vs-desktop audit found the remaining gaps; this closes the
top ten.
Raster images: IMAGE attach read the picked file via image::open on a
name-only path (dead on wasm), and raster references inside opened
drawings decoded the same way. Picked bytes are now registered in a
name-keyed store (the PDF-underlay pattern), decoding runs from memory,
and dropped .png/.jpg/.bmp/.tif files register by name so unresolved
references in opened drawings re-resolve and render (and export to PDF).
Command gaps fixed with the bytes-at-pick / download_bytes pattern:
- WBLOCK now downloads the extracted block instead of failing on fs.
- SAVEALL saves every dirty tab instead of printing a no-op message.
- SCRIPT picks and reads the .scr file through the browser picker.
- CENTERLTYPEFILE picks the .lin/.dnl file and populates from text.
- Custom .ctb tables picked on web now parse, register for the
session, appear in the plot dialog list, and apply (load_named
previously returned builtin-only on wasm).
- LAYTRANS 'Load standards file' parses the picked drawing on the
existing web worker.
- INSERT 'from file' in the block palette parses picked bytes and
feeds the shared import path.
Text fidelity: TTF-named styles rendered as thin stroke glyphs on web
because the font database was empty. Fetched Noto faces are now
registered into it with a family alias table (Arial, Times New Roman,
Cambria, ... -> Noto Sans/Serif), so those styles render filled, shape,
export to PDF as vector fills, and appear in the style picker.
ViewCube labels request semibold again on web.
docs/native-vs-web.md: the hatch and font rows were stale (both work on
web now), the GPU row claimed WebGPU is used where available (the
backend is pinned to OpenGL), and the parallelism row missed the parse
worker — all corrected.
(cherry picked from commit
|
||
|
|
69fa7cae4f |
web: fix red-team breaks in restore, drop-open, and plot paths
Three attack agents (state-machine tracing, executable input fuzzing,
browser-API review) found two breaks and several degradations; all are
fixed here, with the fuzzer's 22 tests kept as regression suites.
Breaks:
- Untitled tabs (and dot-names like ".dxf") autosave as DXF, but the
restore name defaulted to .dwg — the worker dispatches its reader by
the name's extension, so the only copy of unsaved work could never
be restored and was re-offered forever. recovered_name now uses the
worker's rsplit('.') convention and defaults extensionless names to
dxf, matching new-document serialization.
- " (recovered)" stacked one suffix per crash-restore cycle; the
marker is now stripped idempotently before appending.
- Opening a file (Ctrl+O / OPEN / automation) while a web open was in
flight clobbered it: the in-flight open's bytes were lost and every
queued restore prompt stalled for the session. on_open_file now
refuses while an open is running (web only).
Hardening:
- Escape on the Recover Drawing modal defers instead of deleting the
only snapshot; the Discard button still removes it.
- A cap-rejected restore enqueue warns in-app and re-offers the next
snapshot; the drop queue cap rises to 32.
- Exiting mid-round no longer races snapshot removals (deferrals are
drained, the sweep skips while a round is in flight); closing a tab
with "Don't save" now also removes its web snapshot; the snapshot
key derivation is shared via web_autosave_key.
- The plot-preview overlay no longer leaks a full PDF copy per preview
(the Download closure lives in a replaceable registry).
- A corrupt autosave index.json fails the round/boot instead of
silently resetting every row; plot pages with non-finite or non-
positive sheet dimensions error instead of emitting a NaN MediaBox.
- The drop filter accepts dot-less "DWG"/"dxf" names the worker
parses (same rsplit convention on both gates).
(cherry picked from commit
|
||
|
|
9611f40400 |
web: never resurface an emptied autosave-restore prompt
A queued AutosaveRestore startup modal can outlive the pending list
that justifies it: a file opened while the prompt is up displaces the
modal, the entry is consumed, and the after-message hook then resurfaces
a stale, empty Recover Drawing prompt. The hook now drops queued
restore prompts whose pending list is empty.
(cherry picked from commit
|
||
|
|
7b467e16ea |
web: restore deletes its snapshot by open identity, not name
Second review pass found the restore marker matched WebFileOpened by
display name: any same-named open finishing while the recovered one
was still queued deleted the only copy. The snapshot key now travels
with the queued file (tagged queue entries), the marker records the
open id assigned at dispatch, and success, failure, and cancel all
match that id. Cancelling an unrelated open no longer clears a
pending restore marker.
Also: the boot scan removes dead index rows (missing or zero-byte
snapshot files) that no other path could discard, and the drop
listener install only latches when the listeners really registered.
(cherry picked from commit
|
||
|
|
3023cefea4 |
web: harden drop-open and autosave after adversarial review
Review of the drop-open and autosave commits surfaced one blocker and
five majors; all are fixed here, and two claims in the autosave commit
message are corrected by this one: tab close does NOT clear a snapshot
(matches native .sv$ semantics — saving, restoring, discarding, exit,
and the capped boot scan do), and serialization runs on the main
thread between awaits, not off the paint path.
- The restore prompt can no longer appear with no entries (empty
"Recover Drawing" modal on every boot once the autosave dir exists).
- Restore no longer consumes the snapshot before the open succeeds:
the recovered drawing goes through the guarded drop queue, and the
snapshot is deleted only after the tab opens; cancel or parse
failure keeps the only copy.
- Saving during an autosave round defers its snapshot cleanup until
the round finishes, so a stale round can no longer resurrect a
snapshot newer than the save.
- The boot scan no longer deletes snapshots by mtime comparison
(re-opening a drawing refreshes the recent copy's mtime, which
silently destroyed wanted snapshots); GC is now a 16-entry cap with
oldest-first eviction.
- OPFS write failures abort the writable stream (a leaked lock could
stall the same-key writer and disable autosave for the session), and
DOMException errors now carry their name/message.
- Empty (crash-window) snapshots are never offered; an unreadable one
warns and stays discardable instead of looping forever.
- Drop-open polish: reads start inside the handler and complete in
drop order (legacy WebKit safety, deterministic multi-file order),
dragenter is canceled too, the install guard only latches on
success, non-drawing drops don't steal propagation, a lock-poison
panic can't cross into JS, and re-dropping an open drawing no
longer risks clobbering an in-flight open (it re-queues).
- The model-space sheet floor is per-axis (a thin 8x400 mm profile
keeps its length) and centers content on the enlarged page.
(cherry picked from commit
|
||
|
|
12fd04790f |
web: autosave snapshots with crash-recovery restore, persistent storage
The web build had no autosave: on_autosave was a no-op and the
subscription was native-only. Both gates are gone; every savetime tick
now serializes each dirty tab (same pre-serialize sync as the web save
path, no thumbnail, serialized serially off the critical paint path)
into a dedicated opencadstudio-autosave OPFS directory, keyed by
drawing name, without touching the dirty flag, downloads, or recents.
On boot the web app scans that directory and offers any snapshot
newer than the last saved copy in a localized Recover Drawing modal
(Restore opens it as "name (recovered).dwg" through the standard
open pipeline; Discard removes it; Escape discards). Saving or
closing a drawing clears its snapshot; the boot scan also garbage-
collects stale entries. run_web now requests navigator.storage.persist
so settings and OPFS data survive browser eviction.
(cherry picked from commit
|
||
|
|
6cb8c00fa0 |
web: enable STL/STEP export and OBJ import, drag-and-drop open
STLOUT/STEPOUT wrote via std::fs and IMPORTOBJ read via std::fs, all
of which fail on wasm32. The export pickers now mirror the PDF path
(pick_*_owned returns a name-only PathBuf; the browser download names
the file) and the write tail swaps fs::write for sys::download_bytes.
OBJ import reads the picked file's bytes directly, like the web open
picker.
Opening by drag-and-drop was dead on the web build: winit never emits
FileDropped there. A wasm-gated io::web_drop module installs DOM
dragover/drop listeners, filters .dwg/.dxf, reads the File bytes
async, and queues them; the existing 50 ms PollWebControl tick drains
the queue into the same open path the picker uses (progress overlay,
recovery, OPFS recent cache).
Also floors the model-space plot sheet: extents smaller than 10 mm
(or the 0x0 paper a fresh unsaved drawing carries) now fall back to
the standard sheet instead of producing a ~3 pt page.
(cherry picked from commit
|
||
|
|
112060e370 |
web: harden plot preview after adversarial review
Three reviewers (security, correctness, performance) converged on:
- Download PDF died on the second click: Closure::once_into_js throws
when invoked twice. The handler is now a plain FnMut kept for the
overlay's lifetime.
- Rasterisation was bounded by page count, not pixels: 12 A0 sheets at
150 DPI peaked near 1.8 GB of RGBA plus ~1.7 GB of decoded images,
and a drawing declaring absurd paper sizes made the rasteriser
saturate its u16 dimensions into a ~17 GB allocation that aborts the
tab. Preview now computes a uniform DPI under a 64-Mpx total budget
(floor 24 DPI) from the page tree before allocating, with a per-page
4096-px edge clamp.
- Overlays stacked when previewing twice and their blob URLs were only
revoked via Close. The overlay is now single-instance (id-tagged);
a replacement or Close revokes every URL through a shared registry.
- emit_image resampled before probing the XObject cache, so a title
block placed on 12 layouts ran 12 Lanczos passes to embed once.
The cache is now probed with the target dimensions first.
- Preview downloads are named {stem}_preview.pdf instead of a constant
plot_preview.pdf, and the page label says 'first N of M' when the
preview is capped while the PDF keeps every page.
(cherry picked from commit
|
||
|
|
8cce362009 |
web: warn when an opened drawing's name collides with an open tab
Web builds identify drawings by bare file name (the browser picker
exposes no real path), so two tabs with the same name also share the
single browser-stored copy: the last save silently replaces the other
tab's. Warn on open instead of letting that surface later.
(cherry picked from commit
|
||
|
|
4d1f9d5960 |
web: render plot preview in-page instead of a new tab
A plot preview should show the plotted result on screen instead of
producing a file. The web build now does: the plotted PDF bytes
are rasterised with the hayro pipeline already used for PDF underlays
(150 DPI, first 12 pages) and shown in an in-page overlay with
Download-PDF and Close actions.
The previous strategy opened a new tab via window.open from the async
plot task; browsers withhold popups without a live user gesture, and
embedded hosts ship no PDF viewer plugin at all — so the fallback
download fired and preview behaved like an export. Plain PNG <img>
elements need neither permission.
(cherry picked from commit
|
||
|
|
c8386c6d3a |
build: make the Trunk web-worker hook work on Windows
Trunk passes TRUNK_STAGING_DIR as an extended-length path (\?\C:\...)
on Windows, which MSYS sh tools cannot stat, so post_build failed and
the whole web build aborted. Strip the prefix with sed before use;
Linux CI paths are unaffected.
(cherry picked from commit
|
||
|
|
38f0e2b25f |
app: wire web export, preview, and print flows through the plot UI
- plot dialog: the web build defaults to 'Save to PDF file...' (its only
output choice); native dropdowns and defaults are untouched.
- on_plot_dlg_commit forces to_file on wasm so a stale page setup can no
longer route the web build into the (unreachable) printer path; both
preview branches now go through preview_page_pdf, which is identical to
the old inline temp-PDF + OS-viewer flow on desktop.
- Print ribbon / PRINTALL on wasm render the PDF and open it in a tab
instead of erroring; PrintAllPdf picks a virtual path and downloads.
- pdf_plot_options maps the dialog's Quality dropdown into PdfPlotOptions.
(cherry picked from commit
|
||
|
|
978000d37c |
io: enable the PDF pipeline on wasm32 and add plot quality presets
- pdf_export: drop the stale wasm32 gates (printpdf 0.9.1 compiles for
wasm; the memchr/lopdf incompatibility is gone with memchr 2.8.3).
Rendering is portable via render_pdf_bytes; only persistence differs:
atomic temp-file write on desktop, browser download on the web.
pick_pdf_path_owned on wasm returns a virtual path so the existing
message flow works unchanged.
- printpdf moves from the native-only dependency table to the shared one.
- print_to_printer: preview_page_pdf / preview_pages_pdf render the same
bytes and open them in a browser tab on the web (the browser's print
dialog takes over); desktop keeps the temp-PDF + OS-viewer flow.
- sys: open_bytes_in_new_tab (blob URL, popup-blocked falls back to a
download).
- New PlotQuality preset caps embedded raster resolution (High = native,
Normal = 300 DPI, Low = 150 DPI effective); vector output is untouched.
The image resource cache keys on the post-resample dims so one pixels
Arc placed at different effective DPIs embeds per-placement XObjects.
(cherry picked from commit
|