Buckets:
| /** | |
| * @license | |
| * Copyright 2010 The Emscripten Authors | |
| * SPDX-License-Identifier: MIT | |
| */ | |
| // Implementation of functions from emscripten/eventloop.h. | |
| LibraryJSEventLoop = { | |
| emscripten_unwind_to_js_event_loop: () => { | |
| throw 'unwind'; | |
| }, | |
| $safeSetTimeout__deps: ['$callUserCallback'], | |
| $safeSetTimeout__docs: '/** @param {number=} timeout */', | |
| $safeSetTimeout: (func, timeout) => { | |
| {{{ runtimeKeepalivePush() }}} | |
| return setTimeout(() => { | |
| {{{ runtimeKeepalivePop() }}} | |
| callUserCallback(func); | |
| }, timeout); | |
| }, | |
| // Just like setImmediate but returns an i32 that can be passed back | |
| // to wasm rather than a JS object. | |
| $setImmediateWrapped: (func) => { | |
| setImmediateWrapped.mapping ||= []; | |
| var id = setImmediateWrapped.mapping.length; | |
| setImmediateWrapped.mapping[id] = setImmediate(() => { | |
| setImmediateWrapped.mapping[id] = undefined; | |
| func(); | |
| }); | |
| return id; | |
| }, | |
| $safeRequestAnimationFrame__deps: ['$MainLoop'], | |
| $safeRequestAnimationFrame: (func) => { | |
| {{{ runtimeKeepalivePush() }}} | |
| return MainLoop.requestAnimationFrame(() => { | |
| {{{ runtimeKeepalivePop() }}} | |
| callUserCallback(func); | |
| }); | |
| }, | |
| // Just like clearImmediate but takes an i32 rather than an object. | |
| $clearImmediateWrapped: (id) => { | |
| #if ASSERTIONS | |
| assert(id); | |
| assert(setImmediateWrapped.mapping[id]); | |
| #endif | |
| clearImmediate(setImmediateWrapped.mapping[id]); | |
| setImmediateWrapped.mapping[id] = undefined; | |
| }, | |
| $emSetImmediate__deps: ['$setImmediateWrapped', '$clearImmediateWrapped', '$emClearImmediate'], | |
| $emSetImmediate__postset: ` | |
| if (globalThis.setImmediate) { | |
| emSetImmediate = setImmediateWrapped; | |
| emClearImmediate = clearImmediateWrapped; | |
| } else if (globalThis.addEventListener) { | |
| var __setImmediate_id_counter = 0; | |
| var __setImmediate_queue = []; | |
| var __setImmediate_message_id = "_si"; | |
| /** @param {Event} e */ | |
| var __setImmediate_cb = (e) => { | |
| if (e.data === __setImmediate_message_id) { | |
| e.stopPropagation(); | |
| __setImmediate_queue.shift()(); | |
| ++__setImmediate_id_counter; | |
| } | |
| } | |
| addEventListener("message", __setImmediate_cb, true); | |
| emSetImmediate = (func) => { | |
| postMessage(__setImmediate_message_id, "*"); | |
| return __setImmediate_id_counter + __setImmediate_queue.push(func) - 1; | |
| } | |
| emClearImmediate = /**@type{function(number=)}*/((id) => { | |
| var index = id - __setImmediate_id_counter; | |
| // must preserve the order and count of elements in the queue, so replace the pending callback with an empty function | |
| if (index >= 0 && index < __setImmediate_queue.length) __setImmediate_queue[index] = () => {}; | |
| }) | |
| }`, | |
| $emSetImmediate: undefined, | |
| $emClearImmediate_deps: ['$emSetImmediate'], | |
| $emClearImmediate: undefined, | |
| emscripten_set_immediate__deps: ['$emSetImmediate', '$callUserCallback'], | |
| emscripten_set_immediate: (cb, userData) => { | |
| {{{ runtimeKeepalivePush(); }}} | |
| return emSetImmediate(() => { | |
| {{{ runtimeKeepalivePop(); }}} | |
| callUserCallback(() => {{{ makeDynCall('vp', 'cb') }}}(userData)); | |
| }); | |
| }, | |
| emscripten_clear_immediate__deps: ['$emClearImmediate'], | |
| emscripten_clear_immediate: (id) => { | |
| {{{ runtimeKeepalivePop(); }}} | |
| emClearImmediate(id); | |
| }, | |
| emscripten_set_immediate_loop__deps: ['$emSetImmediate', '$callUserCallback'], | |
| emscripten_set_immediate_loop: (cb, userData) => { | |
| function tick() { | |
| callUserCallback(() => { | |
| if ({{{ makeDynCall('ip', 'cb') }}}(userData)) { | |
| emSetImmediate(tick); | |
| } else { | |
| {{{ runtimeKeepalivePop(); }}} | |
| } | |
| }); | |
| } | |
| {{{ runtimeKeepalivePush(); }}} | |
| emSetImmediate(tick); | |
| }, | |
| emscripten_set_timeout__deps: ['$safeSetTimeout'], | |
| emscripten_set_timeout: (cb, msecs, userData) => | |
| safeSetTimeout(() => {{{ makeDynCall('vp', 'cb') }}}(userData), msecs), | |
| #if AUDIO_WORKLET | |
| // Use a wrapper function here since simply aliasing `clearTimeout` would | |
| // cause the module to fail to load in the audio worklet context. | |
| emscripten_clear_timeout: (id) => clearTimeout(id), | |
| #else | |
| emscripten_clear_timeout: 'clearTimeout', | |
| #endif | |
| emscripten_set_timeout_loop__deps: ['$callUserCallback', 'emscripten_get_now'], | |
| emscripten_set_timeout_loop: (cb, msecs, userData) => { | |
| function tick() { | |
| var t = _emscripten_get_now(); | |
| var n = t + msecs; | |
| {{{ runtimeKeepalivePop() }}} | |
| callUserCallback(() => { | |
| if ({{{ makeDynCall('idp', 'cb') }}}(t, userData)) { | |
| {{{ runtimeKeepalivePush() }}} | |
| // Save a little bit of code space: modern browsers should treat | |
| // negative setTimeout as timeout of 0 | |
| // (https://stackoverflow.com/questions/8430966/is-calling-settimeout-with-a-negative-delay-ok) | |
| var remaining = n - _emscripten_get_now(); | |
| #if ENVIRONMENT_MAY_BE_NODE | |
| // Recent revisions of node, however, give TimeoutNegativeWarning | |
| remaining = Math.max(0, remaining); | |
| #endif | |
| setTimeout(tick, remaining); | |
| } | |
| }); | |
| } | |
| {{{ runtimeKeepalivePush() }}} | |
| return setTimeout(tick, 0); | |
| }, | |
| emscripten_set_interval__deps: ['$callUserCallback'], | |
| emscripten_set_interval: (cb, msecs, userData) => { | |
| {{{ runtimeKeepalivePush() }}} | |
| return setInterval(() => { | |
| callUserCallback(() => {{{ makeDynCall('vp', 'cb') }}}(userData)); | |
| }, msecs); | |
| }, | |
| emscripten_clear_interval: (id) => { | |
| {{{ runtimeKeepalivePop() }}} | |
| clearInterval(id); | |
| }, | |
| emscripten_async_call__deps: ['$safeSetTimeout', '$safeRequestAnimationFrame'], | |
| emscripten_async_call: (func, arg, millis) => { | |
| var wrapper = () => {{{ makeDynCall('vp', 'func') }}}(arg); | |
| if (millis >= 0 | |
| #if ENVIRONMENT_MAY_BE_NODE | |
| // node does not support requestAnimationFrame | |
| || ENVIRONMENT_IS_NODE | |
| #endif | |
| ) { | |
| safeSetTimeout(wrapper, millis); | |
| } else { | |
| safeRequestAnimationFrame(wrapper); | |
| } | |
| }, | |
| $registerPostMainLoop: (f) => { | |
| // Does nothing unless $MainLoop is included/used. | |
| typeof MainLoop != 'undefined' && MainLoop.postMainLoop.push(f); | |
| }, | |
| $registerPreMainLoop: (f) => { | |
| // Does nothing unless $MainLoop is included/used. | |
| typeof MainLoop != 'undefined' && MainLoop.preMainLoop.push(f); | |
| }, | |
| $MainLoop__internal: true, | |
| $MainLoop__deps: ['$setMainLoop', '$callUserCallback', 'emscripten_set_main_loop_timing'], | |
| $MainLoop__postset: ` | |
| Module['requestAnimationFrame'] = MainLoop.requestAnimationFrame; | |
| Module['pauseMainLoop'] = MainLoop.pause; | |
| Module['resumeMainLoop'] = MainLoop.resume; | |
| MainLoop.init();`, | |
| $MainLoop: { | |
| running: false, | |
| scheduler: null, | |
| // Each main loop is numbered with a ID in sequence order. Only one main | |
| // loop can run at a time. This variable stores the ordinal number of the | |
| // main loop that is currently allowed to run. All previous main loops | |
| // will quit themselves. This is incremented whenever a new main loop is | |
| // created. | |
| currentlyRunningMainloop: 0, | |
| // The main loop tick function that will be called at each iteration. | |
| func: null, | |
| // The argument that will be passed to the main loop. (of type void*) | |
| arg: 0, | |
| timingMode: 0, | |
| timingValue: 0, | |
| currentFrameNumber: 0, | |
| queue: [], | |
| preMainLoop: [], | |
| postMainLoop: [], | |
| pause() { | |
| MainLoop.scheduler = null; | |
| // Incrementing this signals the previous main loop that it's now become old, and it must return. | |
| MainLoop.currentlyRunningMainloop++; | |
| }, | |
| resume() { | |
| MainLoop.currentlyRunningMainloop++; | |
| var timingMode = MainLoop.timingMode; | |
| var timingValue = MainLoop.timingValue; | |
| var func = MainLoop.func; | |
| MainLoop.func = null; | |
| // do not set timing and call scheduler, we will do it on the next lines | |
| setMainLoop(func, 0, false, MainLoop.arg, true); | |
| _emscripten_set_main_loop_timing(timingMode, timingValue); | |
| MainLoop.scheduler(); | |
| }, | |
| updateStatus() { | |
| #if expectToReceiveOnModule('setStatus') | |
| if (Module['setStatus']) { | |
| var message = Module['statusMessage'] || 'Please wait...'; | |
| var remaining = MainLoop.remainingBlockers ?? 0; | |
| var expected = MainLoop.expectedBlockers ?? 0; | |
| if (remaining) { | |
| if (remaining < expected) { | |
| Module['setStatus'](`{message} ({expected - remaining}/{expected})`); | |
| } else { | |
| Module['setStatus'](message); | |
| } | |
| } else { | |
| Module['setStatus'](''); | |
| } | |
| } | |
| #endif | |
| }, | |
| init() { | |
| #if expectToReceiveOnModule('preMainLoop') | |
| Module['preMainLoop'] && MainLoop.preMainLoop.push(Module['preMainLoop']); | |
| #endif | |
| #if expectToReceiveOnModule('postMainLoop') | |
| Module['postMainLoop'] && MainLoop.postMainLoop.push(Module['postMainLoop']); | |
| #endif | |
| }, | |
| runIter(func) { | |
| if (ABORT) return; | |
| for (var pre of MainLoop.preMainLoop) { | |
| if (pre() === false) { | |
| return; // |return false| skips a frame | |
| } | |
| } | |
| callUserCallback(func); | |
| for (var post of MainLoop.postMainLoop) { | |
| post(); | |
| } | |
| #if STACK_OVERFLOW_CHECK | |
| checkStackCookie(); | |
| #endif | |
| }, | |
| nextRAF: 0, | |
| fakeRequestAnimationFrame(func) { | |
| // try to keep 60fps between calls to here | |
| var now = Date.now(); | |
| if (MainLoop.nextRAF === 0) { | |
| MainLoop.nextRAF = now + 1000/60; | |
| } else { | |
| while (now + 2 >= MainLoop.nextRAF) { // fudge a little, to avoid timer jitter causing us to do lots of delay:0 | |
| MainLoop.nextRAF += 1000/60; | |
| } | |
| } | |
| var delay = Math.max(MainLoop.nextRAF - now, 0); | |
| setTimeout(func, delay); | |
| }, | |
| requestAnimationFrame(func) { | |
| if (globalThis.requestAnimationFrame) { | |
| requestAnimationFrame(func); | |
| } else { | |
| MainLoop.fakeRequestAnimationFrame(func); | |
| } | |
| }, | |
| }, | |
| emscripten_get_main_loop_timing__deps: ['$MainLoop'], | |
| emscripten_get_main_loop_timing: (mode, value) => { | |
| if (mode) {{{ makeSetValue('mode', 0, 'MainLoop.timingMode', 'i32') }}}; | |
| if (value) {{{ makeSetValue('value', 0, 'MainLoop.timingValue', 'i32') }}}; | |
| }, | |
| emscripten_set_main_loop_timing__deps: ['$MainLoop'], | |
| emscripten_set_main_loop_timing: (mode, value) => { | |
| MainLoop.timingMode = mode; | |
| MainLoop.timingValue = value; | |
| if (!MainLoop.func) { | |
| #if ASSERTIONS | |
| err('emscripten_set_main_loop_timing: Cannot set timing mode for main loop since a main loop does not exist! Call emscripten_set_main_loop first to set one up.'); | |
| #endif | |
| return 1; // Return non-zero on failure, can't set timing mode when there is no main loop. | |
| } | |
| if (!MainLoop.running) { | |
| {{{ runtimeKeepalivePush() }}} | |
| MainLoop.running = true; | |
| } | |
| if (mode == {{{ cDefs.EM_TIMING_SETTIMEOUT }}}) { | |
| MainLoop.scheduler = function MainLoop_scheduler_setTimeout() { | |
| var timeUntilNextTick = Math.max(0, MainLoop.tickStartTime + value - _emscripten_get_now())|0; | |
| setTimeout(MainLoop.runner, timeUntilNextTick); // doing this each time means that on exception, we stop | |
| }; | |
| } else if (mode == {{{ cDefs.EM_TIMING_RAF }}}) { | |
| MainLoop.scheduler = function MainLoop_scheduler_rAF() { | |
| MainLoop.requestAnimationFrame(MainLoop.runner); | |
| }; | |
| } else { | |
| #if ASSERTIONS | |
| assert(mode == {{{ cDefs.EM_TIMING_SETIMMEDIATE}}}); | |
| #endif | |
| if (!MainLoop.setImmediate) { | |
| if (globalThis.setImmediate) { | |
| MainLoop.setImmediate = setImmediate; | |
| } else { | |
| // Emulate setImmediate. (note: not a complete polyfill, we don't emulate clearImmediate() to keep code size to minimum, since not needed) | |
| var setImmediates = []; | |
| var emscriptenMainLoopMessageId = 'setimmediate'; | |
| /** @param {Event} event */ | |
| var MainLoop_setImmediate_messageHandler = (event) => { | |
| // When called in current thread or Worker, the main loop ID is structured slightly different to accommodate for --proxy-to-worker runtime listening to Worker events, | |
| // so check for both cases. | |
| if (event.data === emscriptenMainLoopMessageId || event.data.target === emscriptenMainLoopMessageId) { | |
| event.stopPropagation(); | |
| setImmediates.shift()(); | |
| } | |
| }; | |
| addEventListener("message", MainLoop_setImmediate_messageHandler, true); | |
| MainLoop.setImmediate = /** @type{function(function(): ?, ...?): number} */((func) => { | |
| setImmediates.push(func); | |
| if (ENVIRONMENT_IS_WORKER) { | |
| Module['setImmediates'] ??= []; | |
| Module['setImmediates'].push(func); | |
| postMessage({target: emscriptenMainLoopMessageId}); // In --proxy-to-worker, route the message via proxyClient.js | |
| } else postMessage(emscriptenMainLoopMessageId, "*"); // On the main thread, can just send the message to itself. | |
| }); | |
| } | |
| } | |
| MainLoop.scheduler = function MainLoop_scheduler_setImmediate() { | |
| MainLoop.setImmediate(MainLoop.runner); | |
| }; | |
| } | |
| return 0; | |
| }, | |
| emscripten_set_main_loop__deps: ['$setMainLoop'], | |
| emscripten_set_main_loop: (func, fps, simulateInfiniteLoop) => { | |
| var iterFunc = {{{ makeDynCall('v', 'func') }}}; | |
| setMainLoop(iterFunc, fps, simulateInfiniteLoop); | |
| }, | |
| $setMainLoop__internal: true, | |
| $setMainLoop__deps: [ | |
| '$MainLoop', | |
| 'emscripten_set_main_loop_timing', 'emscripten_get_now', | |
| #if !MINIMAL_RUNTIME | |
| '$maybeExit', | |
| #endif | |
| ], | |
| $setMainLoop__docs: ` | |
| /** | |
| * @param {number=} arg | |
| * @param {boolean=} noSetTiming | |
| */`, | |
| $setMainLoop: (iterFunc, fps, simulateInfiniteLoop, arg, noSetTiming) => { | |
| #if ASSERTIONS | |
| assert(!MainLoop.func, 'emscripten_set_main_loop: there can only be one main loop function at once') | |
| #endif | |
| MainLoop.func = iterFunc; | |
| MainLoop.arg = arg; | |
| var thisMainLoopId = MainLoop.currentlyRunningMainloop; | |
| function checkIsRunning() { | |
| if (thisMainLoopId < MainLoop.currentlyRunningMainloop) { | |
| #if RUNTIME_DEBUG | |
| dbg('main loop exiting'); | |
| #endif | |
| {{{ runtimeKeepalivePop() }}} | |
| #if !MINIMAL_RUNTIME | |
| maybeExit(); | |
| #endif | |
| return false; | |
| } | |
| return true; | |
| } | |
| // We create the loop runner here but it is not actually running until | |
| // _emscripten_set_main_loop_timing is called (which might happen at a | |
| // later time). This member signifies that the current runner has not | |
| // yet been started so that we can call runtimeKeepalivePush when it | |
| // gets its timing set for the first time. | |
| MainLoop.running = false; | |
| MainLoop.runner = function MainLoop_runner() { | |
| if (ABORT) return; | |
| if (MainLoop.queue.length > 0) { | |
| var start = Date.now(); | |
| var blocker = MainLoop.queue.shift(); | |
| blocker.func(blocker.arg); | |
| if (MainLoop.remainingBlockers) { | |
| var remaining = MainLoop.remainingBlockers; | |
| var next = remaining%1 == 0 ? remaining-1 : Math.floor(remaining); | |
| if (blocker.counted) { | |
| MainLoop.remainingBlockers = next; | |
| } else { | |
| // not counted, but move the progress along a tiny bit | |
| next = next + 0.5; // do not steal all the next one's progress | |
| MainLoop.remainingBlockers = (8*remaining + next)/9; | |
| } | |
| } | |
| #if RUNTIME_DEBUG | |
| dbg(`main loop blocker "${blocker.name}" took '${Date.now() - start} ms`); //, left: ' + MainLoop.remainingBlockers); | |
| #endif | |
| MainLoop.updateStatus(); | |
| // catches pause/resume main loop from blocker execution | |
| if (!checkIsRunning()) return; | |
| setTimeout(MainLoop.runner, 0); | |
| return; | |
| } | |
| // catch pauses from non-main loop sources | |
| if (!checkIsRunning()) return; | |
| // Implement very basic swap interval control | |
| MainLoop.currentFrameNumber = MainLoop.currentFrameNumber + 1 | 0; | |
| if (MainLoop.timingMode == {{{ cDefs.EM_TIMING_RAF }}} && MainLoop.timingValue > 1 && MainLoop.currentFrameNumber % MainLoop.timingValue != 0) { | |
| // Not the scheduled time to render this frame - skip. | |
| MainLoop.scheduler(); | |
| return; | |
| } else if (MainLoop.timingMode == {{{ cDefs.EM_TIMING_SETTIMEOUT }}}) { | |
| MainLoop.tickStartTime = _emscripten_get_now(); | |
| #if ASSERTIONS | |
| if (Module['ctx']) { | |
| warnOnce('Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!'); | |
| } | |
| #endif | |
| } | |
| MainLoop.runIter(iterFunc); | |
| // catch pauses from the main loop itself | |
| if (!checkIsRunning()) return; | |
| MainLoop.scheduler(); | |
| } | |
| if (!noSetTiming) { | |
| if (fps > 0) { | |
| _emscripten_set_main_loop_timing({{{ cDefs.EM_TIMING_SETTIMEOUT }}}, 1000.0 / fps); | |
| } else { | |
| // Do rAF by rendering each frame (no decimating) | |
| _emscripten_set_main_loop_timing({{{ cDefs.EM_TIMING_RAF }}}, 1); | |
| } | |
| MainLoop.scheduler(); | |
| } | |
| if (simulateInfiniteLoop) { | |
| throw 'unwind'; | |
| } | |
| }, | |
| emscripten_set_main_loop_arg__deps: ['$setMainLoop'], | |
| emscripten_set_main_loop_arg: (func, arg, fps, simulateInfiniteLoop) => { | |
| var iterFunc = () => {{{ makeDynCall('vp', 'func') }}}(arg); | |
| setMainLoop(iterFunc, fps, simulateInfiniteLoop, arg); | |
| }, | |
| emscripten_cancel_main_loop__deps: ['$MainLoop'], | |
| emscripten_cancel_main_loop: () => { | |
| MainLoop.pause(); | |
| MainLoop.func = null; | |
| }, | |
| emscripten_pause_main_loop__deps: ['$MainLoop'], | |
| emscripten_pause_main_loop: () => MainLoop.pause(), | |
| emscripten_resume_main_loop__deps: ['$MainLoop'], | |
| emscripten_resume_main_loop: () => MainLoop.resume(), | |
| _emscripten_push_main_loop_blocker__deps: ['$MainLoop'], | |
| _emscripten_push_main_loop_blocker: (func, arg, name) => { | |
| MainLoop.queue.push({ func: () => { | |
| {{{ makeDynCall('vp', 'func') }}}(arg); | |
| }, name: UTF8ToString(name), counted: true }); | |
| MainLoop.updateStatus(); | |
| }, | |
| _emscripten_push_uncounted_main_loop_blocker__deps: ['$MainLoop'], | |
| _emscripten_push_uncounted_main_loop_blocker: (func, arg, name) => { | |
| MainLoop.queue.push({ func: () => { | |
| {{{ makeDynCall('vp', 'func') }}}(arg); | |
| }, name: UTF8ToString(name), counted: false }); | |
| MainLoop.updateStatus(); | |
| }, | |
| emscripten_set_main_loop_expected_blockers__deps: ['$MainLoop'], | |
| emscripten_set_main_loop_expected_blockers: (num) => { | |
| MainLoop.expectedBlockers = num; | |
| MainLoop.remainingBlockers = num; | |
| MainLoop.updateStatus(); | |
| }, | |
| }; | |
| addToLibrary(LibraryJSEventLoop); | |
Xet Storage Details
- Size:
- 18.8 kB
- Xet hash:
- efe234b41d74645d696513c3ad1c41dafc65eb24ebd39b787b9add1db6ffaab5
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.