bookcover-3d-web 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/svg.js +26 -4
- package/package.json +1 -1
package/dist/svg.js
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
// SVG parsing and rasterisation utilities
|
|
2
|
+
// Grace period before snapshotting an SVG that embeds other documents — a pragmatic
|
|
3
|
+
// workaround for a Safari rasterisation quirk (see svg_to_bitmap), not a guarantee. Raise it
|
|
4
|
+
// if a cover ever renders in the 3D view without its background again.
|
|
5
|
+
const NESTED_RASTER_SETTLE_MS = 250;
|
|
6
|
+
// Feature detection is no help here (decode()/createImageBitmap exist everywhere) — this is
|
|
7
|
+
// a behavioural quirk specific to WebKit's renderer, so UA/platform sniffing is the only
|
|
8
|
+
// option. WebKit means desktop Safari, or ANY browser on iOS/iPadOS — Apple requires every
|
|
9
|
+
// iOS browser (Chrome, Firefox, Edge included) to run on WebKit under the hood, so those UAs
|
|
10
|
+
// need the same workaround despite naming another browser. Android and desktop Chrome/
|
|
11
|
+
// Firefox/Edge are the real Blink/Gecko engines this doesn't apply to.
|
|
12
|
+
const is_ios = typeof navigator !== 'undefined' && (/iPad|iPhone|iPod/.test(navigator.userAgent)
|
|
13
|
+
// iPadOS reports as "Macintosh" in its UA but is touch-capable, unlike a real Mac
|
|
14
|
+
|| (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1));
|
|
15
|
+
const is_safari_desktop = typeof navigator !== 'undefined'
|
|
16
|
+
&& /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
17
|
+
const is_webkit = is_ios || is_safari_desktop;
|
|
2
18
|
/** Parse dimensions from the root SVG element's width/height attributes.
|
|
3
19
|
* Values are in pt (Typst's SVG renderer uses pt as its coordinate system).
|
|
4
20
|
* Accepts both "Xpt" (node backend) and bare "X" (web backend) forms. */
|
|
@@ -31,11 +47,17 @@ export async function svg_to_bitmap(svg, w_pt, h_pt) {
|
|
|
31
47
|
img.onerror = () => reject(new Error('[cover-3d] SVG failed to load as image'));
|
|
32
48
|
img.src = url;
|
|
33
49
|
});
|
|
34
|
-
// onload alone doesn't guarantee
|
|
35
|
-
//
|
|
36
|
-
// notably on Safari, this can race and snapshot a blank background.
|
|
37
|
-
// decode() is spec-guaranteed to wait until the image is fully paintable.
|
|
50
|
+
// onload alone doesn't guarantee the image is actually paintable yet; decode() is
|
|
51
|
+
// spec-guaranteed to wait until it is.
|
|
38
52
|
await img.decode();
|
|
53
|
+
// WebKit can resolve decode() before it has finished rasterising documents nested
|
|
54
|
+
// inside this one, snapshotting a cover whose background is missing while its text
|
|
55
|
+
// (native to the outer document) is fine. Everything is inline, so this is decode
|
|
56
|
+
// time only, with nothing to wait on over the network. Only covers with something
|
|
57
|
+
// embedded are affected, so plain ones skip the wait entirely, and only WebKit needs
|
|
58
|
+
// the wait at all.
|
|
59
|
+
if (is_webkit && cleaned_svg.includes('data:image/'))
|
|
60
|
+
await new Promise(resolve => setTimeout(resolve, NESTED_RASTER_SETTLE_MS));
|
|
39
61
|
// Must be awaited here (not returned directly) — the blob URL is revoked in
|
|
40
62
|
// `finally` right after this call returns, and on Safari that can race ahead of
|
|
41
63
|
// createImageBitmap still reading from the img element, capturing a blank bitmap.
|