@push.rocks/smartbrowser 4.1.0 → 4.3.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_ts/00_commitinfo_data.js +1 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/classes.livebrowsercanvasrenderer.d.ts +4 -187
- package/dist_ts_web/classes.livebrowsercanvasrenderer.js +5 -1750
- package/dist_ts_web/classes.livebrowserrenderer.d.ts +194 -0
- package/dist_ts_web/classes.livebrowserrenderer.js +1830 -0
- package/dist_ts_web/classes.livebrowservideoreceiver.d.ts +46 -0
- package/dist_ts_web/classes.livebrowservideoreceiver.js +243 -0
- package/dist_ts_web/classes.livebrowservideorenderer.d.ts +6 -0
- package/dist_ts_web/classes.livebrowservideorenderer.js +8 -0
- package/dist_ts_web/index.d.ts +3 -0
- package/dist_ts_web/index.js +2 -1
- package/dist_ts_web/interfaces.livebrowsercanvas.d.ts +8 -2
- package/dist_ts_web/interfaces.livebrowservideo.d.ts +31 -0
- package/dist_ts_web/interfaces.livebrowservideo.js +2 -0
- package/package.json +4 -4
- package/readme.md +25 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/classes.livebrowsercanvasrenderer.ts +5 -2151
- package/ts_web/classes.livebrowserrenderer.ts +2232 -0
- package/ts_web/classes.livebrowservideoreceiver.ts +250 -0
- package/ts_web/classes.livebrowservideorenderer.ts +9 -0
- package/ts_web/index.ts +4 -0
- package/ts_web/interfaces.livebrowsercanvas.ts +11 -1
- package/ts_web/interfaces.livebrowservideo.ts +46 -0
- package/readme.hints.md +0 -34
|
@@ -0,0 +1,1830 @@
|
|
|
1
|
+
import { LiveBrowserVideoReceiver } from './classes.livebrowservideoreceiver.js';
|
|
2
|
+
const maxInputQueueLength = 128;
|
|
3
|
+
const maxInFlightInputCommands = 4;
|
|
4
|
+
const maxQueuedCoalescableCommands = 32;
|
|
5
|
+
const maxWheelDelta = 1000000;
|
|
6
|
+
const animationFrameFallbackMs = 16;
|
|
7
|
+
const resizeDebounceMs = 100;
|
|
8
|
+
const maxPendingAcknowledgements = 16;
|
|
9
|
+
const maxInputReleaseAttempts = 2;
|
|
10
|
+
const maxFrameDimension = 12288;
|
|
11
|
+
const maxFramePixelArea = 8294400;
|
|
12
|
+
const maxFrameByteLength = (maxFramePixelArea * 4) + 1048576;
|
|
13
|
+
const maxViewportWidth = 4096;
|
|
14
|
+
const maxViewportHeight = 4096;
|
|
15
|
+
const minDeviceScaleFactor = 0.25;
|
|
16
|
+
const maxDeviceScaleFactor = 3;
|
|
17
|
+
const coordinateEdgeInset = 0.001;
|
|
18
|
+
const defaultOperationTimeoutMs = 10000;
|
|
19
|
+
class LiveBrowserOperationTimeoutError extends Error {
|
|
20
|
+
}
|
|
21
|
+
class LiveBrowserRunAbortedError extends Error {
|
|
22
|
+
}
|
|
23
|
+
class LiveBrowserFrameProtocolError extends Error {
|
|
24
|
+
}
|
|
25
|
+
class LiveBrowserFrameIntegrityError extends Error {
|
|
26
|
+
}
|
|
27
|
+
const isCoalescableInputCommand = (kindArg) => kindArg === 'mouseMove' || kindArg === 'wheel';
|
|
28
|
+
const clampWheelDelta = (valueArg) => (Math.max(-maxWheelDelta, Math.min(maxWheelDelta, valueArg)));
|
|
29
|
+
const mergeWheelInput = (targetArg, sourceArg) => {
|
|
30
|
+
targetArg.x = sourceArg.x;
|
|
31
|
+
targetArg.y = sourceArg.y;
|
|
32
|
+
targetArg.deltaX = clampWheelDelta(targetArg.deltaX + sourceArg.deltaX);
|
|
33
|
+
targetArg.deltaY = clampWheelDelta(targetArg.deltaY + sourceArg.deltaY);
|
|
34
|
+
targetArg.modifiers = sourceArg.modifiers;
|
|
35
|
+
};
|
|
36
|
+
const inputIdentityEquals = (firstArg, secondArg) => (firstArg.tabId === secondArg.tabId
|
|
37
|
+
&& firstArg.generation === secondArg.generation
|
|
38
|
+
&& firstArg.viewportRevision === secondArg.viewportRevision);
|
|
39
|
+
const viewportEquals = (firstArg, secondArg) => (firstArg.width === secondArg.width
|
|
40
|
+
&& firstArg.height === secondArg.height
|
|
41
|
+
&& firstArg.deviceScaleFactor === secondArg.deviceScaleFactor);
|
|
42
|
+
const createModifiers = (eventArg) => ({
|
|
43
|
+
alt: eventArg.altKey,
|
|
44
|
+
control: eventArg.ctrlKey,
|
|
45
|
+
meta: eventArg.metaKey,
|
|
46
|
+
shift: eventArg.shiftKey,
|
|
47
|
+
});
|
|
48
|
+
const createFrameAcknowledgementRequest = (frameArg) => ({
|
|
49
|
+
tabId: frameArg.tabId,
|
|
50
|
+
sequence: frameArg.sequence,
|
|
51
|
+
generation: frameArg.generation,
|
|
52
|
+
viewportRevision: frameArg.viewportRevision,
|
|
53
|
+
});
|
|
54
|
+
const createInputIdentity = (displayedFrameArg) => ({
|
|
55
|
+
tabId: displayedFrameArg.tabId,
|
|
56
|
+
generation: displayedFrameArg.generation,
|
|
57
|
+
viewportRevision: displayedFrameArg.viewportRevision,
|
|
58
|
+
});
|
|
59
|
+
const getErrorMessage = (errorArg) => (errorArg instanceof Error ? errorArg.message : String(errorArg));
|
|
60
|
+
/**
|
|
61
|
+
* Renders transport-neutral live browser frames and maps DOM input back to the
|
|
62
|
+
* currently displayed SmartPuppeteer frame identity.
|
|
63
|
+
*/
|
|
64
|
+
export class LiveBrowserRenderer {
|
|
65
|
+
constructor(optionsArg) {
|
|
66
|
+
this.lifecycleTail = Promise.resolve();
|
|
67
|
+
this.runEpoch = 0;
|
|
68
|
+
this.running = false;
|
|
69
|
+
this.suspended = false;
|
|
70
|
+
this.stopping = false;
|
|
71
|
+
this.interruptionRequested = false;
|
|
72
|
+
this.operationControllers = new Set();
|
|
73
|
+
this.acceptingFrames = false;
|
|
74
|
+
this.focusWasAdjusted = false;
|
|
75
|
+
this.focusHadTabIndex = false;
|
|
76
|
+
this.focusTabIndexValue = null;
|
|
77
|
+
this.highestFrameSequence = -1;
|
|
78
|
+
this.acknowledgementPromises = new Set();
|
|
79
|
+
this.rawDecodeSettlementPromises = new Set();
|
|
80
|
+
this.inputBlocked = true;
|
|
81
|
+
this.inputCommands = [];
|
|
82
|
+
this.inFlightInputCommands = 0;
|
|
83
|
+
this.inFlightWheelCommands = 0;
|
|
84
|
+
this.inputIdleResolvers = [];
|
|
85
|
+
this.inputResetTail = Promise.resolve();
|
|
86
|
+
this.inputResetCount = 0;
|
|
87
|
+
this.wheelFrameElapsed = true;
|
|
88
|
+
this.pressedKeys = new Map();
|
|
89
|
+
this.pressedMouseButtons = new Map();
|
|
90
|
+
this.capturedPointerIds = new Set();
|
|
91
|
+
this.viewportProcessing = false;
|
|
92
|
+
this.statistics = {
|
|
93
|
+
framesReceived: 0,
|
|
94
|
+
framesDecoded: 0,
|
|
95
|
+
framesSkipped: 0,
|
|
96
|
+
inputCommandsEnqueued: 0,
|
|
97
|
+
inputCommandsCoalesced: 0,
|
|
98
|
+
lastInputRoundTripMs: 0,
|
|
99
|
+
};
|
|
100
|
+
this.canvas = 'video' in optionsArg ? optionsArg.video : optionsArg.canvas;
|
|
101
|
+
this.client = optionsArg.client;
|
|
102
|
+
this.focusTarget = optionsArg.focusTarget ?? this.canvas;
|
|
103
|
+
this.resizeTarget = optionsArg.resizeTarget;
|
|
104
|
+
this.getDeviceScaleFactor = optionsArg.getDeviceScaleFactor
|
|
105
|
+
?? (() => window.devicePixelRatio || 1);
|
|
106
|
+
this.operationTimeoutMs = this.validateTimeout(optionsArg.operationTimeoutMs ?? defaultOperationTimeoutMs, 'operationTimeoutMs');
|
|
107
|
+
this.frameDecodeTimeoutMs = this.validateTimeout(('frameDecodeTimeoutMs' in optionsArg ? optionsArg.frameDecodeTimeoutMs : undefined) ?? this.operationTimeoutMs, 'frameDecodeTimeoutMs');
|
|
108
|
+
this.onError = optionsArg.onError;
|
|
109
|
+
this.onFrameRendered = 'onFrameRendered' in optionsArg ? optionsArg.onFrameRendered : undefined;
|
|
110
|
+
this.initialCanvasWidth = this.canvas.width;
|
|
111
|
+
this.initialCanvasHeight = this.canvas.height;
|
|
112
|
+
if ('video' in optionsArg) {
|
|
113
|
+
this.videoReceiver = new LiveBrowserVideoReceiver({
|
|
114
|
+
video: optionsArg.video, client: optionsArg.client, operationTimeoutMs: this.operationTimeoutMs,
|
|
115
|
+
onUnavailable: () => {
|
|
116
|
+
this.displayedFrame = undefined;
|
|
117
|
+
this.inputBlocked = true;
|
|
118
|
+
if (this.running)
|
|
119
|
+
void this.scheduleInputReset(false, this.runEpoch);
|
|
120
|
+
},
|
|
121
|
+
onPresented: (sourceArg) => this.presentVideo(sourceArg),
|
|
122
|
+
onError: (errorArg) => this.reportError(errorArg, this.runEpoch),
|
|
123
|
+
});
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const bitmapContext = optionsArg.canvas.getContext('bitmaprenderer');
|
|
127
|
+
if (bitmapContext) {
|
|
128
|
+
this.bitmapContext = bitmapContext;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
// A canvas that already owns a 2D context keeps the 2D drawing path.
|
|
132
|
+
const canvasContext = optionsArg.canvas.getContext('2d');
|
|
133
|
+
if (!canvasContext) {
|
|
134
|
+
throw new Error('LiveBrowserCanvasRenderer requires a bitmaprenderer or 2D canvas context');
|
|
135
|
+
}
|
|
136
|
+
this.canvasContext = canvasContext;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
get isRunning() {
|
|
140
|
+
return this.running;
|
|
141
|
+
}
|
|
142
|
+
get isSuspended() {
|
|
143
|
+
return this.suspended;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Cumulative frame and input counters for this renderer instance across runs.
|
|
147
|
+
*/
|
|
148
|
+
getStatistics() {
|
|
149
|
+
return {
|
|
150
|
+
...this.statistics,
|
|
151
|
+
...this.videoReceiver?.getCounters(),
|
|
152
|
+
...(this.videoReceiver ? { video: this.videoReceiver.getStatistics() } : {}),
|
|
153
|
+
inputCommandsInFlight: this.inFlightInputCommands,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
start() {
|
|
157
|
+
return this.enqueueLifecycle(async () => {
|
|
158
|
+
if (this.running) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (this.suspended) {
|
|
162
|
+
throw new Error('Live browser renderer is suspended; call resume() to start a fresh run');
|
|
163
|
+
}
|
|
164
|
+
await this.startRun(false);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
stop() {
|
|
168
|
+
this.interruptRun(this.runEpoch);
|
|
169
|
+
return this.enqueueLifecycle(async () => {
|
|
170
|
+
const runEpoch = this.runEpoch;
|
|
171
|
+
this.interruptRun(runEpoch);
|
|
172
|
+
if (this.stopping) {
|
|
173
|
+
await this.finishRun(runEpoch, false);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (!this.suspended) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
this.suspended = false;
|
|
180
|
+
this.restoreCanvasAndFocus();
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Aborts the current transport generation without replaying input recovery.
|
|
185
|
+
*/
|
|
186
|
+
suspend() {
|
|
187
|
+
this.interruptRun(this.runEpoch);
|
|
188
|
+
return this.enqueueLifecycle(async () => {
|
|
189
|
+
const runEpoch = this.runEpoch;
|
|
190
|
+
this.interruptRun(runEpoch);
|
|
191
|
+
if (!this.stopping) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
await this.finishRun(runEpoch, true);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Starts a new transport generation that requires new state and a new frame.
|
|
199
|
+
*/
|
|
200
|
+
resume() {
|
|
201
|
+
return this.enqueueLifecycle(async () => {
|
|
202
|
+
if (this.running) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (!this.suspended) {
|
|
206
|
+
throw new Error('Live browser renderer is not suspended');
|
|
207
|
+
}
|
|
208
|
+
await this.startRun(true);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Sends arbitrary committed text, including text produced by an external IME.
|
|
213
|
+
*/
|
|
214
|
+
async insertText(textArg) {
|
|
215
|
+
const displayedFrame = this.requireInputFrame();
|
|
216
|
+
const inputIdentity = createInputIdentity(displayedFrame);
|
|
217
|
+
await this.enqueueInputCommand({
|
|
218
|
+
kind: 'text',
|
|
219
|
+
runEpoch: this.runEpoch,
|
|
220
|
+
execute: async (optionsArg) => {
|
|
221
|
+
await this.client.insertText({
|
|
222
|
+
...inputIdentity,
|
|
223
|
+
text: textArg,
|
|
224
|
+
}, optionsArg);
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Reads the configured stable resize target and requests the corresponding
|
|
230
|
+
* remote CSS viewport. Intrinsic canvas dimensions are never used here.
|
|
231
|
+
*/
|
|
232
|
+
syncViewport() {
|
|
233
|
+
if (!this.running || this.stopping || this.interruptionRequested || !this.resizeTarget) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
this.queueViewport(this.resizeTarget.clientWidth, this.resizeTarget.clientHeight, this.runEpoch);
|
|
237
|
+
}
|
|
238
|
+
enqueueLifecycle(operationArg) {
|
|
239
|
+
const operation = this.lifecycleTail.then(operationArg, operationArg);
|
|
240
|
+
this.lifecycleTail = operation.then(() => undefined, () => undefined);
|
|
241
|
+
return operation;
|
|
242
|
+
}
|
|
243
|
+
async startRun(resumingArg) {
|
|
244
|
+
await Promise.all([...this.rawDecodeSettlementPromises]);
|
|
245
|
+
const runEpoch = ++this.runEpoch;
|
|
246
|
+
this.runController = new AbortController();
|
|
247
|
+
this.running = true;
|
|
248
|
+
this.suspended = false;
|
|
249
|
+
this.stopping = false;
|
|
250
|
+
this.interruptionRequested = false;
|
|
251
|
+
this.acceptingFrames = true;
|
|
252
|
+
this.inputBlocked = true;
|
|
253
|
+
this.wheelFrameElapsed = true;
|
|
254
|
+
this.state = undefined;
|
|
255
|
+
this.displayedFrame = undefined;
|
|
256
|
+
this.highestFrameSequence = -1;
|
|
257
|
+
this.clearCanvas();
|
|
258
|
+
try {
|
|
259
|
+
this.makeFocusTargetFocusable();
|
|
260
|
+
this.installDomListeners(runEpoch);
|
|
261
|
+
this.unsubscribe = this.client.onEvent((eventArg) => {
|
|
262
|
+
this.handleEvent(eventArg, runEpoch);
|
|
263
|
+
});
|
|
264
|
+
this.applyState(this.client.getState(), runEpoch);
|
|
265
|
+
this.installResizeObserver(runEpoch);
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
this.interruptRun(runEpoch);
|
|
269
|
+
await this.finishRun(runEpoch, resumingArg);
|
|
270
|
+
throw error;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
interruptRun(runEpochArg) {
|
|
274
|
+
if (runEpochArg !== this.runEpoch
|
|
275
|
+
|| (!this.running && !this.stopping)) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
this.running = false;
|
|
279
|
+
this.stopping = true;
|
|
280
|
+
this.interruptionRequested = true;
|
|
281
|
+
this.acceptingFrames = false;
|
|
282
|
+
this.inputBlocked = true;
|
|
283
|
+
this.pendingViewport = undefined;
|
|
284
|
+
this.queuedFrame = undefined;
|
|
285
|
+
this.displayedFrame = undefined;
|
|
286
|
+
this.resizeFence = undefined;
|
|
287
|
+
this.discardPendingDraw();
|
|
288
|
+
this.discardPendingWheel();
|
|
289
|
+
this.releasePointerCaptures();
|
|
290
|
+
this.clearCanvas();
|
|
291
|
+
this.videoReceiver?.interrupt();
|
|
292
|
+
const interruptionError = new LiveBrowserRunAbortedError(`Live browser renderer run ${runEpochArg} was interrupted`);
|
|
293
|
+
this.runController?.abort(interruptionError);
|
|
294
|
+
for (const controller of this.operationControllers) {
|
|
295
|
+
controller.abort(interruptionError);
|
|
296
|
+
}
|
|
297
|
+
const abandonedCommands = this.inputCommands.splice(0);
|
|
298
|
+
for (const command of abandonedCommands) {
|
|
299
|
+
command.reject(interruptionError);
|
|
300
|
+
}
|
|
301
|
+
this.pressedKeys.clear();
|
|
302
|
+
this.pressedMouseButtons.clear();
|
|
303
|
+
}
|
|
304
|
+
async finishRun(runEpochArg, suspendArg) {
|
|
305
|
+
if (runEpochArg !== this.runEpoch) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
try {
|
|
309
|
+
this.resizeObserver?.disconnect();
|
|
310
|
+
this.resizeObserver = undefined;
|
|
311
|
+
this.clearResizeDebounce();
|
|
312
|
+
this.listenerController?.abort();
|
|
313
|
+
this.listenerController = undefined;
|
|
314
|
+
const unsubscribe = this.unsubscribe;
|
|
315
|
+
this.unsubscribe = undefined;
|
|
316
|
+
if (unsubscribe) {
|
|
317
|
+
try {
|
|
318
|
+
unsubscribe();
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
this.reportError({
|
|
322
|
+
code: 'renderer_cleanup_failed',
|
|
323
|
+
message: `Could not unsubscribe the live browser renderer: ${getErrorMessage(error)}`,
|
|
324
|
+
cause: error,
|
|
325
|
+
}, runEpochArg);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
await Promise.allSettled([
|
|
329
|
+
this.videoReceiver?.stop(),
|
|
330
|
+
this.viewportProcessingPromise,
|
|
331
|
+
this.inputResetTail,
|
|
332
|
+
this.waitForInputIdle(),
|
|
333
|
+
this.frameProcessingPromise,
|
|
334
|
+
...this.acknowledgementPromises,
|
|
335
|
+
]);
|
|
336
|
+
}
|
|
337
|
+
finally {
|
|
338
|
+
for (const controller of this.operationControllers) {
|
|
339
|
+
controller.abort(new LiveBrowserRunAbortedError(`Live browser renderer run ${runEpochArg} finished`));
|
|
340
|
+
}
|
|
341
|
+
this.operationControllers.clear();
|
|
342
|
+
this.runController = undefined;
|
|
343
|
+
this.running = false;
|
|
344
|
+
this.suspended = suspendArg;
|
|
345
|
+
this.acceptingFrames = false;
|
|
346
|
+
this.state = undefined;
|
|
347
|
+
this.displayedFrame = undefined;
|
|
348
|
+
this.highestFrameSequence = -1;
|
|
349
|
+
this.queuedFrame = undefined;
|
|
350
|
+
this.frameProcessingPromise = undefined;
|
|
351
|
+
this.discardPendingDraw();
|
|
352
|
+
this.discardPendingWheel();
|
|
353
|
+
this.clearResizeDebounce();
|
|
354
|
+
this.acknowledgementPromises.clear();
|
|
355
|
+
this.resizeFence = undefined;
|
|
356
|
+
this.lastRequestedViewport = undefined;
|
|
357
|
+
this.pendingViewport = undefined;
|
|
358
|
+
this.inFlightViewport = undefined;
|
|
359
|
+
this.viewportProcessing = false;
|
|
360
|
+
this.viewportProcessingPromise = undefined;
|
|
361
|
+
this.inputResetPromise = undefined;
|
|
362
|
+
this.inputResetTail = Promise.resolve();
|
|
363
|
+
this.inputResetCount = 0;
|
|
364
|
+
this.inputBlocked = true;
|
|
365
|
+
this.pressedKeys.clear();
|
|
366
|
+
this.pressedMouseButtons.clear();
|
|
367
|
+
this.releasePointerCaptures();
|
|
368
|
+
const abandonedCommands = this.inputCommands.splice(0);
|
|
369
|
+
for (const command of abandonedCommands) {
|
|
370
|
+
command.reject(new Error('Live browser renderer stopped before dispatching input'));
|
|
371
|
+
}
|
|
372
|
+
const inputIdleResolvers = this.inputIdleResolvers;
|
|
373
|
+
this.inputIdleResolvers = [];
|
|
374
|
+
for (const resolver of inputIdleResolvers) {
|
|
375
|
+
resolver();
|
|
376
|
+
}
|
|
377
|
+
this.restoreCanvasAndFocus();
|
|
378
|
+
this.interruptionRequested = false;
|
|
379
|
+
this.stopping = false;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
restoreCanvasAndFocus() {
|
|
383
|
+
this.canvas.width = this.initialCanvasWidth;
|
|
384
|
+
this.canvas.height = this.initialCanvasHeight;
|
|
385
|
+
this.restoreFocusTarget();
|
|
386
|
+
}
|
|
387
|
+
installDomListeners(runEpochArg) {
|
|
388
|
+
const listenerController = new AbortController();
|
|
389
|
+
const signal = listenerController.signal;
|
|
390
|
+
this.listenerController = listenerController;
|
|
391
|
+
this.canvas.addEventListener('pointerdown', (eventArg) => {
|
|
392
|
+
this.handlePointerDown(eventArg, runEpochArg);
|
|
393
|
+
}, { signal });
|
|
394
|
+
this.canvas.addEventListener('pointermove', (eventArg) => {
|
|
395
|
+
this.handlePointerMove(eventArg, runEpochArg);
|
|
396
|
+
}, { signal });
|
|
397
|
+
this.canvas.addEventListener('pointerup', (eventArg) => {
|
|
398
|
+
this.handlePointerUp(eventArg, runEpochArg);
|
|
399
|
+
}, { signal });
|
|
400
|
+
this.canvas.addEventListener('pointercancel', (eventArg) => {
|
|
401
|
+
this.releasePointerCapture(eventArg.pointerId);
|
|
402
|
+
void this.scheduleInputReset(false, runEpochArg);
|
|
403
|
+
}, { signal });
|
|
404
|
+
this.canvas.addEventListener('lostpointercapture', (eventArg) => {
|
|
405
|
+
this.capturedPointerIds.delete(eventArg.pointerId);
|
|
406
|
+
if (this.pressedMouseButtons.size > 0) {
|
|
407
|
+
void this.scheduleInputReset(false, runEpochArg);
|
|
408
|
+
}
|
|
409
|
+
}, { signal });
|
|
410
|
+
this.canvas.addEventListener('contextmenu', (eventArg) => {
|
|
411
|
+
eventArg.preventDefault();
|
|
412
|
+
}, { signal });
|
|
413
|
+
this.canvas.addEventListener('wheel', (eventArg) => {
|
|
414
|
+
this.handleWheel(eventArg, runEpochArg);
|
|
415
|
+
}, { passive: false, signal });
|
|
416
|
+
this.focusTarget.addEventListener('keydown', (eventArg) => {
|
|
417
|
+
this.handleKey(eventArg, 'down', runEpochArg);
|
|
418
|
+
}, { signal });
|
|
419
|
+
this.focusTarget.addEventListener('keyup', (eventArg) => {
|
|
420
|
+
this.handleKey(eventArg, 'up', runEpochArg);
|
|
421
|
+
}, { signal });
|
|
422
|
+
this.focusTarget.addEventListener('compositionend', (eventArg) => {
|
|
423
|
+
if (!this.inputBlocked && eventArg.data) {
|
|
424
|
+
void this.insertText(eventArg.data).catch(() => undefined);
|
|
425
|
+
}
|
|
426
|
+
}, { signal });
|
|
427
|
+
window.addEventListener('blur', () => {
|
|
428
|
+
void this.scheduleInputReset(false, runEpochArg);
|
|
429
|
+
}, { signal });
|
|
430
|
+
window.addEventListener('resize', () => {
|
|
431
|
+
this.syncViewport();
|
|
432
|
+
}, { signal });
|
|
433
|
+
document.addEventListener('visibilitychange', () => {
|
|
434
|
+
if (this.state && this.running)
|
|
435
|
+
this.videoReceiver?.update(this.state);
|
|
436
|
+
if (document.visibilityState === 'hidden') {
|
|
437
|
+
void this.scheduleInputReset(false, runEpochArg);
|
|
438
|
+
}
|
|
439
|
+
}, { signal });
|
|
440
|
+
}
|
|
441
|
+
installResizeObserver(runEpochArg) {
|
|
442
|
+
if (!this.resizeTarget) {
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
this.resizeObserver = new ResizeObserver((entriesArg) => {
|
|
446
|
+
const matchingEntry = entriesArg.find((entryArg) => entryArg.target === this.resizeTarget);
|
|
447
|
+
if (!matchingEntry || runEpochArg !== this.runEpoch) {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
this.pendingResizeSize = {
|
|
451
|
+
width: matchingEntry.contentRect.width,
|
|
452
|
+
height: matchingEntry.contentRect.height,
|
|
453
|
+
};
|
|
454
|
+
if (this.resizeDebounceTimer !== undefined) {
|
|
455
|
+
globalThis.clearTimeout(this.resizeDebounceTimer);
|
|
456
|
+
}
|
|
457
|
+
this.resizeDebounceTimer = globalThis.setTimeout(() => {
|
|
458
|
+
this.resizeDebounceTimer = undefined;
|
|
459
|
+
const pendingResizeSize = this.pendingResizeSize;
|
|
460
|
+
this.pendingResizeSize = undefined;
|
|
461
|
+
if (pendingResizeSize) {
|
|
462
|
+
this.queueViewport(pendingResizeSize.width, pendingResizeSize.height, runEpochArg);
|
|
463
|
+
}
|
|
464
|
+
}, resizeDebounceMs);
|
|
465
|
+
});
|
|
466
|
+
this.resizeObserver.observe(this.resizeTarget);
|
|
467
|
+
this.syncViewport();
|
|
468
|
+
}
|
|
469
|
+
clearResizeDebounce() {
|
|
470
|
+
if (this.resizeDebounceTimer !== undefined) {
|
|
471
|
+
globalThis.clearTimeout(this.resizeDebounceTimer);
|
|
472
|
+
this.resizeDebounceTimer = undefined;
|
|
473
|
+
}
|
|
474
|
+
this.pendingResizeSize = undefined;
|
|
475
|
+
}
|
|
476
|
+
handleEvent(eventArg, runEpochArg) {
|
|
477
|
+
if (eventArg.type === 'frame') {
|
|
478
|
+
if (this.videoReceiver)
|
|
479
|
+
return;
|
|
480
|
+
this.queueFrame(eventArg.frame, runEpochArg);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
if (!this.running || runEpochArg !== this.runEpoch) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
if (eventArg.type === 'state') {
|
|
487
|
+
this.applyState(eventArg.state, runEpochArg);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
this.reportError({
|
|
491
|
+
code: 'remote_browser_error',
|
|
492
|
+
message: `${eventArg.error.code}: ${eventArg.error.message}`,
|
|
493
|
+
cause: eventArg.error,
|
|
494
|
+
}, runEpochArg);
|
|
495
|
+
}
|
|
496
|
+
applyState(stateArg, runEpochArg) {
|
|
497
|
+
if (!this.running || runEpochArg !== this.runEpoch) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
this.state = stateArg;
|
|
501
|
+
this.followNegotiatedViewport();
|
|
502
|
+
this.videoReceiver?.update(stateArg);
|
|
503
|
+
if (this.displayedFrame && this.isStateAheadOfDisplayedFrame(stateArg, this.displayedFrame)) {
|
|
504
|
+
this.displayedFrame = undefined;
|
|
505
|
+
this.clearCanvas();
|
|
506
|
+
void this.scheduleInputReset(false, runEpochArg);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
this.updateInputAvailability();
|
|
510
|
+
}
|
|
511
|
+
presentVideo(sourceArg) {
|
|
512
|
+
if (!this.running || !this.state)
|
|
513
|
+
return;
|
|
514
|
+
const tab = this.state.tabs.find((tabArg) => tabArg.id === sourceArg.tabId);
|
|
515
|
+
if (this.state.status !== 'running' || this.state.activeTabId !== sourceArg.tabId
|
|
516
|
+
|| this.state.viewportRevision !== sourceArg.viewportRevision || !tab?.streaming
|
|
517
|
+
|| tab.status !== 'open' || tab.generation !== sourceArg.generation)
|
|
518
|
+
return;
|
|
519
|
+
this.displayedFrame = { ...sourceArg, viewport: { ...sourceArg.viewport }, sequence: 0 };
|
|
520
|
+
this.updateInputAvailability();
|
|
521
|
+
}
|
|
522
|
+
isStateAheadOfDisplayedFrame(stateArg, displayedFrameArg) {
|
|
523
|
+
if (stateArg.status !== 'running' || stateArg.activeTabId !== displayedFrameArg.tabId) {
|
|
524
|
+
return true;
|
|
525
|
+
}
|
|
526
|
+
const activeTab = stateArg.tabs.find((tabArg) => tabArg.id === displayedFrameArg.tabId);
|
|
527
|
+
if (!activeTab || activeTab.status !== 'open' || !activeTab.streaming) {
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
return stateArg.viewportRevision > displayedFrameArg.viewportRevision
|
|
531
|
+
|| activeTab.generation > displayedFrameArg.generation;
|
|
532
|
+
}
|
|
533
|
+
queueFrame(frameArg, runEpochArg) {
|
|
534
|
+
if (!this.running || !this.acceptingFrames || runEpochArg !== this.runEpoch) {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
this.statistics.framesReceived++;
|
|
538
|
+
try {
|
|
539
|
+
this.validateFrame(frameArg);
|
|
540
|
+
if (frameArg.sequence <= this.highestFrameSequence) {
|
|
541
|
+
throw new LiveBrowserFrameProtocolError(`frame.sequence ${frameArg.sequence} must be strictly greater than current run high-water ${this.highestFrameSequence}`);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
catch (error) {
|
|
545
|
+
this.requestSuspend(runEpochArg);
|
|
546
|
+
this.reportError({
|
|
547
|
+
code: 'frame_render_failed',
|
|
548
|
+
message: `Rejected invalid live browser frame: ${getErrorMessage(error)}`,
|
|
549
|
+
cause: error,
|
|
550
|
+
frame: frameArg,
|
|
551
|
+
}, runEpochArg);
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
this.highestFrameSequence = frameArg.sequence;
|
|
555
|
+
const frameWork = {
|
|
556
|
+
frame: frameArg,
|
|
557
|
+
runEpoch: runEpochArg,
|
|
558
|
+
acknowledgementAttempted: false,
|
|
559
|
+
};
|
|
560
|
+
if (this.queuedFrame) {
|
|
561
|
+
// The superseded frame was already acknowledged at receipt.
|
|
562
|
+
this.queuedFrame = undefined;
|
|
563
|
+
this.statistics.framesSkipped++;
|
|
564
|
+
}
|
|
565
|
+
this.queuedFrame = frameWork;
|
|
566
|
+
void this.acknowledgeFrame(frameWork);
|
|
567
|
+
this.ensureFrameProcessor();
|
|
568
|
+
}
|
|
569
|
+
ensureFrameProcessor() {
|
|
570
|
+
if (this.frameProcessingPromise || !this.queuedFrame) {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
const processingPromise = this.processFrameQueue().finally(() => {
|
|
574
|
+
if (this.frameProcessingPromise === processingPromise) {
|
|
575
|
+
this.frameProcessingPromise = undefined;
|
|
576
|
+
if (this.queuedFrame) {
|
|
577
|
+
this.ensureFrameProcessor();
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
this.frameProcessingPromise = processingPromise;
|
|
582
|
+
}
|
|
583
|
+
async processFrameQueue() {
|
|
584
|
+
while (this.queuedFrame) {
|
|
585
|
+
const frameWork = this.queuedFrame;
|
|
586
|
+
this.queuedFrame = undefined;
|
|
587
|
+
await this.processFrame(frameWork);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
async processFrame(frameWorkArg) {
|
|
591
|
+
const { frame, runEpoch } = frameWorkArg;
|
|
592
|
+
let imageBitmap;
|
|
593
|
+
let terminalFailure = false;
|
|
594
|
+
let terminalError;
|
|
595
|
+
try {
|
|
596
|
+
if (!this.canRenderFrame(frame, runEpoch)) {
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
const frameBytes = new Uint8Array(frame.data.byteLength);
|
|
600
|
+
frameBytes.set(frame.data);
|
|
601
|
+
imageBitmap = await this.decodeFrame(new Blob([frameBytes.buffer], {
|
|
602
|
+
type: frame.mimeType,
|
|
603
|
+
}), runEpoch);
|
|
604
|
+
if (imageBitmap.width !== frame.width || imageBitmap.height !== frame.height) {
|
|
605
|
+
throw new LiveBrowserFrameIntegrityError(`decoded frame dimensions ${imageBitmap.width}x${imageBitmap.height} do not match ${frame.width}x${frame.height}`);
|
|
606
|
+
}
|
|
607
|
+
this.statistics.framesDecoded++;
|
|
608
|
+
if (!this.canRenderFrame(frame, runEpoch)) {
|
|
609
|
+
this.statistics.framesSkipped++;
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
this.setPendingDraw({ bitmap: imageBitmap, frame, runEpoch });
|
|
613
|
+
imageBitmap = undefined;
|
|
614
|
+
}
|
|
615
|
+
catch (error) {
|
|
616
|
+
if (error instanceof LiveBrowserRunAbortedError) {
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
terminalFailure = true;
|
|
620
|
+
terminalError = error;
|
|
621
|
+
}
|
|
622
|
+
finally {
|
|
623
|
+
imageBitmap?.close();
|
|
624
|
+
if (terminalFailure) {
|
|
625
|
+
this.requestSuspend(runEpoch);
|
|
626
|
+
this.reportError({
|
|
627
|
+
code: 'frame_render_failed',
|
|
628
|
+
message: `Could not render live browser frame: ${getErrorMessage(terminalError)}`,
|
|
629
|
+
cause: terminalError,
|
|
630
|
+
frame,
|
|
631
|
+
}, runEpoch);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Keeps only the newest decoded bitmap and presents it on the next animation frame.
|
|
637
|
+
*/
|
|
638
|
+
setPendingDraw(pendingDrawArg) {
|
|
639
|
+
if (this.pendingDraw) {
|
|
640
|
+
this.pendingDraw.bitmap.close();
|
|
641
|
+
this.statistics.framesSkipped++;
|
|
642
|
+
}
|
|
643
|
+
this.pendingDraw = pendingDrawArg;
|
|
644
|
+
if (!this.drawSchedule) {
|
|
645
|
+
this.drawSchedule = this.scheduleAnimationFrame(() => {
|
|
646
|
+
this.drawSchedule = undefined;
|
|
647
|
+
this.drawPendingFrame();
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
discardPendingDraw() {
|
|
652
|
+
if (this.drawSchedule) {
|
|
653
|
+
this.cancelScheduledFrame(this.drawSchedule);
|
|
654
|
+
this.drawSchedule = undefined;
|
|
655
|
+
}
|
|
656
|
+
const pendingDraw = this.pendingDraw;
|
|
657
|
+
this.pendingDraw = undefined;
|
|
658
|
+
if (pendingDraw) {
|
|
659
|
+
pendingDraw.bitmap.close();
|
|
660
|
+
this.statistics.framesSkipped++;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
drawPendingFrame() {
|
|
664
|
+
const pendingDraw = this.pendingDraw;
|
|
665
|
+
this.pendingDraw = undefined;
|
|
666
|
+
if (!pendingDraw) {
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
const { bitmap, frame, runEpoch } = pendingDraw;
|
|
670
|
+
if (!this.canRenderFrame(frame, runEpoch)) {
|
|
671
|
+
bitmap.close();
|
|
672
|
+
this.statistics.framesSkipped++;
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
try {
|
|
676
|
+
this.paintBitmap(bitmap, frame.width, frame.height);
|
|
677
|
+
}
|
|
678
|
+
catch (error) {
|
|
679
|
+
bitmap.close();
|
|
680
|
+
this.requestSuspend(runEpoch);
|
|
681
|
+
this.reportError({
|
|
682
|
+
code: 'frame_render_failed',
|
|
683
|
+
message: `Could not render live browser frame: ${getErrorMessage(error)}`,
|
|
684
|
+
cause: error,
|
|
685
|
+
frame,
|
|
686
|
+
}, runEpoch);
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
this.displayedFrame = {
|
|
690
|
+
tabId: frame.tabId,
|
|
691
|
+
sequence: frame.sequence,
|
|
692
|
+
generation: frame.generation,
|
|
693
|
+
viewportRevision: frame.viewportRevision,
|
|
694
|
+
viewport: { ...frame.viewport },
|
|
695
|
+
};
|
|
696
|
+
if (this.resizeFence
|
|
697
|
+
&& !this.viewportProcessing
|
|
698
|
+
&& frame.viewportRevision >= this.resizeFence.minimumViewportRevision
|
|
699
|
+
&& viewportEquals(frame.viewport, this.resizeFence.target)) {
|
|
700
|
+
this.resizeFence = undefined;
|
|
701
|
+
}
|
|
702
|
+
this.updateInputAvailability();
|
|
703
|
+
this.callFrameRendered(frame, runEpoch);
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Presents one decoded bitmap. The canvas backing store is reallocated only
|
|
707
|
+
* when the frame dimensions differ from the current intrinsic dimensions.
|
|
708
|
+
*/
|
|
709
|
+
paintBitmap(bitmapArg, widthArg, heightArg) {
|
|
710
|
+
if (this.canvas.width !== widthArg) {
|
|
711
|
+
this.canvas.width = widthArg;
|
|
712
|
+
}
|
|
713
|
+
if (this.canvas.height !== heightArg) {
|
|
714
|
+
this.canvas.height = heightArg;
|
|
715
|
+
}
|
|
716
|
+
if (this.bitmapContext) {
|
|
717
|
+
this.bitmapContext.transferFromImageBitmap(bitmapArg);
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
if (!this.canvasContext) {
|
|
721
|
+
throw new Error('LiveBrowserCanvasRenderer has no rendering context');
|
|
722
|
+
}
|
|
723
|
+
this.canvasContext.clearRect(0, 0, widthArg, heightArg);
|
|
724
|
+
this.canvasContext.drawImage(bitmapArg, 0, 0, widthArg, heightArg);
|
|
725
|
+
bitmapArg.close();
|
|
726
|
+
}
|
|
727
|
+
canRenderFrame(frameArg, runEpochArg) {
|
|
728
|
+
if (!this.running
|
|
729
|
+
|| !this.acceptingFrames
|
|
730
|
+
|| runEpochArg !== this.runEpoch) {
|
|
731
|
+
return false;
|
|
732
|
+
}
|
|
733
|
+
const state = this.state;
|
|
734
|
+
if (!state || state.status !== 'running' || state.activeTabId !== frameArg.tabId) {
|
|
735
|
+
return false;
|
|
736
|
+
}
|
|
737
|
+
const activeTab = state.tabs.find((tabArg) => tabArg.id === frameArg.tabId);
|
|
738
|
+
if (!activeTab || activeTab.status !== 'open' || !activeTab.streaming) {
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
if (state.viewportRevision > frameArg.viewportRevision
|
|
742
|
+
|| activeTab.generation > frameArg.generation) {
|
|
743
|
+
return false;
|
|
744
|
+
}
|
|
745
|
+
if (this.resizeFence && !this.viewportProcessing) {
|
|
746
|
+
return frameArg.viewportRevision >= this.resizeFence.minimumViewportRevision
|
|
747
|
+
&& viewportEquals(frameArg.viewport, this.resizeFence.target);
|
|
748
|
+
}
|
|
749
|
+
return true;
|
|
750
|
+
}
|
|
751
|
+
acknowledgeFrame(frameWorkArg) {
|
|
752
|
+
if (frameWorkArg.acknowledgementAttempted) {
|
|
753
|
+
return Promise.resolve();
|
|
754
|
+
}
|
|
755
|
+
frameWorkArg.acknowledgementAttempted = true;
|
|
756
|
+
if (!this.isRunActive(frameWorkArg.runEpoch)) {
|
|
757
|
+
return Promise.resolve();
|
|
758
|
+
}
|
|
759
|
+
if (this.acknowledgementPromises.size >= maxPendingAcknowledgements) {
|
|
760
|
+
this.requestSuspend(frameWorkArg.runEpoch);
|
|
761
|
+
this.reportError({
|
|
762
|
+
code: 'frame_acknowledgement_failed',
|
|
763
|
+
message: `Live browser frame acknowledgement capacity of ${maxPendingAcknowledgements} was reached`,
|
|
764
|
+
}, frameWorkArg.runEpoch);
|
|
765
|
+
return Promise.resolve();
|
|
766
|
+
}
|
|
767
|
+
const acknowledgement = this.runClientOperation((optionsArg) => {
|
|
768
|
+
if (!('acknowledgeFrame' in this.client))
|
|
769
|
+
throw new Error('Video clients do not acknowledge image frames');
|
|
770
|
+
return this.client.acknowledgeFrame(createFrameAcknowledgementRequest(frameWorkArg.frame), optionsArg);
|
|
771
|
+
}, 'frame acknowledgement', frameWorkArg.runEpoch)
|
|
772
|
+
.then(() => undefined)
|
|
773
|
+
.catch((error) => {
|
|
774
|
+
if (error instanceof LiveBrowserRunAbortedError) {
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
this.requestSuspend(frameWorkArg.runEpoch);
|
|
778
|
+
this.reportError({
|
|
779
|
+
code: 'frame_acknowledgement_failed',
|
|
780
|
+
message: `Could not acknowledge live browser frame: ${getErrorMessage(error)}`,
|
|
781
|
+
cause: error,
|
|
782
|
+
frame: frameWorkArg.frame,
|
|
783
|
+
}, frameWorkArg.runEpoch);
|
|
784
|
+
});
|
|
785
|
+
let trackedAcknowledgement;
|
|
786
|
+
trackedAcknowledgement = acknowledgement.finally(() => {
|
|
787
|
+
this.acknowledgementPromises.delete(trackedAcknowledgement);
|
|
788
|
+
});
|
|
789
|
+
this.acknowledgementPromises.add(trackedAcknowledgement);
|
|
790
|
+
return trackedAcknowledgement;
|
|
791
|
+
}
|
|
792
|
+
handlePointerDown(eventArg, runEpochArg) {
|
|
793
|
+
if (eventArg.pointerType && eventArg.pointerType !== 'mouse') {
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
const button = this.getMouseButton(eventArg.button);
|
|
797
|
+
if (!button) {
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
const displayedFrame = this.getInputFrame();
|
|
801
|
+
if (!displayedFrame || runEpochArg !== this.runEpoch) {
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
eventArg.preventDefault();
|
|
805
|
+
const coordinates = this.mapCoordinates(eventArg, displayedFrame.viewport);
|
|
806
|
+
if (!coordinates) {
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
this.focusTarget.focus({ preventScroll: true });
|
|
810
|
+
try {
|
|
811
|
+
this.canvas.setPointerCapture(eventArg.pointerId);
|
|
812
|
+
this.capturedPointerIds.add(eventArg.pointerId);
|
|
813
|
+
}
|
|
814
|
+
catch {
|
|
815
|
+
// Pointer capture may already have been released by the browser.
|
|
816
|
+
}
|
|
817
|
+
const input = {
|
|
818
|
+
...createInputIdentity(displayedFrame),
|
|
819
|
+
type: 'down',
|
|
820
|
+
...coordinates,
|
|
821
|
+
button,
|
|
822
|
+
buttons: eventArg.buttons,
|
|
823
|
+
clickCount: Math.min(3, Math.max(1, eventArg.detail || 1)),
|
|
824
|
+
modifiers: createModifiers(eventArg),
|
|
825
|
+
};
|
|
826
|
+
void this.enqueueInputCommand({
|
|
827
|
+
kind: 'mouse',
|
|
828
|
+
runEpoch: runEpochArg,
|
|
829
|
+
execute: async (optionsArg) => this.client.dispatchMouse(input, optionsArg),
|
|
830
|
+
onAttempt: () => this.pressedMouseButtons.set(button, input),
|
|
831
|
+
}).catch(() => undefined);
|
|
832
|
+
}
|
|
833
|
+
handlePointerMove(eventArg, runEpochArg) {
|
|
834
|
+
if (eventArg.pointerType && eventArg.pointerType !== 'mouse') {
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
const displayedFrame = this.getInputFrame();
|
|
838
|
+
if (!displayedFrame || runEpochArg !== this.runEpoch) {
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
eventArg.preventDefault();
|
|
842
|
+
const coordinates = this.mapCoordinates(eventArg, displayedFrame.viewport);
|
|
843
|
+
if (!coordinates) {
|
|
844
|
+
this.releasePointerCapture(eventArg.pointerId);
|
|
845
|
+
void this.scheduleInputReset(false, runEpochArg);
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
const input = {
|
|
849
|
+
...createInputIdentity(displayedFrame),
|
|
850
|
+
type: 'move',
|
|
851
|
+
...coordinates,
|
|
852
|
+
button: 'none',
|
|
853
|
+
buttons: eventArg.buttons,
|
|
854
|
+
modifiers: createModifiers(eventArg),
|
|
855
|
+
};
|
|
856
|
+
void this.enqueueInputCommand({
|
|
857
|
+
kind: 'mouseMove',
|
|
858
|
+
runEpoch: runEpochArg,
|
|
859
|
+
execute: async (optionsArg) => this.client.dispatchMouse(input, optionsArg),
|
|
860
|
+
}).catch(() => undefined);
|
|
861
|
+
}
|
|
862
|
+
handlePointerUp(eventArg, runEpochArg) {
|
|
863
|
+
if (eventArg.pointerType && eventArg.pointerType !== 'mouse') {
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
const button = this.getMouseButton(eventArg.button);
|
|
867
|
+
const displayedFrame = this.getInputFrame();
|
|
868
|
+
if (!button || !displayedFrame || runEpochArg !== this.runEpoch) {
|
|
869
|
+
this.releasePointerCapture(eventArg.pointerId);
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
eventArg.preventDefault();
|
|
873
|
+
const coordinates = this.mapCoordinates(eventArg, displayedFrame.viewport);
|
|
874
|
+
if (!coordinates) {
|
|
875
|
+
this.releasePointerCapture(eventArg.pointerId);
|
|
876
|
+
void this.scheduleInputReset(false, runEpochArg);
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
const input = {
|
|
880
|
+
...createInputIdentity(displayedFrame),
|
|
881
|
+
type: 'up',
|
|
882
|
+
...coordinates,
|
|
883
|
+
button,
|
|
884
|
+
buttons: eventArg.buttons,
|
|
885
|
+
clickCount: Math.min(3, Math.max(1, eventArg.detail || 1)),
|
|
886
|
+
modifiers: createModifiers(eventArg),
|
|
887
|
+
};
|
|
888
|
+
void this.enqueueInputCommand({
|
|
889
|
+
kind: 'mouse',
|
|
890
|
+
runEpoch: runEpochArg,
|
|
891
|
+
execute: async (optionsArg) => this.client.dispatchMouse(input, optionsArg),
|
|
892
|
+
onSuccess: () => this.pressedMouseButtons.delete(button),
|
|
893
|
+
}).catch(() => undefined);
|
|
894
|
+
this.releasePointerCapture(eventArg.pointerId);
|
|
895
|
+
}
|
|
896
|
+
handleWheel(eventArg, runEpochArg) {
|
|
897
|
+
const displayedFrame = this.getInputFrame();
|
|
898
|
+
if (!displayedFrame || runEpochArg !== this.runEpoch) {
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
eventArg.preventDefault();
|
|
902
|
+
const coordinates = this.mapCoordinates(eventArg, displayedFrame.viewport);
|
|
903
|
+
if (!coordinates) {
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
const multiplier = eventArg.deltaMode === WheelEvent.DOM_DELTA_LINE
|
|
907
|
+
? 16
|
|
908
|
+
: eventArg.deltaMode === WheelEvent.DOM_DELTA_PAGE
|
|
909
|
+
? displayedFrame.viewport.height
|
|
910
|
+
: 1;
|
|
911
|
+
const inputIdentity = createInputIdentity(displayedFrame);
|
|
912
|
+
const modifiers = createModifiers(eventArg);
|
|
913
|
+
this.statistics.inputCommandsEnqueued++;
|
|
914
|
+
const pendingWheel = this.pendingWheel;
|
|
915
|
+
if (pendingWheel
|
|
916
|
+
&& pendingWheel.runEpoch === runEpochArg
|
|
917
|
+
&& inputIdentityEquals(pendingWheel, inputIdentity)) {
|
|
918
|
+
mergeWheelInput(pendingWheel, {
|
|
919
|
+
...inputIdentity,
|
|
920
|
+
...coordinates,
|
|
921
|
+
deltaX: eventArg.deltaX * multiplier,
|
|
922
|
+
deltaY: eventArg.deltaY * multiplier,
|
|
923
|
+
modifiers,
|
|
924
|
+
});
|
|
925
|
+
this.statistics.inputCommandsCoalesced++;
|
|
926
|
+
}
|
|
927
|
+
else {
|
|
928
|
+
if (pendingWheel) {
|
|
929
|
+
this.flushPendingWheel();
|
|
930
|
+
}
|
|
931
|
+
this.pendingWheel = {
|
|
932
|
+
...inputIdentity,
|
|
933
|
+
...coordinates,
|
|
934
|
+
deltaX: clampWheelDelta(eventArg.deltaX * multiplier),
|
|
935
|
+
deltaY: clampWheelDelta(eventArg.deltaY * multiplier),
|
|
936
|
+
modifiers,
|
|
937
|
+
runEpoch: runEpochArg,
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
this.tryFlushPendingWheel();
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Flushes accumulated wheel input at most once per animation frame and only
|
|
944
|
+
* while no wheel dispatch is in flight; the settling dispatch flushes the rest.
|
|
945
|
+
*/
|
|
946
|
+
tryFlushPendingWheel() {
|
|
947
|
+
if (!this.pendingWheel) {
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
if (!this.wheelFrameElapsed) {
|
|
951
|
+
this.scheduleWheelFlush();
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
if (this.inFlightWheelCommands > 0) {
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
this.flushPendingWheel();
|
|
958
|
+
}
|
|
959
|
+
scheduleWheelFlush() {
|
|
960
|
+
if (this.wheelFlushSchedule) {
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
this.wheelFlushSchedule = this.scheduleAnimationFrame(() => {
|
|
964
|
+
this.wheelFlushSchedule = undefined;
|
|
965
|
+
this.wheelFrameElapsed = true;
|
|
966
|
+
this.tryFlushPendingWheel();
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Moves the accumulated wheel input into the command queue regardless of the
|
|
971
|
+
* frame gate so that later discrete commands stay behind it.
|
|
972
|
+
*/
|
|
973
|
+
flushPendingWheel() {
|
|
974
|
+
const pendingWheel = this.pendingWheel;
|
|
975
|
+
if (!pendingWheel) {
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
this.pendingWheel = undefined;
|
|
979
|
+
this.wheelFrameElapsed = false;
|
|
980
|
+
this.scheduleWheelFlush();
|
|
981
|
+
const displayedFrame = this.getInputFrame();
|
|
982
|
+
if (!displayedFrame
|
|
983
|
+
|| pendingWheel.runEpoch !== this.runEpoch
|
|
984
|
+
|| !inputIdentityEquals(pendingWheel, createInputIdentity(displayedFrame))) {
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
const { runEpoch, ...wheelInput } = pendingWheel;
|
|
988
|
+
void this.enqueueInputCommand({
|
|
989
|
+
kind: 'wheel',
|
|
990
|
+
runEpoch,
|
|
991
|
+
wheelInput,
|
|
992
|
+
execute: async (optionsArg) => this.client.dispatchWheel({
|
|
993
|
+
...wheelInput,
|
|
994
|
+
deltaX: clampWheelDelta(wheelInput.deltaX),
|
|
995
|
+
deltaY: clampWheelDelta(wheelInput.deltaY),
|
|
996
|
+
}, optionsArg),
|
|
997
|
+
}).catch(() => undefined);
|
|
998
|
+
}
|
|
999
|
+
discardPendingWheel() {
|
|
1000
|
+
this.pendingWheel = undefined;
|
|
1001
|
+
if (this.wheelFlushSchedule) {
|
|
1002
|
+
this.cancelScheduledFrame(this.wheelFlushSchedule);
|
|
1003
|
+
this.wheelFlushSchedule = undefined;
|
|
1004
|
+
}
|
|
1005
|
+
this.wheelFrameElapsed = true;
|
|
1006
|
+
}
|
|
1007
|
+
handleKey(eventArg, typeArg, runEpochArg) {
|
|
1008
|
+
const displayedFrame = this.getInputFrame();
|
|
1009
|
+
if (!displayedFrame
|
|
1010
|
+
|| runEpochArg !== this.runEpoch
|
|
1011
|
+
|| eventArg.isComposing
|
|
1012
|
+
|| eventArg.key === 'Process') {
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
eventArg.preventDefault();
|
|
1016
|
+
const text = typeArg === 'down'
|
|
1017
|
+
&& eventArg.key.length === 1
|
|
1018
|
+
&& !eventArg.metaKey
|
|
1019
|
+
&& (!eventArg.ctrlKey || eventArg.altKey)
|
|
1020
|
+
? eventArg.key
|
|
1021
|
+
: undefined;
|
|
1022
|
+
const input = {
|
|
1023
|
+
...createInputIdentity(displayedFrame),
|
|
1024
|
+
type: typeArg,
|
|
1025
|
+
key: eventArg.key,
|
|
1026
|
+
code: eventArg.code || undefined,
|
|
1027
|
+
text,
|
|
1028
|
+
windowsVirtualKeyCode: eventArg.keyCode || undefined,
|
|
1029
|
+
autoRepeat: eventArg.repeat,
|
|
1030
|
+
isKeypad: eventArg.location === KeyboardEvent.DOM_KEY_LOCATION_NUMPAD,
|
|
1031
|
+
location: eventArg.location,
|
|
1032
|
+
modifiers: createModifiers(eventArg),
|
|
1033
|
+
};
|
|
1034
|
+
const keyIdentity = eventArg.code || eventArg.key;
|
|
1035
|
+
void this.enqueueInputCommand({
|
|
1036
|
+
kind: 'key',
|
|
1037
|
+
runEpoch: runEpochArg,
|
|
1038
|
+
execute: async (optionsArg) => this.client.dispatchKey(input, optionsArg),
|
|
1039
|
+
onAttempt: typeArg === 'down'
|
|
1040
|
+
? () => this.pressedKeys.set(keyIdentity, input)
|
|
1041
|
+
: undefined,
|
|
1042
|
+
onSuccess: () => {
|
|
1043
|
+
if (typeArg === 'up') {
|
|
1044
|
+
this.pressedKeys.delete(keyIdentity);
|
|
1045
|
+
}
|
|
1046
|
+
},
|
|
1047
|
+
}).catch(() => undefined);
|
|
1048
|
+
}
|
|
1049
|
+
mapCoordinates(eventArg, viewportArg) {
|
|
1050
|
+
const bounds = this.canvas.getBoundingClientRect();
|
|
1051
|
+
let canvasBounds = { left: bounds.left, top: bounds.top, width: bounds.width, height: bounds.height };
|
|
1052
|
+
if (this.videoReceiver && bounds.width > 0 && bounds.height > 0) {
|
|
1053
|
+
const scale = Math.min(bounds.width / viewportArg.width, bounds.height / viewportArg.height);
|
|
1054
|
+
canvasBounds = {
|
|
1055
|
+
left: bounds.left + (bounds.width - viewportArg.width * scale) / 2,
|
|
1056
|
+
top: bounds.top + (bounds.height - viewportArg.height * scale) / 2,
|
|
1057
|
+
width: viewportArg.width * scale, height: viewportArg.height * scale,
|
|
1058
|
+
};
|
|
1059
|
+
if (this.pressedMouseButtons.size === 0 && (eventArg.clientX < canvasBounds.left
|
|
1060
|
+
|| eventArg.clientX >= canvasBounds.left + canvasBounds.width
|
|
1061
|
+
|| eventArg.clientY < canvasBounds.top || eventArg.clientY >= canvasBounds.top + canvasBounds.height))
|
|
1062
|
+
return undefined;
|
|
1063
|
+
}
|
|
1064
|
+
if (canvasBounds.width <= 0 || canvasBounds.height <= 0) {
|
|
1065
|
+
return undefined;
|
|
1066
|
+
}
|
|
1067
|
+
const x = ((eventArg.clientX - canvasBounds.left) / canvasBounds.width) * viewportArg.width;
|
|
1068
|
+
const y = ((eventArg.clientY - canvasBounds.top) / canvasBounds.height) * viewportArg.height;
|
|
1069
|
+
return {
|
|
1070
|
+
x: Math.max(0, Math.min(viewportArg.width - coordinateEdgeInset, x)),
|
|
1071
|
+
y: Math.max(0, Math.min(viewportArg.height - coordinateEdgeInset, y)),
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
getMouseButton(buttonArg) {
|
|
1075
|
+
return buttonArg === 0
|
|
1076
|
+
? 'left'
|
|
1077
|
+
: buttonArg === 1
|
|
1078
|
+
? 'middle'
|
|
1079
|
+
: buttonArg === 2
|
|
1080
|
+
? 'right'
|
|
1081
|
+
: buttonArg === 3
|
|
1082
|
+
? 'back'
|
|
1083
|
+
: buttonArg === 4
|
|
1084
|
+
? 'forward'
|
|
1085
|
+
: undefined;
|
|
1086
|
+
}
|
|
1087
|
+
getInputFrame() {
|
|
1088
|
+
return this.inputBlocked || !this.isDisplayedFrameCurrent()
|
|
1089
|
+
? undefined
|
|
1090
|
+
: this.displayedFrame;
|
|
1091
|
+
}
|
|
1092
|
+
requireInputFrame() {
|
|
1093
|
+
const displayedFrame = this.getInputFrame();
|
|
1094
|
+
if (!displayedFrame) {
|
|
1095
|
+
throw new Error('Live browser input is unavailable until a current frame is displayed');
|
|
1096
|
+
}
|
|
1097
|
+
return displayedFrame;
|
|
1098
|
+
}
|
|
1099
|
+
isDisplayedFrameCurrent() {
|
|
1100
|
+
const state = this.state;
|
|
1101
|
+
const displayedFrame = this.displayedFrame;
|
|
1102
|
+
if (!state || !displayedFrame || state.status !== 'running') {
|
|
1103
|
+
return false;
|
|
1104
|
+
}
|
|
1105
|
+
if (state.activeTabId !== displayedFrame.tabId
|
|
1106
|
+
|| state.viewportRevision > displayedFrame.viewportRevision) {
|
|
1107
|
+
return false;
|
|
1108
|
+
}
|
|
1109
|
+
const activeTab = state.tabs.find((tabArg) => tabArg.id === displayedFrame.tabId);
|
|
1110
|
+
return Boolean(activeTab
|
|
1111
|
+
&& activeTab.status === 'open'
|
|
1112
|
+
&& activeTab.streaming
|
|
1113
|
+
&& activeTab.generation <= displayedFrame.generation);
|
|
1114
|
+
}
|
|
1115
|
+
enqueueInputCommand(commandArg) {
|
|
1116
|
+
if (!this.running || this.inputBlocked || commandArg.runEpoch !== this.runEpoch) {
|
|
1117
|
+
return Promise.reject(new Error('Live browser input is currently blocked'));
|
|
1118
|
+
}
|
|
1119
|
+
return new Promise((resolve, reject) => {
|
|
1120
|
+
const command = {
|
|
1121
|
+
...commandArg,
|
|
1122
|
+
resolve,
|
|
1123
|
+
reject,
|
|
1124
|
+
};
|
|
1125
|
+
if (isCoalescableInputCommand(command.kind)) {
|
|
1126
|
+
this.enqueueCoalescableCommand(command);
|
|
1127
|
+
}
|
|
1128
|
+
else {
|
|
1129
|
+
const queuedDiscreteCommands = this.inputCommands.filter((queuedCommand) => (!isCoalescableInputCommand(queuedCommand.kind))).length;
|
|
1130
|
+
if (queuedDiscreteCommands >= maxInputQueueLength) {
|
|
1131
|
+
const error = new Error('Live browser input queue reached its capacity');
|
|
1132
|
+
this.reportError({
|
|
1133
|
+
code: 'input_queue_capacity_exceeded',
|
|
1134
|
+
message: error.message,
|
|
1135
|
+
cause: error,
|
|
1136
|
+
}, command.runEpoch);
|
|
1137
|
+
reject(error);
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
// Accumulated wheel input precedes this command in event order.
|
|
1141
|
+
this.flushPendingWheel();
|
|
1142
|
+
this.statistics.inputCommandsEnqueued++;
|
|
1143
|
+
this.inputCommands.push(command);
|
|
1144
|
+
}
|
|
1145
|
+
this.processInputCommands();
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Coalescable commands never exhaust capacity: they merge into a same-kind
|
|
1150
|
+
* queue tail or evict the oldest queued coalescable command under pressure.
|
|
1151
|
+
*/
|
|
1152
|
+
enqueueCoalescableCommand(commandArg) {
|
|
1153
|
+
// Wheel submissions are counted per DOM event before accumulation.
|
|
1154
|
+
if (commandArg.kind === 'mouseMove') {
|
|
1155
|
+
this.statistics.inputCommandsEnqueued++;
|
|
1156
|
+
}
|
|
1157
|
+
const lastCommand = this.inputCommands.at(-1);
|
|
1158
|
+
if (lastCommand && lastCommand.kind === commandArg.kind) {
|
|
1159
|
+
this.statistics.inputCommandsCoalesced++;
|
|
1160
|
+
if (commandArg.kind === 'wheel' && lastCommand.wheelInput && commandArg.wheelInput) {
|
|
1161
|
+
mergeWheelInput(lastCommand.wheelInput, commandArg.wheelInput);
|
|
1162
|
+
commandArg.resolve();
|
|
1163
|
+
}
|
|
1164
|
+
else {
|
|
1165
|
+
lastCommand.resolve();
|
|
1166
|
+
this.inputCommands[this.inputCommands.length - 1] = commandArg;
|
|
1167
|
+
}
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
const queuedCoalescableCommands = this.inputCommands.filter((queuedCommand) => (isCoalescableInputCommand(queuedCommand.kind)));
|
|
1171
|
+
if (queuedCoalescableCommands.length >= maxQueuedCoalescableCommands) {
|
|
1172
|
+
this.dropOldestCoalescableCommand(queuedCoalescableCommands[0]);
|
|
1173
|
+
}
|
|
1174
|
+
this.inputCommands.push(commandArg);
|
|
1175
|
+
}
|
|
1176
|
+
dropOldestCoalescableCommand(oldestCommandArg) {
|
|
1177
|
+
const index = this.inputCommands.indexOf(oldestCommandArg);
|
|
1178
|
+
if (index < 0) {
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
this.inputCommands.splice(index, 1);
|
|
1182
|
+
this.statistics.inputCommandsCoalesced++;
|
|
1183
|
+
if (oldestCommandArg.kind === 'wheel' && oldestCommandArg.wheelInput) {
|
|
1184
|
+
const nextWheelCommand = this.inputCommands.find((queuedCommand) => (queuedCommand.kind === 'wheel' && queuedCommand.wheelInput));
|
|
1185
|
+
if (nextWheelCommand?.wheelInput) {
|
|
1186
|
+
const nextWheelInput = nextWheelCommand.wheelInput;
|
|
1187
|
+
nextWheelInput.deltaX = clampWheelDelta(nextWheelInput.deltaX + oldestCommandArg.wheelInput.deltaX);
|
|
1188
|
+
nextWheelInput.deltaY = clampWheelDelta(nextWheelInput.deltaY + oldestCommandArg.wheelInput.deltaY);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
oldestCommandArg.resolve();
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Dispatches queued commands in order with a bounded number in flight. The
|
|
1195
|
+
* remote session processes operations sequentially, so order is preserved.
|
|
1196
|
+
*/
|
|
1197
|
+
processInputCommands() {
|
|
1198
|
+
while (this.inputCommands.length > 0
|
|
1199
|
+
&& this.inFlightInputCommands < maxInFlightInputCommands) {
|
|
1200
|
+
const command = this.inputCommands.shift();
|
|
1201
|
+
if (!this.isRunActive(command.runEpoch)) {
|
|
1202
|
+
command.reject(new LiveBrowserRunAbortedError(`Live browser input belongs to inactive run ${command.runEpoch}`));
|
|
1203
|
+
continue;
|
|
1204
|
+
}
|
|
1205
|
+
this.dispatchInputCommand(command);
|
|
1206
|
+
}
|
|
1207
|
+
if (this.inputCommands.length === 0 && this.inFlightInputCommands === 0) {
|
|
1208
|
+
const resolvers = this.inputIdleResolvers;
|
|
1209
|
+
this.inputIdleResolvers = [];
|
|
1210
|
+
for (const resolver of resolvers) {
|
|
1211
|
+
resolver();
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
dispatchInputCommand(commandArg) {
|
|
1216
|
+
this.inFlightInputCommands++;
|
|
1217
|
+
if (commandArg.kind === 'wheel') {
|
|
1218
|
+
this.inFlightWheelCommands++;
|
|
1219
|
+
}
|
|
1220
|
+
const startedAt = performance.now();
|
|
1221
|
+
let dispatch;
|
|
1222
|
+
try {
|
|
1223
|
+
commandArg.onAttempt?.();
|
|
1224
|
+
dispatch = this.runClientOperation(commandArg.execute, 'input dispatch', commandArg.runEpoch);
|
|
1225
|
+
}
|
|
1226
|
+
catch (error) {
|
|
1227
|
+
dispatch = Promise.reject(error);
|
|
1228
|
+
}
|
|
1229
|
+
void dispatch.then(() => {
|
|
1230
|
+
if (!this.isRunActive(commandArg.runEpoch)) {
|
|
1231
|
+
throw new LiveBrowserRunAbortedError(`Live browser input belongs to inactive run ${commandArg.runEpoch}`);
|
|
1232
|
+
}
|
|
1233
|
+
this.statistics.lastInputRoundTripMs = performance.now() - startedAt;
|
|
1234
|
+
commandArg.onSuccess?.();
|
|
1235
|
+
commandArg.resolve();
|
|
1236
|
+
}).catch((error) => {
|
|
1237
|
+
commandArg.reject(error);
|
|
1238
|
+
this.handleInputDispatchFailure(error, commandArg.runEpoch);
|
|
1239
|
+
}).finally(() => {
|
|
1240
|
+
this.inFlightInputCommands--;
|
|
1241
|
+
if (commandArg.kind === 'wheel') {
|
|
1242
|
+
this.inFlightWheelCommands--;
|
|
1243
|
+
if (this.inFlightWheelCommands === 0) {
|
|
1244
|
+
this.tryFlushPendingWheel();
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
this.processInputCommands();
|
|
1248
|
+
});
|
|
1249
|
+
}
|
|
1250
|
+
handleInputDispatchFailure(errorArg, runEpochArg) {
|
|
1251
|
+
if (errorArg instanceof LiveBrowserRunAbortedError) {
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
if (errorArg instanceof LiveBrowserOperationTimeoutError) {
|
|
1255
|
+
this.requestSuspend(runEpochArg);
|
|
1256
|
+
}
|
|
1257
|
+
this.reportError({
|
|
1258
|
+
code: 'input_dispatch_failed',
|
|
1259
|
+
message: `Could not dispatch live browser input: ${getErrorMessage(errorArg)}`,
|
|
1260
|
+
cause: errorArg,
|
|
1261
|
+
}, runEpochArg);
|
|
1262
|
+
this.discardPendingWheel();
|
|
1263
|
+
const abandonedCommands = this.inputCommands.splice(0);
|
|
1264
|
+
for (const abandonedCommand of abandonedCommands) {
|
|
1265
|
+
abandonedCommand.reject(new Error('Live browser input was abandoned after a dispatch failure'));
|
|
1266
|
+
}
|
|
1267
|
+
if (!(errorArg instanceof LiveBrowserOperationTimeoutError) && !this.stopping) {
|
|
1268
|
+
void this.scheduleInputReset(true, runEpochArg);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
waitForInputIdle() {
|
|
1272
|
+
if (this.inFlightInputCommands === 0 && this.inputCommands.length === 0) {
|
|
1273
|
+
return Promise.resolve();
|
|
1274
|
+
}
|
|
1275
|
+
return new Promise((resolve) => {
|
|
1276
|
+
this.inputIdleResolvers.push(resolve);
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1279
|
+
scheduleInputReset(clearDisplayArg, runEpochArg) {
|
|
1280
|
+
if (runEpochArg !== this.runEpoch || this.stopping) {
|
|
1281
|
+
return Promise.resolve();
|
|
1282
|
+
}
|
|
1283
|
+
this.inputBlocked = true;
|
|
1284
|
+
this.releasePointerCaptures();
|
|
1285
|
+
if (clearDisplayArg) {
|
|
1286
|
+
this.displayedFrame = undefined;
|
|
1287
|
+
this.clearCanvas();
|
|
1288
|
+
}
|
|
1289
|
+
if (this.inputResetPromise) {
|
|
1290
|
+
return this.inputResetPromise;
|
|
1291
|
+
}
|
|
1292
|
+
this.inputResetCount++;
|
|
1293
|
+
let resetOperation;
|
|
1294
|
+
resetOperation = this.inputResetTail.then(async () => {
|
|
1295
|
+
await this.waitForInputIdle();
|
|
1296
|
+
await this.releasePressedInput(runEpochArg);
|
|
1297
|
+
}).finally(() => {
|
|
1298
|
+
this.inputResetCount--;
|
|
1299
|
+
if (this.inputResetPromise === resetOperation) {
|
|
1300
|
+
this.inputResetPromise = undefined;
|
|
1301
|
+
}
|
|
1302
|
+
this.updateInputAvailability();
|
|
1303
|
+
});
|
|
1304
|
+
this.inputResetPromise = resetOperation;
|
|
1305
|
+
this.inputResetTail = resetOperation.then(() => undefined, () => undefined);
|
|
1306
|
+
return resetOperation;
|
|
1307
|
+
}
|
|
1308
|
+
async releasePressedInput(runEpochArg) {
|
|
1309
|
+
for (const [keyIdentity, pressedKey] of [...this.pressedKeys.entries()]) {
|
|
1310
|
+
const released = await this.tryInputRelease((optionsArg) => this.client.dispatchKey({
|
|
1311
|
+
...pressedKey,
|
|
1312
|
+
type: 'up',
|
|
1313
|
+
text: undefined,
|
|
1314
|
+
autoRepeat: false,
|
|
1315
|
+
modifiers: {},
|
|
1316
|
+
}, optionsArg), runEpochArg);
|
|
1317
|
+
if (released && this.pressedKeys.get(keyIdentity) === pressedKey) {
|
|
1318
|
+
this.pressedKeys.delete(keyIdentity);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
for (const [button, pressedButton] of [...this.pressedMouseButtons.entries()]) {
|
|
1322
|
+
const released = await this.tryInputRelease((optionsArg) => this.client.dispatchMouse({
|
|
1323
|
+
...pressedButton,
|
|
1324
|
+
type: 'up',
|
|
1325
|
+
buttons: 0,
|
|
1326
|
+
clickCount: 1,
|
|
1327
|
+
modifiers: {},
|
|
1328
|
+
}, optionsArg), runEpochArg);
|
|
1329
|
+
if (released && this.pressedMouseButtons.get(button) === pressedButton) {
|
|
1330
|
+
this.pressedMouseButtons.delete(button);
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
async tryInputRelease(operationArg, runEpochArg) {
|
|
1335
|
+
let lastError;
|
|
1336
|
+
for (let attempt = 0; attempt < maxInputReleaseAttempts; attempt++) {
|
|
1337
|
+
try {
|
|
1338
|
+
await this.runClientOperation(operationArg, 'input release', runEpochArg);
|
|
1339
|
+
return true;
|
|
1340
|
+
}
|
|
1341
|
+
catch (error) {
|
|
1342
|
+
if (error instanceof LiveBrowserRunAbortedError) {
|
|
1343
|
+
return false;
|
|
1344
|
+
}
|
|
1345
|
+
lastError = error;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
this.requestSuspend(runEpochArg);
|
|
1349
|
+
this.reportInputReleaseError(lastError, runEpochArg);
|
|
1350
|
+
return false;
|
|
1351
|
+
}
|
|
1352
|
+
reportInputReleaseError(errorArg, runEpochArg) {
|
|
1353
|
+
this.reportError({
|
|
1354
|
+
code: 'input_dispatch_failed',
|
|
1355
|
+
message: `Could not release live browser input: ${getErrorMessage(errorArg)}`,
|
|
1356
|
+
cause: errorArg,
|
|
1357
|
+
}, runEpochArg);
|
|
1358
|
+
}
|
|
1359
|
+
queueViewport(widthArg, heightArg, runEpochArg) {
|
|
1360
|
+
if (!this.running
|
|
1361
|
+
|| this.stopping
|
|
1362
|
+
|| this.interruptionRequested
|
|
1363
|
+
|| runEpochArg !== this.runEpoch) {
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
const viewport = this.normalizeGeneratedViewport(widthArg, heightArg, runEpochArg);
|
|
1367
|
+
if (!viewport)
|
|
1368
|
+
return;
|
|
1369
|
+
if (this.pendingViewport && viewportEquals(viewport, this.pendingViewport)) {
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
if (this.inFlightViewport && viewportEquals(viewport, this.inFlightViewport)) {
|
|
1373
|
+
this.pendingViewport = undefined;
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
if (!this.inFlightViewport && this.lastRequestedViewport && viewportEquals(viewport, this.lastRequestedViewport)) {
|
|
1377
|
+
this.pendingViewport = undefined;
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
if (!this.inFlightViewport
|
|
1381
|
+
&& this.resizeFence
|
|
1382
|
+
&& !this.resizeFence.negotiated
|
|
1383
|
+
&& viewportEquals(viewport, this.resizeFence.target)) {
|
|
1384
|
+
this.pendingViewport = undefined;
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
if (!this.inFlightViewport
|
|
1388
|
+
&& !this.resizeFence
|
|
1389
|
+
&& !this.lastRequestedViewport
|
|
1390
|
+
&& this.state
|
|
1391
|
+
&& viewportEquals(viewport, this.state.viewport)) {
|
|
1392
|
+
this.pendingViewport = undefined;
|
|
1393
|
+
this.lastRequestedViewport = { ...viewport };
|
|
1394
|
+
this.updateInputAvailability();
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
this.pendingViewport = viewport;
|
|
1398
|
+
this.inputBlocked = true;
|
|
1399
|
+
this.ensureViewportProcessor(runEpochArg);
|
|
1400
|
+
}
|
|
1401
|
+
normalizeGeneratedViewport(widthArg, heightArg, runEpochArg) {
|
|
1402
|
+
if (!Number.isFinite(widthArg)
|
|
1403
|
+
|| !Number.isFinite(heightArg)
|
|
1404
|
+
|| widthArg <= 0
|
|
1405
|
+
|| heightArg <= 0) {
|
|
1406
|
+
this.reportError({
|
|
1407
|
+
code: 'viewport_update_failed',
|
|
1408
|
+
message: 'Live browser viewport dimensions must be positive finite numbers',
|
|
1409
|
+
}, runEpochArg);
|
|
1410
|
+
return undefined;
|
|
1411
|
+
}
|
|
1412
|
+
const measuredWidth = Math.max(1, Math.floor(widthArg));
|
|
1413
|
+
const measuredHeight = Math.max(1, Math.floor(heightArg));
|
|
1414
|
+
const reductionFactor = Math.min(1, maxViewportWidth / measuredWidth, maxViewportHeight / measuredHeight);
|
|
1415
|
+
const width = Math.max(1, Math.floor(measuredWidth * reductionFactor));
|
|
1416
|
+
const height = Math.max(1, Math.floor(measuredHeight * reductionFactor));
|
|
1417
|
+
const providedScale = this.getDeviceScaleFactor();
|
|
1418
|
+
if (!Number.isFinite(providedScale) || providedScale <= 0) {
|
|
1419
|
+
this.reportError({
|
|
1420
|
+
code: 'viewport_update_failed',
|
|
1421
|
+
message: 'Live browser device scale factor must be a positive finite number',
|
|
1422
|
+
}, runEpochArg);
|
|
1423
|
+
return undefined;
|
|
1424
|
+
}
|
|
1425
|
+
const desiredScale = Math.min(maxDeviceScaleFactor, Math.max(minDeviceScaleFactor, providedScale));
|
|
1426
|
+
const physicalAreaIsValid = (scaleArg) => (Math.ceil(width * scaleArg) * Math.ceil(height * scaleArg) <= maxFramePixelArea);
|
|
1427
|
+
let deviceScaleFactor = desiredScale;
|
|
1428
|
+
if (!physicalAreaIsValid(deviceScaleFactor)) {
|
|
1429
|
+
let lower = minDeviceScaleFactor;
|
|
1430
|
+
let upper = desiredScale;
|
|
1431
|
+
for (let iteration = 0; iteration < 40; iteration += 1) {
|
|
1432
|
+
const candidate = (lower + upper) / 2;
|
|
1433
|
+
if (physicalAreaIsValid(candidate))
|
|
1434
|
+
lower = candidate;
|
|
1435
|
+
else
|
|
1436
|
+
upper = candidate;
|
|
1437
|
+
}
|
|
1438
|
+
deviceScaleFactor = lower;
|
|
1439
|
+
}
|
|
1440
|
+
return { width, height, deviceScaleFactor };
|
|
1441
|
+
}
|
|
1442
|
+
ensureViewportProcessor(runEpochArg) {
|
|
1443
|
+
if (this.viewportProcessingPromise || !this.pendingViewport) {
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
const processingPromise = this.processViewportQueue(runEpochArg).finally(() => {
|
|
1447
|
+
if (this.viewportProcessingPromise === processingPromise) {
|
|
1448
|
+
this.viewportProcessingPromise = undefined;
|
|
1449
|
+
if (this.pendingViewport
|
|
1450
|
+
&& this.running
|
|
1451
|
+
&& !this.stopping
|
|
1452
|
+
&& runEpochArg === this.runEpoch) {
|
|
1453
|
+
this.ensureViewportProcessor(runEpochArg);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
});
|
|
1457
|
+
this.viewportProcessingPromise = processingPromise;
|
|
1458
|
+
}
|
|
1459
|
+
async processViewportQueue(runEpochArg) {
|
|
1460
|
+
this.viewportProcessing = true;
|
|
1461
|
+
try {
|
|
1462
|
+
while (this.pendingViewport
|
|
1463
|
+
&& this.running
|
|
1464
|
+
&& !this.stopping
|
|
1465
|
+
&& runEpochArg === this.runEpoch) {
|
|
1466
|
+
const viewport = this.pendingViewport;
|
|
1467
|
+
this.pendingViewport = undefined;
|
|
1468
|
+
this.inFlightViewport = viewport;
|
|
1469
|
+
if (!this.resizeFence && !this.lastRequestedViewport && this.state && viewportEquals(viewport, this.state.viewport)) {
|
|
1470
|
+
this.inFlightViewport = undefined;
|
|
1471
|
+
this.lastRequestedViewport = { ...viewport };
|
|
1472
|
+
continue;
|
|
1473
|
+
}
|
|
1474
|
+
await this.scheduleInputReset(false, runEpochArg);
|
|
1475
|
+
if (!this.running || this.stopping || runEpochArg !== this.runEpoch) {
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1478
|
+
const currentRevision = this.state?.viewportRevision ?? 0;
|
|
1479
|
+
const previousMinimumRevision = this.resizeFence?.minimumViewportRevision ?? currentRevision;
|
|
1480
|
+
try {
|
|
1481
|
+
const result = await this.runClientOperation((optionsArg) => this.client.setViewport(viewport, optionsArg), 'viewport update', runEpochArg);
|
|
1482
|
+
if (!this.running || this.stopping || runEpochArg !== this.runEpoch) {
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
if (result !== undefined) {
|
|
1486
|
+
this.validateViewport(result.viewport, 'viewport result');
|
|
1487
|
+
this.validateProtocolInteger(result.viewportRevision, 'viewport result revision', Math.max(1, currentRevision));
|
|
1488
|
+
this.resizeFence = { target: { ...result.viewport }, minimumViewportRevision: result.viewportRevision, negotiated: true };
|
|
1489
|
+
this.followNegotiatedViewport();
|
|
1490
|
+
}
|
|
1491
|
+
else {
|
|
1492
|
+
this.resizeFence = { target: viewport, minimumViewportRevision: Math.max(currentRevision, previousMinimumRevision) + 1 };
|
|
1493
|
+
}
|
|
1494
|
+
this.lastRequestedViewport = { ...viewport };
|
|
1495
|
+
}
|
|
1496
|
+
catch (error) {
|
|
1497
|
+
if (runEpochArg === this.runEpoch && !(error instanceof LiveBrowserRunAbortedError)) {
|
|
1498
|
+
this.resizeFence = undefined;
|
|
1499
|
+
if (error instanceof LiveBrowserOperationTimeoutError) {
|
|
1500
|
+
this.requestSuspend(runEpochArg);
|
|
1501
|
+
}
|
|
1502
|
+
this.reportError({
|
|
1503
|
+
code: 'viewport_update_failed',
|
|
1504
|
+
message: `Could not update live browser viewport: ${getErrorMessage(error)}`,
|
|
1505
|
+
cause: error,
|
|
1506
|
+
}, runEpochArg);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
finally {
|
|
1510
|
+
if (this.inFlightViewport && viewportEquals(this.inFlightViewport, viewport)) {
|
|
1511
|
+
this.inFlightViewport = undefined;
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
finally {
|
|
1517
|
+
this.viewportProcessing = false;
|
|
1518
|
+
this.updateInputAvailability();
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
updateInputAvailability() {
|
|
1522
|
+
if (this.resizeFence && !this.viewportProcessing && this.displayedFrame && this.isDisplayedFrameCurrent()
|
|
1523
|
+
&& this.displayedFrame.viewportRevision >= this.resizeFence.minimumViewportRevision
|
|
1524
|
+
&& viewportEquals(this.displayedFrame.viewport, this.resizeFence.target)) {
|
|
1525
|
+
this.resizeFence = undefined;
|
|
1526
|
+
}
|
|
1527
|
+
this.inputBlocked = !(this.running
|
|
1528
|
+
&& this.acceptingFrames
|
|
1529
|
+
&& !this.viewportProcessing
|
|
1530
|
+
&& !this.resizeFence
|
|
1531
|
+
&& this.inputResetCount === 0
|
|
1532
|
+
&& this.isDisplayedFrameCurrent());
|
|
1533
|
+
}
|
|
1534
|
+
followNegotiatedViewport() {
|
|
1535
|
+
if (this.resizeFence?.negotiated && this.state && this.state.viewportRevision > this.resizeFence.minimumViewportRevision) {
|
|
1536
|
+
this.resizeFence = { target: { ...this.state.viewport }, minimumViewportRevision: this.state.viewportRevision, negotiated: true };
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
makeFocusTargetFocusable() {
|
|
1540
|
+
this.focusWasAdjusted = false;
|
|
1541
|
+
if (this.focusTarget.tabIndex >= 0) {
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
this.focusHadTabIndex = this.focusTarget.hasAttribute('tabindex');
|
|
1545
|
+
this.focusTabIndexValue = this.focusTarget.getAttribute('tabindex');
|
|
1546
|
+
this.focusTarget.setAttribute('tabindex', '0');
|
|
1547
|
+
this.focusWasAdjusted = true;
|
|
1548
|
+
}
|
|
1549
|
+
restoreFocusTarget() {
|
|
1550
|
+
if (!this.focusWasAdjusted) {
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1553
|
+
if (this.focusHadTabIndex && this.focusTabIndexValue !== null) {
|
|
1554
|
+
this.focusTarget.setAttribute('tabindex', this.focusTabIndexValue);
|
|
1555
|
+
}
|
|
1556
|
+
else {
|
|
1557
|
+
this.focusTarget.removeAttribute('tabindex');
|
|
1558
|
+
}
|
|
1559
|
+
this.focusWasAdjusted = false;
|
|
1560
|
+
}
|
|
1561
|
+
clearCanvas() {
|
|
1562
|
+
if (this.bitmapContext) {
|
|
1563
|
+
this.bitmapContext.transferFromImageBitmap(null);
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
this.canvasContext?.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
1567
|
+
}
|
|
1568
|
+
/**
|
|
1569
|
+
* Runs work on the next animation frame, or after one nominal frame period
|
|
1570
|
+
* when the document is not visible and animation frames would not fire.
|
|
1571
|
+
*/
|
|
1572
|
+
scheduleAnimationFrame(callbackArg) {
|
|
1573
|
+
const schedule = {};
|
|
1574
|
+
if (typeof document !== 'undefined'
|
|
1575
|
+
&& document.visibilityState === 'visible'
|
|
1576
|
+
&& typeof globalThis.requestAnimationFrame === 'function') {
|
|
1577
|
+
schedule.animationFrameId = globalThis.requestAnimationFrame(() => {
|
|
1578
|
+
schedule.animationFrameId = undefined;
|
|
1579
|
+
callbackArg();
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1582
|
+
else {
|
|
1583
|
+
schedule.timeoutId = globalThis.setTimeout(() => {
|
|
1584
|
+
schedule.timeoutId = undefined;
|
|
1585
|
+
callbackArg();
|
|
1586
|
+
}, animationFrameFallbackMs);
|
|
1587
|
+
}
|
|
1588
|
+
return schedule;
|
|
1589
|
+
}
|
|
1590
|
+
cancelScheduledFrame(scheduleArg) {
|
|
1591
|
+
if (scheduleArg.animationFrameId !== undefined) {
|
|
1592
|
+
globalThis.cancelAnimationFrame(scheduleArg.animationFrameId);
|
|
1593
|
+
scheduleArg.animationFrameId = undefined;
|
|
1594
|
+
}
|
|
1595
|
+
if (scheduleArg.timeoutId !== undefined) {
|
|
1596
|
+
globalThis.clearTimeout(scheduleArg.timeoutId);
|
|
1597
|
+
scheduleArg.timeoutId = undefined;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
callFrameRendered(frameArg, runEpochArg) {
|
|
1601
|
+
if (!this.onFrameRendered || runEpochArg !== this.runEpoch || !this.running) {
|
|
1602
|
+
return;
|
|
1603
|
+
}
|
|
1604
|
+
try {
|
|
1605
|
+
this.onFrameRendered(frameArg);
|
|
1606
|
+
}
|
|
1607
|
+
catch (error) {
|
|
1608
|
+
this.reportError({
|
|
1609
|
+
code: 'renderer_callback_failed',
|
|
1610
|
+
message: `Live browser frame callback failed: ${getErrorMessage(error)}`,
|
|
1611
|
+
cause: error,
|
|
1612
|
+
frame: frameArg,
|
|
1613
|
+
}, runEpochArg);
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
reportError(errorArg, runEpochArg) {
|
|
1617
|
+
if (!this.onError || runEpochArg !== this.runEpoch) {
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
try {
|
|
1621
|
+
this.onError(errorArg);
|
|
1622
|
+
}
|
|
1623
|
+
catch {
|
|
1624
|
+
// Consumer error reporting must not break renderer cleanup.
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
requestSuspend(runEpochArg) {
|
|
1628
|
+
if (!this.isRunActive(runEpochArg) || this.interruptionRequested) {
|
|
1629
|
+
return;
|
|
1630
|
+
}
|
|
1631
|
+
this.interruptRun(runEpochArg);
|
|
1632
|
+
void this.suspend();
|
|
1633
|
+
}
|
|
1634
|
+
validateTimeout(timeoutArg, nameArg) {
|
|
1635
|
+
if (!Number.isFinite(timeoutArg) || timeoutArg <= 0) {
|
|
1636
|
+
throw new Error(`${nameArg} must be a positive finite number`);
|
|
1637
|
+
}
|
|
1638
|
+
return timeoutArg;
|
|
1639
|
+
}
|
|
1640
|
+
runClientOperation(operationArg, operationNameArg, runEpochArg) {
|
|
1641
|
+
return this.runAbortableOperation((signalArg) => operationArg({ signal: signalArg }), this.operationTimeoutMs, operationNameArg, runEpochArg);
|
|
1642
|
+
}
|
|
1643
|
+
runAbortableOperation(operationArg, timeoutMsArg, operationNameArg, runEpochArg) {
|
|
1644
|
+
const runController = this.runController;
|
|
1645
|
+
if (!runController
|
|
1646
|
+
|| !this.isRunActive(runEpochArg)
|
|
1647
|
+
|| runController.signal.aborted) {
|
|
1648
|
+
return Promise.reject(new LiveBrowserRunAbortedError(`Cannot start ${operationNameArg} for inactive run ${runEpochArg}`));
|
|
1649
|
+
}
|
|
1650
|
+
const operationController = new AbortController();
|
|
1651
|
+
this.operationControllers.add(operationController);
|
|
1652
|
+
const abortFromRun = () => {
|
|
1653
|
+
const reason = runController.signal.reason instanceof Error
|
|
1654
|
+
? runController.signal.reason
|
|
1655
|
+
: new LiveBrowserRunAbortedError(`Live browser renderer run ${runEpochArg} was interrupted`);
|
|
1656
|
+
operationController.abort(reason);
|
|
1657
|
+
};
|
|
1658
|
+
runController.signal.addEventListener('abort', abortFromRun, { once: true });
|
|
1659
|
+
const timeout = globalThis.setTimeout(() => {
|
|
1660
|
+
operationController.abort(new LiveBrowserOperationTimeoutError(`${operationNameArg} timed out after ${timeoutMsArg}ms`));
|
|
1661
|
+
}, timeoutMsArg);
|
|
1662
|
+
let abortOperation = () => undefined;
|
|
1663
|
+
const operation = new Promise((resolve, reject) => {
|
|
1664
|
+
let settled = false;
|
|
1665
|
+
const settle = (callbackArg) => {
|
|
1666
|
+
if (!settled) {
|
|
1667
|
+
settled = true;
|
|
1668
|
+
callbackArg();
|
|
1669
|
+
}
|
|
1670
|
+
};
|
|
1671
|
+
abortOperation = () => {
|
|
1672
|
+
const reason = operationController.signal.reason instanceof Error
|
|
1673
|
+
? operationController.signal.reason
|
|
1674
|
+
: new LiveBrowserRunAbortedError(`${operationNameArg} was aborted`);
|
|
1675
|
+
settle(() => reject(reason));
|
|
1676
|
+
};
|
|
1677
|
+
operationController.signal.addEventListener('abort', abortOperation, { once: true });
|
|
1678
|
+
let operationResult;
|
|
1679
|
+
try {
|
|
1680
|
+
operationResult = operationArg(operationController.signal);
|
|
1681
|
+
}
|
|
1682
|
+
catch (error) {
|
|
1683
|
+
settle(() => reject(error));
|
|
1684
|
+
return;
|
|
1685
|
+
}
|
|
1686
|
+
operationResult.then((valueArg) => {
|
|
1687
|
+
settle(() => resolve(valueArg));
|
|
1688
|
+
}, (errorArg) => {
|
|
1689
|
+
settle(() => reject(errorArg));
|
|
1690
|
+
});
|
|
1691
|
+
}).finally(() => {
|
|
1692
|
+
globalThis.clearTimeout(timeout);
|
|
1693
|
+
runController.signal.removeEventListener('abort', abortFromRun);
|
|
1694
|
+
operationController.signal.removeEventListener('abort', abortOperation);
|
|
1695
|
+
this.operationControllers.delete(operationController);
|
|
1696
|
+
});
|
|
1697
|
+
return operation;
|
|
1698
|
+
}
|
|
1699
|
+
async decodeFrame(blobArg, runEpochArg) {
|
|
1700
|
+
let decodeOperation;
|
|
1701
|
+
try {
|
|
1702
|
+
decodeOperation = createImageBitmap(blobArg);
|
|
1703
|
+
}
|
|
1704
|
+
catch (error) {
|
|
1705
|
+
throw error;
|
|
1706
|
+
}
|
|
1707
|
+
let rawDecodeSettlementPromise;
|
|
1708
|
+
rawDecodeSettlementPromise = decodeOperation.then(() => undefined, () => undefined).finally(() => {
|
|
1709
|
+
this.rawDecodeSettlementPromises.delete(rawDecodeSettlementPromise);
|
|
1710
|
+
});
|
|
1711
|
+
this.rawDecodeSettlementPromises.add(rawDecodeSettlementPromise);
|
|
1712
|
+
try {
|
|
1713
|
+
return await this.runAbortableOperation(async () => decodeOperation, this.frameDecodeTimeoutMs, 'frame decode', runEpochArg);
|
|
1714
|
+
}
|
|
1715
|
+
catch (error) {
|
|
1716
|
+
if (error instanceof LiveBrowserOperationTimeoutError
|
|
1717
|
+
|| error instanceof LiveBrowserRunAbortedError) {
|
|
1718
|
+
void decodeOperation.then((lateBitmapArg) => lateBitmapArg.close(), () => undefined);
|
|
1719
|
+
throw error;
|
|
1720
|
+
}
|
|
1721
|
+
throw new LiveBrowserFrameIntegrityError(`frame bytes could not be decoded: ${getErrorMessage(error)}`, { cause: error });
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
isRunActive(runEpochArg) {
|
|
1725
|
+
return Boolean(this.running
|
|
1726
|
+
&& !this.stopping
|
|
1727
|
+
&& runEpochArg === this.runEpoch
|
|
1728
|
+
&& this.runController
|
|
1729
|
+
&& !this.runController.signal.aborted);
|
|
1730
|
+
}
|
|
1731
|
+
validateFrame(frameArg) {
|
|
1732
|
+
if (!frameArg || typeof frameArg !== 'object') {
|
|
1733
|
+
throw new LiveBrowserFrameProtocolError('frame must be an object');
|
|
1734
|
+
}
|
|
1735
|
+
if (typeof frameArg.tabId !== 'string'
|
|
1736
|
+
|| frameArg.tabId.length === 0
|
|
1737
|
+
|| frameArg.tabId.length > 4096) {
|
|
1738
|
+
throw new LiveBrowserFrameProtocolError('frame.tabId must be a non-empty bounded string');
|
|
1739
|
+
}
|
|
1740
|
+
this.validateProtocolInteger(frameArg.sequence, 'frame.sequence', 1);
|
|
1741
|
+
this.validateProtocolInteger(frameArg.generation, 'frame.generation', 1);
|
|
1742
|
+
this.validateProtocolInteger(frameArg.viewportRevision, 'frame.viewportRevision', 1);
|
|
1743
|
+
this.validateViewport(frameArg.viewport, 'frame.viewport');
|
|
1744
|
+
if (frameArg.format !== 'jpeg' && frameArg.format !== 'png') {
|
|
1745
|
+
throw new LiveBrowserFrameProtocolError('frame.format must be jpeg or png');
|
|
1746
|
+
}
|
|
1747
|
+
const expectedMimeType = frameArg.format === 'jpeg' ? 'image/jpeg' : 'image/png';
|
|
1748
|
+
if (frameArg.mimeType !== expectedMimeType) {
|
|
1749
|
+
throw new LiveBrowserFrameProtocolError(`frame.mimeType must be ${expectedMimeType} for ${frameArg.format}`);
|
|
1750
|
+
}
|
|
1751
|
+
this.validateProtocolInteger(frameArg.width, 'frame.width', 1, maxFrameDimension);
|
|
1752
|
+
this.validateProtocolInteger(frameArg.height, 'frame.height', 1, maxFrameDimension);
|
|
1753
|
+
if (frameArg.width * frameArg.height > maxFramePixelArea) {
|
|
1754
|
+
throw new LiveBrowserFrameProtocolError(`frame pixel area must not exceed ${maxFramePixelArea}`);
|
|
1755
|
+
}
|
|
1756
|
+
if (!(frameArg.data instanceof Uint8Array)) {
|
|
1757
|
+
throw new LiveBrowserFrameProtocolError('frame.data must be a Uint8Array');
|
|
1758
|
+
}
|
|
1759
|
+
if (frameArg.data.byteLength === 0 || frameArg.data.byteLength > maxFrameByteLength) {
|
|
1760
|
+
throw new LiveBrowserFrameProtocolError(`frame.data byte length must be between 1 and ${maxFrameByteLength}`);
|
|
1761
|
+
}
|
|
1762
|
+
const metadata = frameArg.metadata;
|
|
1763
|
+
if (!metadata || typeof metadata !== 'object') {
|
|
1764
|
+
throw new LiveBrowserFrameProtocolError('frame.metadata must be an object');
|
|
1765
|
+
}
|
|
1766
|
+
this.validateProtocolNumber(metadata.offsetTop, 'frame.metadata.offsetTop');
|
|
1767
|
+
this.validateProtocolNumber(metadata.pageScaleFactor, 'frame.metadata.pageScaleFactor', true);
|
|
1768
|
+
this.validateProtocolNumber(metadata.deviceWidth, 'frame.metadata.deviceWidth', true);
|
|
1769
|
+
this.validateProtocolNumber(metadata.deviceHeight, 'frame.metadata.deviceHeight', true);
|
|
1770
|
+
if (metadata.deviceWidth > maxFrameDimension
|
|
1771
|
+
|| metadata.deviceHeight > maxFrameDimension
|
|
1772
|
+
|| metadata.deviceWidth * metadata.deviceHeight > maxFramePixelArea) {
|
|
1773
|
+
throw new LiveBrowserFrameProtocolError(`frame metadata dimensions must fit within ${maxFramePixelArea} pixels`);
|
|
1774
|
+
}
|
|
1775
|
+
this.validateProtocolNumber(metadata.scrollOffsetX, 'frame.metadata.scrollOffsetX');
|
|
1776
|
+
this.validateProtocolNumber(metadata.scrollOffsetY, 'frame.metadata.scrollOffsetY');
|
|
1777
|
+
if (metadata.timestamp !== undefined) {
|
|
1778
|
+
this.validateProtocolNumber(metadata.timestamp, 'frame.metadata.timestamp');
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
validateViewport(viewportArg, nameArg) {
|
|
1782
|
+
if (!viewportArg || typeof viewportArg !== 'object') {
|
|
1783
|
+
throw new LiveBrowserFrameProtocolError(`${nameArg} must be an object`);
|
|
1784
|
+
}
|
|
1785
|
+
this.validateProtocolInteger(viewportArg.width, `${nameArg}.width`, 1, maxViewportWidth);
|
|
1786
|
+
this.validateProtocolInteger(viewportArg.height, `${nameArg}.height`, 1, maxViewportHeight);
|
|
1787
|
+
this.validateProtocolNumber(viewportArg.deviceScaleFactor, `${nameArg}.deviceScaleFactor`, true);
|
|
1788
|
+
if (viewportArg.deviceScaleFactor > maxDeviceScaleFactor) {
|
|
1789
|
+
throw new LiveBrowserFrameProtocolError(`${nameArg}.deviceScaleFactor must not exceed ${maxDeviceScaleFactor}`);
|
|
1790
|
+
}
|
|
1791
|
+
const physicalArea = viewportArg.width
|
|
1792
|
+
* viewportArg.height
|
|
1793
|
+
* viewportArg.deviceScaleFactor
|
|
1794
|
+
* viewportArg.deviceScaleFactor;
|
|
1795
|
+
if (physicalArea > maxFramePixelArea) {
|
|
1796
|
+
throw new LiveBrowserFrameProtocolError(`${nameArg} physical pixel area must not exceed ${maxFramePixelArea}`);
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
validateProtocolInteger(valueArg, nameArg, minimumArg, maximumArg = Number.MAX_SAFE_INTEGER) {
|
|
1800
|
+
if (!Number.isSafeInteger(valueArg)
|
|
1801
|
+
|| valueArg < minimumArg
|
|
1802
|
+
|| valueArg > maximumArg) {
|
|
1803
|
+
throw new LiveBrowserFrameProtocolError(`${nameArg} must be an integer between ${minimumArg} and ${maximumArg}`);
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
validateProtocolNumber(valueArg, nameArg, positiveArg = false) {
|
|
1807
|
+
if (!Number.isFinite(valueArg) || (positiveArg && valueArg <= 0)) {
|
|
1808
|
+
throw new LiveBrowserFrameProtocolError(`${nameArg} must be a ${positiveArg ? 'positive ' : ''}finite number`);
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
releasePointerCapture(pointerIdArg) {
|
|
1812
|
+
this.capturedPointerIds.delete(pointerIdArg);
|
|
1813
|
+
try {
|
|
1814
|
+
if (this.canvas.hasPointerCapture(pointerIdArg)) {
|
|
1815
|
+
this.canvas.releasePointerCapture(pointerIdArg);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
catch {
|
|
1819
|
+
// Pointer capture may already have been released by the browser.
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
releasePointerCaptures() {
|
|
1823
|
+
const pointerIds = [...this.capturedPointerIds];
|
|
1824
|
+
this.capturedPointerIds.clear();
|
|
1825
|
+
for (const pointerId of pointerIds) {
|
|
1826
|
+
this.releasePointerCapture(pointerId);
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5saXZlYnJvd3NlcnJlbmRlcmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfd2ViL2NsYXNzZXMubGl2ZWJyb3dzZXJyZW5kZXJlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFvQkEsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFHakYsTUFBTSxtQkFBbUIsR0FBRyxHQUFHLENBQUM7QUFDaEMsTUFBTSx3QkFBd0IsR0FBRyxDQUFDLENBQUM7QUFDbkMsTUFBTSw0QkFBNEIsR0FBRyxFQUFFLENBQUM7QUFDeEMsTUFBTSxhQUFhLEdBQUcsT0FBTyxDQUFDO0FBQzlCLE1BQU0sd0JBQXdCLEdBQUcsRUFBRSxDQUFDO0FBQ3BDLE1BQU0sZ0JBQWdCLEdBQUcsR0FBRyxDQUFDO0FBQzdCLE1BQU0sMEJBQTBCLEdBQUcsRUFBRSxDQUFDO0FBQ3RDLE1BQU0sdUJBQXVCLEdBQUcsQ0FBQyxDQUFDO0FBQ2xDLE1BQU0saUJBQWlCLEdBQUcsS0FBSyxDQUFDO0FBQ2hDLE1BQU0saUJBQWlCLEdBQUcsT0FBTyxDQUFDO0FBQ2xDLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxpQkFBaUIsR0FBRyxDQUFDLENBQUMsR0FBRyxPQUFPLENBQUM7QUFDN0QsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUM7QUFDOUIsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLENBQUM7QUFDL0IsTUFBTSxvQkFBb0IsR0FBRyxJQUFJLENBQUM7QUFDbEMsTUFBTSxvQkFBb0IsR0FBRyxDQUFDLENBQUM7QUFDL0IsTUFBTSxtQkFBbUIsR0FBRyxLQUFLLENBQUM7QUFDbEMsTUFBTSx5QkFBeUIsR0FBRyxLQUFLLENBQUM7QUFFeEMsTUFBTSxnQ0FBaUMsU0FBUSxLQUFLO0NBQUc7QUFDdkQsTUFBTSwwQkFBMkIsU0FBUSxLQUFLO0NBQUc7QUFDakQsTUFBTSw2QkFBOEIsU0FBUSxLQUFLO0NBQUc7QUFDcEQsTUFBTSw4QkFBK0Is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
|