fix: webview should maximize on requestFullscreen (#29988)

* fix: webview should maximize on requestFullscreen

* fix merge error

* chore: update patches

Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
This commit is contained in:
trop[bot]
2021-07-05 13:42:35 -04:00
committed by GitHub
parent 1f21dfd838
commit f1f9a76579
8 changed files with 127 additions and 4 deletions

View File

@@ -137,3 +137,4 @@ cherry-pick-b77b38a3380c.patch
cherry-pick-910e9e40d376.patch
cherry-pick-d9556a80a790.patch
cherry-pick-ee6aee64e24c.patch
webview_fullscreen.patch

View File

@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Cheng Zhao <zcbenz@gmail.com>
Date: Thu, 4 Oct 2018 14:57:02 -0700
Subject: fix: also propagate fullscreen state for outer frame
When entering fullscreen with Element.requestFullscreen in child frames,
the parent frame should also enter fullscreen mode too. Chromium handles
this for iframes, but not for webviews as they are essentially main
frames instead of child frames.
This patch makes webviews propagate the fullscreen state to embedder.
Note that we also need to manually update embedder's
`api::WebContents::IsFullscreenForTabOrPending` value.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 2e222a1bf9cb50efa990f875b102001998691f06..385080e04ed3fb6b82a1ed993889913546f0ba20 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -4728,6 +4728,15 @@ void RenderFrameHostImpl::EnterFullscreen(
notified_instances.insert(parent_site_instance);
}
+ // Entering fullscreen from webview should also notify its outer frame.
+ if (frame_tree_node()->render_manager()->IsMainFrameForInnerDelegate()) {
+ RenderFrameProxyHost* outer_proxy =
+ frame_tree_node()->render_manager()->GetProxyToOuterDelegate();
+ DCHECK(outer_proxy);
+ outer_proxy->GetAssociatedRemoteFrame()->WillEnterFullscreen(
+ options.Clone());
+ }
+
delegate_->EnterFullscreenMode(this, *options);
delegate_->FullscreenStateChanged(this, true /* is_fullscreen */,
std::move(options));

View File

@@ -99,6 +99,7 @@
#include "shell/browser/web_contents_zoom_controller.h"
#include "shell/browser/web_dialog_helper.h"
#include "shell/browser/web_view_guest_delegate.h"
#include "shell/browser/web_view_manager.h"
#include "shell/common/api/electron_api_native_image.h"
#include "shell/common/color_util.h"
#include "shell/common/electron_constants.h"
@@ -3534,13 +3535,13 @@ void WebContents::SetHtmlApiFullscreen(bool enter_fullscreen) {
// Window is already in fullscreen mode, save the state.
if (enter_fullscreen && owner_window_->IsFullscreen()) {
native_fullscreen_ = true;
html_fullscreen_ = true;
UpdateHtmlApiFullscreen(true);
return;
}
// Exit html fullscreen state but not window's fullscreen mode.
if (!enter_fullscreen && native_fullscreen_) {
html_fullscreen_ = false;
UpdateHtmlApiFullscreen(false);
return;
}
@@ -3555,10 +3556,41 @@ void WebContents::SetHtmlApiFullscreen(bool enter_fullscreen) {
owner_window_->SetFullScreen(enter_fullscreen);
}
html_fullscreen_ = enter_fullscreen;
UpdateHtmlApiFullscreen(enter_fullscreen);
native_fullscreen_ = false;
}
void WebContents::UpdateHtmlApiFullscreen(bool fullscreen) {
if (fullscreen == html_fullscreen_)
return;
html_fullscreen_ = fullscreen;
// Notify renderer of the html fullscreen change.
web_contents()
->GetRenderViewHost()
->GetWidget()
->SynchronizeVisualProperties();
// The embedder WebContents is spearated from the frame tree of webview, so
// we must manually sync their fullscreen states.
if (embedder_)
embedder_->SetHtmlApiFullscreen(fullscreen);
// Make sure all child webviews quit html fullscreen.
if (!fullscreen && !IsGuest()) {
auto* manager = WebViewManager::GetWebViewManager(web_contents());
manager->ForEachGuest(
web_contents(), base::BindRepeating([](content::WebContents* guest) {
WebContents* api_web_contents = WebContents::From(guest);
// Use UpdateHtmlApiFullscreen instead of SetXXX becuase there is no
// need to interact with the owner window.
api_web_contents->UpdateHtmlApiFullscreen(false);
return false;
}));
}
}
// static
v8::Local<v8::ObjectTemplate> WebContents::FillObjectTemplate(
v8::Isolate* isolate,

View File

@@ -693,6 +693,8 @@ class WebContents : public gin::Wrappable<WebContents>,
// Set fullscreen mode triggered by html api.
void SetHtmlApiFullscreen(bool enter_fullscreen);
// Update the html fullscreen flag in both browser and renderer.
void UpdateHtmlApiFullscreen(bool fullscreen);
v8::Global<v8::Value> session_;
v8::Global<v8::Value> devtools_web_contents_;

View File

@@ -25,7 +25,6 @@ class WebViewManager : public content::BrowserPluginGuestManager {
static WebViewManager* GetWebViewManager(content::WebContents* web_contents);
protected:
// content::BrowserPluginGuestManager:
bool ForEachGuest(content::WebContents* embedder,
const GuestCallback& callback) override;

View File

@@ -0,0 +1,12 @@
<body>
<div id="div">
WebView
</div>
<script type="text/javascript" charset="utf-8">
const {ipcRenderer} = require('electron')
ipcRenderer.send('webview-ready')
document.addEventListener('fullscreenchange', () => {
ipcRenderer.send('webview-fullscreenchange')
})
</script>
</body>

View File

@@ -0,0 +1,12 @@
<body>
<webview id="webview" nodeintegration="on" webpreferences="contextIsolation=no" src="frame.html"/>
<script type="text/javascript" charset="utf-8">
document.addEventListener('fullscreenchange', () => {
require('electron').ipcRenderer.send('fullscreenchange')
})
function isIframeFullscreen() {
return document.getElementById('webview').shadowRoot.lastElementChild.matches(':fullscreen')
}
</script>
</body>

View File

@@ -381,6 +381,36 @@ describe('<webview> tag', function () {
});
});
describe('requestFullscreen from webview', () => {
const loadWebViewWindow = async () => {
const w = new BrowserWindow({
webPreferences: {
webviewTag: true,
nodeIntegration: true,
contextIsolation: false
}
});
const attachPromise = emittedOnce(w.webContents, 'did-attach-webview');
const readyPromise = emittedOnce(ipcMain, 'webview-ready');
w.loadFile(path.join(__dirname, 'fixtures', 'webview', 'fullscreen', 'main.html'));
const [, webview] = await attachPromise;
await readyPromise;
return [w, webview];
};
afterEach(closeAllWindows);
it('should make parent frame element fullscreen too', async () => {
const [w, webview] = await loadWebViewWindow();
expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.false();
const parentFullscreen = emittedOnce(ipcMain, 'fullscreenchange');
await webview.executeJavaScript('document.getElementById("div").requestFullscreen()', true);
await parentFullscreen;
expect(await w.webContents.executeJavaScript('isIframeFullscreen()')).to.be.true();
});
});
describe('nativeWindowOpen option', () => {
let w: BrowserWindow;
beforeEach(async () => {