Skip to content

Commit

Permalink
Add linker flag -s HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS=0 …
Browse files Browse the repository at this point in the history
…to allow disabling fullscreen mode and pointer lock request deferring if deferring support is not needed (emscripten-core#10098)
  • Loading branch information
juj authored Jan 7, 2020
1 parent cd4b7ba commit f599bbf
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 14 deletions.
3 changes: 3 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ Current Trunk
- Added options MEMORY_GROWTH_GEOMETRIC_STEP and MEMORY_GROWTH_GEOMETRIC_CAP
to allow customizing the heap growth rates.
- Renamed MEMORY_GROWTH_STEP option to MEMORY_GROWTH_LINEAR_STEP option.
- Added new linker option -s HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS=0
(default enabled) to allow disabling support for deferred fullscreen mode and
pointer lock requests for applications that do not need deferring support.

v1.39.5: 12/20/2019
-------------------
Expand Down
44 changes: 31 additions & 13 deletions src/library_html5.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ var LibraryJSEvents = {
JSEvents._removeHandler(i);
}
JSEvents.eventHandlers = [];
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
JSEvents.deferredCalls = [];
#endif
},

#if !MINIMAL_RUNTIME // In minimal runtime, there is no concept of the page running vs being closed, and hence __ATEXIT__ is not present
Expand All @@ -48,6 +50,7 @@ var LibraryJSEvents = {
},
#endif

#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
deferredCalls: [],

