@oh-just-another/renderer-canvas 0.57.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/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/canvas-target.d.ts +83 -0
- package/dist/canvas-target.d.ts.map +1 -0
- package/dist/canvas-target.js +208 -0
- package/dist/canvas-target.js.map +1 -0
- package/dist/canvas-text-shaper.d.ts +11 -0
- package/dist/canvas-text-shaper.d.ts.map +1 -0
- package/dist/canvas-text-shaper.js +56 -0
- package/dist/canvas-text-shaper.js.map +1 -0
- package/dist/constants.d.ts +52 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +52 -0
- package/dist/constants.js.map +1 -0
- package/dist/hi-dpi.d.ts +26 -0
- package/dist/hi-dpi.d.ts.map +1 -0
- package/dist/hi-dpi.js +62 -0
- package/dist/hi-dpi.js.map +1 -0
- package/dist/image-source.d.ts +3 -0
- package/dist/image-source.d.ts.map +1 -0
- package/dist/image-source.js +65 -0
- package/dist/image-source.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/layered-canvas.d.ts +46 -0
- package/dist/layered-canvas.d.ts.map +1 -0
- package/dist/layered-canvas.js +95 -0
- package/dist/layered-canvas.js.map +1 -0
- package/dist/layered-surface.d.ts +75 -0
- package/dist/layered-surface.d.ts.map +1 -0
- package/dist/layered-surface.js +262 -0
- package/dist/layered-surface.js.map +1 -0
- package/dist/offscreen.d.ts +30 -0
- package/dist/offscreen.d.ts.map +1 -0
- package/dist/offscreen.js +50 -0
- package/dist/offscreen.js.map +1 -0
- package/dist/recording-target.d.ts +203 -0
- package/dist/recording-target.d.ts.map +1 -0
- package/dist/recording-target.js +260 -0
- package/dist/recording-target.js.map +1 -0
- package/dist/render-worker.d.ts +2 -0
- package/dist/render-worker.d.ts.map +1 -0
- package/dist/render-worker.js +112 -0
- package/dist/render-worker.js.map +1 -0
- package/dist/tile-compositor.d.ts +44 -0
- package/dist/tile-compositor.d.ts.map +1 -0
- package/dist/tile-compositor.js +110 -0
- package/dist/tile-compositor.js.map +1 -0
- package/dist/webgl2-color.d.ts +13 -0
- package/dist/webgl2-color.d.ts.map +1 -0
- package/dist/webgl2-color.js +26 -0
- package/dist/webgl2-color.js.map +1 -0
- package/dist/webgl2-curve.d.ts +46 -0
- package/dist/webgl2-curve.d.ts.map +1 -0
- package/dist/webgl2-curve.js +162 -0
- package/dist/webgl2-curve.js.map +1 -0
- package/dist/webgl2-ellipse.d.ts +52 -0
- package/dist/webgl2-ellipse.d.ts.map +1 -0
- package/dist/webgl2-ellipse.js +171 -0
- package/dist/webgl2-ellipse.js.map +1 -0
- package/dist/webgl2-msdf-text.d.ts +84 -0
- package/dist/webgl2-msdf-text.d.ts.map +1 -0
- package/dist/webgl2-msdf-text.js +306 -0
- package/dist/webgl2-msdf-text.js.map +1 -0
- package/dist/webgl2-stroke.d.ts +52 -0
- package/dist/webgl2-stroke.d.ts.map +1 -0
- package/dist/webgl2-stroke.js +318 -0
- package/dist/webgl2-stroke.js.map +1 -0
- package/dist/webgl2-target.d.ts +311 -0
- package/dist/webgl2-target.d.ts.map +1 -0
- package/dist/webgl2-target.js +1368 -0
- package/dist/webgl2-target.js.map +1 -0
- package/dist/webgpu-detect.d.ts +30 -0
- package/dist/webgpu-detect.d.ts.map +1 -0
- package/dist/webgpu-detect.js +74 -0
- package/dist/webgpu-detect.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { LAYER_ORDER } from "@oh-just-another/renderer-core";
|
|
2
|
+
import { LayeredCanvas } from "./layered-canvas.js";
|
|
3
|
+
import { WebGL2Target } from "./webgl2-target.js";
|
|
4
|
+
import { RecordingTarget } from "./recording-target.js";
|
|
5
|
+
import { setupHiDpiNoContext } from "./hi-dpi.js";
|
|
6
|
+
/**
|
|
7
|
+
* Factory entry point. Picks the right backend implementation, builds
|
|
8
|
+
* it, and returns the common `LayeredSurface` interface. Canvas2D is
|
|
9
|
+
* always safe; WebGL2 throws if the browser doesn't expose
|
|
10
|
+
* `getContext("webgl2")`; Offscreen throws if either `OffscreenCanvas`
|
|
11
|
+
* or `transferControlToOffscreen` is missing.
|
|
12
|
+
*
|
|
13
|
+
* The host (DiagramRoot) catches errors and falls back to `canvas2d`
|
|
14
|
+
* automatically when an opt-in backend isn't supported.
|
|
15
|
+
*/
|
|
16
|
+
export const createLayeredSurface = (host, width, height, options = {}) => {
|
|
17
|
+
const backend = options.backend ?? "canvas2d";
|
|
18
|
+
switch (backend) {
|
|
19
|
+
case "canvas2d":
|
|
20
|
+
return new Canvas2DLayeredSurface(host, width, height);
|
|
21
|
+
case "webgl2":
|
|
22
|
+
return new WebGL2LayeredSurface(host, width, height);
|
|
23
|
+
case "offscreen":
|
|
24
|
+
if (!options.workerFactory) {
|
|
25
|
+
throw new Error("createLayeredSurface: workerFactory is required for the offscreen backend");
|
|
26
|
+
}
|
|
27
|
+
return new OffscreenLayeredSurface(host, width, height, options.workerFactory);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Build the requested surface and fall back to `canvas2d` if the
|
|
32
|
+
* opt-in backend throws (no WebGL2 / no OffscreenCanvas / per-page
|
|
33
|
+
* WebGL context limit hit). On fallback, `onFallback` is invoked
|
|
34
|
+
* with the original error so the host can surface a toast / log.
|
|
35
|
+
*
|
|
36
|
+
* Use this when the backend is user-controlled (demo dropdown,
|
|
37
|
+
* URL param) so a misclick doesn't crash the React tree. Hosts
|
|
38
|
+
* that want hard failures should call `createLayeredSurface`
|
|
39
|
+
* directly and handle the throw themselves.
|
|
40
|
+
*/
|
|
41
|
+
export const createLayeredSurfaceWithFallback = (host, width, height, options = {}, onFallback) => {
|
|
42
|
+
const requested = options.backend ?? "canvas2d";
|
|
43
|
+
try {
|
|
44
|
+
return { surface: createLayeredSurface(host, width, height, options), effectiveBackend: requested };
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
if (requested === "canvas2d")
|
|
48
|
+
throw err;
|
|
49
|
+
onFallback?.(requested, err);
|
|
50
|
+
return {
|
|
51
|
+
surface: createLayeredSurface(host, width, height, { ...options, backend: "canvas2d" }),
|
|
52
|
+
effectiveBackend: "canvas2d",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
/** Canvas2D surface — wraps `LayeredCanvas` (3× Canvas2DTarget). */
|
|
57
|
+
class Canvas2DLayeredSurface {
|
|
58
|
+
backend = "canvas2d";
|
|
59
|
+
inner;
|
|
60
|
+
constructor(host, width, height) {
|
|
61
|
+
this.inner = new LayeredCanvas(host, width, height);
|
|
62
|
+
}
|
|
63
|
+
get(name) {
|
|
64
|
+
return this.inner.get(name);
|
|
65
|
+
}
|
|
66
|
+
getCanvas(name) {
|
|
67
|
+
return this.inner.getCanvas(name);
|
|
68
|
+
}
|
|
69
|
+
resize(width, height) {
|
|
70
|
+
this.inner.resize(width, height);
|
|
71
|
+
}
|
|
72
|
+
get size() {
|
|
73
|
+
return this.inner.size;
|
|
74
|
+
}
|
|
75
|
+
present() {
|
|
76
|
+
// No-op — Canvas2D paints synchronously.
|
|
77
|
+
}
|
|
78
|
+
dispose() {
|
|
79
|
+
this.inner.dispose();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* WebGL2 surface — hybrid: GPU only for the heavy `main` layer;
|
|
84
|
+
* `overlay` / `background` stay on Canvas2D.
|
|
85
|
+
*
|
|
86
|
+
* Overlay paints handles / selection halo / port hints — a few dozen
|
|
87
|
+
* primitives per frame, trivially fast in Canvas2D. Background paints
|
|
88
|
+
* the grid — a repeating rect, also Canvas2D-cheap. Giving each its own
|
|
89
|
+
* WebGL2 context would triple GL state churn, triple GPU memory, and
|
|
90
|
+
* triple the chance of hitting the browser's per-page WebGL context cap
|
|
91
|
+
* (~16 in Chrome).
|
|
92
|
+
*/
|
|
93
|
+
class WebGL2LayeredSurface {
|
|
94
|
+
backend = "webgl2";
|
|
95
|
+
/** Canvas2D layered for overlay + background. */
|
|
96
|
+
base;
|
|
97
|
+
/** WebGL2 only for `main`. */
|
|
98
|
+
mainCanvas;
|
|
99
|
+
mainTarget;
|
|
100
|
+
_width;
|
|
101
|
+
_height;
|
|
102
|
+
constructor(host, width, height) {
|
|
103
|
+
this._width = width;
|
|
104
|
+
this._height = height;
|
|
105
|
+
// Build the Canvas2D layers first; the WebGL2 main canvas is
|
|
106
|
+
// spliced into the same stack between background and overlay.
|
|
107
|
+
this.base = new LayeredCanvas(host, width, height, {
|
|
108
|
+
layers: LAYER_ORDER.filter((name) => name !== "main"),
|
|
109
|
+
});
|
|
110
|
+
const overlay = this.base.getCanvas("overlay");
|
|
111
|
+
const canvas = host.ownerDocument.createElement("canvas");
|
|
112
|
+
canvas.dataset.layer = "main";
|
|
113
|
+
canvas.dataset.backend = "webgl2";
|
|
114
|
+
canvas.style.position = "absolute";
|
|
115
|
+
canvas.style.inset = "0";
|
|
116
|
+
canvas.style.pointerEvents = "none";
|
|
117
|
+
// Insert main before overlay so overlay sits on top in z-order.
|
|
118
|
+
host.insertBefore(canvas, overlay);
|
|
119
|
+
// Never call `getContext("2d")` on this canvas: the WebGL2 slot is
|
|
120
|
+
// exclusive — one canvas, one context kind, for the life of the
|
|
121
|
+
// element. `setupHiDpiNoContext` sizes the bitmap without touching
|
|
122
|
+
// the context.
|
|
123
|
+
setupHiDpiNoContext(canvas, width, height);
|
|
124
|
+
try {
|
|
125
|
+
this.mainCanvas = canvas;
|
|
126
|
+
this.mainTarget = new WebGL2Target(canvas, width, height);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
canvas.remove();
|
|
130
|
+
this.base.dispose();
|
|
131
|
+
throw err;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
get(name) {
|
|
135
|
+
if (name === "main")
|
|
136
|
+
return this.mainTarget;
|
|
137
|
+
return this.base.get(name);
|
|
138
|
+
}
|
|
139
|
+
getCanvas(name) {
|
|
140
|
+
if (name === "main")
|
|
141
|
+
return this.mainCanvas;
|
|
142
|
+
return this.base.getCanvas(name);
|
|
143
|
+
}
|
|
144
|
+
resize(width, height) {
|
|
145
|
+
if (this._width === width && this._height === height)
|
|
146
|
+
return;
|
|
147
|
+
this._width = width;
|
|
148
|
+
this._height = height;
|
|
149
|
+
this.base.resize(width, height);
|
|
150
|
+
setupHiDpiNoContext(this.mainCanvas, width, height);
|
|
151
|
+
this.mainTarget.resize(width, height);
|
|
152
|
+
}
|
|
153
|
+
get size() {
|
|
154
|
+
return { width: this._width, height: this._height };
|
|
155
|
+
}
|
|
156
|
+
present() {
|
|
157
|
+
// Canvas2D + WebGL2 both paint synchronously — nothing to flush.
|
|
158
|
+
}
|
|
159
|
+
dispose() {
|
|
160
|
+
this.mainTarget.dispose();
|
|
161
|
+
this.mainCanvas.remove();
|
|
162
|
+
this.base.dispose();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Offscreen surface — main-thread `RecordingTarget` per layer + a
|
|
167
|
+
* dedicated worker per layer that owns the transferred OffscreenCanvas
|
|
168
|
+
* and replays the buffered command stream on each `present()`.
|
|
169
|
+
*
|
|
170
|
+
* Trade-offs:
|
|
171
|
+
* • Latency: every `present()` posts one message per layer; on
|
|
172
|
+
* desktop browsers this is sub-millisecond, but interactive
|
|
173
|
+
* overlay (pointer-following handles) sees one rAF of delay
|
|
174
|
+
* because the worker draws after the main thread yields.
|
|
175
|
+
* • Memory: 3× workers, each owning a DPR-sized OffscreenCanvas.
|
|
176
|
+
* • drawImage is silently skipped — see `RecordingTarget` docs.
|
|
177
|
+
*/
|
|
178
|
+
class OffscreenLayeredSurface {
|
|
179
|
+
backend = "offscreen";
|
|
180
|
+
canvases = new Map();
|
|
181
|
+
targets = new Map();
|
|
182
|
+
workers = new Map();
|
|
183
|
+
_width;
|
|
184
|
+
_height;
|
|
185
|
+
dpr;
|
|
186
|
+
constructor(host, width, height, workerFactory) {
|
|
187
|
+
this._width = width;
|
|
188
|
+
this._height = height;
|
|
189
|
+
this.dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
190
|
+
if (getComputedStyle(host).position === "static") {
|
|
191
|
+
host.style.position = "relative";
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
for (const name of LAYER_ORDER) {
|
|
195
|
+
const canvas = host.ownerDocument.createElement("canvas");
|
|
196
|
+
canvas.dataset.layer = name;
|
|
197
|
+
canvas.dataset.backend = "offscreen";
|
|
198
|
+
canvas.style.position = "absolute";
|
|
199
|
+
canvas.style.inset = "0";
|
|
200
|
+
canvas.style.pointerEvents = name === "overlay" ? "auto" : "none";
|
|
201
|
+
canvas.style.width = `${width}px`;
|
|
202
|
+
canvas.style.height = `${height}px`;
|
|
203
|
+
host.appendChild(canvas);
|
|
204
|
+
const worker = workerFactory();
|
|
205
|
+
const offscreen = canvas.transferControlToOffscreen();
|
|
206
|
+
worker.postMessage({ type: "init", canvas: offscreen, width, height, dpr: this.dpr }, [offscreen]);
|
|
207
|
+
this.canvases.set(name, canvas);
|
|
208
|
+
this.workers.set(name, worker);
|
|
209
|
+
this.targets.set(name, new RecordingTarget(width, height));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
this.dispose();
|
|
214
|
+
throw err;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
get(name) {
|
|
218
|
+
const t = this.targets.get(name);
|
|
219
|
+
if (!t)
|
|
220
|
+
throw new Error(`Layer not created: ${name}`);
|
|
221
|
+
return t;
|
|
222
|
+
}
|
|
223
|
+
getCanvas(name) {
|
|
224
|
+
const c = this.canvases.get(name);
|
|
225
|
+
if (!c)
|
|
226
|
+
throw new Error(`Layer not created: ${name}`);
|
|
227
|
+
return c;
|
|
228
|
+
}
|
|
229
|
+
resize(width, height) {
|
|
230
|
+
if (this._width === width && this._height === height)
|
|
231
|
+
return;
|
|
232
|
+
this._width = width;
|
|
233
|
+
this._height = height;
|
|
234
|
+
for (const [name, canvas] of this.canvases) {
|
|
235
|
+
canvas.style.width = `${width}px`;
|
|
236
|
+
canvas.style.height = `${height}px`;
|
|
237
|
+
this.targets.get(name)?.resize(width, height);
|
|
238
|
+
this.workers.get(name)?.postMessage({ type: "resize", width, height });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
get size() {
|
|
242
|
+
return { width: this._width, height: this._height };
|
|
243
|
+
}
|
|
244
|
+
present() {
|
|
245
|
+
for (const [name, target] of this.targets) {
|
|
246
|
+
const cmds = target.flush();
|
|
247
|
+
if (cmds.length === 0)
|
|
248
|
+
continue;
|
|
249
|
+
this.workers.get(name)?.postMessage({ type: "replay", commands: cmds });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
dispose() {
|
|
253
|
+
for (const worker of this.workers.values())
|
|
254
|
+
worker.terminate();
|
|
255
|
+
for (const canvas of this.canvases.values())
|
|
256
|
+
canvas.remove();
|
|
257
|
+
this.workers.clear();
|
|
258
|
+
this.canvases.clear();
|
|
259
|
+
this.targets.clear();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=layered-surface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layered-surface.js","sourceRoot":"","sources":["../src/layered-surface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqC,MAAM,gCAAgC,CAAC;AAChG,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAiDlD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,IAAiB,EACjB,KAAa,EACb,MAAc,EACd,UAAuC,EAAE,EACzB,EAAE;IAClB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,UAAU,CAAC;IAC9C,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,UAAU;YACb,OAAO,IAAI,sBAAsB,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACzD,KAAK,QAAQ;YACX,OAAO,IAAI,oBAAoB,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACvD,KAAK,WAAW;YACd,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CACb,2EAA2E,CAC5E,CAAC;YACJ,CAAC;YACD,OAAO,IAAI,uBAAuB,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACnF,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAC9C,IAAiB,EACjB,KAAa,EACb,MAAc,EACd,UAAuC,EAAE,EACzC,UAA+D,EACC,EAAE;IAClE,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,IAAI,UAAU,CAAC;IAChD,IAAI,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,oBAAoB,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAC;IACtG,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,SAAS,KAAK,UAAU;YAAE,MAAM,GAAG,CAAC;QACxC,UAAU,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC7B,OAAO;YACL,OAAO,EAAE,oBAAoB,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;YACvF,gBAAgB,EAAE,UAAU;SAC7B,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAEF,oEAAoE;AACpE,MAAM,sBAAsB;IACjB,OAAO,GAAG,UAAmB,CAAC;IACtB,KAAK,CAAgB;IAEtC,YAAY,IAAiB,EAAE,KAAa,EAAE,MAAc;QAC1D,IAAI,CAAC,KAAK,GAAG,IAAI,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC;IAED,GAAG,CAAC,IAAe;QACjB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IACD,SAAS,CAAC,IAAe;QACvB,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,MAAM,CAAC,KAAa,EAAE,MAAc;QAClC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;IACD,OAAO;QACL,yCAAyC;IAC3C,CAAC;IACD,OAAO;QACL,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;IACvB,CAAC;CACF;AAED;;;;;;;;;;GAUG;AACH,MAAM,oBAAoB;IACf,OAAO,GAAG,QAAiB,CAAC;IACrC,iDAAiD;IAChC,IAAI,CAAgB;IACrC,8BAA8B;IACb,UAAU,CAAoB;IAC9B,UAAU,CAAe;IAClC,MAAM,CAAS;IACf,OAAO,CAAS;IAExB,YAAY,IAAiB,EAAE,KAAa,EAAE,MAAc;QAC1D,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,6DAA6D;QAC7D,8DAA8D;QAC9D,IAAI,CAAC,IAAI,GAAG,IAAI,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE;YACjD,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,EAAoC,EAAE,CAAC,IAAI,KAAK,MAAM,CAAC;SACxF,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC1D,MAAM,CAAC,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC;QAC9B,MAAM,CAAC,OAAO,CAAC,OAAO,GAAG,QAAQ,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,UAAU,CAAC;QACnC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC;QACzB,MAAM,CAAC,KAAK,CAAC,aAAa,GAAG,MAAM,CAAC;QACpC,gEAAgE;QAChE,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnC,mEAAmE;QACnE,gEAAgE;QAChE,mEAAmE;QACnE,eAAe;QACf,mBAAmB,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC;YACH,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;YACzB,IAAI,CAAC,UAAU,GAAG,IAAI,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,GAAG,CAAC,IAAe;QACjB,IAAI,IAAI,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC;QAC5C,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IACD,SAAS,CAAC,IAAe;QACvB,IAAI,IAAI,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC;QAC5C,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IACD,MAAM,CAAC,KAAa,EAAE,MAAc;QAClC,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM;YAAE,OAAO;QAC7D,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAChC,mBAAmB,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACpD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,IAAI;QACN,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;IACtD,CAAC;IACD,OAAO;QACL,iEAAiE;IACnE,CAAC;IACD,OAAO;QACL,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC;CACF;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,uBAAuB;IAClB,OAAO,GAAG,WAAoB,CAAC;IACvB,QAAQ,GAAG,IAAI,GAAG,EAAgC,CAAC;IACnD,OAAO,GAAG,IAAI,GAAG,EAA8B,CAAC;IAChD,OAAO,GAAG,IAAI,GAAG,EAAqB,CAAC;IAChD,MAAM,CAAS;IACf,OAAO,CAAS;IACP,GAAG,CAAS;IAE7B,YACE,IAAiB,EACjB,KAAa,EACb,MAAc,EACd,aAA2B;QAE3B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,GAAG,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE5E,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACjD,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,UAAU,CAAC;QACnC,CAAC;QAED,IAAI,CAAC;YACH,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;gBAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;gBAC1D,MAAM,CAAC,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;gBAC5B,MAAM,CAAC,OAAO,CAAC,OAAO,GAAG,WAAW,CAAC;gBACrC,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,UAAU,CAAC;gBACnC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC;gBACzB,MAAM,CAAC,KAAK,CAAC,aAAa,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;gBAClE,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,KAAK,IAAI,CAAC;gBAClC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC;gBACpC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;gBAEzB,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;gBAC/B,MAAM,SAAS,GAAG,MAAM,CAAC,0BAA0B,EAAE,CAAC;gBACtD,MAAM,CAAC,WAAW,CAChB,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EACjE,CAAC,SAAS,CAAC,CACZ,CAAC;gBAEF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBAChC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBAC/B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,GAAG,CAAC,IAAe;QACjB,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,SAAS,CAAC,IAAe;QACvB,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,CAAC,KAAa,EAAE,MAAc;QAClC,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM;YAAE,OAAO;QAC7D,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC3C,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,KAAK,IAAI,CAAC;YAClC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC;YACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC9C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IACD,IAAI,IAAI;QACN,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;IACtD,CAAC;IACD,OAAO;QACL,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;YAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YAChC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;IACD,OAAO;QACL,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;YAAE,MAAM,CAAC,SAAS,EAAE,CAAC;QAC/D,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;YAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QAC7D,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Canvas2DTarget } from "./canvas-target.js";
|
|
2
|
+
/**
|
|
3
|
+
* Browser-feature detection. `true` when both `OffscreenCanvas` and the
|
|
4
|
+
* `transferControlToOffscreen` upgrade path on `HTMLCanvasElement` are
|
|
5
|
+
* available. False in Safari < 16.4 and in test environments without a
|
|
6
|
+
* canvas implementation — callers should fall back to the on-main
|
|
7
|
+
* `Canvas2DTarget` in that case.
|
|
8
|
+
*/
|
|
9
|
+
export declare const supportsOffscreenCanvas: () => boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Build a `Canvas2DTarget` backed by a fresh `OffscreenCanvas`. The CSS
|
|
12
|
+
* dimensions match the bitmap (no DPR scaling here — callers that want
|
|
13
|
+
* crisp output on hi-DPI displays should size the bitmap by `dpr` and
|
|
14
|
+
* pass a pre-scaled transform to draw calls).
|
|
15
|
+
*/
|
|
16
|
+
export declare const createOffscreenCanvas2DTarget: (width: number, height: number) => {
|
|
17
|
+
readonly canvas: OffscreenCanvas;
|
|
18
|
+
readonly target: Canvas2DTarget;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Transfer a canvas's rendering ownership to a worker. The returned
|
|
22
|
+
* `OffscreenCanvas` is now controlled by the worker (the host can no
|
|
23
|
+
* longer get a 2D context on the same element). Posts the offscreen
|
|
24
|
+
* to the worker via `worker.postMessage(msg, [offscreen])`.
|
|
25
|
+
*
|
|
26
|
+
* Throws when offscreen is unsupported — guard with
|
|
27
|
+
* `supportsOffscreenCanvas()` before calling.
|
|
28
|
+
*/
|
|
29
|
+
export declare const transferCanvasToWorker: (canvas: HTMLCanvasElement, worker: Worker, initMessage?: Record<string, unknown>) => OffscreenCanvas;
|
|
30
|
+
//# sourceMappingURL=offscreen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offscreen.d.ts","sourceRoot":"","sources":["../src/offscreen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,QAAO,OAI1C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,GACxC,OAAO,MAAM,EACb,QAAQ,MAAM,KACb;IAAE,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CASrE,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,GACjC,QAAQ,iBAAiB,EACzB,QAAQ,MAAM,EACd,cAAa,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,KACxC,eAOF,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Canvas2DTarget } from "./canvas-target.js";
|
|
2
|
+
/**
|
|
3
|
+
* Browser-feature detection. `true` when both `OffscreenCanvas` and the
|
|
4
|
+
* `transferControlToOffscreen` upgrade path on `HTMLCanvasElement` are
|
|
5
|
+
* available. False in Safari < 16.4 and in test environments without a
|
|
6
|
+
* canvas implementation — callers should fall back to the on-main
|
|
7
|
+
* `Canvas2DTarget` in that case.
|
|
8
|
+
*/
|
|
9
|
+
export const supportsOffscreenCanvas = () => {
|
|
10
|
+
if (typeof OffscreenCanvas === "undefined")
|
|
11
|
+
return false;
|
|
12
|
+
if (typeof HTMLCanvasElement === "undefined")
|
|
13
|
+
return false;
|
|
14
|
+
return typeof HTMLCanvasElement.prototype.transferControlToOffscreen === "function";
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Build a `Canvas2DTarget` backed by a fresh `OffscreenCanvas`. The CSS
|
|
18
|
+
* dimensions match the bitmap (no DPR scaling here — callers that want
|
|
19
|
+
* crisp output on hi-DPI displays should size the bitmap by `dpr` and
|
|
20
|
+
* pass a pre-scaled transform to draw calls).
|
|
21
|
+
*/
|
|
22
|
+
export const createOffscreenCanvas2DTarget = (width, height) => {
|
|
23
|
+
const canvas = new OffscreenCanvas(width, height);
|
|
24
|
+
const ctx = canvas.getContext("2d");
|
|
25
|
+
if (!ctx)
|
|
26
|
+
throw new Error("OffscreenCanvas 2D context unavailable");
|
|
27
|
+
// The OffscreenCanvasRenderingContext2D API is a superset of the
|
|
28
|
+
// 2D path / state / text methods Canvas2DTarget calls, so the cast
|
|
29
|
+
// relies on structural compatibility.
|
|
30
|
+
const target = new Canvas2DTarget(ctx, width, height);
|
|
31
|
+
return { canvas, target };
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Transfer a canvas's rendering ownership to a worker. The returned
|
|
35
|
+
* `OffscreenCanvas` is now controlled by the worker (the host can no
|
|
36
|
+
* longer get a 2D context on the same element). Posts the offscreen
|
|
37
|
+
* to the worker via `worker.postMessage(msg, [offscreen])`.
|
|
38
|
+
*
|
|
39
|
+
* Throws when offscreen is unsupported — guard with
|
|
40
|
+
* `supportsOffscreenCanvas()` before calling.
|
|
41
|
+
*/
|
|
42
|
+
export const transferCanvasToWorker = (canvas, worker, initMessage = {}) => {
|
|
43
|
+
if (!supportsOffscreenCanvas()) {
|
|
44
|
+
throw new Error("OffscreenCanvas not supported in this environment");
|
|
45
|
+
}
|
|
46
|
+
const offscreen = canvas.transferControlToOffscreen();
|
|
47
|
+
worker.postMessage({ type: "init", canvas: offscreen, ...initMessage }, [offscreen]);
|
|
48
|
+
return offscreen;
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=offscreen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offscreen.js","sourceRoot":"","sources":["../src/offscreen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAY,EAAE;IACnD,IAAI,OAAO,eAAe,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC;IACzD,IAAI,OAAO,iBAAiB,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC;IAC3D,OAAO,OAAO,iBAAiB,CAAC,SAAS,CAAC,0BAA0B,KAAK,UAAU,CAAC;AACtF,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,KAAa,EACb,MAAc,EACyD,EAAE;IACzE,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACpE,iEAAiE;IACjE,mEAAmE;IACnE,sCAAsC;IACtC,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,GAA0C,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC7F,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,MAAyB,EACzB,MAAc,EACd,cAAuC,EAAE,EACxB,EAAE;IACnB,IAAI,CAAC,uBAAuB,EAAE,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,0BAA0B,EAAE,CAAC;IACtD,MAAM,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,WAAW,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IACrF,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import type { Bounds, Color, Transform } from "@oh-just-another/types";
|
|
2
|
+
import type { FillRule, LineCap, LineJoin, RenderTarget, TextAlign, TextBaseline } from "@oh-just-another/renderer-core";
|
|
3
|
+
/**
|
|
4
|
+
* Backend-agnostic RenderTarget that captures every method call as a
|
|
5
|
+
* structured command. Powers the "offscreen" pipeline: the main thread
|
|
6
|
+
* renders into a RecordingTarget, the resulting buffer is shipped to a
|
|
7
|
+
* worker via postMessage, and the worker replays the commands onto its
|
|
8
|
+
* OffscreenCanvas.
|
|
9
|
+
*
|
|
10
|
+
* Commands are a tagged union of primitive payloads (no class
|
|
11
|
+
* instances) so they survive `structuredClone` cleanly across the
|
|
12
|
+
* worker boundary. `flush()` returns the buffered commands and resets
|
|
13
|
+
* the internal log.
|
|
14
|
+
*/
|
|
15
|
+
export type RenderCommand = {
|
|
16
|
+
readonly k: "setFill";
|
|
17
|
+
readonly color: Color | null;
|
|
18
|
+
} | {
|
|
19
|
+
readonly k: "setStroke";
|
|
20
|
+
readonly color: Color | null;
|
|
21
|
+
} | {
|
|
22
|
+
readonly k: "setStrokeWidth";
|
|
23
|
+
readonly w: number;
|
|
24
|
+
} | {
|
|
25
|
+
readonly k: "setOpacity";
|
|
26
|
+
readonly a: number;
|
|
27
|
+
} | {
|
|
28
|
+
readonly k: "setLineCap";
|
|
29
|
+
readonly cap: LineCap;
|
|
30
|
+
} | {
|
|
31
|
+
readonly k: "setLineJoin";
|
|
32
|
+
readonly join: LineJoin;
|
|
33
|
+
} | {
|
|
34
|
+
readonly k: "setDashArray";
|
|
35
|
+
readonly dash: readonly number[] | null;
|
|
36
|
+
} | {
|
|
37
|
+
readonly k: "setFont";
|
|
38
|
+
readonly family: string;
|
|
39
|
+
readonly size: number;
|
|
40
|
+
readonly options?: {
|
|
41
|
+
readonly weight?: "normal" | "bold";
|
|
42
|
+
readonly style?: "normal" | "italic";
|
|
43
|
+
};
|
|
44
|
+
} | {
|
|
45
|
+
readonly k: "setTextAlign";
|
|
46
|
+
readonly align: TextAlign;
|
|
47
|
+
} | {
|
|
48
|
+
readonly k: "setTextBaseline";
|
|
49
|
+
readonly baseline: TextBaseline;
|
|
50
|
+
} | {
|
|
51
|
+
readonly k: "save";
|
|
52
|
+
} | {
|
|
53
|
+
readonly k: "restore";
|
|
54
|
+
} | {
|
|
55
|
+
readonly k: "translate";
|
|
56
|
+
readonly x: number;
|
|
57
|
+
readonly y: number;
|
|
58
|
+
} | {
|
|
59
|
+
readonly k: "rotate";
|
|
60
|
+
readonly r: number;
|
|
61
|
+
} | {
|
|
62
|
+
readonly k: "scale";
|
|
63
|
+
readonly sx: number;
|
|
64
|
+
readonly sy: number;
|
|
65
|
+
} | {
|
|
66
|
+
readonly k: "setTransform";
|
|
67
|
+
readonly t: Transform;
|
|
68
|
+
} | {
|
|
69
|
+
readonly k: "resetTransform";
|
|
70
|
+
} | {
|
|
71
|
+
readonly k: "beginPath";
|
|
72
|
+
} | {
|
|
73
|
+
readonly k: "closePath";
|
|
74
|
+
} | {
|
|
75
|
+
readonly k: "moveTo";
|
|
76
|
+
readonly x: number;
|
|
77
|
+
readonly y: number;
|
|
78
|
+
} | {
|
|
79
|
+
readonly k: "lineTo";
|
|
80
|
+
readonly x: number;
|
|
81
|
+
readonly y: number;
|
|
82
|
+
} | {
|
|
83
|
+
readonly k: "quadraticCurveTo";
|
|
84
|
+
readonly cx: number;
|
|
85
|
+
readonly cy: number;
|
|
86
|
+
readonly x: number;
|
|
87
|
+
readonly y: number;
|
|
88
|
+
} | {
|
|
89
|
+
readonly k: "bezierCurveTo";
|
|
90
|
+
readonly c1x: number;
|
|
91
|
+
readonly c1y: number;
|
|
92
|
+
readonly c2x: number;
|
|
93
|
+
readonly c2y: number;
|
|
94
|
+
readonly x: number;
|
|
95
|
+
readonly y: number;
|
|
96
|
+
} | {
|
|
97
|
+
readonly k: "rect";
|
|
98
|
+
readonly x: number;
|
|
99
|
+
readonly y: number;
|
|
100
|
+
readonly w: number;
|
|
101
|
+
readonly h: number;
|
|
102
|
+
} | {
|
|
103
|
+
readonly k: "ellipse";
|
|
104
|
+
readonly cx: number;
|
|
105
|
+
readonly cy: number;
|
|
106
|
+
readonly rx: number;
|
|
107
|
+
readonly ry: number;
|
|
108
|
+
} | {
|
|
109
|
+
readonly k: "fill";
|
|
110
|
+
readonly rule?: FillRule;
|
|
111
|
+
} | {
|
|
112
|
+
readonly k: "stroke";
|
|
113
|
+
} | {
|
|
114
|
+
readonly k: "fillText";
|
|
115
|
+
readonly text: string;
|
|
116
|
+
readonly x: number;
|
|
117
|
+
readonly y: number;
|
|
118
|
+
readonly maxWidth?: number;
|
|
119
|
+
} | {
|
|
120
|
+
readonly k: "clear";
|
|
121
|
+
readonly bounds?: Bounds;
|
|
122
|
+
} | {
|
|
123
|
+
readonly k: "markDirty";
|
|
124
|
+
readonly bounds: Bounds;
|
|
125
|
+
} | {
|
|
126
|
+
readonly k: "resize";
|
|
127
|
+
readonly w: number;
|
|
128
|
+
readonly h: number;
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* `drawImage` is NOT serialisable through this command stream — image
|
|
132
|
+
* sources (HTMLImageElement, ImageBitmap, HTMLCanvasElement) either
|
|
133
|
+
* can't cross the postMessage boundary cleanly or require expensive
|
|
134
|
+
* transfers. The recording target silently skips `drawImage` calls and
|
|
135
|
+
* counts them in `skippedImageDraws` so the host UI can warn (or fall
|
|
136
|
+
* back to main-thread compositing for image-heavy scenes).
|
|
137
|
+
*
|
|
138
|
+
* `measureText` returns a synchronous heuristic — the worker has the
|
|
139
|
+
* authoritative measurement, but routing per-call is too chatty. Hosts
|
|
140
|
+
* that care about pixel-perfect text in offscreen mode should
|
|
141
|
+
* pre-measure on a sidecar text shaper.
|
|
142
|
+
*/
|
|
143
|
+
export declare class RecordingTarget implements RenderTarget {
|
|
144
|
+
private commands;
|
|
145
|
+
private _width;
|
|
146
|
+
private _height;
|
|
147
|
+
/** Counter so hosts can warn when images are silently skipped. */
|
|
148
|
+
skippedImageDraws: number;
|
|
149
|
+
constructor(width: number, height: number);
|
|
150
|
+
get size(): {
|
|
151
|
+
readonly width: number;
|
|
152
|
+
readonly height: number;
|
|
153
|
+
};
|
|
154
|
+
resize(width: number, height: number): void;
|
|
155
|
+
/** Pop the buffered commands and clear the internal log. */
|
|
156
|
+
flush(): readonly RenderCommand[];
|
|
157
|
+
/** Snapshot of the buffered commands without clearing. */
|
|
158
|
+
peek(): readonly RenderCommand[];
|
|
159
|
+
setFill(color: Color | null): void;
|
|
160
|
+
setStroke(color: Color | null): void;
|
|
161
|
+
setStrokeWidth(w: number): void;
|
|
162
|
+
setOpacity(a: number): void;
|
|
163
|
+
setLineCap(cap: LineCap): void;
|
|
164
|
+
setLineJoin(join: LineJoin): void;
|
|
165
|
+
setDashArray(dash: readonly number[] | null): void;
|
|
166
|
+
setFont(family: string, size: number, options?: {
|
|
167
|
+
weight?: "normal" | "bold";
|
|
168
|
+
style?: "normal" | "italic";
|
|
169
|
+
}): void;
|
|
170
|
+
setTextAlign(align: TextAlign): void;
|
|
171
|
+
setTextBaseline(baseline: TextBaseline): void;
|
|
172
|
+
save(): void;
|
|
173
|
+
restore(): void;
|
|
174
|
+
translate(x: number, y: number): void;
|
|
175
|
+
rotate(r: number): void;
|
|
176
|
+
scale(sx: number, sy: number): void;
|
|
177
|
+
setTransform(t: Transform): void;
|
|
178
|
+
resetTransform(): void;
|
|
179
|
+
beginPath(): void;
|
|
180
|
+
closePath(): void;
|
|
181
|
+
moveTo(x: number, y: number): void;
|
|
182
|
+
lineTo(x: number, y: number): void;
|
|
183
|
+
quadraticCurveTo(cx: number, cy: number, x: number, y: number): void;
|
|
184
|
+
bezierCurveTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): void;
|
|
185
|
+
rect(x: number, y: number, w: number, h: number): void;
|
|
186
|
+
ellipse(cx: number, cy: number, rx: number, ry: number): void;
|
|
187
|
+
fill(rule?: FillRule): void;
|
|
188
|
+
stroke(): void;
|
|
189
|
+
fillText(text: string, x: number, y: number, maxWidth?: number): void;
|
|
190
|
+
measureText(text: string): {
|
|
191
|
+
width: number;
|
|
192
|
+
};
|
|
193
|
+
drawImage(_image: unknown, _dx: number, _dy: number, _dw: number, _dh: number): void;
|
|
194
|
+
clear(bounds?: Bounds): void;
|
|
195
|
+
markDirty(bounds: Bounds): void;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Replay a previously-flushed command buffer onto a real RenderTarget.
|
|
199
|
+
* Used by the worker entry point to apply commands shipped from the
|
|
200
|
+
* main thread.
|
|
201
|
+
*/
|
|
202
|
+
export declare const replayCommands: (target: RenderTarget, commands: readonly RenderCommand[]) => void;
|
|
203
|
+
//# sourceMappingURL=recording-target.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recording-target.d.ts","sourceRoot":"","sources":["../src/recording-target.ts"],"names":[],"mappings":"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"}
|