file_fullscreen-utils.js (3393B)
1 // Keep track of how many fullscreenChange enters we've received, so that 2 // we can balance them with the number of exits we receive. We reset this 3 // to 0 when we load a test. 4 var fullscreenChangeEnters = 0; 5 6 addLoadEvent(function () { 7 info(`Resetting fullscreen enter count.`); 8 fullscreenChangeEnters = 0; 9 }); 10 11 // This can be used to force a certain value for fullscreenChangeEnters 12 // to handle unusual conditions -- such as exiting multiple levels of 13 // fullscreen forcibly. 14 function setFullscreenChangeEnters(enters) { 15 info(`Setting fullscreen enter count to ${enters}.`); 16 fullscreenChangeEnters = enters; 17 } 18 19 // Returns true if the window believes it is in fullscreen. This may be true even 20 // before an asynchronous fullscreen transition is complete. 21 function inFullscreenMode(win) { 22 return win.document.fullscreenElement; 23 } 24 25 // Adds a listener that will be called once a fullscreen transition 26 // is complete. When type==='enter', callback is called when we've 27 // received a fullscreenchange event, and the fullscreen transition is 28 // complete. When type==='exit', callback is called when we've 29 // received a fullscreenchange event and the window is out of 30 // fullscreen. inDoc is the document which the listeners are added on, 31 // if absent, the listeners are added to the current document. 32 // the current document. 33 function addFullscreenChangeContinuation(type, callback, inDoc) { 34 var doc = inDoc || document; 35 var topWin = doc.defaultView.top; 36 function checkCondition() { 37 if (type == "enter") { 38 fullscreenChangeEnters++; 39 return inFullscreenMode(topWin); 40 } else if (type == "exit") { 41 fullscreenChangeEnters--; 42 return fullscreenChangeEnters 43 ? inFullscreenMode(topWin) 44 : !inFullscreenMode(topWin); 45 } 46 throw new Error("'type' must be either 'enter', or 'exit'."); 47 } 48 function onFullscreenChange(event) { 49 doc.removeEventListener("fullscreenchange", onFullscreenChange); 50 ok(checkCondition(), `Should ${type} fullscreen.`); 51 // Delay invocation so other listeners have a chance to respond before 52 // we continue. 53 requestAnimationFrame(() => setTimeout(() => callback(event), 0), 0); 54 } 55 doc.addEventListener("fullscreenchange", onFullscreenChange); 56 } 57 58 // Calls |callback| when the next fullscreenerror is dispatched to inDoc||document. 59 function addFullscreenErrorContinuation(callback, inDoc) { 60 let doc = inDoc || document; 61 let listener = function (event) { 62 doc.removeEventListener("fullscreenerror", listener); 63 // Delay invocation so other listeners have a chance to respond before 64 // we continue. 65 requestAnimationFrame(() => setTimeout(() => callback(event), 0), 0); 66 }; 67 doc.addEventListener("fullscreenerror", listener); 68 } 69 70 // Waits until the window has both the load event and a MozAfterPaint called on 71 // it, and then invokes the callback 72 function waitForLoadAndPaint(win, callback) { 73 win.addEventListener( 74 "MozAfterPaint", 75 function () { 76 // The load event may have fired before the MozAfterPaint, in which case 77 // listening for it now will hang. Instead we check the readyState to see if 78 // it already fired, and if so, invoke the callback right away. 79 if (win.document.readyState == "complete") { 80 callback(); 81 } else { 82 win.addEventListener("load", callback, { once: true }); 83 } 84 }, 85 { once: true } 86 ); 87 }