// Queues the given function call to occur the next time we enter an event handler.
Expand Down Expand Up @@ -110,6 +113,7 @@ var LibraryJSEvents = {
inEventHandler: 0,
// If we are in an event handler, specifies the event handler object from the eventHandlers array that is currently running.
currentEventHandler: null,
#endif

// Stores objects representing each currently registered JS event handler.
eventHandlers: [],
Expand All @@ -136,17 +140,21 @@ var LibraryJSEvents = {

registerOrRemoveHandler: function(eventHandler) {
var jsEventHandler = function jsEventHandler(event) {
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
// Increment nesting count for the event handler.
++JSEvents.inEventHandler;
JSEvents.currentEventHandler = eventHandler;
// Process any old deferred calls the user has placed.
JSEvents.runDeferredCalls();
#endif
// Process the actual event, calls back to user C code handler.
eventHandler.handlerFunc(event);
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
// Process any new deferred calls that were placed right now from this event handler.
JSEvents.runDeferredCalls();
// Out of event handler - restore nesting count.
--JSEvents.inEventHandler;
#endif
};

if (eventHandler.callbackfunc) {
Expand Down Expand Up @@ -255,10 +263,12 @@ var LibraryJSEvents = {

var eventHandler = {
target: __findEventTarget(target),
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
#if MIN_IE_VERSION != TARGET_NOT_SUPPORTED
allowsDeferredCalls: JSEvents.isInternetExplorer() ? false : true, // MSIE doesn't allow fullscreen and pointerlock requests from key handlers, others do.
#else
allowsDeferredCalls: true,
#endif
#endif
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
Expand Down Expand Up @@ -485,13 +495,15 @@ var LibraryJSEvents = {

var eventHandler = {
target: target,
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
allowsDeferredCalls: eventTypeString != 'mousemove' && eventTypeString != 'mouseenter' && eventTypeString != 'mouseleave', // Mouse move events do not allow fullscreen/pointer lock requests to be handled in them!
#endif
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: mouseEventHandlerFunc,
useCapture: useCapture
};
#if MIN_IE_VERSION != TARGET_NOT_SUPPORTED
#if MIN_IE_VERSION != TARGET_NOT_SUPPORTED && HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
// In IE, mousedown events don't either allow deferred calls to be run!
if (JSEvents.isInternetExplorer() && eventTypeString == 'mousedown') eventHandler.allowsDeferredCalls = false;
#endif
Expand Down Expand Up @@ -628,7 +640,9 @@ var LibraryJSEvents = {

var eventHandler = {
target: target,
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
allowsDeferredCalls: true,
#endif
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
#if MIN_IE_VERSION <= 8 || MIN_SAFARI_VERSION < 130000 // https://caniuse.com/#feat=mdn-api_wheelevent
Expand Down Expand Up @@ -710,7 +724,6 @@ var LibraryJSEvents = {

var eventHandler = {
target: target,
allowsDeferredCalls: false, // Neither scroll or resize events allow running requests inside them.
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: uiEventHandlerFunc,
Expand Down Expand Up @@ -765,7 +778,6 @@ var LibraryJSEvents = {

var eventHandler = {
target: __findEventTarget(target),
allowsDeferredCalls: false,
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: focusEventHandlerFunc,
Expand Down Expand Up @@ -838,7 +850,6 @@ var LibraryJSEvents = {

var eventHandler = {
target: __findEventTarget(target),
allowsDeferredCalls: false,
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: deviceOrientationEventHandlerFunc,
Expand Down Expand Up @@ -914,7 +925,6 @@ var LibraryJSEvents = {

var eventHandler = {
target: __findEventTarget(target),
allowsDeferredCalls: false,
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: deviceMotionEventHandlerFunc,
Expand Down Expand Up @@ -994,7 +1004,6 @@ var LibraryJSEvents = {

var eventHandler = {
target: target,
allowsDeferredCalls: false,
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: orientationChangeEventHandlerFunc,
Expand Down Expand Up @@ -1114,7 +1123,6 @@ var LibraryJSEvents = {

var eventHandler = {
target: target,
allowsDeferredCalls: false,
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: fullscreenChangeEventhandlerFunc,
Expand Down Expand Up @@ -1502,6 +1510,7 @@ var LibraryJSEvents = {
return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}};
}

#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
var canPerformRequests = JSEvents.canPerformEventHandlerRequests();

// Queue this function call if we're not currently in an event handler and the user saw it appropriate to do so.
Expand All @@ -1513,6 +1522,7 @@ var LibraryJSEvents = {
return {{{ cDefine('EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED') }}};
}
}
#endif

return _JSEvents_requestFullscreen(target, strategy);
},
Expand All @@ -1526,7 +1536,9 @@ var LibraryJSEvents = {
strategy.scaleMode = {{{ cDefine('EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT') }}};
strategy.canvasResolutionScaleMode = {{{ cDefine('EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE') }}};
strategy.filteringMode = {{{ cDefine('EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT') }}};
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
strategy.deferUntilInEventHandler = deferUntilInEventHandler;
#endif
strategy.canvasResizedCallbackTargetThread = {{{ cDefine('EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD') }}};

return __emscripten_do_request_fullscreen(target, strategy);
Expand All @@ -1540,7 +1552,9 @@ var LibraryJSEvents = {
strategy.scaleMode = {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.scaleMode, 'i32') }}};
strategy.canvasResolutionScaleMode = {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResolutionScaleMode, 'i32') }}};
strategy.filteringMode = {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.filteringMode, 'i32') }}};
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
strategy.deferUntilInEventHandler = deferUntilInEventHandler;
#endif
strategy.canvasResizedCallback = {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResizedCallback, 'i32') }}};
strategy.canvasResizedCallbackUserData = {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.canvasResizedCallbackUserData, 'i32') }}};
#if USE_PTHREADS
Expand Down Expand Up @@ -1625,8 +1639,10 @@ var LibraryJSEvents = {
emscripten_exit_fullscreen__sig: 'i',
emscripten_exit_fullscreen: function() {
if (!JSEvents.fullscreenEnabled()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}};
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
// Make sure no queued up calls will fire after this.
JSEvents.removeDeferredCalls(_JSEvents_requestFullscreen);
#endif

var d = __specialEventTargets[{{{ cDefine('EMSCRIPTEN_EVENT_TARGET_DOCUMENT') }}}];
if (d.exitFullscreen) {
Expand Down Expand Up @@ -1687,7 +1703,6 @@ var LibraryJSEvents = {

var eventHandler = {
target: target,
allowsDeferredCalls: false,
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: pointerlockChangeEventHandlerFunc,
Expand Down Expand Up @@ -1732,7 +1747,6 @@ var LibraryJSEvents = {

var eventHandler = {
target: target,
allowsDeferredCalls: false,
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: pointerlockErrorEventHandlerFunc,
Expand Down Expand Up @@ -1835,6 +1849,7 @@ var LibraryJSEvents = {
return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}};
}

#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
var canPerformRequests = JSEvents.canPerformEventHandlerRequests();

// Queue this function call if we're not currently in an event handler and the user saw it appropriate to do so.
Expand All @@ -1846,6 +1861,7 @@ var LibraryJSEvents = {
return {{{ cDefine('EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED') }}};
}
}
#endif

return __requestPointerLock(target);
},
Expand All @@ -1854,8 +1870,10 @@ var LibraryJSEvents = {
emscripten_exit_pointerlock__sig: 'i',
emscripten_exit_pointerlock__deps: ['$JSEvents', '_requestPointerLock'],
emscripten_exit_pointerlock: function() {
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
// Make sure no queued up calls will fire after this.
JSEvents.removeDeferredCalls(__requestPointerLock);
#endif

if (document.exitPointerLock) {
document.exitPointerLock();
Expand Down Expand Up @@ -1934,7 +1952,6 @@ var LibraryJSEvents = {

var eventHandler = {
target: target,
allowsDeferredCalls: false,
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: visibilityChangeEventHandlerFunc,
Expand Down Expand Up @@ -2051,7 +2068,9 @@ var LibraryJSEvents = {

var eventHandler = {
target: target,
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
allowsDeferredCalls: eventTypeString == 'touchstart' || eventTypeString == 'touchend',
#endif
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: touchEventHandlerFunc,
Expand Down Expand Up @@ -2145,7 +2164,9 @@ var LibraryJSEvents = {

var eventHandler = {
target: __findEventTarget(target),
#if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS
allowsDeferredCalls: true,
#endif
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: gamepadEventHandlerFunc,
Expand Down Expand Up @@ -2233,7 +2254,6 @@ var LibraryJSEvents = {

var eventHandler = {
target: __findEventTarget(target),
allowsDeferredCalls: false,
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: beforeUnloadEventHandlerFunc,
Expand Down Expand Up @@ -2289,7 +2309,6 @@ var LibraryJSEvents = {

var eventHandler = {
target: __findEventTarget(target),
allowsDeferredCalls: false,
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: batteryEventHandlerFunc,
Expand Down Expand Up @@ -2701,7 +2720,6 @@ var LibraryJSEvents = {

var eventHandler = {
target: __findEventTarget(target),
allowsDeferredCalls: false,
eventTypeString: eventTypeString,
callbackfunc: callbackfunc,
handlerFunc: webGlEventHandlerFunc,
Expand Down
11 changes: 11 additions & 0 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -1640,6 +1640,17 @@ var SUPPORT_LONGJMP = 1;
// selectors, instead of referring to DOM IDs.
var DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR = 1;

// Certain browser DOM API operations, such as requesting fullscreen mode
// transition or pointer lock require that the request originates from within
// an user initiated event, such as mouse click or keyboard press. Refactoring
// an application to follow this kind of program structure can be difficult, so
// HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS=1 flag allows transparent
// emulation of this by deferring synchronous fullscreen mode and pointer lock
// requests until a suitable event callback is generated. Set this to 0
// to disable support for deferring to save code space if your application does
// not need support for deferred calls.
var HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS = 1;

// Specifies whether the generated .html file is run through html-minifier. The
// set of optimization passes run by html-minifier depends on debug and
// optimization levels. In -g2 and higher, no minification is performed. In -g1,
Expand Down
2 changes: 1 addition & 1 deletion tests/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2568,7 +2568,7 @@ def test_doublestart_bug(self):

@requires_threads
def test_html5(self):
for opts in [[], ['-O2', '-g1', '--closure', '1'], ['-s', 'USE_PTHREADS=1', '-s', 'PROXY_TO_PTHREAD=1'], ['-s', 'MIN_FIREFOX_VERSION=0', '-s', 'MIN_SAFARI_VERSION=0', '-s', 'MIN_IE_VERSION=0', '-s', 'MIN_EDGE_VERSION=0', '-s', 'MIN_CHROME_VERSION=0']]:
for opts in [[], ['-O2', '-g1', '--closure', '1', '-s', 'HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS=0'], ['-s', 'USE_PTHREADS=1', '-s', 'PROXY_TO_PTHREAD=1'], ['-s', 'MIN_FIREFOX_VERSION=0', '-s', 'MIN_SAFARI_VERSION=0', '-s', 'MIN_IE_VERSION=0', '-s', 'MIN_EDGE_VERSION=0', '-s', 'MIN_CHROME_VERSION=0']]:
print(opts)
self.btest(path_from_root('tests', 'test_html5.c'), args=[] + opts, expected='0')

Expand Down

0 comments on commit f599bbf

Please sign in to comment.