fix: webview should maximize on requestFullscreen (#29987)

* fix: webview should maximize on requestFullscreen

* 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 14:36:39 -04:00
committed by GitHub
parent ddc44e1af4
commit fc75bf0a9e
8 changed files with 127 additions and 4 deletions

View File

@@ -102,6 +102,7 @@ fix_export_zlib_symbols.patch
don_t_use_potentially_null_getwebframe_-_view_when_get_blink.patch
web_contents.patch
fix_route_mouse_event_navigations_through_the_web_contents_delegate.patch
webview_fullscreen.patch
disable_unload_metrics.patch
fix_add_check_for_sandbox_then_result.patch
moves_background_color_setter_of_webview_to_blinks_webprefs_logic.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 59d855ec17efe9117ee9bca5074b1ab28dfb40fa..4af3384ebbd000926a1f7606511fd6b94dc8aabe 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -4844,6 +4844,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"
@@ -3563,13 +3564,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;
}
@@ -3584,10 +3585,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

@@ -695,6 +695,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 () => {