Skip to content

Commit

Permalink
fix: webview should maximize on requestFullscreen (#29988)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
3 people committed Jul 5, 2021
1 parent 1f21dfd commit f1f9a76
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 4 deletions.
1 change: 1 addition & 0 deletions patches/chromium/.patches
Expand Up @@ -137,3 +137,4 @@ cherry-pick-b77b38a3380c.patch
cherry-pick-910e9e40d376.patch
cherry-pick-d9556a80a790.patch
cherry-pick-ee6aee64e24c.patch
webview_fullscreen.patch
35 changes: 35 additions & 0 deletions patches/chromium/webview_fullscreen.patch
@@ -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));
38 changes: 35 additions & 3 deletions shell/browser/api/electron_api_web_contents.cc
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
}

Expand All @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions shell/browser/api/electron_api_web_contents.h
Expand Up @@ -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_;
Expand Down
1 change: 0 additions & 1 deletion shell/browser/web_view_manager.h
Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions spec-main/fixtures/webview/fullscreen/frame.html
@@ -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>
12 changes: 12 additions & 0 deletions spec-main/fixtures/webview/fullscreen/main.html
@@ -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>
30 changes: 30 additions & 0 deletions spec-main/webview-spec.ts
Expand Up @@ -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 () => {
Expand Down

0 comments on commit f1f9a76

Please sign in to comment.