browser_domFullscreen_fullscreenMode.js (7202B)
1 /* eslint-disable mozilla/no-arbitrary-setTimeout */ 2 3 "use strict"; 4 5 function listenOneEvent(aEvent, aListener) { 6 function listener(evt) { 7 removeEventListener(aEvent, listener); 8 aListener(evt); 9 } 10 addEventListener(aEvent, listener); 11 } 12 13 function queryFullscreenState(browser) { 14 return SpecialPowers.spawn(browser, [], () => { 15 return { 16 inDOMFullscreen: !!content.document.fullscreenElement, 17 inFullscreen: content.fullScreen, 18 }; 19 }); 20 } 21 22 function captureUnexpectedFullscreenChange() { 23 ok(false, "catched an unexpected fullscreen change"); 24 } 25 26 const FS_CHANGE_DOM = 1 << 0; 27 const FS_CHANGE_SIZE = 1 << 1; 28 const FS_CHANGE_BOTH = FS_CHANGE_DOM | FS_CHANGE_SIZE; 29 30 function waitForDocActivated(aBrowser) { 31 return SpecialPowers.spawn(aBrowser, [], () => { 32 return ContentTaskUtils.waitForCondition( 33 () => content.browsingContext.isActive && content.document.hasFocus() 34 ); 35 }); 36 } 37 38 function waitForFullscreenChanges(aBrowser, aFlags) { 39 return new Promise(resolve => { 40 let fullscreenData = null; 41 let sizemodeChanged = false; 42 function tryResolve() { 43 if ( 44 (!(aFlags & FS_CHANGE_DOM) || fullscreenData) && 45 (!(aFlags & FS_CHANGE_SIZE) || sizemodeChanged) 46 ) { 47 // In the platforms that support reporting occlusion state (e.g. Mac), 48 // enter/exit fullscreen mode will trigger docshell being set to 49 // non-activate and then set to activate back again. 50 // For those platform, we should wait until the docshell has been 51 // activated again, otherwise, the fullscreen request might be denied. 52 waitForDocActivated(aBrowser).then(() => { 53 if (!fullscreenData) { 54 queryFullscreenState(aBrowser).then(resolve); 55 } else { 56 resolve(fullscreenData); 57 } 58 }); 59 } 60 } 61 if (aFlags & FS_CHANGE_SIZE) { 62 listenOneEvent("sizemodechange", () => { 63 sizemodeChanged = true; 64 tryResolve(); 65 }); 66 } 67 if (aFlags & FS_CHANGE_DOM) { 68 BrowserTestUtils.waitForContentEvent(aBrowser, "fullscreenchange").then( 69 async () => { 70 fullscreenData = await queryFullscreenState(aBrowser); 71 tryResolve(); 72 } 73 ); 74 } 75 }); 76 } 77 78 var gTests = [ 79 { 80 desc: "document method", 81 affectsFullscreenMode: false, 82 exitFunc: browser => { 83 SpecialPowers.spawn(browser, [], () => { 84 content.document.exitFullscreen(); 85 }); 86 }, 87 }, 88 { 89 desc: "escape key", 90 affectsFullscreenMode: false, 91 exitFunc: () => { 92 executeSoon(() => EventUtils.synthesizeKey("KEY_Escape")); 93 }, 94 }, 95 { 96 desc: "F11 key", 97 affectsFullscreenMode: true, 98 exitFunc() { 99 executeSoon(() => EventUtils.synthesizeKey("KEY_F11")); 100 }, 101 }, 102 ]; 103 104 function checkState(expectedStates, contentStates) { 105 is( 106 contentStates.inDOMFullscreen, 107 expectedStates.inDOMFullscreen, 108 "The DOM fullscreen state of the content should match" 109 ); 110 // TODO window.fullScreen is not updated as soon as the fullscreen 111 // state flips in child process, hence checking it could cause 112 // anonying intermittent failure. As we just want to confirm the 113 // fullscreen state of the browser window, we can just check the 114 // that on the chrome window below. 115 // is(contentStates.inFullscreen, expectedStates.inFullscreen, 116 // "The fullscreen state of the content should match"); 117 is( 118 !!document.fullscreenElement, 119 expectedStates.inDOMFullscreen, 120 "The DOM fullscreen state of the chrome should match" 121 ); 122 is( 123 window.fullScreen, 124 expectedStates.inFullscreen, 125 "The fullscreen state of the chrome should match" 126 ); 127 } 128 129 const kPage = 130 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 131 "http://example.org/browser/browser/" + 132 "base/content/test/general/dummy_page.html"; 133 134 add_task(async function () { 135 await pushPrefs( 136 ["full-screen-api.transition-duration.enter", "0 0"], 137 ["full-screen-api.transition-duration.leave", "0 0"] 138 ); 139 140 registerCleanupFunction(async function () { 141 if (window.fullScreen) { 142 let fullscreenPromise = waitForFullscreenChanges( 143 gBrowser.selectedBrowser, 144 FS_CHANGE_SIZE 145 ); 146 executeSoon(() => BrowserCommands.fullScreen()); 147 await fullscreenPromise; 148 } 149 }); 150 151 let tab = await BrowserTestUtils.openNewForegroundTab({ 152 gBrowser, 153 url: kPage, 154 }); 155 let browser = tab.linkedBrowser; 156 157 // As requestFullscreen checks the active state of the docshell, 158 // wait for the document to be activated, just to be sure that 159 // the fullscreen request won't be denied. 160 await waitForDocActivated(browser); 161 162 for (let test of gTests) { 163 let contentStates; 164 info("Testing exit DOM fullscreen via " + test.desc); 165 166 contentStates = await queryFullscreenState(browser); 167 checkState({ inDOMFullscreen: false, inFullscreen: false }, contentStates); 168 169 /* DOM fullscreen without fullscreen mode */ 170 171 info("> Enter DOM fullscreen"); 172 let fullscreenPromise = waitForFullscreenChanges(browser, FS_CHANGE_BOTH); 173 await SpecialPowers.spawn(browser, [], () => { 174 content.document.body.requestFullscreen(); 175 }); 176 contentStates = await fullscreenPromise; 177 checkState({ inDOMFullscreen: true, inFullscreen: true }, contentStates); 178 179 info("> Exit DOM fullscreen"); 180 fullscreenPromise = waitForFullscreenChanges(browser, FS_CHANGE_BOTH); 181 test.exitFunc(browser); 182 contentStates = await fullscreenPromise; 183 checkState({ inDOMFullscreen: false, inFullscreen: false }, contentStates); 184 185 /* DOM fullscreen with fullscreen mode */ 186 187 info("> Enter fullscreen mode"); 188 // Need to be asynchronous because sizemodechange event could be 189 // dispatched synchronously, which would cause the event listener 190 // miss that event and wait infinitely. 191 fullscreenPromise = waitForFullscreenChanges(browser, FS_CHANGE_SIZE); 192 executeSoon(() => BrowserCommands.fullScreen()); 193 contentStates = await fullscreenPromise; 194 checkState({ inDOMFullscreen: false, inFullscreen: true }, contentStates); 195 196 info("> Enter DOM fullscreen in fullscreen mode"); 197 fullscreenPromise = waitForFullscreenChanges(browser, FS_CHANGE_DOM); 198 await SpecialPowers.spawn(browser, [], () => { 199 content.document.body.requestFullscreen(); 200 }); 201 contentStates = await fullscreenPromise; 202 checkState({ inDOMFullscreen: true, inFullscreen: true }, contentStates); 203 204 info("> Exit DOM fullscreen in fullscreen mode"); 205 fullscreenPromise = waitForFullscreenChanges( 206 browser, 207 test.affectsFullscreenMode ? FS_CHANGE_BOTH : FS_CHANGE_DOM 208 ); 209 test.exitFunc(browser); 210 contentStates = await fullscreenPromise; 211 checkState( 212 { 213 inDOMFullscreen: false, 214 inFullscreen: !test.affectsFullscreenMode, 215 }, 216 contentStates 217 ); 218 219 /* Cleanup */ 220 221 // Exit fullscreen mode if we are still in 222 if (window.fullScreen) { 223 info("> Cleanup"); 224 fullscreenPromise = waitForFullscreenChanges(browser, FS_CHANGE_SIZE); 225 executeSoon(() => BrowserCommands.fullScreen()); 226 await fullscreenPromise; 227 } 228 } 229 230 BrowserTestUtils.removeTab(tab); 231 });