diff --git a/patches/chromium/.patches b/patches/chromium/.patches index bcd042cdb48de..1a8187135442b 100644 --- a/patches/chromium/.patches +++ b/patches/chromium/.patches @@ -89,6 +89,7 @@ export_gin_v8platform_pageallocator_for_usage_outside_of_the_gin.patch fix_export_zlib_symbols.patch don_t_use_potentially_null_getwebframe_-_view_when_get_blink.patch web_contents.patch +webview_fullscreen.patch disable_unload_metrics.patch fix_add_check_for_sandbox_then_result.patch extend_apply_webpreferences.patch diff --git a/patches/chromium/webview_fullscreen.patch b/patches/chromium/webview_fullscreen.patch new file mode 100644 index 0000000000000..44483526b7d84 --- /dev/null +++ b/patches/chromium/webview_fullscreen.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cheng Zhao +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 5c16a9ee9bbf461c24456613ff709f4f608e3441..4e4d1fdf50e2d480e099c9af71a45fc864d2cf56 100644 +--- a/content/browser/renderer_host/render_frame_host_impl.cc ++++ b/content/browser/renderer_host/render_frame_host_impl.cc +@@ -5520,6 +5520,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)); diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index dc829a4977c4d..e383371bbb11a 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -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" @@ -3552,13 +3553,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; } @@ -3573,10 +3574,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 WebContents::FillObjectTemplate( v8::Isolate* isolate, diff --git a/shell/browser/api/electron_api_web_contents.h b/shell/browser/api/electron_api_web_contents.h index 0978a6d5713c7..2cd7a03166d5c 100644 --- a/shell/browser/api/electron_api_web_contents.h +++ b/shell/browser/api/electron_api_web_contents.h @@ -685,6 +685,8 @@ class WebContents : public gin::Wrappable, // 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 session_; v8::Global devtools_web_contents_; diff --git a/shell/browser/web_view_manager.h b/shell/browser/web_view_manager.h index c0da183745101..695a29ed403cd 100644 --- a/shell/browser/web_view_manager.h +++ b/shell/browser/web_view_manager.h @@ -24,7 +24,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; diff --git a/spec-main/fixtures/webview/fullscreen/frame.html b/spec-main/fixtures/webview/fullscreen/frame.html new file mode 100644 index 0000000000000..c92571eef4a8b --- /dev/null +++ b/spec-main/fixtures/webview/fullscreen/frame.html @@ -0,0 +1,12 @@ + +
+ WebView +
+ + diff --git a/spec-main/fixtures/webview/fullscreen/main.html b/spec-main/fixtures/webview/fullscreen/main.html new file mode 100644 index 0000000000000..aeb460578f97d --- /dev/null +++ b/spec-main/fixtures/webview/fullscreen/main.html @@ -0,0 +1,12 @@ + + + + diff --git a/spec-main/webview-spec.ts b/spec-main/webview-spec.ts index d89adb141df4a..dfbfcdf0bbbd6 100644 --- a/spec-main/webview-spec.ts +++ b/spec-main/webview-spec.ts @@ -378,6 +378,36 @@ describe(' 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 () => {