Browse Source

fix: allow iframe-initiated HTML fullscreen to exit while in macOS fullscreen (6-1-x) (#21020)

* fix: explicitly resize the contents when exiting html fullscreen while in OS fullscreen

* test: ensure HTML fullscreen toggles while in OS fullscreen
loc 5 years ago
parent
commit
3d10d4c7e0

+ 7 - 0
atom/browser/common_web_contents_delegate.cc

@@ -342,6 +342,13 @@ void CommonWebContentsDelegate::ExitFullscreenModeForTab(
     return;
   SetHtmlApiFullscreen(false);
   owner_window_->NotifyWindowLeaveHtmlFullScreen();
+
+  if (native_fullscreen_) {
+    // Explicitly trigger a view resize, as the size is not actually changing if
+    // the browser is fullscreened, too. Chrome does this indirectly from
+    // `chrome/browser/ui/exclusive_access/fullscreen_controller.cc`.
+    source->GetRenderViewHost()->GetWidget()->SynchronizeVisualProperties();
+  }
 }
 
 bool CommonWebContentsDelegate::IsFullscreenForTabOrPending(

+ 79 - 0
spec/chromium-spec.js

@@ -9,6 +9,7 @@ const url = require('url')
 const ChildProcess = require('child_process')
 const { ipcRenderer, remote } = require('electron')
 const { emittedOnce } = require('./events-helpers')
+const { promisify } = require('util')
 const { closeWindow, waitForWebContentsToLoad } = require('./window-helpers')
 const { resolveGetters } = require('./assert-helpers')
 const { app, BrowserWindow, ipcMain, protocol, session, webContents } = remote
@@ -1574,3 +1575,81 @@ describe('font fallback', () => {
     }[process.platform])
   })
 })
+
+describe('iframe using HTML fullscreen API while window is OS-fullscreened', () => {
+  const fixtures = path.resolve(__dirname, 'fixtures')
+  const fullscreenChildHtml = promisify(fs.readFile)(
+    path.join(fixtures, 'pages', 'fullscreen-oopif.html')
+  )
+  let w, server
+
+  before(() => {
+    server = http.createServer(async (_req, res) => {
+      res.writeHead(200, { 'Content-Type': 'text/html' })
+      res.write(await fullscreenChildHtml)
+      res.end()
+    })
+
+    server.listen(8989, '127.0.0.1')
+  })
+
+  beforeEach(() => {
+    w = new BrowserWindow({
+      show: true,
+      fullscreen: true,
+      webPreferences: {
+        nodeIntegration: true,
+        nodeIntegrationInSubFrames: true
+      }
+    })
+  })
+
+  afterEach(() => {
+    closeWindow(w).then(() => { w = null })
+    server.close()
+  })
+
+  it('can fullscreen from out-of-process iframes (OOPIFs)', done => {
+    ipcMain.once('fullscreenChange', async () => {
+      const fullscreenWidth = await w.webContents.executeJavaScript(
+        "document.querySelector('iframe').offsetWidth"
+      )
+      expect(fullscreenWidth > 0).to.be.true()
+
+      await w.webContents.executeJavaScript(
+        "document.querySelector('iframe').contentWindow.postMessage('exitFullscreen', '*')"
+      )
+
+      await new Promise(resolve => setTimeout(resolve, 500))
+
+      const width = await w.webContents.executeJavaScript(
+        "document.querySelector('iframe').offsetWidth"
+      )
+      expect(width).to.equal(0)
+
+      done()
+    })
+
+    const html =
+      '<iframe style="width: 0" frameborder=0 src="http://localhost:8989" allowfullscreen></iframe>'
+    w.loadURL(`data:text/html,${html}`)
+  })
+
+  it('can fullscreen from in-process iframes', done => {
+    ipcMain.once('fullscreenChange', async () => {
+      const fullscreenWidth = await w.webContents.executeJavaScript(
+        "document.querySelector('iframe').offsetWidth"
+      )
+      expect(fullscreenWidth > 0).to.true()
+
+      await w.webContents.executeJavaScript('document.exitFullscreen()')
+      const width = await w.webContents.executeJavaScript(
+        "document.querySelector('iframe').offsetWidth"
+      )
+      expect(width).to.equal(0)
+      done()
+    })
+
+    w.loadFile(path.join(fixtures, 'pages', 'fullscreen-ipif.html'))
+  })
+})

+ 15 - 0
spec/fixtures/pages/fullscreen-ipif.html

@@ -0,0 +1,15 @@
+<body>
+    <iframe style="width: 0" frameborder=0 src="fullscreen.html" allowfullscreen></iframe>
+    <script>
+        const { webFrame, ipcRenderer } = require('electron')
+        const iframe = document.querySelector('iframe')
+
+        document.addEventListener('fullscreenchange', () => {
+            ipcRenderer.send('fullscreenChange')
+        })
+
+        iframe.addEventListener('load', () => {
+            webFrame.executeJavaScript("document.querySelector('iframe').contentDocument.querySelector('video').requestFullscreen()", true)
+        })
+    </script>
+</body>

+ 19 - 0
spec/fixtures/pages/fullscreen-oopif.html

@@ -0,0 +1,19 @@
+<script>
+    const { webFrame, ipcRenderer } = require('electron')
+
+    document.addEventListener('fullscreenchange', () => {
+        ipcRenderer.send('fullscreenChange', webFrame.routingId)
+    });
+
+    window.addEventListener('message', ({ data }) => {
+        if (data === 'exitFullscreen') {
+            document.exitFullscreen()
+        }
+    })
+
+    window.addEventListener('load', () => {
+        window.focus()
+        webFrame.executeJavaScript('document.querySelector("video").requestFullscreen()', true)
+    });
+</script>
+<video></video>