Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/src/lib/libhtml5.js
4150 views
1
/**
2
* @license
3
* Copyright 2014 The Emscripten Authors
4
* SPDX-License-Identifier: MIT
5
*/
6
7
var LibraryHTML5 = {
8
$JSEvents__deps: [
9
#if PTHREADS
10
'_emscripten_run_callback_on_thread',
11
#endif
12
'$addOnExit',
13
],
14
$JSEvents: {
15
16
#if USE_CLOSURE_COMPILER
17
// pointers to structs malloc()ed to Emscripten HEAP for JS->C interop.
18
batteryEvent: 0,
19
gamepadEvent: 0,
20
keyEvent: 0,
21
mouseEvent: 0,
22
wheelEvent: 0,
23
uiEvent: 0,
24
focusEvent: 0,
25
deviceOrientationEvent: 0,
26
orientationChangeEvent: 0,
27
deviceMotionEvent: 0,
28
fullscreenChangeEvent: 0,
29
pointerlockChangeEvent: 0,
30
visibilityChangeEvent: 0,
31
touchEvent: 0,
32
#endif
33
34
/* We do not depend on the exact initial values of falsey member fields - these
35
fields can be populated on-demand to save code size.
36
(but still documented here to keep track of what is supposed to be present)
37
38
// When we transition from fullscreen to windowed mode, we remember here the
39
// element that was just in fullscreen mode so that we can report
40
// information about that element in the event message.
41
previousFullscreenElement: null,
42
43
// When the C runtime exits via exit(), we unregister all event handlers
44
// added by this library to be nice and clean.
45
// Track in this field whether we have yet registered that onExit handler.
46
removeEventListenersRegistered: false,
47
48
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
49
// If we are in an event handler, specifies the event handler object from
50
// the eventHandlers array that is currently running.
51
currentEventHandler: null,
52
#endif
53
*/
54
memcpy(target, src, size) {
55
HEAP8.set(HEAP8.subarray(src, src + size), target);
56
},
57
58
removeAllEventListeners() {
59
while (JSEvents.eventHandlers.length) {
60
JSEvents._removeHandler(JSEvents.eventHandlers.length - 1);
61
}
62
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
63
JSEvents.deferredCalls = [];
64
#endif
65
},
66
67
#if EXIT_RUNTIME
68
registerRemoveEventListeners() {
69
if (!JSEvents.removeEventListenersRegistered) {
70
addOnExit(JSEvents.removeAllEventListeners);
71
JSEvents.removeEventListenersRegistered = true;
72
}
73
},
74
#endif
75
76
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
77
// If positive, we are currently executing in a JS event handler.
78
// (this particular property must be initialized to zero, as we ++/-- it)
79
inEventHandler: 0,
80
81
deferredCalls: [],
82
83
// Queues the given function call to occur the next time we enter an event handler.
84
// Existing implementations of pointerlock apis have required that
85
// the target element is active in fullscreen mode first. Therefore give
86
// fullscreen mode request a precedence of 1 and pointer lock a precedence of 2
87
// and sort by that to always request fullscreen before pointer lock.
88
deferCall(targetFunction, precedence, argsList) {
89
function arraysHaveEqualContent(arrA, arrB) {
90
if (arrA.length != arrB.length) return false;
91
92
for (var i in arrA) {
93
if (arrA[i] != arrB[i]) return false;
94
}
95
return true;
96
}
97
// Test if the given call was already queued, and if so, don't add it again.
98
for (var call of JSEvents.deferredCalls) {
99
if (call.targetFunction == targetFunction && arraysHaveEqualContent(call.argsList, argsList)) {
100
return;
101
}
102
}
103
JSEvents.deferredCalls.push({
104
targetFunction,
105
precedence,
106
argsList
107
});
108
109
JSEvents.deferredCalls.sort((x,y) => x.precedence < y.precedence);
110
},
111
112
// Erases all deferred calls to the given target function from the queue list.
113
removeDeferredCalls(targetFunction) {
114
JSEvents.deferredCalls = JSEvents.deferredCalls.filter((call) => call.targetFunction != targetFunction);
115
},
116
117
canPerformEventHandlerRequests() {
118
if (navigator.userActivation) {
119
// Verify against transient activation status from UserActivation API
120
// whether it is possible to perform a request here without needing to defer. See
121
// https://developer.mozilla.org/en-US/docs/Web/Security/User_activation#transient_activation
122
// and https://caniuse.com/mdn-api_useractivation
123
// At the time of writing, Firefox does not support this API: https://bugzilla.mozilla.org/show_bug.cgi?id=1791079
124
return navigator.userActivation.isActive;
125
}
126
127
return JSEvents.inEventHandler && JSEvents.currentEventHandler.allowsDeferredCalls;
128
},
129
130
runDeferredCalls() {
131
if (!JSEvents.canPerformEventHandlerRequests()) {
132
return;
133
}
134
var deferredCalls = JSEvents.deferredCalls;
135
JSEvents.deferredCalls = [];
136
for (var call of deferredCalls) {
137
call.targetFunction(...call.argsList);
138
}
139
},
140
#endif
141
142
// Stores objects representing each currently registered JS event handler.
143
eventHandlers: [],
144
145
// Removes all event handlers on the given DOM element of the given type.
146
// Pass in eventTypeString == undefined/null to remove all event handlers
147
// regardless of the type.
148
removeAllHandlersOnTarget: (target, eventTypeString) => {
149
for (var i = 0; i < JSEvents.eventHandlers.length; ++i) {
150
if (JSEvents.eventHandlers[i].target == target &&
151
(!eventTypeString || eventTypeString == JSEvents.eventHandlers[i].eventTypeString)) {
152
JSEvents._removeHandler(i--);
153
}
154
}
155
},
156
157
_removeHandler(i) {
158
var h = JSEvents.eventHandlers[i];
159
h.target.removeEventListener(h.eventTypeString, h.eventListenerFunc, h.useCapture);
160
JSEvents.eventHandlers.splice(i, 1);
161
},
162
163
registerOrRemoveHandler(eventHandler) {
164
if (!eventHandler.target) {
165
#if ASSERTIONS
166
err('registerOrRemoveHandler: the target element for event handler registration does not exist, when processing the following event handler registration:');
167
console.dir(eventHandler);
168
#endif
169
return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
170
}
171
if (eventHandler.callbackfunc) {
172
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
173
eventHandler.eventListenerFunc = function(event) {
174
// Increment nesting count for the event handler.
175
++JSEvents.inEventHandler;
176
JSEvents.currentEventHandler = eventHandler;
177
// Process any old deferred calls the user has placed.
178
JSEvents.runDeferredCalls();
179
// Process the actual event, calls back to user C code handler.
180
eventHandler.handlerFunc(event);
181
// Process any new deferred calls that were placed right now from this event handler.
182
JSEvents.runDeferredCalls();
183
// Out of event handler - restore nesting count.
184
--JSEvents.inEventHandler;
185
};
186
#else
187
eventHandler.eventListenerFunc = eventHandler.handlerFunc;
188
#endif
189
190
eventHandler.target.addEventListener(eventHandler.eventTypeString,
191
eventHandler.eventListenerFunc,
192
eventHandler.useCapture);
193
JSEvents.eventHandlers.push(eventHandler);
194
#if EXIT_RUNTIME
195
JSEvents.registerRemoveEventListeners();
196
#endif
197
} else {
198
for (var i = 0; i < JSEvents.eventHandlers.length; ++i) {
199
if (JSEvents.eventHandlers[i].target == eventHandler.target
200
&& JSEvents.eventHandlers[i].eventTypeString == eventHandler.eventTypeString) {
201
JSEvents._removeHandler(i--);
202
}
203
}
204
}
205
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
206
},
207
208
#if PTHREADS
209
getTargetThreadForEventCallback(targetThread) {
210
switch (targetThread) {
211
case {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD }}}:
212
// The event callback for the current event should be called on the
213
// main browser thread. (0 == don't proxy)
214
return 0;
215
case {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD }}}:
216
// The event callback for the current event should be backproxied to
217
// the thread that is registering the event.
218
// This can be 0 in the case that the caller uses
219
// EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD but on the main thread
220
// itself.
221
return PThread.currentProxiedOperationCallerThread;
222
default:
223
// The event callback for the current event should be proxied to the
224
// given specific thread.
225
return targetThread;
226
}
227
},
228
#endif
229
230
getNodeNameForTarget(target) {
231
if (!target) return '';
232
if (target == window) return '#window';
233
if (target == screen) return '#screen';
234
return target?.nodeName || '';
235
},
236
237
fullscreenEnabled() {
238
return document.fullscreenEnabled
239
#if MIN_FIREFOX_VERSION <= 63
240
// Firefox 64 shipped unprefixed form of fullscreenEnabled (https://caniuse.com/#feat=mdn-api_document_fullscreenenabled)
241
|| document.mozFullScreenEnabled
242
#endif
243
#if MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
244
// Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitFullscreenEnabled.
245
// TODO: If Safari at some point ships with unprefixed version, update the version check above.
246
|| document.webkitFullscreenEnabled
247
#endif
248
;
249
},
250
},
251
252
$getFullscreenElement__internal: true,
253
$getFullscreenElement() {
254
return document.fullscreenElement || document.mozFullScreenElement ||
255
document.webkitFullscreenElement || document.webkitCurrentFullScreenElement ||
256
document.msFullscreenElement;
257
},
258
259
$registerKeyEventCallback__noleakcheck: true,
260
$registerKeyEventCallback__deps: ['$JSEvents', '$findEventTarget', '$stringToUTF8', 'malloc'],
261
$registerKeyEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
262
#if PTHREADS
263
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
264
#endif
265
JSEvents.keyEvent ||= _malloc({{{ C_STRUCTS.EmscriptenKeyboardEvent.__size__ }}});
266
267
var keyEventHandlerFunc = (e) => {
268
#if ASSERTIONS
269
assert(e);
270
#endif
271
272
#if PTHREADS
273
var keyEventData = targetThread ? _malloc({{{ C_STRUCTS.EmscriptenKeyboardEvent.__size__ }}}) : JSEvents.keyEvent; // This allocated block is passed as satellite data to the proxied function call, so the call frees up the data block when done.
274
#else
275
var keyEventData = JSEvents.keyEvent;
276
#endif
277
{{{ makeSetValue('keyEventData', C_STRUCTS.EmscriptenKeyboardEvent.timestamp, 'e.timeStamp', 'double') }}};
278
279
var idx = {{{ getHeapOffset('keyEventData', 'i32') }}};
280
281
HEAP32[idx + {{{ C_STRUCTS.EmscriptenKeyboardEvent.location / 4 }}}] = e.location;
282
HEAP8[keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.ctrlKey }}}] = e.ctrlKey;
283
HEAP8[keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.shiftKey }}}] = e.shiftKey;
284
HEAP8[keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.altKey }}}] = e.altKey;
285
HEAP8[keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.metaKey }}}] = e.metaKey;
286
HEAP8[keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.repeat }}}] = e.repeat;
287
HEAP32[idx + {{{ C_STRUCTS.EmscriptenKeyboardEvent.charCode / 4 }}}] = e.charCode;
288
HEAP32[idx + {{{ C_STRUCTS.EmscriptenKeyboardEvent.keyCode / 4 }}}] = e.keyCode;
289
HEAP32[idx + {{{ C_STRUCTS.EmscriptenKeyboardEvent.which / 4 }}}] = e.which;
290
stringToUTF8(e.key || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.key }}}, {{{ cDefs.EM_HTML5_SHORT_STRING_LEN_BYTES }}});
291
stringToUTF8(e.code || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.code }}}, {{{ cDefs.EM_HTML5_SHORT_STRING_LEN_BYTES }}});
292
stringToUTF8(e.char || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.charValue }}}, {{{ cDefs.EM_HTML5_SHORT_STRING_LEN_BYTES }}});
293
stringToUTF8(e.locale || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.locale }}}, {{{ cDefs.EM_HTML5_SHORT_STRING_LEN_BYTES }}});
294
295
#if PTHREADS
296
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, keyEventData, userData);
297
else
298
#endif
299
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, keyEventData, userData)) e.preventDefault();
300
};
301
302
var eventHandler = {
303
target: findEventTarget(target),
304
eventTypeString,
305
callbackfunc,
306
handlerFunc: keyEventHandlerFunc,
307
useCapture
308
};
309
return JSEvents.registerOrRemoveHandler(eventHandler);
310
},
311
312
// In DOM capturing and bubbling sequence, there are two special elements at the top of the event chain that can be of interest
313
// to register many events to: document and window. These cannot be addressed by using document.querySelector(), so
314
// a special mechanism to address them is needed. (For any other special object, such as screen.orientation, no general access
315
// scheme should be needed, but the object-specific event callback registration functions should handle them individually).
316
//
317
// Users can also add more special event targets, basically by just doing something like
318
// specialHTMLTargets["!canvas"] = Module.canvas;
319
// (that will let !canvas map to the canvas held in Module.canvas).
320
$specialHTMLTargets__docs: '/** @type {Object} */',
321
#if ENVIRONMENT_MAY_BE_WORKER || ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL || PTHREADS
322
$specialHTMLTargets: "[0, typeof document != 'undefined' ? document : 0, typeof window != 'undefined' ? window : 0]",
323
#else
324
$specialHTMLTargets: "[0, document, window]",
325
#endif
326
327
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
328
$maybeCStringToJsString: (cString) => {
329
// "cString > 2" checks if the input is a number, and isn't of the special
330
// values we accept here, EMSCRIPTEN_EVENT_TARGET_* (which map to 0, 1, 2).
331
// In other words, if cString > 2 then it's a pointer to a valid place in
332
// memory, and points to a C string.
333
return cString > 2 ? UTF8ToString(cString) : cString;
334
},
335
336
// Find a DOM element with the given ID, or null if none is found.
337
$findEventTarget__deps: ['$maybeCStringToJsString', '$specialHTMLTargets'],
338
$findEventTarget: (target) => {
339
target = maybeCStringToJsString(target);
340
#if ENVIRONMENT_MAY_BE_WORKER || ENVIRONMENT_MAY_BE_NODE
341
var domElement = specialHTMLTargets[target] || (typeof document != 'undefined' ? document.querySelector(target) : null);
342
#else
343
var domElement = specialHTMLTargets[target] || document.querySelector(target);
344
#endif
345
return domElement;
346
},
347
348
#if OFFSCREENCANVAS_SUPPORT
349
$findCanvasEventTarget__deps: ['$GL', '$maybeCStringToJsString'],
350
$findCanvasEventTarget: (target) => {
351
target = maybeCStringToJsString(target);
352
353
// When compiling with OffscreenCanvas support and looking up a canvas to target,
354
// we first look up if the target Canvas has been transferred to OffscreenCanvas use.
355
// These transfers are represented/tracked by GL.offscreenCanvases object, which contain
356
// the OffscreenCanvas element for each regular Canvas element that has been transferred.
357
358
// Note that each pthread/worker have their own set of GL.offscreenCanvases. That is,
359
// when an OffscreenCanvas is transferred from a pthread/main thread to another pthread,
360
// it will move in the GL.offscreenCanvases array between threads. Hence GL.offscreenCanvases
361
// represents the set of OffscreenCanvases owned by the current calling thread.
362
363
// First check out the list of OffscreenCanvases by CSS selector ID ('#myCanvasID')
364
return GL.offscreenCanvases[target.slice(1)] // Remove '#' prefix
365
// If not found, if one is querying by using DOM tag name selector 'canvas', grab the first
366
// OffscreenCanvas that we can find.
367
|| (target == 'canvas' && Object.keys(GL.offscreenCanvases)[0])
368
// If that is not found either, query via the regular DOM selector.
369
#if PTHREADS
370
|| (typeof document != 'undefined' && document.querySelector(target));
371
#else
372
|| document.querySelector(target);
373
#endif
374
},
375
#else
376
$findCanvasEventTarget: '$findEventTarget',
377
#endif
378
379
#else
380
// Find a DOM element with the given ID, or null if none is found.
381
$findEventTarget__deps: ['$specialHTMLTargets'],
382
$findEventTarget: (target) => {
383
#if ASSERTIONS
384
warnOnce('Rules for selecting event targets in HTML5 API are changing: instead of using document.getElementById() that only can refer to elements by their DOM ID, new event target selection mechanism uses the more flexible function document.querySelector() that can look up element names, classes, and complex CSS selectors. Build with -sDISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR to change to the new lookup rules. See https://github.com/emscripten-core/emscripten/pull/7977 for more details.');
385
#endif
386
// The sensible "default" target varies between events, but use window as the default
387
// since DOM events mostly can default to that. Specific callback registrations
388
// override their own defaults.
389
if (!target) return window;
390
if (typeof target == "number") target = specialHTMLTargets[target] || UTF8ToString(target);
391
if (target === '#window') return window;
392
else if (target === '#document') return document;
393
else if (target === '#screen') return screen;
394
else if (target === '#canvas') return Module['canvas'];
395
else if (typeof target == 'string')
396
#if ENVIRONMENT_MAY_BE_WORKER || ENVIRONMENT_MAY_BE_NODE
397
return (typeof document != 'undefined') ? document.getElementById(target) : null;
398
#else
399
return document.getElementById(target);
400
#endif
401
return target;
402
},
403
404
// Like findEventTarget, but looks for OffscreenCanvas elements first
405
$findCanvasEventTarget__deps: ['$findEventTarget'],
406
$findCanvasEventTarget: (target) => {
407
if (typeof target == 'number') target = UTF8ToString(target);
408
if (!target || target === '#canvas') {
409
if (typeof GL != 'undefined' && GL.offscreenCanvases['canvas']) return GL.offscreenCanvases['canvas']; // TODO: Remove this line, target '#canvas' should refer only to Module['canvas'], not to GL.offscreenCanvases['canvas'] - but need stricter tests to be able to remove this line.
410
return Module['canvas'];
411
}
412
if (typeof GL != 'undefined' && GL.offscreenCanvases[target]) return GL.offscreenCanvases[target];
413
return findEventTarget(target);
414
},
415
#endif
416
417
emscripten_set_keypress_callback_on_thread__proxy: 'sync',
418
emscripten_set_keypress_callback_on_thread__deps: ['$registerKeyEventCallback'],
419
emscripten_set_keypress_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
420
registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYPRESS }}}, "keypress", targetThread),
421
422
emscripten_set_keydown_callback_on_thread__proxy: 'sync',
423
emscripten_set_keydown_callback_on_thread__deps: ['$registerKeyEventCallback'],
424
emscripten_set_keydown_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
425
registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYDOWN }}}, "keydown", targetThread),
426
427
emscripten_set_keyup_callback_on_thread__proxy: 'sync',
428
emscripten_set_keyup_callback_on_thread__deps: ['$registerKeyEventCallback'],
429
emscripten_set_keyup_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
430
registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYUP }}}, "keyup", targetThread),
431
432
// Outline access to function .getBoundingClientRect() since it is a long string. Closure compiler does not outline access to it by itself, but it can inline access if
433
// there is only one caller to this function.
434
$getBoundingClientRect__deps: ['$specialHTMLTargets'],
435
$getBoundingClientRect: (e) => specialHTMLTargets.indexOf(e) < 0 ? e.getBoundingClientRect() : {'left':0,'top':0},
436
437
// Copies mouse event data from the given JS mouse event 'e' to the specified Emscripten mouse event structure in the HEAP.
438
// eventStruct: the structure to populate.
439
// e: The JS mouse event to read data from.
440
// target: Specifies a target DOM element that will be used as the reference to populate targetX and targetY parameters.
441
$fillMouseEventData__deps: ['$getBoundingClientRect'],
442
$fillMouseEventData: (eventStruct, e, target) => {
443
#if ASSERTIONS
444
assert(eventStruct % 4 == 0);
445
#endif
446
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.timestamp, 'e.timeStamp', 'double') }}};
447
var idx = {{{ getHeapOffset('eventStruct', 'i32') }}};
448
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.screenX / 4 }}}] = e.screenX;
449
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.screenY / 4 }}}] = e.screenY;
450
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.clientX / 4 }}}] = e.clientX;
451
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.clientY / 4 }}}] = e.clientY;
452
HEAP8[eventStruct + {{{ C_STRUCTS.EmscriptenMouseEvent.ctrlKey }}}] = e.ctrlKey;
453
HEAP8[eventStruct + {{{ C_STRUCTS.EmscriptenMouseEvent.shiftKey }}}] = e.shiftKey;
454
HEAP8[eventStruct + {{{ C_STRUCTS.EmscriptenMouseEvent.altKey }}}] = e.altKey;
455
HEAP8[eventStruct + {{{ C_STRUCTS.EmscriptenMouseEvent.metaKey }}}] = e.metaKey;
456
HEAP16[idx*2 + {{{ C_STRUCTS.EmscriptenMouseEvent.button / 2 }}}] = e.button;
457
HEAP16[idx*2 + {{{ C_STRUCTS.EmscriptenMouseEvent.buttons / 2 }}}] = e.buttons;
458
459
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.movementX / 4 }}}] = e["movementX"];
460
461
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.movementY / 4 }}}] = e["movementY"];
462
463
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
464
if (Module['canvas']) {
465
var rect = getBoundingClientRect(Module['canvas']);
466
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.canvasX / 4 }}}] = e.clientX - (rect.left | 0);
467
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.canvasY / 4 }}}] = e.clientY - (rect.top | 0);
468
} else { // Canvas is not initialized, return 0.
469
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.canvasX / 4 }}}] = 0;
470
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.canvasY / 4 }}}] = 0;
471
}
472
#endif
473
// Note: rect contains doubles (truncated to placate SAFE_HEAP, which is the same behaviour when writing to HEAP32 anyway)
474
var rect = getBoundingClientRect(target);
475
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.targetX / 4 }}}] = e.clientX - (rect.left | 0);
476
HEAP32[idx + {{{ C_STRUCTS.EmscriptenMouseEvent.targetY / 4 }}}] = e.clientY - (rect.top | 0);
477
},
478
479
$registerMouseEventCallback__noleakcheck: true,
480
$registerMouseEventCallback__deps: ['$JSEvents', '$fillMouseEventData', '$findEventTarget', 'malloc'],
481
$registerMouseEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
482
#if PTHREADS
483
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
484
#endif
485
JSEvents.mouseEvent ||= _malloc({{{ C_STRUCTS.EmscriptenMouseEvent.__size__ }}});
486
target = findEventTarget(target);
487
488
var mouseEventHandlerFunc = (e = event) => {
489
// TODO: Make this access thread safe, or this could update live while app is reading it.
490
fillMouseEventData(JSEvents.mouseEvent, e, target);
491
492
#if PTHREADS
493
if (targetThread) {
494
var mouseEventData = _malloc({{{ C_STRUCTS.EmscriptenMouseEvent.__size__ }}}); // This allocated block is passed as satellite data to the proxied function call, so the call frees up the data block when done.
495
fillMouseEventData(mouseEventData, e, target);
496
__emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, mouseEventData, userData);
497
} else
498
#endif
499
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, JSEvents.mouseEvent, userData)) e.preventDefault();
500
};
501
502
var eventHandler = {
503
target,
504
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
505
allowsDeferredCalls: eventTypeString != 'mousemove' && eventTypeString != 'mouseenter' && eventTypeString != 'mouseleave', // Mouse move events do not allow fullscreen/pointer lock requests to be handled in them!
506
#endif
507
eventTypeString,
508
callbackfunc,
509
handlerFunc: mouseEventHandlerFunc,
510
useCapture
511
};
512
return JSEvents.registerOrRemoveHandler(eventHandler);
513
},
514
515
emscripten_set_click_callback_on_thread__proxy: 'sync',
516
emscripten_set_click_callback_on_thread__deps: ['$registerMouseEventCallback'],
517
emscripten_set_click_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
518
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_CLICK }}}, "click", targetThread),
519
520
emscripten_set_mousedown_callback_on_thread__proxy: 'sync',
521
emscripten_set_mousedown_callback_on_thread__deps: ['$registerMouseEventCallback'],
522
emscripten_set_mousedown_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
523
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEDOWN }}}, "mousedown", targetThread),
524
525
emscripten_set_mouseup_callback_on_thread__proxy: 'sync',
526
emscripten_set_mouseup_callback_on_thread__deps: ['$registerMouseEventCallback'],
527
emscripten_set_mouseup_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
528
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEUP }}}, "mouseup", targetThread),
529
530
emscripten_set_dblclick_callback_on_thread__proxy: 'sync',
531
emscripten_set_dblclick_callback_on_thread__deps: ['$registerMouseEventCallback'],
532
emscripten_set_dblclick_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
533
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DBLCLICK }}}, "dblclick", targetThread),
534
535
emscripten_set_mousemove_callback_on_thread__proxy: 'sync',
536
emscripten_set_mousemove_callback_on_thread__deps: ['$registerMouseEventCallback'],
537
emscripten_set_mousemove_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
538
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEMOVE }}}, "mousemove", targetThread),
539
540
emscripten_set_mouseenter_callback_on_thread__proxy: 'sync',
541
emscripten_set_mouseenter_callback_on_thread__deps: ['$registerMouseEventCallback'],
542
emscripten_set_mouseenter_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
543
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEENTER }}}, "mouseenter", targetThread),
544
545
emscripten_set_mouseleave_callback_on_thread__proxy: 'sync',
546
emscripten_set_mouseleave_callback_on_thread__deps: ['$registerMouseEventCallback'],
547
emscripten_set_mouseleave_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
548
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSELEAVE }}}, "mouseleave", targetThread),
549
550
emscripten_set_mouseover_callback_on_thread__proxy: 'sync',
551
emscripten_set_mouseover_callback_on_thread__deps: ['$registerMouseEventCallback'],
552
emscripten_set_mouseover_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
553
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEOVER }}}, "mouseover", targetThread),
554
555
emscripten_set_mouseout_callback_on_thread__proxy: 'sync',
556
emscripten_set_mouseout_callback_on_thread__deps: ['$registerMouseEventCallback'],
557
emscripten_set_mouseout_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
558
registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEOUT }}}, "mouseout", targetThread),
559
560
emscripten_get_mouse_status__proxy: 'sync',
561
emscripten_get_mouse_status__deps: ['$JSEvents'],
562
emscripten_get_mouse_status: (mouseState) => {
563
if (!JSEvents.mouseEvent) return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}};
564
// HTML5 does not really have a polling API for mouse events, so implement one manually by
565
// returning the data from the most recently received event. This requires that user has registered
566
// at least some no-op function as an event handler to any of the mouse function.
567
JSEvents.memcpy(mouseState, JSEvents.mouseEvent, {{{ C_STRUCTS.EmscriptenMouseEvent.__size__ }}});
568
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
569
},
570
571
$registerWheelEventCallback__noleakcheck: true,
572
$registerWheelEventCallback__deps: ['$JSEvents', '$fillMouseEventData', 'malloc'],
573
$registerWheelEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
574
#if PTHREADS
575
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
576
#endif
577
JSEvents.wheelEvent ||= _malloc({{{ C_STRUCTS.EmscriptenWheelEvent.__size__ }}});
578
579
// The DOM Level 3 events spec event 'wheel'
580
var wheelHandlerFunc = (e = event) => {
581
#if PTHREADS
582
var wheelEvent = targetThread ? _malloc({{{ C_STRUCTS.EmscriptenWheelEvent.__size__ }}}) : JSEvents.wheelEvent; // This allocated block is passed as satellite data to the proxied function call, so the call frees up the data block when done.
583
#else
584
var wheelEvent = JSEvents.wheelEvent;
585
#endif
586
fillMouseEventData(wheelEvent, e, target);
587
{{{ makeSetValue('wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaX, 'e["deltaX"]', 'double') }}};
588
{{{ makeSetValue('wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaY, 'e["deltaY"]', 'double') }}};
589
{{{ makeSetValue('wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaZ, 'e["deltaZ"]', 'double') }}};
590
{{{ makeSetValue('wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaMode, 'e["deltaMode"]', 'i32') }}};
591
#if PTHREADS
592
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, wheelEvent, userData);
593
else
594
#endif
595
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, wheelEvent, userData)) e.preventDefault();
596
};
597
598
var eventHandler = {
599
target,
600
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
601
allowsDeferredCalls: true,
602
#endif
603
eventTypeString,
604
callbackfunc,
605
handlerFunc: wheelHandlerFunc,
606
useCapture
607
};
608
return JSEvents.registerOrRemoveHandler(eventHandler);
609
},
610
611
emscripten_set_wheel_callback_on_thread__proxy: 'sync',
612
emscripten_set_wheel_callback_on_thread__deps: ['$registerWheelEventCallback', '$findEventTarget'],
613
emscripten_set_wheel_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) => {
614
target = findEventTarget(target);
615
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
616
if (typeof target.onwheel != 'undefined') {
617
return registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WHEEL }}}, "wheel", targetThread);
618
} else {
619
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
620
}
621
},
622
623
$registerUiEventCallback__noleakcheck: true,
624
$registerUiEventCallback__deps: ['$JSEvents', '$findEventTarget', 'malloc'],
625
$registerUiEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
626
#if PTHREADS
627
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
628
#endif
629
JSEvents.uiEvent ||= _malloc({{{ C_STRUCTS.EmscriptenUiEvent.__size__ }}});
630
631
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
632
target = findEventTarget(target);
633
#else
634
if (eventTypeId == {{{ cDefs.EMSCRIPTEN_EVENT_SCROLL }}} && !target) {
635
target = document; // By default read scroll events on document rather than window.
636
} else {
637
target = findEventTarget(target);
638
}
639
#else
640
#endif
641
642
var uiEventHandlerFunc = (e = event) => {
643
if (e.target != target) {
644
// Never take ui events such as scroll via a 'bubbled' route, but always from the direct element that
645
// was targeted. Otherwise e.g. if app logs a message in response to a page scroll, the Emscripten log
646
// message box could cause to scroll, generating a new (bubbled) scroll message, causing a new log print,
647
// causing a new scroll, etc..
648
return;
649
}
650
var b = document.body; // Take document.body to a variable, Closure compiler does not outline access to it on its own.
651
if (!b) {
652
// During a page unload 'body' can be null, with "Cannot read property 'clientWidth' of null" being thrown
653
return;
654
}
655
#if PTHREADS
656
var uiEvent = targetThread ? _malloc({{{ C_STRUCTS.EmscriptenUiEvent.__size__ }}}) : JSEvents.uiEvent;
657
#else
658
var uiEvent = JSEvents.uiEvent;
659
#endif
660
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.detail, '0', 'i32') }}}; // always zero for resize and scroll
661
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.documentBodyClientWidth, 'b.clientWidth', 'i32') }}};
662
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.documentBodyClientHeight, 'b.clientHeight', 'i32') }}};
663
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.windowInnerWidth, 'innerWidth', 'i32') }}};
664
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.windowInnerHeight, 'innerHeight', 'i32') }}};
665
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.windowOuterWidth, 'outerWidth', 'i32') }}};
666
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.windowOuterHeight, 'outerHeight', 'i32') }}};
667
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.scrollTop, 'pageXOffset | 0', 'i32') }}}; // scroll offsets are float
668
{{{ makeSetValue('uiEvent', C_STRUCTS.EmscriptenUiEvent.scrollLeft, 'pageYOffset | 0', 'i32') }}};
669
#if PTHREADS
670
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, uiEvent, userData);
671
else
672
#endif
673
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, uiEvent, userData)) e.preventDefault();
674
};
675
676
var eventHandler = {
677
target,
678
eventTypeString,
679
callbackfunc,
680
handlerFunc: uiEventHandlerFunc,
681
useCapture
682
};
683
return JSEvents.registerOrRemoveHandler(eventHandler);
684
},
685
686
emscripten_set_resize_callback_on_thread__proxy: 'sync',
687
emscripten_set_resize_callback_on_thread__deps: ['$registerUiEventCallback'],
688
emscripten_set_resize_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
689
registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_RESIZE }}}, "resize", targetThread),
690
691
emscripten_set_scroll_callback_on_thread__proxy: 'sync',
692
emscripten_set_scroll_callback_on_thread__deps: ['$registerUiEventCallback'],
693
emscripten_set_scroll_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
694
registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_SCROLL }}}, "scroll", targetThread),
695
696
$registerFocusEventCallback__noleakcheck: true,
697
$registerFocusEventCallback__deps: ['$JSEvents', '$findEventTarget', 'malloc', '$stringToUTF8'],
698
$registerFocusEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
699
#if PTHREADS
700
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
701
#endif
702
JSEvents.focusEvent ||= _malloc({{{ C_STRUCTS.EmscriptenFocusEvent.__size__ }}});
703
704
var focusEventHandlerFunc = (e = event) => {
705
var nodeName = JSEvents.getNodeNameForTarget(e.target);
706
var id = e.target.id ? e.target.id : '';
707
708
#if PTHREADS
709
var focusEvent = targetThread ? _malloc({{{ C_STRUCTS.EmscriptenFocusEvent.__size__ }}}) : JSEvents.focusEvent;
710
#else
711
var focusEvent = JSEvents.focusEvent;
712
#endif
713
stringToUTF8(nodeName, focusEvent + {{{ C_STRUCTS.EmscriptenFocusEvent.nodeName }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}});
714
stringToUTF8(id, focusEvent + {{{ C_STRUCTS.EmscriptenFocusEvent.id }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}});
715
716
#if PTHREADS
717
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, focusEvent, userData);
718
else
719
#endif
720
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, focusEvent, userData)) e.preventDefault();
721
};
722
723
var eventHandler = {
724
target: findEventTarget(target),
725
eventTypeString,
726
callbackfunc,
727
handlerFunc: focusEventHandlerFunc,
728
useCapture
729
};
730
return JSEvents.registerOrRemoveHandler(eventHandler);
731
},
732
733
emscripten_set_blur_callback_on_thread__proxy: 'sync',
734
emscripten_set_blur_callback_on_thread__deps: ['$registerFocusEventCallback'],
735
emscripten_set_blur_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
736
registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BLUR }}}, "blur", targetThread),
737
738
emscripten_set_focus_callback_on_thread__proxy: 'sync',
739
emscripten_set_focus_callback_on_thread__deps: ['$registerFocusEventCallback'],
740
emscripten_set_focus_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
741
registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUS }}}, "focus", targetThread),
742
743
emscripten_set_focusin_callback_on_thread__proxy: 'sync',
744
emscripten_set_focusin_callback_on_thread__deps: ['$registerFocusEventCallback'],
745
emscripten_set_focusin_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
746
registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUSIN }}}, "focusin", targetThread),
747
748
emscripten_set_focusout_callback_on_thread__proxy: 'sync',
749
emscripten_set_focusout_callback_on_thread__deps: ['$registerFocusEventCallback'],
750
emscripten_set_focusout_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
751
registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUSOUT }}}, "focusout", targetThread),
752
753
$fillDeviceOrientationEventData: (eventStruct, e, target) => {
754
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceOrientationEvent.alpha, 'e.alpha', 'double') }}};
755
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceOrientationEvent.beta, 'e.beta', 'double') }}};
756
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceOrientationEvent.gamma, 'e.gamma', 'double') }}};
757
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceOrientationEvent.absolute, 'e.absolute', 'i8') }}};
758
},
759
760
$registerDeviceOrientationEventCallback__noleakcheck: true,
761
$registerDeviceOrientationEventCallback__deps: ['$JSEvents', '$fillDeviceOrientationEventData', '$findEventTarget'],
762
$registerDeviceOrientationEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
763
#if PTHREADS
764
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
765
#endif
766
JSEvents.deviceOrientationEvent ||= _malloc({{{ C_STRUCTS.EmscriptenDeviceOrientationEvent.__size__ }}});
767
768
var deviceOrientationEventHandlerFunc = (e = event) => {
769
fillDeviceOrientationEventData(JSEvents.deviceOrientationEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_deviceorientation_status()
770
771
#if PTHREADS
772
if (targetThread) {
773
var deviceOrientationEvent = _malloc({{{ C_STRUCTS.EmscriptenDeviceOrientationEvent.__size__ }}});
774
fillDeviceOrientationEventData(deviceOrientationEvent, e, target);
775
__emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, deviceOrientationEvent, userData);
776
} else
777
#endif
778
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, JSEvents.deviceOrientationEvent, userData)) e.preventDefault();
779
};
780
781
var eventHandler = {
782
target: findEventTarget(target),
783
eventTypeString,
784
callbackfunc,
785
handlerFunc: deviceOrientationEventHandlerFunc,
786
useCapture
787
};
788
return JSEvents.registerOrRemoveHandler(eventHandler);
789
},
790
791
emscripten_set_deviceorientation_callback_on_thread__proxy: 'sync',
792
emscripten_set_deviceorientation_callback_on_thread__deps: ['$registerDeviceOrientationEventCallback'],
793
emscripten_set_deviceorientation_callback_on_thread: (userData, useCapture, callbackfunc, targetThread) => {
794
return registerDeviceOrientationEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DEVICEORIENTATION }}}, "deviceorientation", targetThread);
795
},
796
797
emscripten_get_deviceorientation_status__proxy: 'sync',
798
emscripten_get_deviceorientation_status__deps: ['$JSEvents'],
799
emscripten_get_deviceorientation_status: (orientationState) => {
800
if (!JSEvents.deviceOrientationEvent) return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}};
801
// HTML5 does not really have a polling API for device orientation events, so implement one manually by
802
// returning the data from the most recently received event. This requires that user has registered
803
// at least some no-op function as an event handler.
804
JSEvents.memcpy(orientationState, JSEvents.deviceOrientationEvent, {{{ C_STRUCTS.EmscriptenDeviceOrientationEvent.__size__ }}});
805
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
806
},
807
808
$fillDeviceMotionEventData: (eventStruct, e, target) => {
809
var supportedFields = 0;
810
var a = e['acceleration'];
811
supportedFields |= a && {{{ cDefs.EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ACCELERATION }}};
812
var ag = e['accelerationIncludingGravity'];
813
supportedFields |= ag && {{{ cDefs.EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ACCELERATION_INCLUDING_GRAVITY }}};
814
var rr = e['rotationRate'];
815
supportedFields |= rr && {{{ cDefs.EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ROTATION_RATE }}};
816
a = a || {};
817
ag = ag || {};
818
rr = rr || {};
819
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationX, 'a["x"]', 'double') }}};
820
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationY, 'a["y"]', 'double') }}};
821
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationZ, 'a["z"]', 'double') }}};
822
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationIncludingGravityX, 'ag["x"]', 'double') }}};
823
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationIncludingGravityY, 'ag["y"]', 'double') }}};
824
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationIncludingGravityZ, 'ag["z"]', 'double') }}};
825
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.rotationRateAlpha, 'rr["alpha"]', 'double') }}};
826
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.rotationRateBeta, 'rr["beta"]', 'double') }}};
827
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.rotationRateGamma, 'rr["gamma"]', 'double') }}};
828
},
829
830
$registerDeviceMotionEventCallback__noleakcheck: true,
831
$registerDeviceMotionEventCallback__deps: ['$JSEvents', '$fillDeviceMotionEventData', '$findEventTarget', 'malloc'],
832
$registerDeviceMotionEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
833
#if PTHREADS
834
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
835
#endif
836
JSEvents.deviceMotionEvent ||= _malloc({{{ C_STRUCTS.EmscriptenDeviceMotionEvent.__size__ }}});
837
838
var deviceMotionEventHandlerFunc = (e = event) => {
839
fillDeviceMotionEventData(JSEvents.deviceMotionEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_devicemotion_status()
840
841
#if PTHREADS
842
if (targetThread) {
843
var deviceMotionEvent = _malloc({{{ C_STRUCTS.EmscriptenDeviceMotionEvent.__size__ }}});
844
fillDeviceMotionEventData(deviceMotionEvent, e, target);
845
__emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, deviceMotionEvent, userData);
846
} else
847
#endif
848
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, JSEvents.deviceMotionEvent, userData)) e.preventDefault();
849
};
850
851
var eventHandler = {
852
target: findEventTarget(target),
853
eventTypeString,
854
callbackfunc,
855
handlerFunc: deviceMotionEventHandlerFunc,
856
useCapture
857
};
858
return JSEvents.registerOrRemoveHandler(eventHandler);
859
},
860
861
emscripten_set_devicemotion_callback_on_thread__proxy: 'sync',
862
emscripten_set_devicemotion_callback_on_thread__deps: ['$registerDeviceMotionEventCallback'],
863
emscripten_set_devicemotion_callback_on_thread: (userData, useCapture, callbackfunc, targetThread) =>
864
registerDeviceMotionEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DEVICEMOTION }}}, "devicemotion", targetThread),
865
866
emscripten_get_devicemotion_status__proxy: 'sync',
867
emscripten_get_devicemotion_status__deps: ['$JSEvents'],
868
emscripten_get_devicemotion_status: (motionState) => {
869
if (!JSEvents.deviceMotionEvent) return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}};
870
// HTML5 does not really have a polling API for device motion events, so implement one manually by
871
// returning the data from the most recently received event. This requires that user has registered
872
// at least some no-op function as an event handler.
873
JSEvents.memcpy(motionState, JSEvents.deviceMotionEvent, {{{ C_STRUCTS.EmscriptenDeviceMotionEvent.__size__ }}});
874
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
875
},
876
877
$screenOrientation: () => {
878
if (!window.screen) return undefined;
879
return screen.orientation || screen['mozOrientation'] || screen['webkitOrientation'];
880
},
881
882
$fillOrientationChangeEventData__deps: ['$screenOrientation'],
883
$fillOrientationChangeEventData: (eventStruct) => {
884
// OrientationType enum
885
var orientationsType1 = ['portrait-primary', 'portrait-secondary', 'landscape-primary', 'landscape-secondary'];
886
// alternative selection from OrientationLockType enum
887
var orientationsType2 = ['portrait', 'portrait', 'landscape', 'landscape'];
888
889
var orientationIndex = {{{ cDefs.EMSCRIPTEN_ORIENTATION_UNSUPPORTED }}};
890
var orientationAngle = 0;
891
var screenOrientObj = screenOrientation();
892
if (typeof screenOrientObj === 'object') {
893
orientationIndex = orientationsType1.indexOf(screenOrientObj.type);
894
if (orientationIndex < 0) {
895
orientationIndex = orientationsType2.indexOf(screenOrientObj.type);
896
}
897
if (orientationIndex >= 0) {
898
orientationIndex = 1 << orientationIndex;
899
}
900
orientationAngle = screenOrientObj.angle;
901
}
902
#if MIN_SAFARI_VERSION < 160400
903
else {
904
// fallback for Safari earlier than 16.4 (March 2023)
905
orientationAngle = window.orientation;
906
}
907
#endif
908
909
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenOrientationChangeEvent.orientationIndex, 'orientationIndex', 'i32') }}};
910
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenOrientationChangeEvent.orientationAngle, 'orientationAngle', 'i32') }}};
911
},
912
913
$registerOrientationChangeEventCallback__noleakcheck: true,
914
$registerOrientationChangeEventCallback__deps: ['$JSEvents', '$fillOrientationChangeEventData', 'malloc'],
915
$registerOrientationChangeEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
916
#if PTHREADS
917
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
918
#endif
919
JSEvents.orientationChangeEvent ||= _malloc({{{ C_STRUCTS.EmscriptenOrientationChangeEvent.__size__ }}});
920
921
var orientationChangeEventHandlerFunc = (e = event) => {
922
#if PTHREADS
923
var orientationChangeEvent = targetThread ? _malloc({{{ C_STRUCTS.EmscriptenOrientationChangeEvent.__size__ }}}) : JSEvents.orientationChangeEvent;
924
#else
925
var orientationChangeEvent = JSEvents.orientationChangeEvent;
926
#endif
927
928
fillOrientationChangeEventData(orientationChangeEvent);
929
930
#if PTHREADS
931
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, orientationChangeEvent, userData);
932
else
933
#endif
934
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, orientationChangeEvent, userData)) e.preventDefault();
935
};
936
937
var eventHandler = {
938
target,
939
eventTypeString,
940
callbackfunc,
941
handlerFunc: orientationChangeEventHandlerFunc,
942
useCapture
943
};
944
return JSEvents.registerOrRemoveHandler(eventHandler);
945
},
946
947
emscripten_set_orientationchange_callback_on_thread__proxy: 'sync',
948
emscripten_set_orientationchange_callback_on_thread__deps: ['$registerOrientationChangeEventCallback'],
949
emscripten_set_orientationchange_callback_on_thread: (userData, useCapture, callbackfunc, targetThread) => {
950
if (!window.screen || !screen.orientation) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
951
return registerOrientationChangeEventCallback(screen.orientation, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_ORIENTATIONCHANGE }}}, 'change', targetThread);
952
},
953
954
emscripten_get_orientation_status__proxy: 'sync',
955
emscripten_get_orientation_status__deps: ['$fillOrientationChangeEventData', '$screenOrientation'],
956
emscripten_get_orientation_status: (orientationChangeEvent) => {
957
// screenOrientation() resolving standard, window.orientation being the deprecated mobile-only
958
if (!screenOrientation() && typeof orientation == 'undefined') return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
959
fillOrientationChangeEventData(orientationChangeEvent);
960
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
961
},
962
963
emscripten_lock_orientation__proxy: 'sync',
964
emscripten_lock_orientation: (allowedOrientations) => {
965
var orientations = [];
966
if (allowedOrientations & 1) orientations.push("portrait-primary");
967
if (allowedOrientations & 2) orientations.push("portrait-secondary");
968
if (allowedOrientations & 4) orientations.push("landscape-primary");
969
if (allowedOrientations & 8) orientations.push("landscape-secondary");
970
var succeeded;
971
if (screen.lockOrientation) {
972
succeeded = screen.lockOrientation(orientations);
973
} else if (screen.mozLockOrientation) {
974
succeeded = screen.mozLockOrientation(orientations);
975
} else if (screen.webkitLockOrientation) {
976
succeeded = screen.webkitLockOrientation(orientations);
977
} else {
978
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
979
}
980
if (succeeded) {
981
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
982
}
983
return {{{ cDefs.EMSCRIPTEN_RESULT_FAILED }}};
984
},
985
986
emscripten_unlock_orientation__proxy: 'sync',
987
emscripten_unlock_orientation: () => {
988
if (screen.unlockOrientation) {
989
screen.unlockOrientation();
990
} else if (screen.mozUnlockOrientation) {
991
screen.mozUnlockOrientation();
992
} else if (screen.webkitUnlockOrientation) {
993
screen.webkitUnlockOrientation();
994
} else {
995
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
996
}
997
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
998
},
999
1000
$fillFullscreenChangeEventData__deps: ['$JSEvents', '$stringToUTF8', '$getFullscreenElement'],
1001
$fillFullscreenChangeEventData: (eventStruct) => {
1002
var fullscreenElement = getFullscreenElement();
1003
var isFullscreen = !!fullscreenElement;
1004
#if !SAFE_HEAP
1005
// Assigning a boolean to HEAP32 with expected type coercion.
1006
/** @suppress{checkTypes} */
1007
#endif
1008
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.isFullscreen, 'isFullscreen', 'i8') }}};
1009
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.fullscreenEnabled, 'JSEvents.fullscreenEnabled()', 'i8') }}};
1010
// If transitioning to fullscreen, report info about the element that is now fullscreen.
1011
// If transitioning to windowed mode, report info about the element that just was fullscreen.
1012
var reportedElement = isFullscreen ? fullscreenElement : JSEvents.previousFullscreenElement;
1013
var nodeName = JSEvents.getNodeNameForTarget(reportedElement);
1014
var id = reportedElement?.id || '';
1015
stringToUTF8(nodeName, eventStruct + {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.nodeName }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}});
1016
stringToUTF8(id, eventStruct + {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.id }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}});
1017
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.elementWidth, 'reportedElement ? reportedElement.clientWidth : 0', 'i32') }}};
1018
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.elementHeight, 'reportedElement ? reportedElement.clientHeight : 0', 'i32') }}};
1019
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.screenWidth, 'screen.width', 'i32') }}};
1020
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.screenHeight, 'screen.height', 'i32') }}};
1021
if (isFullscreen) {
1022
JSEvents.previousFullscreenElement = fullscreenElement;
1023
}
1024
},
1025
1026
$registerFullscreenChangeEventCallback__noleakcheck: true,
1027
$registerFullscreenChangeEventCallback__deps: ['$JSEvents', '$fillFullscreenChangeEventData', 'malloc'],
1028
$registerFullscreenChangeEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
1029
#if PTHREADS
1030
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
1031
#endif
1032
JSEvents.fullscreenChangeEvent ||= _malloc({{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.__size__ }}});
1033
1034
var fullscreenChangeEventhandlerFunc = (e = event) => {
1035
#if PTHREADS
1036
var fullscreenChangeEvent = targetThread ? _malloc({{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.__size__ }}}) : JSEvents.fullscreenChangeEvent;
1037
#else
1038
var fullscreenChangeEvent = JSEvents.fullscreenChangeEvent;
1039
#endif
1040
1041
fillFullscreenChangeEventData(fullscreenChangeEvent);
1042
1043
#if PTHREADS
1044
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, fullscreenChangeEvent, userData);
1045
else
1046
#endif
1047
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, fullscreenChangeEvent, userData)) e.preventDefault();
1048
};
1049
1050
var eventHandler = {
1051
target,
1052
eventTypeString,
1053
callbackfunc,
1054
handlerFunc: fullscreenChangeEventhandlerFunc,
1055
useCapture
1056
};
1057
return JSEvents.registerOrRemoveHandler(eventHandler);
1058
},
1059
1060
emscripten_set_fullscreenchange_callback_on_thread__proxy: 'sync',
1061
emscripten_set_fullscreenchange_callback_on_thread__deps: ['$JSEvents', '$registerFullscreenChangeEventCallback', '$findEventTarget',
1062
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1063
'$specialHTMLTargets'
1064
#endif
1065
],
1066
emscripten_set_fullscreenchange_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) => {
1067
if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1068
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1069
target = findEventTarget(target);
1070
#else
1071
target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}];
1072
#endif
1073
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1074
1075
#if MIN_FIREFOX_VERSION <= 63 // https://caniuse.com/#feat=mdn-api_element_fullscreenchange_event
1076
registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FULLSCREENCHANGE }}}, "mozfullscreenchange", targetThread);
1077
#endif
1078
1079
#if MIN_CHROME_VERSION < 71 || MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
1080
// Unprefixed Fullscreen API shipped in Chromium 71 (https://bugs.chromium.org/p/chromium/issues/detail?id=383813)
1081
// As of Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitfullscreenchange. TODO: revisit this check once Safari ships unprefixed version.
1082
registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FULLSCREENCHANGE }}}, "webkitfullscreenchange", targetThread);
1083
#endif
1084
1085
return registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FULLSCREENCHANGE }}}, "fullscreenchange", targetThread);
1086
},
1087
1088
emscripten_get_fullscreen_status__proxy: 'sync',
1089
emscripten_get_fullscreen_status__deps: ['$JSEvents', '$fillFullscreenChangeEventData'],
1090
emscripten_get_fullscreen_status: (fullscreenStatus) => {
1091
if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1092
fillFullscreenChangeEventData(fullscreenStatus);
1093
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1094
},
1095
1096
$JSEvents_requestFullscreen__deps: ['$JSEvents', '$JSEvents_resizeCanvasForFullscreen'],
1097
$JSEvents_requestFullscreen: (target, strategy) => {
1098
// EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT + EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE is a mode where no extra logic is performed to the DOM elements.
1099
if (strategy.scaleMode != {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT }}} || strategy.canvasResolutionScaleMode != {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE }}}) {
1100
JSEvents_resizeCanvasForFullscreen(target, strategy);
1101
}
1102
1103
if (target.requestFullscreen) {
1104
target.requestFullscreen();
1105
#if MIN_FIREFOX_VERSION <= 63 // https://caniuse.com/#feat=fullscreen
1106
} else if (target.mozRequestFullScreen) {
1107
target.mozRequestFullScreen();
1108
} else if (target.mozRequestFullscreen) {
1109
target.mozRequestFullscreen();
1110
#endif
1111
#if MIN_CHROME_VERSION <= 70 || MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
1112
} else if (target.webkitRequestFullscreen) {
1113
target.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
1114
#endif
1115
} else {
1116
return JSEvents.fullscreenEnabled() ? {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}} : {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1117
}
1118
1119
currentFullscreenStrategy = strategy;
1120
1121
if (strategy.canvasResizedCallback) {
1122
#if PTHREADS
1123
if (strategy.canvasResizedCallbackTargetThread) __emscripten_run_callback_on_thread(strategy.canvasResizedCallbackTargetThread, strategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData);
1124
else
1125
#endif
1126
{{{ makeDynCall('iipp', 'strategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData);
1127
}
1128
1129
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1130
},
1131
1132
$JSEvents_resizeCanvasForFullscreen__deps: ['$registerRestoreOldStyle', '$getCanvasElementSize', '$setLetterbox', '$setCanvasElementSize', '$getBoundingClientRect'],
1133
$JSEvents_resizeCanvasForFullscreen: (target, strategy) => {
1134
var restoreOldStyle = registerRestoreOldStyle(target);
1135
var cssWidth = strategy.softFullscreen ? innerWidth : screen.width;
1136
var cssHeight = strategy.softFullscreen ? innerHeight : screen.height;
1137
var rect = getBoundingClientRect(target);
1138
var windowedCssWidth = rect.width;
1139
var windowedCssHeight = rect.height;
1140
var canvasSize = getCanvasElementSize(target);
1141
var windowedRttWidth = canvasSize[0];
1142
var windowedRttHeight = canvasSize[1];
1143
1144
if (strategy.scaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_CENTER }}}) {
1145
setLetterbox(target, (cssHeight - windowedCssHeight) / 2, (cssWidth - windowedCssWidth) / 2);
1146
cssWidth = windowedCssWidth;
1147
cssHeight = windowedCssHeight;
1148
} else if (strategy.scaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT }}}) {
1149
if (cssWidth*windowedRttHeight < windowedRttWidth*cssHeight) {
1150
var desiredCssHeight = windowedRttHeight * cssWidth / windowedRttWidth;
1151
setLetterbox(target, (cssHeight - desiredCssHeight) / 2, 0);
1152
cssHeight = desiredCssHeight;
1153
} else {
1154
var desiredCssWidth = windowedRttWidth * cssHeight / windowedRttHeight;
1155
setLetterbox(target, 0, (cssWidth - desiredCssWidth) / 2);
1156
cssWidth = desiredCssWidth;
1157
}
1158
}
1159
1160
// If we are adding padding, must choose a background color or otherwise Chrome will give the
1161
// padding a default white color. Do it only if user has not customized their own background color.
1162
target.style.backgroundColor ||= 'black';
1163
// IE11 does the same, but requires the color to be set in the document body.
1164
document.body.style.backgroundColor ||= 'black'; // IE11
1165
// Firefox always shows black letterboxes independent of style color.
1166
1167
target.style.width = cssWidth + 'px';
1168
target.style.height = cssHeight + 'px';
1169
1170
if (strategy.filteringMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST }}}) {
1171
target.style.imageRendering = 'optimizeSpeed';
1172
target.style.imageRendering = '-moz-crisp-edges';
1173
target.style.imageRendering = '-o-crisp-edges';
1174
target.style.imageRendering = '-webkit-optimize-contrast';
1175
target.style.imageRendering = 'optimize-contrast';
1176
target.style.imageRendering = 'crisp-edges';
1177
target.style.imageRendering = 'pixelated';
1178
}
1179
1180
var dpiScale = (strategy.canvasResolutionScaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF }}}) ? devicePixelRatio : 1;
1181
if (strategy.canvasResolutionScaleMode != {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE }}}) {
1182
var newWidth = (cssWidth * dpiScale)|0;
1183
var newHeight = (cssHeight * dpiScale)|0;
1184
setCanvasElementSize(target, newWidth, newHeight);
1185
if (target.GLctxObject) target.GLctxObject.GLctx.viewport(0, 0, newWidth, newHeight);
1186
}
1187
return restoreOldStyle;
1188
},
1189
1190
$registerRestoreOldStyle__deps: ['$getCanvasElementSize', '$setCanvasElementSize', '$currentFullscreenStrategy'],
1191
$registerRestoreOldStyle: (canvas) => {
1192
var canvasSize = getCanvasElementSize(canvas);
1193
var oldWidth = canvasSize[0];
1194
var oldHeight = canvasSize[1];
1195
var oldCssWidth = canvas.style.width;
1196
var oldCssHeight = canvas.style.height;
1197
var oldBackgroundColor = canvas.style.backgroundColor; // Chrome reads color from here.
1198
var oldDocumentBackgroundColor = document.body.style.backgroundColor; // IE11 reads color from here.
1199
// Firefox always has black background color.
1200
var oldPaddingLeft = canvas.style.paddingLeft; // Chrome, FF, Safari
1201
var oldPaddingRight = canvas.style.paddingRight;
1202
var oldPaddingTop = canvas.style.paddingTop;
1203
var oldPaddingBottom = canvas.style.paddingBottom;
1204
var oldMarginLeft = canvas.style.marginLeft; // IE11
1205
var oldMarginRight = canvas.style.marginRight;
1206
var oldMarginTop = canvas.style.marginTop;
1207
var oldMarginBottom = canvas.style.marginBottom;
1208
var oldDocumentBodyMargin = document.body.style.margin;
1209
var oldDocumentOverflow = document.documentElement.style.overflow; // Chrome, Firefox
1210
var oldDocumentScroll = document.body.scroll; // IE
1211
var oldImageRendering = canvas.style.imageRendering;
1212
1213
function restoreOldStyle() {
1214
if (!getFullscreenElement()) {
1215
document.removeEventListener('fullscreenchange', restoreOldStyle);
1216
1217
#if MIN_FIREFOX_VERSION <= 63 // https://caniuse.com/#feat=mdn-api_element_fullscreenchange_event
1218
document.removeEventListener('mozfullscreenchange', restoreOldStyle);
1219
#endif
1220
1221
#if MIN_CHROME_VERSION < 71 || MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
1222
// Unprefixed Fullscreen API shipped in Chromium 71 (https://bugs.chromium.org/p/chromium/issues/detail?id=383813)
1223
// As of Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitfullscreenchange. TODO: revisit this check once Safari ships unprefixed version.
1224
document.removeEventListener('webkitfullscreenchange', restoreOldStyle);
1225
#endif
1226
1227
setCanvasElementSize(canvas, oldWidth, oldHeight);
1228
1229
canvas.style.width = oldCssWidth;
1230
canvas.style.height = oldCssHeight;
1231
canvas.style.backgroundColor = oldBackgroundColor; // Chrome
1232
// IE11 hack: assigning 'undefined' or an empty string to document.body.style.backgroundColor has no effect, so first assign back the default color
1233
// before setting the undefined value. Setting undefined value is also important, or otherwise we would later treat that as something that the user
1234
// had explicitly set so subsequent fullscreen transitions would not set background color properly.
1235
if (!oldDocumentBackgroundColor) document.body.style.backgroundColor = 'white';
1236
document.body.style.backgroundColor = oldDocumentBackgroundColor; // IE11
1237
canvas.style.paddingLeft = oldPaddingLeft; // Chrome, FF, Safari
1238
canvas.style.paddingRight = oldPaddingRight;
1239
canvas.style.paddingTop = oldPaddingTop;
1240
canvas.style.paddingBottom = oldPaddingBottom;
1241
canvas.style.marginLeft = oldMarginLeft; // IE11
1242
canvas.style.marginRight = oldMarginRight;
1243
canvas.style.marginTop = oldMarginTop;
1244
canvas.style.marginBottom = oldMarginBottom;
1245
document.body.style.margin = oldDocumentBodyMargin;
1246
document.documentElement.style.overflow = oldDocumentOverflow; // Chrome, Firefox
1247
document.body.scroll = oldDocumentScroll; // IE
1248
canvas.style.imageRendering = oldImageRendering;
1249
if (canvas.GLctxObject) canvas.GLctxObject.GLctx.viewport(0, 0, oldWidth, oldHeight);
1250
1251
if (currentFullscreenStrategy.canvasResizedCallback) {
1252
#if PTHREADS
1253
if (currentFullscreenStrategy.canvasResizedCallbackTargetThread) __emscripten_run_callback_on_thread(currentFullscreenStrategy.canvasResizedCallbackTargetThread, currentFullscreenStrategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData);
1254
else
1255
#endif
1256
{{{ makeDynCall('iipp', 'currentFullscreenStrategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData);
1257
}
1258
}
1259
}
1260
document.addEventListener('fullscreenchange', restoreOldStyle);
1261
#if MIN_FIREFOX_VERSION <= 63 // https://caniuse.com/#feat=mdn-api_element_fullscreenchange_event
1262
document.addEventListener('mozfullscreenchange', restoreOldStyle);
1263
#endif
1264
#if MIN_CHROME_VERSION < 71 || MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
1265
// Unprefixed Fullscreen API shipped in Chromium 71 (https://bugs.chromium.org/p/chromium/issues/detail?id=383813)
1266
// As of Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitfullscreenchange. TODO: revisit this check once Safari ships unprefixed version.
1267
document.addEventListener('webkitfullscreenchange', restoreOldStyle);
1268
#endif
1269
return restoreOldStyle;
1270
},
1271
1272
// Walks the DOM tree and hides every element by setting "display: none;" except the given element.
1273
// Returns a list of [{node: element, displayState: oldDisplayStyle}] entries to allow restoring previous
1274
// visibility states after done.
1275
$hideEverythingExceptGivenElement: (onlyVisibleElement) => {
1276
var child = onlyVisibleElement;
1277
var parent = child.parentNode;
1278
var hiddenElements = [];
1279
while (child != document.body) {
1280
var children = parent.children;
1281
for (var currChild of children) {
1282
if (currChild != child) {
1283
hiddenElements.push({ node: currChild, displayState: currChild.style.display });
1284
currChild.style.display = 'none';
1285
}
1286
}
1287
child = parent;
1288
parent = parent.parentNode;
1289
}
1290
return hiddenElements;
1291
},
1292
1293
// Applies old visibility states, given a list of changes returned by hideEverythingExceptGivenElement().
1294
$restoreHiddenElements: (hiddenElements) => {
1295
for (var elem of hiddenElements) {
1296
elem.node.style.display = elem.displayState;
1297
}
1298
},
1299
1300
// Add letterboxes to a fullscreen element in a cross-browser way.
1301
$setLetterbox: (element, topBottom, leftRight) => {
1302
// Cannot use margin to specify letterboxes in FF or Chrome, since those ignore margins in fullscreen mode.
1303
element.style.paddingLeft = element.style.paddingRight = leftRight + 'px';
1304
element.style.paddingTop = element.style.paddingBottom = topBottom + 'px';
1305
},
1306
1307
$currentFullscreenStrategy: {},
1308
$restoreOldWindowedStyle: null,
1309
1310
$softFullscreenResizeWebGLRenderTarget__deps: ['$setLetterbox', '$currentFullscreenStrategy', '$getCanvasElementSize', '$setCanvasElementSize', '$jstoi_q'],
1311
$softFullscreenResizeWebGLRenderTarget: () => {
1312
var dpr = devicePixelRatio;
1313
var inHiDPIFullscreenMode = currentFullscreenStrategy.canvasResolutionScaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF }}};
1314
var inAspectRatioFixedFullscreenMode = currentFullscreenStrategy.scaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT }}};
1315
var inPixelPerfectFullscreenMode = currentFullscreenStrategy.canvasResolutionScaleMode != {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE }}};
1316
var inCenteredWithoutScalingFullscreenMode = currentFullscreenStrategy.scaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_CENTER }}};
1317
var screenWidth = inHiDPIFullscreenMode ? Math.round(innerWidth*dpr) : innerWidth;
1318
var screenHeight = inHiDPIFullscreenMode ? Math.round(innerHeight*dpr) : innerHeight;
1319
var w = screenWidth;
1320
var h = screenHeight;
1321
var canvas = currentFullscreenStrategy.target;
1322
var canvasSize = getCanvasElementSize(canvas);
1323
var x = canvasSize[0];
1324
var y = canvasSize[1];
1325
var topMargin;
1326
1327
if (inAspectRatioFixedFullscreenMode) {
1328
if (w*y < x*h) h = (w * y / x) | 0;
1329
else if (w*y > x*h) w = (h * x / y) | 0;
1330
topMargin = ((screenHeight - h) / 2) | 0;
1331
}
1332
1333
if (inPixelPerfectFullscreenMode) {
1334
setCanvasElementSize(canvas, w, h);
1335
if (canvas.GLctxObject) canvas.GLctxObject.GLctx.viewport(0, 0, w, h);
1336
}
1337
1338
// Back to CSS pixels.
1339
if (inHiDPIFullscreenMode) {
1340
topMargin /= dpr;
1341
w /= dpr;
1342
h /= dpr;
1343
// Round to nearest 4 digits of precision.
1344
w = Math.round(w*1e4)/1e4;
1345
h = Math.round(h*1e4)/1e4;
1346
topMargin = Math.round(topMargin*1e4)/1e4;
1347
}
1348
1349
if (inCenteredWithoutScalingFullscreenMode) {
1350
var t = (innerHeight - jstoi_q(canvas.style.height)) / 2;
1351
var b = (innerWidth - jstoi_q(canvas.style.width)) / 2;
1352
setLetterbox(canvas, t, b);
1353
} else {
1354
canvas.style.width = w + 'px';
1355
canvas.style.height = h + 'px';
1356
var b = (innerWidth - w) / 2;
1357
setLetterbox(canvas, topMargin, b);
1358
}
1359
1360
if (!inCenteredWithoutScalingFullscreenMode && currentFullscreenStrategy.canvasResizedCallback) {
1361
#if PTHREADS
1362
if (currentFullscreenStrategy.canvasResizedCallbackTargetThread) __emscripten_run_callback_on_thread(currentFullscreenStrategy.canvasResizedCallbackTargetThread, currentFullscreenStrategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData);
1363
else
1364
#endif
1365
{{{ makeDynCall('iipp', 'currentFullscreenStrategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData);
1366
}
1367
},
1368
1369
// https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_full_screen_mode
1370
$doRequestFullscreen__deps: ['$JSEvents', '$JSEvents_requestFullscreen', '$findEventTarget'],
1371
$doRequestFullscreen: (target, strategy) => {
1372
if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1373
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1374
target ||= '#canvas';
1375
#endif
1376
target = findEventTarget(target);
1377
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1378
1379
if (!target.requestFullscreen
1380
#if MIN_FIREFOX_VERSION <= 63 // https://caniuse.com/#feat=fullscreen
1381
&& !target.mozRequestFullScreen
1382
&& !target.mozRequestFullscreen
1383
#endif
1384
#if MIN_CHROME_VERSION <= 70 || MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED
1385
&& !target.webkitRequestFullscreen
1386
#endif
1387
) {
1388
return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}};
1389
}
1390
1391
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1392
// Queue this function call if we're not currently in an event handler and
1393
// the user saw it appropriate to do so.
1394
if (!JSEvents.canPerformEventHandlerRequests()) {
1395
if (strategy.deferUntilInEventHandler) {
1396
JSEvents.deferCall(JSEvents_requestFullscreen, 1 /* priority over pointer lock */, [target, strategy]);
1397
return {{{ cDefs.EMSCRIPTEN_RESULT_DEFERRED }}};
1398
}
1399
return {{{ cDefs.EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED }}};
1400
}
1401
#endif
1402
1403
return JSEvents_requestFullscreen(target, strategy);
1404
},
1405
1406
emscripten_request_fullscreen__deps: ['$doRequestFullscreen'],
1407
emscripten_request_fullscreen__proxy: 'sync',
1408
emscripten_request_fullscreen: (target, deferUntilInEventHandler) => {
1409
var strategy = {
1410
// These options perform no added logic, but just bare request fullscreen.
1411
scaleMode: {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT }}},
1412
canvasResolutionScaleMode: {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE }}},
1413
filteringMode: {{{ cDefs.EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT }}},
1414
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1415
deferUntilInEventHandler,
1416
#endif
1417
canvasResizedCallbackTargetThread: {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD }}}
1418
};
1419
return doRequestFullscreen(target, strategy);
1420
},
1421
1422
emscripten_request_fullscreen_strategy__deps: ['$doRequestFullscreen'],
1423
emscripten_request_fullscreen_strategy__proxy: 'sync',
1424
emscripten_request_fullscreen_strategy: (target, deferUntilInEventHandler, fullscreenStrategy) => {
1425
var strategy = {
1426
scaleMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.scaleMode, 'i32') }}},
1427
canvasResolutionScaleMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResolutionScaleMode, 'i32') }}},
1428
filteringMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.filteringMode, 'i32') }}},
1429
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1430
deferUntilInEventHandler,
1431
#endif
1432
#if PTHREADS
1433
canvasResizedCallbackTargetThread: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResizedCallbackTargetThread, 'i32') }}},
1434
#endif
1435
canvasResizedCallback: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResizedCallback, 'i32') }}},
1436
canvasResizedCallbackUserData: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResizedCallbackUserData, 'i32') }}}
1437
};
1438
1439
return doRequestFullscreen(target, strategy);
1440
},
1441
1442
emscripten_enter_soft_fullscreen__deps: ['$JSEvents', '$hideEverythingExceptGivenElement', '$restoreOldWindowedStyle', '$restoreHiddenElements', '$currentFullscreenStrategy', '$softFullscreenResizeWebGLRenderTarget', '$JSEvents_resizeCanvasForFullscreen', '$findEventTarget'],
1443
emscripten_enter_soft_fullscreen__proxy: 'sync',
1444
emscripten_enter_soft_fullscreen: (target, fullscreenStrategy) => {
1445
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1446
target ||= '#canvas';
1447
#endif
1448
target = findEventTarget(target);
1449
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1450
1451
var strategy = {
1452
scaleMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.scaleMode, 'i32') }}},
1453
canvasResolutionScaleMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResolutionScaleMode, 'i32') }}},
1454
filteringMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.filteringMode, 'i32') }}},
1455
canvasResizedCallback: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResizedCallback, 'i32') }}},
1456
canvasResizedCallbackUserData: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResizedCallbackUserData, 'i32') }}},
1457
#if PTHREADS
1458
canvasResizedCallbackTargetThread: JSEvents.getTargetThreadForEventCallback(),
1459
#endif
1460
target,
1461
softFullscreen: true
1462
};
1463
1464
var restoreOldStyle = JSEvents_resizeCanvasForFullscreen(target, strategy);
1465
1466
document.documentElement.style.overflow = 'hidden'; // Firefox, Chrome
1467
document.body.scroll = "no"; // IE11
1468
document.body.style.margin = '0px'; // Override default document margin area on all browsers.
1469
1470
var hiddenElements = hideEverythingExceptGivenElement(target);
1471
1472
function restoreWindowedState() {
1473
restoreOldStyle();
1474
restoreHiddenElements(hiddenElements);
1475
removeEventListener('resize', softFullscreenResizeWebGLRenderTarget);
1476
if (strategy.canvasResizedCallback) {
1477
#if PTHREADS
1478
if (strategy.canvasResizedCallbackTargetThread) __emscripten_run_callback_on_thread(strategy.canvasResizedCallbackTargetThread, strategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData);
1479
else
1480
#endif
1481
{{{ makeDynCall('iipp', 'strategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData);
1482
}
1483
currentFullscreenStrategy = 0;
1484
}
1485
restoreOldWindowedStyle = restoreWindowedState;
1486
currentFullscreenStrategy = strategy;
1487
addEventListener('resize', softFullscreenResizeWebGLRenderTarget);
1488
1489
// Inform the caller that the canvas size has changed.
1490
if (strategy.canvasResizedCallback) {
1491
#if PTHREADS
1492
if (strategy.canvasResizedCallbackTargetThread) __emscripten_run_callback_on_thread(strategy.canvasResizedCallbackTargetThread, strategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData);
1493
else
1494
#endif
1495
{{{ makeDynCall('iipp', 'strategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData);
1496
}
1497
1498
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1499
},
1500
1501
emscripten_exit_soft_fullscreen__deps: ['$restoreOldWindowedStyle'],
1502
emscripten_exit_soft_fullscreen__proxy: 'sync',
1503
emscripten_exit_soft_fullscreen: () => {
1504
restoreOldWindowedStyle?.();
1505
restoreOldWindowedStyle = null;
1506
1507
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1508
},
1509
1510
emscripten_exit_fullscreen__deps: [
1511
'$JSEvents',
1512
'$specialHTMLTargets',
1513
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1514
'$JSEvents_requestFullscreen',
1515
#endif
1516
],
1517
emscripten_exit_fullscreen__proxy: 'sync',
1518
emscripten_exit_fullscreen: () => {
1519
if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1520
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1521
// Make sure no queued up calls will fire after this.
1522
JSEvents.removeDeferredCalls(JSEvents_requestFullscreen);
1523
#endif
1524
1525
var d = specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}];
1526
if (d.exitFullscreen) {
1527
d.fullscreenElement && d.exitFullscreen();
1528
#if MIN_FIREFOX_VERSION < 64 // https://caniuse.com/#feat=mdn-api_document_exitfullscreen
1529
} else if (d.mozCancelFullScreen) {
1530
d.mozFullScreenElement && d.mozCancelFullScreen();
1531
#endif
1532
#if MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED // https://caniuse.com/#feat=mdn-api_document_exitfullscreen
1533
} else if (d.webkitExitFullscreen) {
1534
d.webkitFullscreenElement && d.webkitExitFullscreen();
1535
#endif
1536
} else {
1537
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1538
}
1539
1540
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1541
},
1542
1543
$fillPointerlockChangeEventData__deps: ['$JSEvents', '$stringToUTF8'],
1544
$fillPointerlockChangeEventData: (eventStruct) => {
1545
var pointerLockElement = document.pointerLockElement;
1546
var isPointerlocked = !!pointerLockElement;
1547
#if !SAFE_HEAP
1548
// Assigning a boolean to HEAP32 with expected type coercion.
1549
/** @suppress{checkTypes} */
1550
#endif
1551
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenPointerlockChangeEvent.isActive, 'isPointerlocked', 'i8') }}};
1552
var nodeName = JSEvents.getNodeNameForTarget(pointerLockElement);
1553
var id = pointerLockElement?.id || '';
1554
stringToUTF8(nodeName, eventStruct + {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.nodeName }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}});
1555
stringToUTF8(id, eventStruct + {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.id }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}});
1556
},
1557
1558
$registerPointerlockChangeEventCallback__noleakcheck: true,
1559
$registerPointerlockChangeEventCallback__deps: ['$JSEvents', '$fillPointerlockChangeEventData', 'malloc'],
1560
$registerPointerlockChangeEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
1561
#if PTHREADS
1562
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
1563
#endif
1564
JSEvents.pointerlockChangeEvent ||= _malloc({{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.__size__ }}});
1565
1566
var pointerlockChangeEventHandlerFunc = (e = event) => {
1567
#if PTHREADS
1568
var pointerlockChangeEvent = targetThread ? _malloc({{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.__size__ }}}) : JSEvents.pointerlockChangeEvent;
1569
#else
1570
var pointerlockChangeEvent = JSEvents.pointerlockChangeEvent;
1571
#endif
1572
fillPointerlockChangeEventData(pointerlockChangeEvent);
1573
1574
#if PTHREADS
1575
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, pointerlockChangeEvent, userData);
1576
else
1577
#endif
1578
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, pointerlockChangeEvent, userData)) e.preventDefault();
1579
};
1580
1581
var eventHandler = {
1582
target,
1583
eventTypeString,
1584
callbackfunc,
1585
handlerFunc: pointerlockChangeEventHandlerFunc,
1586
useCapture
1587
};
1588
return JSEvents.registerOrRemoveHandler(eventHandler);
1589
},
1590
1591
emscripten_set_pointerlockchange_callback_on_thread__proxy: 'sync',
1592
emscripten_set_pointerlockchange_callback_on_thread__deps: ['$registerPointerlockChangeEventCallback', '$findEventTarget',
1593
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1594
'$specialHTMLTargets'
1595
#endif
1596
],
1597
emscripten_set_pointerlockchange_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) => {
1598
if (!document.body?.requestPointerLock) {
1599
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1600
}
1601
1602
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1603
target = findEventTarget(target);
1604
#else
1605
target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}]; // Pointer lock change events need to be captured from 'document' by default instead of 'window'
1606
#endif
1607
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1608
return registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKCHANGE }}}, "pointerlockchange", targetThread);
1609
},
1610
1611
$registerPointerlockErrorEventCallback__deps: ['$JSEvents'],
1612
$registerPointerlockErrorEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
1613
#if PTHREADS
1614
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
1615
#endif
1616
1617
var pointerlockErrorEventHandlerFunc = (e = event) => {
1618
#if PTHREADS
1619
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, 0, userData);
1620
else
1621
#endif
1622
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, 0, userData)) e.preventDefault();
1623
};
1624
1625
var eventHandler = {
1626
target,
1627
eventTypeString,
1628
callbackfunc,
1629
handlerFunc: pointerlockErrorEventHandlerFunc,
1630
useCapture
1631
};
1632
return JSEvents.registerOrRemoveHandler(eventHandler);
1633
},
1634
1635
emscripten_set_pointerlockerror_callback_on_thread__proxy: 'sync',
1636
emscripten_set_pointerlockerror_callback_on_thread__deps: ['$registerPointerlockErrorEventCallback', '$findEventTarget',
1637
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1638
'$specialHTMLTargets'
1639
#endif
1640
],
1641
emscripten_set_pointerlockerror_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) => {
1642
if (!document.body?.requestPointerLock) {
1643
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1644
}
1645
1646
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1647
target = findEventTarget(target);
1648
#else
1649
target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}]; // Pointer lock change events need to be captured from 'document' by default instead of 'window'
1650
#endif
1651
1652
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1653
return registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKERROR }}}, "pointerlockerror", targetThread);
1654
},
1655
1656
emscripten_get_pointerlock_status__proxy: 'sync',
1657
emscripten_get_pointerlock_status__deps: ['$fillPointerlockChangeEventData'],
1658
emscripten_get_pointerlock_status: (pointerlockStatus) => {
1659
if (pointerlockStatus) fillPointerlockChangeEventData(pointerlockStatus);
1660
if (!document.body?.requestPointerLock) {
1661
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1662
}
1663
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1664
},
1665
1666
$requestPointerLock: (target) => {
1667
if (target.requestPointerLock) {
1668
target.requestPointerLock();
1669
} else {
1670
// document.body is known to accept pointer lock, so use that to differentiate if the user passed a bad element,
1671
// or if the whole browser just doesn't support the feature.
1672
if (document.body.requestPointerLock) {
1673
return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}};
1674
}
1675
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1676
}
1677
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1678
},
1679
1680
emscripten_request_pointerlock__proxy: 'sync',
1681
emscripten_request_pointerlock__deps: ['$requestPointerLock', '$findEventTarget',
1682
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1683
'$JSEvents',
1684
#endif
1685
],
1686
emscripten_request_pointerlock: (target, deferUntilInEventHandler) => {
1687
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1688
target ||= '#canvas';
1689
#endif
1690
target = findEventTarget(target);
1691
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1692
if (!target.requestPointerLock) {
1693
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1694
}
1695
1696
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1697
// Queue this function call if we're not currently in an event handler and
1698
// the user saw it appropriate to do so.
1699
if (!JSEvents.canPerformEventHandlerRequests()) {
1700
if (deferUntilInEventHandler) {
1701
JSEvents.deferCall(requestPointerLock, 2 /* priority below fullscreen */, [target]);
1702
return {{{ cDefs.EMSCRIPTEN_RESULT_DEFERRED }}};
1703
}
1704
return {{{ cDefs.EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED }}};
1705
}
1706
#endif
1707
1708
return requestPointerLock(target);
1709
},
1710
1711
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1712
emscripten_exit_pointerlock__deps: ['$JSEvents', '$requestPointerLock'],
1713
#endif
1714
emscripten_exit_pointerlock__proxy: 'sync',
1715
emscripten_exit_pointerlock: () => {
1716
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1717
// Make sure no queued up calls will fire after this.
1718
JSEvents.removeDeferredCalls(requestPointerLock);
1719
#endif
1720
if (!document.exitPointerLock) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1721
document.exitPointerLock();
1722
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1723
},
1724
1725
emscripten_vibrate__proxy: 'sync',
1726
emscripten_vibrate: (msecs) => {
1727
if (!navigator.vibrate) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1728
navigator.vibrate(msecs);
1729
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1730
},
1731
1732
emscripten_vibrate_pattern__proxy: 'sync',
1733
emscripten_vibrate_pattern: (msecsArray, numEntries) => {
1734
if (!navigator.vibrate) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1735
1736
var vibrateList = [];
1737
for (var i = 0; i < numEntries; ++i) {
1738
var msecs = {{{ makeGetValue('msecsArray', 'i*4', 'i32') }}};
1739
vibrateList.push(msecs);
1740
}
1741
navigator.vibrate(vibrateList);
1742
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1743
},
1744
1745
$fillVisibilityChangeEventData: (eventStruct) => {
1746
var visibilityStates = [ "hidden", "visible", "prerender", "unloaded" ];
1747
var visibilityState = visibilityStates.indexOf(document.visibilityState);
1748
1749
#if !SAFE_HEAP
1750
// Assigning a boolean to HEAP32 with expected type coercion.
1751
/** @suppress{checkTypes} */
1752
#endif
1753
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenVisibilityChangeEvent.hidden, 'document.hidden', 'i8') }}};
1754
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenVisibilityChangeEvent.visibilityState, 'visibilityState', 'i32') }}};
1755
},
1756
1757
$registerVisibilityChangeEventCallback__noleakcheck: true,
1758
$registerVisibilityChangeEventCallback__deps: ['$JSEvents', '$fillVisibilityChangeEventData', 'malloc'],
1759
$registerVisibilityChangeEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
1760
#if PTHREADS
1761
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
1762
#endif
1763
JSEvents.visibilityChangeEvent ||= _malloc({{{ C_STRUCTS.EmscriptenVisibilityChangeEvent.__size__ }}});
1764
1765
var visibilityChangeEventHandlerFunc = (e = event) => {
1766
#if PTHREADS
1767
var visibilityChangeEvent = targetThread ? _malloc({{{ C_STRUCTS.EmscriptenVisibilityChangeEvent.__size__ }}}) : JSEvents.visibilityChangeEvent;
1768
#else
1769
var visibilityChangeEvent = JSEvents.visibilityChangeEvent;
1770
#endif
1771
1772
fillVisibilityChangeEventData(visibilityChangeEvent);
1773
1774
#if PTHREADS
1775
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, visibilityChangeEvent, userData);
1776
else
1777
#endif
1778
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, visibilityChangeEvent, userData)) e.preventDefault();
1779
};
1780
1781
var eventHandler = {
1782
target,
1783
eventTypeString,
1784
callbackfunc,
1785
handlerFunc: visibilityChangeEventHandlerFunc,
1786
useCapture
1787
};
1788
return JSEvents.registerOrRemoveHandler(eventHandler);
1789
},
1790
1791
emscripten_set_visibilitychange_callback_on_thread__proxy: 'sync',
1792
emscripten_set_visibilitychange_callback_on_thread__deps: ['$registerVisibilityChangeEventCallback', '$specialHTMLTargets'],
1793
emscripten_set_visibilitychange_callback_on_thread: (userData, useCapture, callbackfunc, targetThread) => {
1794
#if ENVIRONMENT_MAY_BE_WORKER || ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
1795
if (!specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}]) {
1796
return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
1797
}
1798
#endif
1799
return registerVisibilityChangeEventCallback(specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}], userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_VISIBILITYCHANGE }}}, "visibilitychange", targetThread);
1800
},
1801
1802
emscripten_get_visibility_status__proxy: 'sync',
1803
emscripten_get_visibility_status__deps: ['$fillVisibilityChangeEventData'],
1804
emscripten_get_visibility_status: (visibilityStatus) => {
1805
if (typeof document.visibilityState == 'undefined' && typeof document.hidden == 'undefined') {
1806
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
1807
}
1808
fillVisibilityChangeEventData(visibilityStatus);
1809
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
1810
},
1811
1812
$registerTouchEventCallback__noleakcheck: true,
1813
$registerTouchEventCallback__deps: ['$JSEvents', '$findEventTarget', '$getBoundingClientRect', 'malloc'],
1814
$registerTouchEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
1815
#if PTHREADS
1816
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
1817
#endif
1818
JSEvents.touchEvent ||= _malloc({{{ C_STRUCTS.EmscriptenTouchEvent.__size__ }}});
1819
1820
target = findEventTarget(target);
1821
1822
var touchEventHandlerFunc = (e) => {
1823
#if ASSERTIONS
1824
assert(e);
1825
#endif
1826
var t, touches = {}, et = e.touches;
1827
// To ease marshalling different kinds of touches that browser reports (all touches are listed in e.touches,
1828
// only changed touches in e.changedTouches, and touches on target at a.targetTouches), mark a boolean in
1829
// each Touch object so that we can later loop only once over all touches we see to marshall over to Wasm.
1830
1831
for (let t of et) {
1832
// Browser might recycle the generated Touch objects between each frame (Firefox on Android), so reset any
1833
// changed/target states we may have set from previous frame.
1834
t.isChanged = t.onTarget = 0;
1835
touches[t.identifier] = t;
1836
}
1837
// Mark which touches are part of the changedTouches list.
1838
for (let t of e.changedTouches) {
1839
t.isChanged = 1;
1840
touches[t.identifier] = t;
1841
}
1842
// Mark which touches are part of the targetTouches list.
1843
for (let t of e.targetTouches) {
1844
touches[t.identifier].onTarget = 1;
1845
}
1846
1847
#if PTHREADS
1848
var touchEvent = targetThread ? _malloc({{{ C_STRUCTS.EmscriptenTouchEvent.__size__ }}}) : JSEvents.touchEvent;
1849
#else
1850
var touchEvent = JSEvents.touchEvent;
1851
#endif
1852
{{{ makeSetValue('touchEvent', C_STRUCTS.EmscriptenTouchEvent.timestamp, 'e.timeStamp', 'double') }}};
1853
HEAP8[touchEvent + {{{ C_STRUCTS.EmscriptenTouchEvent.ctrlKey }}}] = e.ctrlKey;
1854
HEAP8[touchEvent + {{{ C_STRUCTS.EmscriptenTouchEvent.shiftKey }}}] = e.shiftKey;
1855
HEAP8[touchEvent + {{{ C_STRUCTS.EmscriptenTouchEvent.altKey }}}] = e.altKey;
1856
HEAP8[touchEvent + {{{ C_STRUCTS.EmscriptenTouchEvent.metaKey }}}] = e.metaKey;
1857
var idx = touchEvent + {{{ C_STRUCTS.EmscriptenTouchEvent.touches }}};
1858
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1859
var canvasRect = Module['canvas'] ? getBoundingClientRect(Module['canvas']) : undefined;
1860
#endif
1861
var targetRect = getBoundingClientRect(target);
1862
var numTouches = 0;
1863
for (let t of Object.values(touches)) {
1864
var idx32 = {{{ getHeapOffset('idx', 'i32') }}}; // Pre-shift the ptr to index to HEAP32 to save code size
1865
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.identifier / 4 }}}] = t.identifier;
1866
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.screenX / 4 }}}] = t.screenX;
1867
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.screenY / 4 }}}] = t.screenY;
1868
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.clientX / 4 }}}] = t.clientX;
1869
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.clientY / 4 }}}] = t.clientY;
1870
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.pageX / 4 }}}] = t.pageX;
1871
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.pageY / 4 }}}] = t.pageY;
1872
HEAP8[idx + {{{ C_STRUCTS.EmscriptenTouchPoint.isChanged }}}] = t.isChanged;
1873
HEAP8[idx + {{{ C_STRUCTS.EmscriptenTouchPoint.onTarget }}}] = t.onTarget;
1874
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.targetX / 4 }}}] = t.clientX - (targetRect.left | 0);
1875
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.targetY / 4 }}}] = t.clientY - (targetRect.top | 0);
1876
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
1877
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.canvasX / 4 }}}] = canvasRect ? t.clientX - (canvasRect.left | 0) : 0;
1878
HEAP32[idx32 + {{{ C_STRUCTS.EmscriptenTouchPoint.canvasY / 4 }}}] = canvasRect ? t.clientY - (canvasRect.top | 0) : 0;
1879
#endif
1880
1881
idx += {{{ C_STRUCTS.EmscriptenTouchPoint.__size__ }}};
1882
1883
if (++numTouches > 31) {
1884
break;
1885
}
1886
}
1887
{{{ makeSetValue('touchEvent', C_STRUCTS.EmscriptenTouchEvent.numTouches, 'numTouches', 'i32') }}};
1888
1889
#if PTHREADS
1890
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, touchEvent, userData);
1891
else
1892
#endif
1893
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, touchEvent, userData)) e.preventDefault();
1894
};
1895
1896
var eventHandler = {
1897
target,
1898
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1899
allowsDeferredCalls: eventTypeString == 'touchstart' || eventTypeString == 'touchend',
1900
#endif
1901
eventTypeString,
1902
callbackfunc,
1903
handlerFunc: touchEventHandlerFunc,
1904
useCapture
1905
};
1906
return JSEvents.registerOrRemoveHandler(eventHandler);
1907
},
1908
1909
emscripten_set_touchstart_callback_on_thread__proxy: 'sync',
1910
emscripten_set_touchstart_callback_on_thread__deps: ['$registerTouchEventCallback'],
1911
emscripten_set_touchstart_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
1912
registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHSTART }}}, "touchstart", targetThread),
1913
1914
emscripten_set_touchend_callback_on_thread__proxy: 'sync',
1915
emscripten_set_touchend_callback_on_thread__deps: ['$registerTouchEventCallback'],
1916
emscripten_set_touchend_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
1917
registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHEND }}}, "touchend", targetThread),
1918
1919
emscripten_set_touchmove_callback_on_thread__proxy: 'sync',
1920
emscripten_set_touchmove_callback_on_thread__deps: ['$registerTouchEventCallback'],
1921
emscripten_set_touchmove_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
1922
registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHMOVE }}}, "touchmove", targetThread),
1923
1924
emscripten_set_touchcancel_callback_on_thread__proxy: 'sync',
1925
emscripten_set_touchcancel_callback_on_thread__deps: ['$registerTouchEventCallback'],
1926
emscripten_set_touchcancel_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) =>
1927
registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHCANCEL }}}, "touchcancel", targetThread),
1928
1929
$fillGamepadEventData__deps: ['$stringToUTF8'],
1930
$fillGamepadEventData: (eventStruct, e) => {
1931
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.timestamp, 'e.timestamp', 'double') }}};
1932
for (var i = 0; i < e.axes.length; ++i) {
1933
{{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.axis, 'e.axes[i]', 'double') }}};
1934
}
1935
for (var i = 0; i < e.buttons.length; ++i) {
1936
if (typeof e.buttons[i] == 'object') {
1937
{{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.analogButton, 'e.buttons[i].value', 'double') }}};
1938
} else {
1939
{{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.analogButton, 'e.buttons[i]', 'double') }}};
1940
}
1941
}
1942
for (var i = 0; i < e.buttons.length; ++i) {
1943
if (typeof e.buttons[i] == 'object') {
1944
{{{ makeSetValue('eventStruct+i', C_STRUCTS.EmscriptenGamepadEvent.digitalButton, 'e.buttons[i].pressed', 'i8') }}};
1945
} else {
1946
#if !SAFE_HEAP
1947
// Assigning a boolean to HEAP32, that's ok, but Closure would like to warn about it:
1948
/** @suppress {checkTypes} */
1949
#endif
1950
{{{ makeSetValue('eventStruct+i', C_STRUCTS.EmscriptenGamepadEvent.digitalButton, 'e.buttons[i] == 1', 'i8') }}};
1951
}
1952
}
1953
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.connected, 'e.connected', 'i8') }}};
1954
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.index, 'e.index', 'i32') }}};
1955
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.numAxes, 'e.axes.length', 'i32') }}};
1956
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.numButtons, 'e.buttons.length', 'i32') }}};
1957
stringToUTF8(e.id, eventStruct + {{{ C_STRUCTS.EmscriptenGamepadEvent.id }}}, {{{ cDefs.EM_HTML5_MEDIUM_STRING_LEN_BYTES }}});
1958
stringToUTF8(e.mapping, eventStruct + {{{ C_STRUCTS.EmscriptenGamepadEvent.mapping }}}, {{{ cDefs.EM_HTML5_MEDIUM_STRING_LEN_BYTES }}});
1959
},
1960
1961
$registerGamepadEventCallback__noleakcheck: true,
1962
$registerGamepadEventCallback__deps: ['$JSEvents', '$fillGamepadEventData', '$findEventTarget', 'malloc'],
1963
$registerGamepadEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
1964
#if PTHREADS
1965
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
1966
#endif
1967
JSEvents.gamepadEvent ||= _malloc({{{ C_STRUCTS.EmscriptenGamepadEvent.__size__ }}});
1968
1969
var gamepadEventHandlerFunc = (e = event) => {
1970
#if PTHREADS
1971
var gamepadEvent = targetThread ? _malloc({{{ C_STRUCTS.EmscriptenGamepadEvent.__size__ }}}) : JSEvents.gamepadEvent;
1972
#else
1973
var gamepadEvent = JSEvents.gamepadEvent;
1974
#endif
1975
fillGamepadEventData(gamepadEvent, e["gamepad"]);
1976
1977
#if PTHREADS
1978
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, gamepadEvent, userData);
1979
else
1980
#endif
1981
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, gamepadEvent, userData)) e.preventDefault();
1982
};
1983
1984
var eventHandler = {
1985
target: findEventTarget(target),
1986
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
1987
allowsDeferredCalls: true,
1988
#endif
1989
eventTypeString,
1990
callbackfunc,
1991
handlerFunc: gamepadEventHandlerFunc,
1992
useCapture
1993
};
1994
return JSEvents.registerOrRemoveHandler(eventHandler);
1995
},
1996
1997
emscripten_set_gamepadconnected_callback_on_thread__proxy: 'sync',
1998
emscripten_set_gamepadconnected_callback_on_thread__deps: ['$registerGamepadEventCallback', 'emscripten_sample_gamepad_data'],
1999
emscripten_set_gamepadconnected_callback_on_thread: (userData, useCapture, callbackfunc, targetThread) => {
2000
if (_emscripten_sample_gamepad_data()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
2001
return registerGamepadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_GAMEPADCONNECTED }}}, "gamepadconnected", targetThread);
2002
},
2003
2004
emscripten_set_gamepaddisconnected_callback_on_thread__proxy: 'sync',
2005
emscripten_set_gamepaddisconnected_callback_on_thread__deps: ['$registerGamepadEventCallback', 'emscripten_sample_gamepad_data'],
2006
emscripten_set_gamepaddisconnected_callback_on_thread: (userData, useCapture, callbackfunc, targetThread) => {
2007
if (_emscripten_sample_gamepad_data()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
2008
return registerGamepadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED }}}, "gamepaddisconnected", targetThread);
2009
},
2010
2011
emscripten_sample_gamepad_data__docs: '/** @suppress {checkTypes} */', // We assign null to navigator.getGamepads, which Closure would like to complain about.
2012
emscripten_sample_gamepad_data__proxy: 'sync',
2013
emscripten_sample_gamepad_data__deps: ['$JSEvents'],
2014
emscripten_sample_gamepad_data: () => {
2015
try {
2016
if (navigator.getGamepads) return (JSEvents.lastGamepadState = navigator.getGamepads())
2017
? {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}} : {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
2018
} catch(e) {
2019
#if ASSERTIONS
2020
err(`navigator.getGamepads() exists, but failed to execute with exception ${e}. Disabling Gamepad access.`);
2021
#endif
2022
navigator.getGamepads = null; // Disable getGamepads() so that it won't be attempted to be used again.
2023
}
2024
return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
2025
},
2026
2027
emscripten_get_num_gamepads__proxy: 'sync',
2028
emscripten_get_num_gamepads__deps: ['$JSEvents'],
2029
emscripten_get_num_gamepads: () => {
2030
#if ASSERTIONS
2031
if (!JSEvents.lastGamepadState) throw 'emscripten_get_num_gamepads() can only be called after having first called emscripten_sample_gamepad_data() and that function has returned EMSCRIPTEN_RESULT_SUCCESS!';
2032
#endif
2033
// N.B. Do not call emscripten_get_num_gamepads() unless having first called emscripten_sample_gamepad_data(), and that has returned EMSCRIPTEN_RESULT_SUCCESS.
2034
// Otherwise the following line will throw an exception.
2035
return JSEvents.lastGamepadState.length;
2036
},
2037
2038
emscripten_get_gamepad_status__proxy: 'sync',
2039
emscripten_get_gamepad_status__deps: ['$JSEvents', '$fillGamepadEventData'],
2040
emscripten_get_gamepad_status: (index, gamepadState) => {
2041
#if ASSERTIONS
2042
if (!JSEvents.lastGamepadState) throw 'emscripten_get_gamepad_status() can only be called after having first called emscripten_sample_gamepad_data() and that function has returned EMSCRIPTEN_RESULT_SUCCESS!';
2043
#endif
2044
// INVALID_PARAM is returned on a Gamepad index that never was there.
2045
if (index < 0 || index >= JSEvents.lastGamepadState.length) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}};
2046
2047
// NO_DATA is returned on a Gamepad index that was removed.
2048
// For previously disconnected gamepads there should be an empty slot (null/undefined/false) at the index.
2049
// This is because gamepads must keep their original position in the array.
2050
// For example, removing the first of two gamepads produces [null/undefined/false, gamepad].
2051
if (!JSEvents.lastGamepadState[index]) return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}};
2052
2053
fillGamepadEventData(gamepadState, JSEvents.lastGamepadState[index]);
2054
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2055
},
2056
2057
$registerBeforeUnloadEventCallback__deps: ['$JSEvents', '$findEventTarget'],
2058
$registerBeforeUnloadEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) => {
2059
var beforeUnloadEventHandlerFunc = (e = event) => {
2060
// Note: This is always called on the main browser thread, since it needs synchronously return a value!
2061
var confirmationMessage = {{{ makeDynCall('pipp', 'callbackfunc') }}}(eventTypeId, 0, userData);
2062
2063
if (confirmationMessage) {
2064
confirmationMessage = UTF8ToString(confirmationMessage);
2065
}
2066
if (confirmationMessage) {
2067
e.preventDefault();
2068
e.returnValue = confirmationMessage;
2069
return confirmationMessage;
2070
}
2071
};
2072
2073
var eventHandler = {
2074
target: findEventTarget(target),
2075
eventTypeString,
2076
callbackfunc,
2077
handlerFunc: beforeUnloadEventHandlerFunc,
2078
useCapture
2079
};
2080
return JSEvents.registerOrRemoveHandler(eventHandler);
2081
},
2082
2083
emscripten_set_beforeunload_callback_on_thread__proxy: 'sync',
2084
emscripten_set_beforeunload_callback_on_thread__deps: ['$registerBeforeUnloadEventCallback'],
2085
emscripten_set_beforeunload_callback_on_thread: (userData, callbackfunc, targetThread) => {
2086
if (typeof onbeforeunload == 'undefined') return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
2087
// beforeunload callback can only be registered on the main browser thread, because the page will go away immediately after returning from the handler,
2088
// and there is no time to start proxying it anywhere.
2089
if (targetThread !== {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD }}}) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}};
2090
return registerBeforeUnloadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BEFOREUNLOAD }}}, "beforeunload");
2091
},
2092
2093
$fillBatteryEventData: (eventStruct, battery) => {
2094
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.chargingTime, 'battery.chargingTime', 'double') }}};
2095
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.dischargingTime, 'battery.dischargingTime', 'double') }}};
2096
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.level, 'battery.level', 'double') }}};
2097
{{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.charging, 'battery.charging', 'i8') }}};
2098
},
2099
2100
$hasBatteryAPI: () => typeof navigator != 'undefined' && navigator.getBattery,
2101
$hasBatteryAPI__internal: true,
2102
2103
$registerBatteryEventCallback__noleakcheck: true,
2104
$registerBatteryEventCallback__deps: ['$JSEvents', '$fillBatteryEventData', 'malloc'],
2105
$registerBatteryEventCallback: (battery, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
2106
#if PTHREADS
2107
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
2108
#endif
2109
JSEvents.batteryEvent ||= _malloc({{{ C_STRUCTS.EmscriptenBatteryEvent.__size__ }}});
2110
2111
var batteryEventHandlerFunc = (e = event) => {
2112
#if PTHREADS
2113
var batteryEvent = targetThread ? _malloc({{{ C_STRUCTS.EmscriptenBatteryEvent.__size__ }}}) : JSEvents.batteryEvent;
2114
#else
2115
var batteryEvent = JSEvents.batteryEvent;
2116
#endif
2117
fillBatteryEventData(batteryEvent, battery);
2118
2119
#if PTHREADS
2120
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, batteryEvent, userData);
2121
else
2122
#endif
2123
if ({{{ makeDynCall('iipp', 'callbackfunc') }}}(eventTypeId, batteryEvent, userData)) e.preventDefault();
2124
};
2125
2126
var eventHandler = {
2127
target: battery,
2128
eventTypeString,
2129
callbackfunc,
2130
handlerFunc: batteryEventHandlerFunc,
2131
useCapture
2132
};
2133
return JSEvents.registerOrRemoveHandler(eventHandler);
2134
},
2135
2136
emscripten_set_batterychargingchange_callback_on_thread__proxy: 'sync',
2137
emscripten_set_batterychargingchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$hasBatteryAPI'],
2138
emscripten_set_batterychargingchange_callback_on_thread: (userData, callbackfunc, targetThread) => {
2139
if (!hasBatteryAPI()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
2140
navigator.getBattery().then((b) => {
2141
registerBatteryEventCallback(b, userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE }}}, "chargingchange", targetThread);
2142
});
2143
},
2144
2145
emscripten_set_batterylevelchange_callback_on_thread__proxy: 'sync',
2146
emscripten_set_batterylevelchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$hasBatteryAPI'],
2147
emscripten_set_batterylevelchange_callback_on_thread: (userData, callbackfunc, targetThread) => {
2148
if (!hasBatteryAPI()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
2149
navigator.getBattery().then((b) => {
2150
registerBatteryEventCallback(b, userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE }}}, "levelchange", targetThread);
2151
});
2152
},
2153
2154
$batteryManager: undefined,
2155
$batteryManager__internal: true,
2156
2157
emscripten_get_battery_status__proxy: 'sync',
2158
emscripten_get_battery_status__deps: ['$fillBatteryEventData', '$hasBatteryAPI', '$batteryManager'],
2159
emscripten_get_battery_status: (batteryState) => {
2160
if (!hasBatteryAPI()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}};
2161
if (!batteryManager) {
2162
navigator.getBattery().then((b) => {
2163
batteryManager = b;
2164
});
2165
return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}};
2166
}
2167
fillBatteryEventData(batteryState, batteryManager);
2168
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2169
},
2170
2171
#if PTHREADS
2172
$setCanvasElementSizeCallingThread__deps: [
2173
#if OFFSCREENCANVAS_SUPPORT
2174
'$setOffscreenCanvasSizeOnTargetThread',
2175
#endif
2176
'$findCanvasEventTarget'],
2177
$setCanvasElementSizeCallingThread: (target, width, height) => {
2178
var canvas = findCanvasEventTarget(target);
2179
if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2180
2181
#if OFFSCREENCANVAS_SUPPORT
2182
if (canvas.canvasSharedPtr) {
2183
// N.B. We hold the canvasSharedPtr info structure as the authoritative source for specifying the size of a canvas
2184
// since the actual canvas size changes are asynchronous if the canvas is owned by an OffscreenCanvas on another thread.
2185
// Therefore when setting the size, eagerly set the size of the canvas on the calling thread here, though this thread
2186
// might not be the one that actually ends up specifying the size, but the actual size change may be dispatched
2187
// as an asynchronous event below.
2188
{{{ makeSetValue('canvas.canvasSharedPtr', 0, 'width', 'i32') }}};
2189
{{{ makeSetValue('canvas.canvasSharedPtr', 4, 'height', 'i32') }}};
2190
}
2191
2192
if (canvas.offscreenCanvas || !canvas.controlTransferredOffscreen) {
2193
if (canvas.offscreenCanvas) canvas = canvas.offscreenCanvas;
2194
#else
2195
if (!canvas.controlTransferredOffscreen) {
2196
#endif
2197
var autoResizeViewport = false;
2198
if (canvas.GLctxObject?.GLctx) {
2199
var prevViewport = canvas.GLctxObject.GLctx.getParameter(0xBA2 /* GL_VIEWPORT */);
2200
// TODO: Perhaps autoResizeViewport should only be true if FBO 0 is currently active?
2201
autoResizeViewport = (prevViewport[0] === 0 && prevViewport[1] === 0 && prevViewport[2] === canvas.width && prevViewport[3] === canvas.height);
2202
#if GL_DEBUG
2203
dbg(`Resizing canvas from ${canvas.width}x${canvas.height} to ${width}x${height}. Previous GL viewport size was ${prevViewport}, so autoResizeViewport=${autoResizeViewport}`);
2204
#endif
2205
}
2206
canvas.width = width;
2207
canvas.height = height;
2208
if (autoResizeViewport) {
2209
#if GL_DEBUG
2210
dbg(`Automatically resizing GL viewport to cover whole render target ${width}x${height}`);
2211
#endif
2212
// TODO: Add -sCANVAS_RESIZE_SETS_GL_VIEWPORT=0/1 option (default=1). This is commonly done and several graphics engines depend on this,
2213
// but this can be quite disruptive.
2214
canvas.GLctxObject.GLctx.viewport(0, 0, width, height);
2215
}
2216
#if OFFSCREENCANVAS_SUPPORT
2217
} else if (canvas.canvasSharedPtr) {
2218
var targetThread = {{{ makeGetValue('canvas.canvasSharedPtr', 8, '*') }}};
2219
setOffscreenCanvasSizeOnTargetThread(targetThread, target, width, height);
2220
return {{{ cDefs.EMSCRIPTEN_RESULT_DEFERRED }}}; // This will have to be done asynchronously
2221
#endif
2222
} else {
2223
#if GL_DEBUG
2224
dbg('canvas.controlTransferredOffscreen but we do not own the canvas, and do not know who has (no canvas.canvasSharedPtr present, an internal bug?)!\n');
2225
#endif
2226
return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2227
}
2228
#if OFFSCREEN_FRAMEBUFFER
2229
if (canvas.GLctxObject) GL.resizeOffscreenFramebuffer(canvas.GLctxObject);
2230
#endif
2231
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2232
},
2233
2234
#if OFFSCREENCANVAS_SUPPORT
2235
$setOffscreenCanvasSizeOnTargetThread__deps: ['$stringToNewUTF8', '_emscripten_set_offscreencanvas_size_on_thread'],
2236
$setOffscreenCanvasSizeOnTargetThread: (targetThread, targetCanvas, width, height) => {
2237
targetCanvas = targetCanvas ? UTF8ToString(targetCanvas) : '';
2238
var targetCanvasPtr = 0;
2239
if (targetCanvas) {
2240
targetCanvasPtr = stringToNewUTF8(targetCanvas);
2241
}
2242
__emscripten_set_offscreencanvas_size_on_thread(targetThread, targetCanvasPtr, width, height);
2243
},
2244
#endif
2245
2246
$setCanvasElementSizeMainThread__proxy: 'sync',
2247
$setCanvasElementSizeMainThread__deps: ['$setCanvasElementSizeCallingThread'],
2248
$setCanvasElementSizeMainThread: (target, width, height) => setCanvasElementSizeCallingThread(target, width, height),
2249
2250
emscripten_set_canvas_element_size__deps: ['$setCanvasElementSizeCallingThread', '$setCanvasElementSizeMainThread', '$findCanvasEventTarget'],
2251
emscripten_set_canvas_element_size: (target, width, height) => {
2252
#if GL_DEBUG
2253
dbg(`emscripten_set_canvas_element_size(target=${target},width=${width},height=${height}`);
2254
#endif
2255
var canvas = findCanvasEventTarget(target);
2256
if (canvas) {
2257
return setCanvasElementSizeCallingThread(target, width, height);
2258
}
2259
return setCanvasElementSizeMainThread(target, width, height);
2260
},
2261
#else
2262
emscripten_set_canvas_element_size__deps: ['$findCanvasEventTarget'],
2263
emscripten_set_canvas_element_size: (target, width, height) => {
2264
#if GL_DEBUG
2265
dbg(`emscripten_set_canvas_element_size(target=${target},width=${width},height=${height}`);
2266
#endif
2267
var canvas = findCanvasEventTarget(target);
2268
if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2269
canvas.width = width;
2270
canvas.height = height;
2271
#if OFFSCREEN_FRAMEBUFFER
2272
if (canvas.GLctxObject) GL.resizeOffscreenFramebuffer(canvas.GLctxObject);
2273
#endif
2274
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2275
},
2276
#endif
2277
2278
$setCanvasElementSize__deps: ['emscripten_set_canvas_element_size', '$stackSave', '$stackRestore', '$stringToUTF8OnStack'],
2279
$setCanvasElementSize: (target, width, height) => {
2280
#if GL_DEBUG
2281
dbg(`setCanvasElementSize(target=${target},width=${width},height=${height}`);
2282
#endif
2283
if (!target.controlTransferredOffscreen) {
2284
target.width = width;
2285
target.height = height;
2286
} else {
2287
// This function is being called from high-level JavaScript code instead of asm.js/Wasm,
2288
// and it needs to synchronously proxy over to another thread, so marshal the string onto the heap to do the call.
2289
var sp = stackSave();
2290
var targetInt = stringToUTF8OnStack(target.id);
2291
_emscripten_set_canvas_element_size(targetInt, width, height);
2292
stackRestore(sp);
2293
}
2294
},
2295
2296
#if PTHREADS
2297
$getCanvasSizeCallingThread__deps: ['$findCanvasEventTarget'],
2298
$getCanvasSizeCallingThread: (target, width, height) => {
2299
var canvas = findCanvasEventTarget(target);
2300
if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2301
2302
#if OFFSCREENCANVAS_SUPPORT
2303
if (canvas.canvasSharedPtr) {
2304
// N.B. Reading the size of the Canvas takes priority from our shared state structure, which is not the actual size.
2305
// However if is possible that there is a canvas size set event pending on an OffscreenCanvas owned by another thread,
2306
// so that the real sizes of the canvas have not updated yet. Therefore reading the real values would be racy.
2307
var w = {{{ makeGetValue('canvas.canvasSharedPtr', 0, 'i32') }}};
2308
var h = {{{ makeGetValue('canvas.canvasSharedPtr', 4, 'i32') }}};
2309
{{{ makeSetValue('width', 0, 'w', 'i32') }}};
2310
{{{ makeSetValue('height', 0, 'h', 'i32') }}};
2311
} else if (canvas.offscreenCanvas) {
2312
{{{ makeSetValue('width', 0, 'canvas.offscreenCanvas.width', 'i32') }}};
2313
{{{ makeSetValue('height', 0, 'canvas.offscreenCanvas.height', 'i32') }}};
2314
} else
2315
#endif
2316
if (!canvas.controlTransferredOffscreen) {
2317
{{{ makeSetValue('width', 0, 'canvas.width', 'i32') }}};
2318
{{{ makeSetValue('height', 0, 'canvas.height', 'i32') }}};
2319
} else {
2320
#if GL_DEBUG
2321
dbg('canvas.controlTransferredOffscreen but we do not own the canvas, and do not know who has (no canvas.canvasSharedPtr present, an internal bug?)!\n');
2322
#endif
2323
return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2324
}
2325
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2326
},
2327
2328
$getCanvasSizeMainThread__proxy: 'sync',
2329
$getCanvasSizeMainThread__deps: ['$getCanvasSizeCallingThread'],
2330
$getCanvasSizeMainThread: (target, width, height) => getCanvasSizeCallingThread(target, width, height),
2331
2332
emscripten_get_canvas_element_size__deps: ['$getCanvasSizeCallingThread', '$getCanvasSizeMainThread', '$findCanvasEventTarget'],
2333
emscripten_get_canvas_element_size: (target, width, height) => {
2334
var canvas = findCanvasEventTarget(target);
2335
if (canvas) {
2336
return getCanvasSizeCallingThread(target, width, height);
2337
}
2338
return getCanvasSizeMainThread(target, width, height);
2339
},
2340
#else
2341
emscripten_get_canvas_element_size__deps: ['$findCanvasEventTarget'],
2342
emscripten_get_canvas_element_size: (target, width, height) => {
2343
var canvas = findCanvasEventTarget(target);
2344
if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2345
{{{ makeSetValue('width', '0', 'canvas.width', 'i32') }}};
2346
{{{ makeSetValue('height', '0', 'canvas.height', 'i32') }}};
2347
},
2348
#endif
2349
2350
// JavaScript-friendly API, returns pair [width, height]
2351
$getCanvasElementSize__deps: ['emscripten_get_canvas_element_size', '$stackSave', '$stackRestore', '$stringToUTF8OnStack'],
2352
$getCanvasElementSize: (target) => {
2353
var sp = stackSave();
2354
var w = stackAlloc(8);
2355
var h = w + 4;
2356
2357
var targetInt = stringToUTF8OnStack(target.id);
2358
var ret = _emscripten_get_canvas_element_size(targetInt, w, h);
2359
var size = [{{{ makeGetValue('w', 0, 'i32')}}}, {{{ makeGetValue('h', 0, 'i32')}}}];
2360
stackRestore(sp);
2361
return size;
2362
},
2363
2364
emscripten_set_element_css_size__proxy: 'sync',
2365
emscripten_set_element_css_size__deps: ['$findEventTarget'],
2366
emscripten_set_element_css_size: (target, width, height) => {
2367
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
2368
target = findEventTarget(target);
2369
#else
2370
target = target ? findEventTarget(target) : Module['canvas'];
2371
#endif
2372
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2373
2374
target.style.width = width + "px";
2375
target.style.height = height + "px";
2376
2377
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2378
},
2379
2380
emscripten_get_element_css_size__proxy: 'sync',
2381
emscripten_get_element_css_size__deps: ['$findEventTarget', '$getBoundingClientRect'],
2382
emscripten_get_element_css_size: (target, width, height) => {
2383
#if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
2384
target = findEventTarget(target);
2385
#else
2386
target = target ? findEventTarget(target) : Module['canvas'];
2387
#endif
2388
if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}};
2389
2390
var rect = getBoundingClientRect(target);
2391
{{{ makeSetValue('width', '0', 'rect.width', 'double') }}};
2392
{{{ makeSetValue('height', '0', 'rect.height', 'double') }}};
2393
2394
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
2395
},
2396
2397
emscripten_html5_remove_all_event_listeners__deps: ['$JSEvents'],
2398
emscripten_html5_remove_all_event_listeners: () => JSEvents.removeAllEventListeners(),
2399
2400
emscripten_request_animation_frame: (cb, userData) =>
2401
requestAnimationFrame((timeStamp) => {{{ makeDynCall('idp', 'cb') }}}(timeStamp, userData)),
2402
2403
emscripten_cancel_animation_frame: (id) => cancelAnimationFrame(id),
2404
2405
emscripten_request_animation_frame_loop: (cb, userData) => {
2406
function tick(timeStamp) {
2407
if ({{{ makeDynCall('idp', 'cb') }}}(timeStamp, userData)) {
2408
requestAnimationFrame(tick);
2409
}
2410
}
2411
return requestAnimationFrame(tick);
2412
},
2413
2414
emscripten_get_device_pixel_ratio__proxy: 'sync',
2415
emscripten_get_device_pixel_ratio: () => {
2416
#if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
2417
return (typeof devicePixelRatio == 'number' && devicePixelRatio) || 1.0;
2418
#else // otherwise, on the web and in workers, things are simpler
2419
return devicePixelRatio;
2420
#endif
2421
}
2422
};
2423
2424
addToLibrary(LibraryHTML5);
2425
2426