diff --git a/include/capi/cef_display_handler_capi.h b/include/capi/cef_display_handler_capi.h index b93421de4..2b53b9845 100644 --- a/include/capi/cef_display_handler_capi.h +++ b/include/capi/cef_display_handler_capi.h @@ -33,7 +33,7 @@ // by hand. See the translator.README.txt file in the tools directory for // more information. // -// $hash=1de3354bd0a042cc28199f1f56753b1df9e279a2$ +// $hash=5374127458a7cac3ee9b4d2b4ad8a6f5ca81ec52$ // #ifndef CEF_INCLUDE_CAPI_CEF_DISPLAY_HANDLER_CAPI_H_ @@ -84,8 +84,13 @@ typedef struct _cef_display_handler_t { /// Called when web content in the page has toggled fullscreen mode. If /// |fullscreen| is true (1) the content will automatically be sized to fill /// the browser content area. If |fullscreen| is false (0) the content will - /// automatically return to its original size and position. The client is - /// responsible for resizing the browser if desired. + /// automatically return to its original size and position. With the Alloy + /// runtime the client is responsible for triggering the fullscreen transition + /// (for example, by calling cef_window_t::SetFullscreen when using Views). + /// With the Chrome runtime the fullscreen transition will be triggered + /// automatically. The cef_window_delegate_t::OnWindowFullscreenTransition + /// function will be called during the fullscreen transition for notification + /// purposes. /// void(CEF_CALLBACK* on_fullscreen_mode_change)( struct _cef_display_handler_t* self, diff --git a/include/capi/views/cef_window_capi.h b/include/capi/views/cef_window_capi.h index 4aae64845..e5e04e83e 100644 --- a/include/capi/views/cef_window_capi.h +++ b/include/capi/views/cef_window_capi.h @@ -33,7 +33,7 @@ // by hand. See the translator.README.txt file in the tools directory for // more information. // -// $hash=d53c4a0a7e731a56a0edcb9d705c76b0a2770155$ +// $hash=4b43fe0b493d860e8b28d7a6d892db49d1135b34$ // #ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_WINDOW_CAPI_H_ @@ -155,7 +155,9 @@ typedef struct _cef_window_t { void(CEF_CALLBACK* restore)(struct _cef_window_t* self); /// - /// Set fullscreen Window state. + /// Set fullscreen Window state. The + /// cef_window_delegate_t::OnWindowFullscreenTransition function will be + /// called during the fullscreen transition for notification purposes. /// void(CEF_CALLBACK* set_fullscreen)(struct _cef_window_t* self, int fullscreen); diff --git a/include/capi/views/cef_window_delegate_capi.h b/include/capi/views/cef_window_delegate_capi.h index 3f68aa8ff..2abeb4562 100644 --- a/include/capi/views/cef_window_delegate_capi.h +++ b/include/capi/views/cef_window_delegate_capi.h @@ -33,7 +33,7 @@ // by hand. See the translator.README.txt file in the tools directory for // more information. // -// $hash=61099a1ba8b16a5e46f5a80d326d1f9bfc99317d$ +// $hash=456f00f7afbac910cf36feecd38399a2fb16960d$ // #ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_WINDOW_DELEGATE_CAPI_H_ @@ -96,6 +96,20 @@ typedef struct _cef_window_delegate_t { struct _cef_window_t* window, const cef_rect_t* new_bounds); + /// + /// Called when |window| is transitioning to or from fullscreen mode. On MacOS + /// the transition occurs asynchronously with |is_competed| set to false (0) + /// when the transition starts and true (1) after the transition completes. On + /// other platforms the transition occurs synchronously with |is_completed| + /// set to true (1) after the transition completes. With the Alloy runtime you + /// must also implement cef_display_handler_t::OnFullscreenModeChange to + /// handle fullscreen transitions initiated by browser content. + /// + void(CEF_CALLBACK* on_window_fullscreen_transition)( + struct _cef_window_delegate_t* self, + struct _cef_window_t* window, + int is_completed); + /// /// Return the parent for |window| or NULL if the |window| does not have a /// parent. Windows with parents will not get a taskbar button. Set |is_menu| @@ -210,17 +224,6 @@ typedef struct _cef_window_delegate_t { int(CEF_CALLBACK* on_key_event)(struct _cef_window_delegate_t* self, struct _cef_window_t* window, const cef_key_event_t* event); - - /// - /// Called when the |window| is transitioning to or from fullscreen mode. The - /// transition occurs in two stages, with |is_competed| set to false (0) when - /// the transition starts and true (1) when the transition completes. This - /// function is only supported on macOS. - /// - void(CEF_CALLBACK* on_window_fullscreen_transition)( - struct _cef_window_delegate_t* self, - struct _cef_window_t* window, - int is_completed); } cef_window_delegate_t; #ifdef __cplusplus diff --git a/include/cef_api_hash.h b/include/cef_api_hash.h index 28c5c32f8..37f2ff532 100644 --- a/include/cef_api_hash.h +++ b/include/cef_api_hash.h @@ -42,13 +42,13 @@ // way that may cause binary incompatibility with other builds. The universal // hash value will change if any platform is affected whereas the platform hash // values will change only if that particular platform is affected. -#define CEF_API_HASH_UNIVERSAL "8aa786740cdcadf7b4f6dd3554343abae09ffdfd" +#define CEF_API_HASH_UNIVERSAL "c684c3da478cb88b042bf13c88ab7797e33c29bc" #if defined(OS_WIN) -#define CEF_API_HASH_PLATFORM "f241d73d66f3b7f99aae58a0cc99be36beda4f4f" +#define CEF_API_HASH_PLATFORM "bcc26a8181330fd0dc07e9d2475c048919d4f55f" #elif defined(OS_MAC) -#define CEF_API_HASH_PLATFORM "3708f34f956e6306d09989a88ff1dee9c8f7a2b5" +#define CEF_API_HASH_PLATFORM "2abec7e306f2c474c8a66b585b9c6a0bdcd45276" #elif defined(OS_LINUX) -#define CEF_API_HASH_PLATFORM "cf413edb4edeb80d7d5c1173e342231b26808fce" +#define CEF_API_HASH_PLATFORM "b93f84208be4af554a5b60315a63251263a71e57" #endif #ifdef __cplusplus diff --git a/include/cef_display_handler.h b/include/cef_display_handler.h index 0b6980800..3b776b416 100644 --- a/include/cef_display_handler.h +++ b/include/cef_display_handler.h @@ -75,8 +75,12 @@ class CefDisplayHandler : public virtual CefBaseRefCounted { /// Called when web content in the page has toggled fullscreen mode. If /// |fullscreen| is true the content will automatically be sized to fill the /// browser content area. If |fullscreen| is false the content will - /// automatically return to its original size and position. The client is - /// responsible for resizing the browser if desired. + /// automatically return to its original size and position. With the Alloy + /// runtime the client is responsible for triggering the fullscreen transition + /// (for example, by calling CefWindow::SetFullscreen when using Views). With + /// the Chrome runtime the fullscreen transition will be triggered + /// automatically. The CefWindowDelegate::OnWindowFullscreenTransition method + /// will be called during the fullscreen transition for notification purposes. /// /*--cef()--*/ virtual void OnFullscreenModeChange(CefRefPtr browser, diff --git a/include/views/cef_window.h b/include/views/cef_window.h index 4c8ad09b0..ec3843b25 100644 --- a/include/views/cef_window.h +++ b/include/views/cef_window.h @@ -165,7 +165,9 @@ class CefWindow : public CefPanel { virtual void Restore() = 0; /// - /// Set fullscreen Window state. + /// Set fullscreen Window state. The + /// CefWindowDelegate::OnWindowFullscreenTransition method will be called + /// during the fullscreen transition for notification purposes. /// /*--cef()--*/ virtual void SetFullscreen(bool fullscreen) = 0; diff --git a/include/views/cef_window_delegate.h b/include/views/cef_window_delegate.h index 3b4e80f9e..6c0f239a4 100644 --- a/include/views/cef_window_delegate.h +++ b/include/views/cef_window_delegate.h @@ -84,6 +84,19 @@ class CefWindowDelegate : public CefPanelDelegate { virtual void OnWindowBoundsChanged(CefRefPtr window, const CefRect& new_bounds) {} + /// + /// Called when |window| is transitioning to or from fullscreen mode. On MacOS + /// the transition occurs asynchronously with |is_competed| set to false when + /// the transition starts and true after the transition completes. On other + /// platforms the transition occurs synchronously with |is_completed| set to + /// true after the transition completes. With the Alloy runtime you must also + /// implement CefDisplayHandler::OnFullscreenModeChange to handle fullscreen + /// transitions initiated by browser content. + /// + /*--cef()--*/ + virtual void OnWindowFullscreenTransition(CefRefPtr window, + bool is_completed) {} + /// /// Return the parent for |window| or NULL if the |window| does not have a /// parent. Windows with parents will not get a taskbar button. Set |is_menu| @@ -209,16 +222,6 @@ class CefWindowDelegate : public CefPanelDelegate { const CefKeyEvent& event) { return false; } - - /// - /// Called when the |window| is transitioning to or from fullscreen mode. The - /// transition occurs in two stages, with |is_competed| set to false when the - /// transition starts and true when the transition completes. - /// This method is only supported on macOS. - /// - /*--cef()--*/ - virtual void OnWindowFullscreenTransition(CefRefPtr window, - bool is_completed) {} }; #endif // CEF_INCLUDE_VIEWS_CEF_WINDOW_DELEGATE_H_ diff --git a/libcef/browser/chrome/browser_delegate.h b/libcef/browser/chrome/browser_delegate.h index 8f56cc487..12f5fd07b 100644 --- a/libcef/browser/chrome/browser_delegate.h +++ b/libcef/browser/chrome/browser_delegate.h @@ -126,6 +126,9 @@ class BrowserDelegate : public content::WebContentsDelegate { // Set the draggable region relative to web contents. // Called from DraggableRegionsHostImpl::UpdateDraggableRegions. virtual void UpdateDraggableRegion(const SkRegion& region) {} + + // Called at the end of a fullscreen transition. + virtual void WindowFullscreenStateChanged() {} }; } // namespace cef diff --git a/libcef/browser/chrome/chrome_browser_delegate.cc b/libcef/browser/chrome/chrome_browser_delegate.cc index dcf4402dc..386c6ce84 100644 --- a/libcef/browser/chrome/chrome_browser_delegate.cc +++ b/libcef/browser/chrome/chrome_browser_delegate.cc @@ -15,6 +15,7 @@ #include "libcef/browser/media_access_query.h" #include "libcef/browser/request_context_impl.h" #include "libcef/browser/views/browser_view_impl.h" +#include "libcef/browser/views/window_impl.h" #include "libcef/common/app_manager.h" #include "libcef/common/frame_util.h" @@ -257,6 +258,23 @@ void ChromeBrowserDelegate::UpdateDraggableRegion(const SkRegion& region) { draggable_region_ = region; } +void ChromeBrowserDelegate::WindowFullscreenStateChanged() { + // Use a synchronous callback for notification on Windows/Linux. MacOS gets + // notified asynchronously via CefNativeWidgetMac callbacks. +#if !BUILDFLAG(IS_MAC) + if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) { + if (auto chrome_browser_view = browser->chrome_browser_view()) { + auto* cef_window = chrome_browser_view->cef_browser_view()->cef_window(); + if (auto* delegate = cef_window->delegate()) { + // Give the CefWindowDelegate a chance to handle the event. + delegate->OnWindowFullscreenTransition(cef_window, + /*is_completed=*/true); + } + } + } +#endif +} + void ChromeBrowserDelegate::WebContentsCreated( content::WebContents* source_contents, int opener_render_process_id, diff --git a/libcef/browser/chrome/chrome_browser_delegate.h b/libcef/browser/chrome/chrome_browser_delegate.h index 460c1a444..9a70d3687 100644 --- a/libcef/browser/chrome/chrome_browser_delegate.h +++ b/libcef/browser/chrome/chrome_browser_delegate.h @@ -70,6 +70,7 @@ class ChromeBrowserDelegate : public cef::BrowserDelegate { bool SupportsDraggableRegion() const override; const absl::optional GetDraggableRegion() const override; void UpdateDraggableRegion(const SkRegion& region) override; + void WindowFullscreenStateChanged() override; // WebContentsDelegate methods: void WebContentsCreated(content::WebContents* source_contents, diff --git a/libcef/browser/chrome/views/chrome_browser_frame.cc b/libcef/browser/chrome/views/chrome_browser_frame.cc index d9bfe3370..c6eae43f5 100644 --- a/libcef/browser/chrome/views/chrome_browser_frame.cc +++ b/libcef/browser/chrome/views/chrome_browser_frame.cc @@ -6,6 +6,7 @@ #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/views/frame/browser_view.h" #if BUILDFLAG(IS_MAC) @@ -17,10 +18,10 @@ void ChromeBrowserFrame::Init(BrowserView* browser_view, std::unique_ptr browser) { DCHECK(browser_view); + DCHECK(browser); - DCHECK(!browser_); - browser_ = browser.get(); - DCHECK(browser_); + DCHECK(!browser_view_); + browser_view_ = browser_view; // Initialize BrowserFrame state. InitBrowserView(browser_view); @@ -42,6 +43,10 @@ void ChromeBrowserFrame::Init(BrowserView* browser_view, #endif // BUILDFLAG(IS_MAC) } +void ChromeBrowserFrame::ToggleFullscreenMode() { + chrome::ToggleFullscreenMode(browser_view_->browser()); +} + views::internal::RootView* ChromeBrowserFrame::CreateRootView() { // Bypass the BrowserFrame implementation. return views::Widget::CreateRootView(); diff --git a/libcef/browser/chrome/views/chrome_browser_frame.h b/libcef/browser/chrome/views/chrome_browser_frame.h index 472c1ef9b..e8ffa3bd7 100644 --- a/libcef/browser/chrome/views/chrome_browser_frame.h +++ b/libcef/browser/chrome/views/chrome_browser_frame.h @@ -97,13 +97,17 @@ class ChromeBrowserFrame : public BrowserFrame { void Init(BrowserView* browser_view, std::unique_ptr browser); + void ToggleFullscreenMode(); + // views::Widget methods: views::internal::RootView* CreateRootView() override; std::unique_ptr CreateNonClientFrameView() override; + BrowserView* browser_view() const { return browser_view_; } + private: - Browser* browser_ = nullptr; + BrowserView* browser_view_ = nullptr; }; #endif // CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_BROWSER_FRAME_H_ diff --git a/libcef/browser/views/browser_view_impl.cc b/libcef/browser/views/browser_view_impl.cc index d90a14cfe..ddce105d0 100644 --- a/libcef/browser/views/browser_view_impl.cc +++ b/libcef/browser/views/browser_view_impl.cc @@ -141,10 +141,7 @@ bool CefBrowserViewImpl::HandleKeyboardEvent( } // Give the CefWindowDelegate a chance to handle the event. - CefRefPtr window = - view_util::GetWindowFor(root_view()->GetWidget()); - CefWindowImpl* window_impl = static_cast(window.get()); - if (window_impl) { + if (auto* window_impl = cef_window()) { CefKeyEvent cef_event; if (browser_util::GetCefKeyEvent(event, cef_event) && window_impl->OnKeyEvent(cef_event)) { @@ -319,6 +316,12 @@ ChromeBrowserView* CefBrowserViewImpl::chrome_browser_view() const { return static_cast(root_view()); } +CefWindowImpl* CefBrowserViewImpl::cef_window() const { + CefRefPtr window = + view_util::GetWindowFor(root_view()->GetWidget()); + return static_cast(window.get()); +} + bool CefBrowserViewImpl::HandleAccelerator( const content::NativeWebKeyboardEvent& event, views::FocusManager* focus_manager) { diff --git a/libcef/browser/views/browser_view_impl.h b/libcef/browser/views/browser_view_impl.h index 588d10ea3..74562806b 100644 --- a/libcef/browser/views/browser_view_impl.h +++ b/libcef/browser/views/browser_view_impl.h @@ -18,6 +18,7 @@ #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h" class CefBrowserHostBase; +class CefWindowImpl; class ChromeBrowserView; class CefBrowserViewImpl @@ -83,6 +84,9 @@ class CefBrowserViewImpl // Return the CEF specialization of BrowserView. ChromeBrowserView* chrome_browser_view() const; + // Return the CefWindowImpl hosting this object. + CefWindowImpl* cef_window() const; + private: // Create a new implementation object. // Always call Initialize() after creation. diff --git a/libcef/browser/views/native_widget_mac.h b/libcef/browser/views/native_widget_mac.h index e1b6bf90e..1bd8aa110 100644 --- a/libcef/browser/views/native_widget_mac.h +++ b/libcef/browser/views/native_widget_mac.h @@ -48,6 +48,9 @@ class CefNativeWidgetMac : public views::NativeWidgetMac { const CefRefPtr window_; CefWindowDelegate* const window_delegate_; + // Returns true if the CefWindow is fully initialized. + bool IsCefWindowInitialized() const; + BrowserView* browser_view_ = nullptr; }; diff --git a/libcef/browser/views/native_widget_mac.mm b/libcef/browser/views/native_widget_mac.mm index 73878f30c..ae648a23f 100644 --- a/libcef/browser/views/native_widget_mac.mm +++ b/libcef/browser/views/native_widget_mac.mm @@ -7,6 +7,7 @@ #include "include/views/cef_window.h" #include "include/views/cef_window_delegate.h" #include "libcef/browser/views/ns_window.h" +#include "libcef/browser/views/window_impl.h" #include "chrome/browser/apps/app_shim/app_shim_host_mac.h" #include "chrome/browser/apps/app_shim/app_shim_manager_mac.h" @@ -118,12 +119,16 @@ void CefNativeWidgetMac::GetWindowFrameTitlebarHeight( void CefNativeWidgetMac::OnWindowFullscreenTransitionStart() { views::NativeWidgetMac::OnWindowFullscreenTransitionStart(); - window_delegate_->OnWindowFullscreenTransition(window_, false); + if (IsCefWindowInitialized()) { + window_delegate_->OnWindowFullscreenTransition(window_, false); + } } void CefNativeWidgetMac::OnWindowFullscreenTransitionComplete() { views::NativeWidgetMac::OnWindowFullscreenTransitionComplete(); - window_delegate_->OnWindowFullscreenTransition(window_, true); + if (IsCefWindowInitialized()) { + window_delegate_->OnWindowFullscreenTransition(window_, true); + } } void CefNativeWidgetMac::OnWindowInitialized() { @@ -142,3 +147,7 @@ void CefNativeWidgetMac::OnWindowInitialized() { } } } + +bool CefNativeWidgetMac::IsCefWindowInitialized() const { + return static_cast(window_.get())->initialized(); +} diff --git a/libcef/browser/views/window_impl.cc b/libcef/browser/views/window_impl.cc index e562f0d01..3da94b08a 100644 --- a/libcef/browser/views/window_impl.cc +++ b/libcef/browser/views/window_impl.cc @@ -5,6 +5,7 @@ #include "libcef/browser/views/window_impl.h" #include "libcef/browser/browser_util.h" +#include "libcef/browser/chrome/views/chrome_browser_frame.h" #include "libcef/browser/thread_util.h" #include "libcef/browser/views/browser_view_impl.h" #include "libcef/browser/views/display_impl.h" @@ -12,6 +13,7 @@ #include "libcef/browser/views/layout_util.h" #include "libcef/browser/views/view_util.h" #include "libcef/browser/views/window_view.h" +#include "libcef/features/runtime.h" #include "base/i18n/rtl.h" #include "components/constrained_window/constrained_window_views.h" @@ -116,9 +118,6 @@ CefRefPtr CefWindowImpl::Create( CefRefPtr window = new CefWindowImpl(delegate); window->Initialize(); window->CreateWidget(parent_widget); - if (delegate) { - delegate->OnWindowCreated(window.get()); - } return window; } @@ -253,7 +252,29 @@ void CefWindowImpl::Restore() { void CefWindowImpl::SetFullscreen(bool fullscreen) { CEF_REQUIRE_VALID_RETURN_VOID(); if (widget_ && fullscreen != widget_->IsFullscreen()) { + if (cef::IsChromeRuntimeEnabled()) { + // If a BrowserView exists, toggle fullscreen mode via the Chrome command + // for consistent behavior. + auto* browser_frame = static_cast(widget_); + if (browser_frame->browser_view()) { + browser_frame->ToggleFullscreenMode(); + return; + } + } + + // Call the Widget method directly with Alloy runtime, or Chrome runtime + // when no BrowserView exists. widget_->SetFullscreen(fullscreen); + + // Use a synchronous callback notification on Windows/Linux. Chrome runtime + // on Windows/Linux gets notified synchronously via ChromeBrowserDelegate + // callbacks when a BrowserView exists. MacOS (both runtimes) gets notified + // asynchronously via CefNativeWidgetMac callbacks. +#if !BUILDFLAG(IS_MAC) + if (delegate()) { + delegate()->OnWindowFullscreenTransition(this, /*is_completed=*/true); + } +#endif } } @@ -714,7 +735,7 @@ void CefWindowImpl::RemoveAllAccelerators() { } CefWindowImpl::CefWindowImpl(CefRefPtr delegate) - : ParentClass(delegate), widget_(nullptr), destroyed_(false) {} + : ParentClass(delegate) {} CefWindowView* CefWindowImpl::CreateRootView() { return new CefWindowView(delegate(), this); @@ -740,4 +761,10 @@ void CefWindowImpl::CreateWidget(gfx::AcceleratedWidget parent_widget) { // keep an owned reference. std::unique_ptr view_ptr = view_util::PassOwnership(this); [[maybe_unused]] views::View* view = view_ptr.release(); + + initialized_ = true; + + if (delegate()) { + delegate()->OnWindowCreated(this); + } } diff --git a/libcef/browser/views/window_impl.h b/libcef/browser/views/window_impl.h index ea71c9500..fae0ae832 100644 --- a/libcef/browser/views/window_impl.h +++ b/libcef/browser/views/window_impl.h @@ -132,6 +132,7 @@ class CefWindowImpl void MenuClosed(); views::Widget* widget() const { return widget_; } + bool initialized() const { return initialized_; } private: // Create a new implementation object. @@ -146,10 +147,13 @@ class CefWindowImpl // Initialize the Widget. void CreateWidget(gfx::AcceleratedWidget parent_widget); - views::Widget* widget_; + views::Widget* widget_ = nullptr; + + // True if the window has been initialized. + bool initialized_ = false; // True if the window has been destroyed. - bool destroyed_; + bool destroyed_ = false; // The currently active menu model and runner. CefRefPtr menu_model_; diff --git a/libcef_dll/cpptoc/views/window_delegate_cpptoc.cc b/libcef_dll/cpptoc/views/window_delegate_cpptoc.cc index 0904b0986..bc0335e5d 100644 --- a/libcef_dll/cpptoc/views/window_delegate_cpptoc.cc +++ b/libcef_dll/cpptoc/views/window_delegate_cpptoc.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=10ec416d3aeba7215b08604b1a329adc1c9aaf6f$ +// $hash=61afa22f2b3401bab08c3faeb872e3de7a99ca5b$ // #include "libcef_dll/cpptoc/views/window_delegate_cpptoc.h" @@ -141,6 +141,29 @@ window_delegate_on_window_bounds_changed(struct _cef_window_delegate_t* self, CefWindowCToCpp::Wrap(window), new_boundsVal); } +void CEF_CALLBACK window_delegate_on_window_fullscreen_transition( + struct _cef_window_delegate_t* self, + cef_window_t* window, + int is_completed) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) { + return; + } + // Verify param: window; type: refptr_diff + DCHECK(window); + if (!window) { + return; + } + + // Execute + CefWindowDelegateCppToC::Get(self)->OnWindowFullscreenTransition( + CefWindowCToCpp::Wrap(window), is_completed ? true : false); +} + cef_window_t* CEF_CALLBACK window_delegate_get_parent_window(struct _cef_window_delegate_t* self, cef_window_t* window, @@ -509,29 +532,6 @@ window_delegate_on_key_event(struct _cef_window_delegate_t* self, return _retval; } -void CEF_CALLBACK window_delegate_on_window_fullscreen_transition( - struct _cef_window_delegate_t* self, - cef_window_t* window, - int is_completed) { - shutdown_checker::AssertNotShutdown(); - - // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING - - DCHECK(self); - if (!self) { - return; - } - // Verify param: window; type: refptr_diff - DCHECK(window); - if (!window) { - return; - } - - // Execute - CefWindowDelegateCppToC::Get(self)->OnWindowFullscreenTransition( - CefWindowCToCpp::Wrap(window), is_completed ? true : false); -} - cef_size_t CEF_CALLBACK window_delegate_get_preferred_size(struct _cef_view_delegate_t* self, cef_view_t* view) { @@ -805,6 +805,8 @@ CefWindowDelegateCppToC::CefWindowDelegateCppToC() { window_delegate_on_window_activation_changed; GetStruct()->on_window_bounds_changed = window_delegate_on_window_bounds_changed; + GetStruct()->on_window_fullscreen_transition = + window_delegate_on_window_fullscreen_transition; GetStruct()->get_parent_window = window_delegate_get_parent_window; GetStruct()->is_window_modal_dialog = window_delegate_is_window_modal_dialog; GetStruct()->get_initial_bounds = window_delegate_get_initial_bounds; @@ -819,8 +821,6 @@ CefWindowDelegateCppToC::CefWindowDelegateCppToC() { GetStruct()->can_close = window_delegate_can_close; GetStruct()->on_accelerator = window_delegate_on_accelerator; GetStruct()->on_key_event = window_delegate_on_key_event; - GetStruct()->on_window_fullscreen_transition = - window_delegate_on_window_fullscreen_transition; GetStruct()->base.base.get_preferred_size = window_delegate_get_preferred_size; GetStruct()->base.base.get_minimum_size = window_delegate_get_minimum_size; diff --git a/libcef_dll/ctocpp/views/window_delegate_ctocpp.cc b/libcef_dll/ctocpp/views/window_delegate_ctocpp.cc index a7ec62658..2dae99e7a 100644 --- a/libcef_dll/ctocpp/views/window_delegate_ctocpp.cc +++ b/libcef_dll/ctocpp/views/window_delegate_ctocpp.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=12bd03a8fb7d680a4e2b1a6818313c29bf14f011$ +// $hash=bb69763a25cd013a50504d762a81c0a4454ce8eb$ // #include "libcef_dll/ctocpp/views/window_delegate_ctocpp.h" @@ -129,6 +129,30 @@ void CefWindowDelegateCToCpp::OnWindowBoundsChanged(CefRefPtr window, &new_bounds); } +NO_SANITIZE("cfi-icall") +void CefWindowDelegateCToCpp::OnWindowFullscreenTransition( + CefRefPtr window, + bool is_completed) { + shutdown_checker::AssertNotShutdown(); + + cef_window_delegate_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, on_window_fullscreen_transition)) { + return; + } + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: window; type: refptr_diff + DCHECK(window.get()); + if (!window.get()) { + return; + } + + // Execute + _struct->on_window_fullscreen_transition( + _struct, CefWindowCppToC::Wrap(window), is_completed); +} + NO_SANITIZE("cfi-icall") CefRefPtr CefWindowDelegateCToCpp::GetParentWindow( CefRefPtr window, @@ -487,30 +511,6 @@ bool CefWindowDelegateCToCpp::OnKeyEvent(CefRefPtr window, return _retval ? true : false; } -NO_SANITIZE("cfi-icall") -void CefWindowDelegateCToCpp::OnWindowFullscreenTransition( - CefRefPtr window, - bool is_completed) { - shutdown_checker::AssertNotShutdown(); - - cef_window_delegate_t* _struct = GetStruct(); - if (CEF_MEMBER_MISSING(_struct, on_window_fullscreen_transition)) { - return; - } - - // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING - - // Verify param: window; type: refptr_diff - DCHECK(window.get()); - if (!window.get()) { - return; - } - - // Execute - _struct->on_window_fullscreen_transition( - _struct, CefWindowCppToC::Wrap(window), is_completed); -} - NO_SANITIZE("cfi-icall") CefSize CefWindowDelegateCToCpp::GetPreferredSize(CefRefPtr view) { shutdown_checker::AssertNotShutdown(); diff --git a/libcef_dll/ctocpp/views/window_delegate_ctocpp.h b/libcef_dll/ctocpp/views/window_delegate_ctocpp.h index b11aa6449..fe005af95 100644 --- a/libcef_dll/ctocpp/views/window_delegate_ctocpp.h +++ b/libcef_dll/ctocpp/views/window_delegate_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=25487f4d82069d1e4c0c7b27c1c1fcbcebbbacea$ +// $hash=e1ed42bb378f9f140e006ec582c0e908f711e7fa$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_WINDOW_DELEGATE_CTOCPP_H_ @@ -44,6 +44,8 @@ class CefWindowDelegateCToCpp bool active) override; void OnWindowBoundsChanged(CefRefPtr window, const CefRect& new_bounds) override; + void OnWindowFullscreenTransition(CefRefPtr window, + bool is_completed) override; CefRefPtr GetParentWindow(CefRefPtr window, bool* is_menu, bool* can_activate_menu) override; @@ -61,8 +63,6 @@ class CefWindowDelegateCToCpp bool OnAccelerator(CefRefPtr window, int command_id) override; bool OnKeyEvent(CefRefPtr window, const CefKeyEvent& event) override; - void OnWindowFullscreenTransition(CefRefPtr window, - bool is_completed) override; // CefPanelDelegate methods. diff --git a/patch/patches/chrome_browser_browser.patch b/patch/patches/chrome_browser_browser.patch index 1c24a7e9d..212077eec 100644 --- a/patch/patches/chrome_browser_browser.patch +++ b/patch/patches/chrome_browser_browser.patch @@ -70,7 +70,7 @@ index aaaab0d2783ad..c97e5091c6e9f 100644 ] } diff --git chrome/browser/ui/browser.cc chrome/browser/ui/browser.cc -index fdb96dee05067..7719f86fd4e0e 100644 +index fdb96dee05067..a188b6442b1ca 100644 --- chrome/browser/ui/browser.cc +++ chrome/browser/ui/browser.cc @@ -265,6 +265,25 @@ @@ -123,7 +123,16 @@ index fdb96dee05067..7719f86fd4e0e 100644 } /////////////////////////////////////////////////////////////////////////////// -@@ -1394,6 +1423,14 @@ content::KeyboardEventProcessingResult Browser::PreHandleKeyboardEvent( +@@ -1055,6 +1084,8 @@ void Browser::WindowFullscreenStateChanged() { + ->WindowFullscreenStateChanged(); + command_controller_->FullscreenStateChanged(); + UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TOGGLE_FULLSCREEN); ++ ++ CALL_CEF_DELEGATE(WindowFullscreenStateChanged); + } + + void Browser::FullscreenTopUIStateChanged() { +@@ -1394,6 +1425,14 @@ content::KeyboardEventProcessingResult Browser::PreHandleKeyboardEvent( if (exclusive_access_manager_->HandleUserKeyEvent(event)) return content::KeyboardEventProcessingResult::HANDLED; @@ -138,7 +147,7 @@ index fdb96dee05067..7719f86fd4e0e 100644 return window()->PreHandleKeyboardEvent(event); } -@@ -1401,8 +1438,18 @@ bool Browser::HandleKeyboardEvent(content::WebContents* source, +@@ -1401,8 +1440,18 @@ bool Browser::HandleKeyboardEvent(content::WebContents* source, const NativeWebKeyboardEvent& event) { DevToolsWindow* devtools_window = DevToolsWindow::GetInstanceForInspectedWebContents(source); @@ -159,7 +168,7 @@ index fdb96dee05067..7719f86fd4e0e 100644 } bool Browser::TabsNeedBeforeUnloadFired() { -@@ -1613,6 +1660,14 @@ WebContents* Browser::OpenURLFromTab(WebContents* source, +@@ -1613,6 +1662,14 @@ WebContents* Browser::OpenURLFromTab(WebContents* source, } #endif // BUILDFLAG(IS_CHROMEOS_ASH) @@ -174,7 +183,7 @@ index fdb96dee05067..7719f86fd4e0e 100644 NavigateParams nav_params(this, params.url, params.transition); nav_params.FillNavigateParamsFromOpenURLParams(params); nav_params.source_contents = source; -@@ -1770,6 +1825,8 @@ void Browser::LoadingStateChanged(WebContents* source, +@@ -1770,6 +1827,8 @@ void Browser::LoadingStateChanged(WebContents* source, bool should_show_loading_ui) { ScheduleUIUpdate(source, content::INVALIDATE_TYPE_LOAD); UpdateWindowForLoadingStateChanged(source, should_show_loading_ui); @@ -183,7 +192,7 @@ index fdb96dee05067..7719f86fd4e0e 100644 } void Browser::CloseContents(WebContents* source) { -@@ -1798,6 +1855,8 @@ void Browser::SetContentsBounds(WebContents* source, const gfx::Rect& bounds) { +@@ -1798,6 +1857,8 @@ void Browser::SetContentsBounds(WebContents* source, const gfx::Rect& bounds) { } void Browser::UpdateTargetURL(WebContents* source, const GURL& url) { @@ -192,7 +201,7 @@ index fdb96dee05067..7719f86fd4e0e 100644 if (!GetStatusBubble()) return; -@@ -1805,6 +1864,17 @@ void Browser::UpdateTargetURL(WebContents* source, const GURL& url) { +@@ -1805,6 +1866,17 @@ void Browser::UpdateTargetURL(WebContents* source, const GURL& url) { GetStatusBubble()->SetURL(url); } @@ -210,7 +219,7 @@ index fdb96dee05067..7719f86fd4e0e 100644 void Browser::ContentsMouseEvent(WebContents* source, bool motion, bool exited) { -@@ -1829,6 +1899,19 @@ bool Browser::TakeFocus(content::WebContents* source, bool reverse) { +@@ -1829,6 +1901,19 @@ bool Browser::TakeFocus(content::WebContents* source, bool reverse) { return false; } @@ -230,7 +239,7 @@ index fdb96dee05067..7719f86fd4e0e 100644 void Browser::BeforeUnloadFired(WebContents* web_contents, bool proceed, bool* proceed_to_fire_unload) { -@@ -1921,6 +2004,10 @@ void Browser::WebContentsCreated(WebContents* source_contents, +@@ -1921,6 +2006,10 @@ void Browser::WebContentsCreated(WebContents* source_contents, // Make the tab show up in the task manager. task_manager::WebContentsTags::CreateForTabContents(new_contents); @@ -241,7 +250,7 @@ index fdb96dee05067..7719f86fd4e0e 100644 } void Browser::PortalWebContentsCreated(WebContents* portal_web_contents) { -@@ -2038,11 +2125,15 @@ void Browser::EnterFullscreenModeForTab( +@@ -2038,11 +2127,15 @@ void Browser::EnterFullscreenModeForTab( const blink::mojom::FullscreenOptions& options) { exclusive_access_manager_->fullscreen_controller()->EnterFullscreenModeForTab( requesting_frame, options.display_id); @@ -257,7 +266,7 @@ index fdb96dee05067..7719f86fd4e0e 100644 } bool Browser::IsFullscreenForTabOrPending(const WebContents* web_contents) { -@@ -2232,6 +2323,15 @@ void Browser::RequestMediaAccessPermission( +@@ -2232,6 +2325,15 @@ void Browser::RequestMediaAccessPermission( content::WebContents* web_contents, const content::MediaStreamRequest& request, content::MediaResponseCallback callback) { @@ -273,7 +282,7 @@ index fdb96dee05067..7719f86fd4e0e 100644 const extensions::Extension* extension = GetExtensionForOrigin(profile_, request.security_origin); MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest( -@@ -2783,13 +2883,20 @@ void Browser::RemoveScheduledUpdatesFor(WebContents* contents) { +@@ -2783,13 +2885,20 @@ void Browser::RemoveScheduledUpdatesFor(WebContents* contents) { // Browser, Getters for UI (private): StatusBubble* Browser::GetStatusBubble() { @@ -295,7 +304,7 @@ index fdb96dee05067..7719f86fd4e0e 100644 return window_ ? window_->GetStatusBubble() : nullptr; } -@@ -2923,6 +3030,8 @@ void Browser::SetAsDelegate(WebContents* web_contents, bool set_delegate) { +@@ -2923,6 +3032,8 @@ void Browser::SetAsDelegate(WebContents* web_contents, bool set_delegate) { BookmarkTabHelper::FromWebContents(web_contents)->RemoveObserver(this); web_contents_collection_.StopObserving(web_contents); } @@ -304,7 +313,7 @@ index fdb96dee05067..7719f86fd4e0e 100644 } void Browser::TabDetachedAtImpl(content::WebContents* contents, -@@ -3077,6 +3186,14 @@ bool Browser::PictureInPictureBrowserSupportsWindowFeature( +@@ -3077,6 +3188,14 @@ bool Browser::PictureInPictureBrowserSupportsWindowFeature( bool Browser::SupportsWindowFeatureImpl(WindowFeature feature, bool check_can_support) const { diff --git a/tests/cefclient/browser/views_window.cc b/tests/cefclient/browser/views_window.cc index d81e95cab..7a57e7eaf 100644 --- a/tests/cefclient/browser/views_window.cc +++ b/tests/cefclient/browser/views_window.cc @@ -277,12 +277,18 @@ void ViewsWindow::SetFavicon(CefRefPtr image) { void ViewsWindow::SetFullscreen(bool fullscreen) { CEF_REQUIRE_UI_THREAD(); - if (window_) { - // Hide the top controls while in full-screen mode. - if (with_controls_) { - ShowTopControls(!fullscreen); - } + // For Chrome runtime we ignore this notification from + // ClientHandler::OnFullscreenModeChange(). Chrome runtime will trigger + // the fullscreen change internally and then call + // OnWindowFullscreenTransition(). + if (MainContext::Get()->UseChromeRuntime()) { + return; + } + + // For Alloy runtime we need to explicitly trigger the fullscreen change. + if (window_) { + // Results in a call to OnWindowFullscreenTransition(). window_->SetFullscreen(fullscreen); } } @@ -404,10 +410,12 @@ bool ViewsWindow::GetWindowRestorePreferences( show_state = CEF_SHOW_STATE_NORMAL; if (window_->IsMinimized()) { show_state = CEF_SHOW_STATE_MINIMIZED; + } else if (window_->IsFullscreen()) { + // On MacOS, IsMaximized() will also return true for fullscreen, so check + // IsFullscreen() first. + show_state = CEF_SHOW_STATE_FULLSCREEN; } else if (window_->IsMaximized()) { show_state = CEF_SHOW_STATE_MAXIMIZED; - } else if (window_->IsFullscreen()) { - show_state = CEF_SHOW_STATE_FULLSCREEN; } if (show_state == CEF_SHOW_STATE_NORMAL) { @@ -626,6 +634,25 @@ bool ViewsWindow::OnKeyEvent(CefRefPtr textfield, return false; } +void ViewsWindow::OnWindowFullscreenTransition(CefRefPtr window, + bool is_completed) { +#if defined(OS_MAC) + // On MacOS we get two asynchronous callbacks, and we want to change the UI on + // |is_completed=false| (e.g. when the fullscreen transition begins). + const bool should_change = !is_completed; +#else + // On other platforms we only get a single synchronous callback with + // |is_completed=true|. + DCHECK(is_completed); + const bool should_change = true; +#endif + + // Hide the top controls while in fullscreen mode. + if (should_change && with_controls_) { + ShowTopControls(!window->IsFullscreen()); + } +} + void ViewsWindow::OnWindowCreated(CefRefPtr window) { CEF_REQUIRE_UI_THREAD(); DCHECK(browser_view_); diff --git a/tests/cefclient/browser/views_window.h b/tests/cefclient/browser/views_window.h index 3b791c376..4855c8a55 100644 --- a/tests/cefclient/browser/views_window.h +++ b/tests/cefclient/browser/views_window.h @@ -188,6 +188,8 @@ class ViewsWindow : public CefBrowserViewDelegate, bool OnAccelerator(CefRefPtr window, int command_id) override; bool OnKeyEvent(CefRefPtr window, const CefKeyEvent& event) override; + void OnWindowFullscreenTransition(CefRefPtr window, + bool is_completed) override; // CefViewDelegate methods: CefSize GetPreferredSize(CefRefPtr view) override; diff --git a/tests/cefclient/browser/window_test.cc b/tests/cefclient/browser/window_test.cc index eb781b35e..68c27fb68 100644 --- a/tests/cefclient/browser/window_test.cc +++ b/tests/cefclient/browser/window_test.cc @@ -35,6 +35,7 @@ const char kMessagePositionName[] = "WindowTest.Position"; const char kMessageMinimizeName[] = "WindowTest.Minimize"; const char kMessageMaximizeName[] = "WindowTest.Maximize"; const char kMessageRestoreName[] = "WindowTest.Restore"; +const char kMessageFullscreenName[] = "WindowTest.Fullscreen"; const char kMessageTitlebarHeightName[] = "WindowTest.TitlebarHeight"; // Create the appropriate platform test runner object. @@ -109,6 +110,8 @@ class Handler : public CefMessageRouterBrowserSide::Handler { runner_->Maximize(browser); } else if (message_name == kMessageRestoreName) { runner_->Restore(browser); + } else if (message_name == kMessageFullscreenName) { + runner_->Fullscreen(browser); } else if (message_name.find(kMessageTitlebarHeightName) == 0) { const auto height = ParseHeight(message_name); runner_->SetTitleBarHeight(browser, height); diff --git a/tests/cefclient/browser/window_test_runner.cc b/tests/cefclient/browser/window_test_runner.cc index c3edce6fe..c81810b2b 100644 --- a/tests/cefclient/browser/window_test_runner.cc +++ b/tests/cefclient/browser/window_test_runner.cc @@ -36,6 +36,10 @@ void WindowTestRunner::ModifyBounds(const CefRect& display, CefRect& window) { } } +void WindowTestRunner::Fullscreen(CefRefPtr browser) { + NOTIMPLEMENTED(); +} + void WindowTestRunner::SetTitleBarHeight(CefRefPtr browser, const std::optional& height) { NOTIMPLEMENTED(); diff --git a/tests/cefclient/browser/window_test_runner.h b/tests/cefclient/browser/window_test_runner.h index 877fb59ed..8378d4ce9 100644 --- a/tests/cefclient/browser/window_test_runner.h +++ b/tests/cefclient/browser/window_test_runner.h @@ -27,6 +27,7 @@ class WindowTestRunner { virtual void Minimize(CefRefPtr browser) = 0; virtual void Maximize(CefRefPtr browser) = 0; virtual void Restore(CefRefPtr browser) = 0; + virtual void Fullscreen(CefRefPtr browser); // Fit |window| inside |display|. Coordinates are relative to the upper-left // corner of the display. diff --git a/tests/cefclient/browser/window_test_runner_views.cc b/tests/cefclient/browser/window_test_runner_views.cc index 9efda0ced..9508ca7cf 100644 --- a/tests/cefclient/browser/window_test_runner_views.cc +++ b/tests/cefclient/browser/window_test_runner_views.cc @@ -69,6 +69,17 @@ void WindowTestRunnerViews::Restore(CefRefPtr browser) { GetWindow(browser)->Restore(); } +void WindowTestRunnerViews::Fullscreen(CefRefPtr browser) { + auto window = GetWindow(browser); + + // Results in a call to ViewsWindow::OnWindowFullscreenTransition(). + if (window->IsFullscreen()) { + window->SetFullscreen(false); + } else { + window->SetFullscreen(true); + } +} + void WindowTestRunnerViews::SetTitleBarHeight( CefRefPtr browser, const std::optional& height) { diff --git a/tests/cefclient/browser/window_test_runner_views.h b/tests/cefclient/browser/window_test_runner_views.h index 851e3742d..d8b0bde2a 100644 --- a/tests/cefclient/browser/window_test_runner_views.h +++ b/tests/cefclient/browser/window_test_runner_views.h @@ -24,6 +24,7 @@ class WindowTestRunnerViews : public WindowTestRunner { void Minimize(CefRefPtr browser) override; void Maximize(CefRefPtr browser) override; void Restore(CefRefPtr browser) override; + void Fullscreen(CefRefPtr browser) override; void SetTitleBarHeight(CefRefPtr browser, const std::optional& height) override; }; diff --git a/tests/cefclient/resources/window.html b/tests/cefclient/resources/window.html index f01f7f524..f40e792ef 100644 --- a/tests/cefclient/resources/window.html +++ b/tests/cefclient/resources/window.html @@ -38,6 +38,10 @@ function restore() { setTimeout(function() { send_message('Restore'); }, 1000); } +function fullscreen() { + send_message('Fullscreen'); +} + function position() { var x = parseInt(document.getElementById('x').value); var y = parseInt(document.getElementById('y').value); @@ -64,6 +68,7 @@ Click a button to perform the associated window action.


(minimizes and then restores the window as topmost) +
(works with Views)
X: Y: diff --git a/tests/ceftests/views/test_window_delegate.cc b/tests/ceftests/views/test_window_delegate.cc index f88dfcd1f..e0d101606 100644 --- a/tests/ceftests/views/test_window_delegate.cc +++ b/tests/ceftests/views/test_window_delegate.cc @@ -23,6 +23,11 @@ namespace { // Test timeout in MS. const int kTestTimeout = 5000; +#if defined(OS_MAC) +// Match the value in view_util_mac.mm. +constexpr float kDefaultTitleBarHeight = 30; +#endif + } // namespace // static @@ -33,8 +38,8 @@ void TestWindowDelegate::RunTest(CefRefPtr event, std::unique_ptr config) { CefSize window_size{config->window_size, config->window_size}; -#if defined(OS_WIN) if (!config->frameless) { +#if defined(OS_WIN) // Expand the client area size to full window size based on the default // frame window style. AdjustWindowRect expects pixel coordinates, so // perform the necessary conversions. @@ -53,8 +58,11 @@ void TestWindowDelegate::RunTest(CefRefPtr event, {rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top}, scale_factor); window_size = {scaled_rect.width, scaled_rect.height}; +#elif defined(OS_MAC) + // Expand client area size to include the default titlebar height. + window_size.height += kDefaultTitleBarHeight; +#endif } -#endif // defined(OS_WIN) CefWindow::CreateTopLevelWindow( new TestWindowDelegate(event, std::move(config), window_size)); @@ -67,14 +75,8 @@ void TestWindowDelegate::OnWindowCreated(CefRefPtr window) { EXPECT_TRUE(window->IsValid()); EXPECT_FALSE(window->IsClosed()); - EXPECT_FALSE(window->IsVisible()); - EXPECT_FALSE(window->IsDrawn()); - EXPECT_FALSE(window->IsActive()); EXPECT_FALSE(window->IsAlwaysOnTop()); - EXPECT_FALSE(window->IsMaximized()); - EXPECT_FALSE(window->IsMinimized()); - EXPECT_FALSE(window->IsFullscreen()); const char* title = "ViewsTest"; window->SetTitle(title); @@ -95,26 +97,36 @@ void TestWindowDelegate::OnWindowCreated(CefRefPtr window) { EXPECT_FALSE(got_get_preferred_size_); } - CefRect client_bounds = window->GetBounds(); - if (!config_->window_origin.IsEmpty()) { - EXPECT_EQ(config_->window_origin.x, client_bounds.x); - EXPECT_EQ(config_->window_origin.y, client_bounds.y); - } else { - // Default origin is the upper-left corner of the display's work area. - auto work_area = display->GetWorkArea(); - EXPECT_NEAR(work_area.x, client_bounds.x, 1); - EXPECT_NEAR(work_area.y, client_bounds.y, 1); - } + // Expectations for the default |initial_show_state| value. + if (config_->initial_show_state == CEF_SHOW_STATE_NORMAL) { + EXPECT_FALSE(window->IsVisible()); + EXPECT_FALSE(window->IsDrawn()); - if (config_->frameless) { - EXPECT_NEAR(config_->window_size, client_bounds.width, 2); - EXPECT_NEAR(config_->window_size, client_bounds.height, 2); - } else { - // Client area bounds calculation might have off-by-one errors on Windows - // due to non-client frame size being calculated internally in pixels and - // then converted to DIPs. See https://crbug.com/602692. - EXPECT_NEAR(client_bounds.width, window_size_.width, 2); - EXPECT_NEAR(client_bounds.height, window_size_.height, 2); + EXPECT_FALSE(window->IsMaximized()); + EXPECT_FALSE(window->IsMinimized()); + EXPECT_FALSE(window->IsFullscreen()); + + CefRect client_bounds = window->GetBounds(); + if (!config_->window_origin.IsEmpty()) { + EXPECT_EQ(config_->window_origin.x, client_bounds.x); + EXPECT_EQ(config_->window_origin.y, client_bounds.y); + } else { + // Default origin is the upper-left corner of the display's work area. + auto work_area = display->GetWorkArea(); + EXPECT_NEAR(work_area.x, client_bounds.x, 1); + EXPECT_NEAR(work_area.y, client_bounds.y, 1); + } + + if (config_->frameless) { + EXPECT_NEAR(config_->window_size, client_bounds.width, 2); + EXPECT_NEAR(config_->window_size, client_bounds.height, 2); + } else { + // Client area bounds calculation might have off-by-one errors on Windows + // due to non-client frame size being calculated internally in pixels and + // then converted to DIPs. See https://crbug.com/602692. + EXPECT_NEAR(client_bounds.width, window_size_.width, 2); + EXPECT_NEAR(client_bounds.height, window_size_.height, 2); + } } // Run the callback. @@ -158,6 +170,41 @@ void TestWindowDelegate::OnWindowDestroyed(CefRefPtr window) { weak_ptr_factory_.InvalidateWeakPtrs(); } +void TestWindowDelegate::OnWindowFullscreenTransition( + CefRefPtr window, + bool is_completed) { + EXPECT_TRUE(window->IsSame(window_)); + + EXPECT_TRUE(window->IsValid()); + EXPECT_FALSE(window->IsClosed()); + EXPECT_TRUE(window->IsVisible()); + EXPECT_TRUE(window->IsDrawn()); + + fullscreen_transition_callback_count_++; + +#if defined(OS_MAC) + // Two callbacks on MacOS. + EXPECT_EQ(is_completed ? 2U : 1U, fullscreen_transition_callback_count_); +#else + // Single callback on other platforms. + EXPECT_TRUE(is_completed); + EXPECT_EQ(1U, fullscreen_transition_callback_count_); +#endif + + if (is_completed) { + fullscreen_transition_complete_count_++; + + // Reset intermediate state. + fullscreen_transition_callback_count_ = 0; + + // Run the callback. + if (!config_->on_window_fullscreen_transition_complete.is_null()) { + config_->on_window_fullscreen_transition_complete.Run( + window, fullscreen_transition_complete_count_); + } + } +} + bool TestWindowDelegate::IsFrameless(CefRefPtr window) { return config_->frameless; } @@ -173,6 +220,11 @@ CefRect TestWindowDelegate::GetInitialBounds(CefRefPtr window) { return CefRect(); } +cef_show_state_t TestWindowDelegate::GetInitialShowState( + CefRefPtr window) { + return config_->initial_show_state; +} + CefSize TestWindowDelegate::GetPreferredSize(CefRefPtr view) { got_get_preferred_size_ = true; return window_size_; diff --git a/tests/ceftests/views/test_window_delegate.h b/tests/ceftests/views/test_window_delegate.h index 385998da0..1fba5673d 100644 --- a/tests/ceftests/views/test_window_delegate.h +++ b/tests/ceftests/views/test_window_delegate.h @@ -20,6 +20,8 @@ class TestWindowDelegate : public CefWindowDelegate { base::OnceCallback)>; using OnWindowDestroyedCallback = base::OnceCallback)>; + using OnWindowFullscreenTransitionCompleteCallback = + base::RepeatingCallback, size_t /*count*/)>; using OnAcceleratorCallback = base::RepeatingCallback, int)>; using OnKeyEventCallback = @@ -28,12 +30,15 @@ class TestWindowDelegate : public CefWindowDelegate { struct Config { OnWindowCreatedCallback on_window_created; OnWindowDestroyedCallback on_window_destroyed; + OnWindowFullscreenTransitionCompleteCallback + on_window_fullscreen_transition_complete; OnAcceleratorCallback on_accelerator; OnKeyEventCallback on_key_event; bool frameless = false; bool close_window = true; int window_size = kWSize; CefPoint window_origin = {}; + cef_show_state_t initial_show_state = CEF_SHOW_STATE_NORMAL; }; // Creates a Window with a new TestWindowDelegate instance and executes @@ -48,8 +53,11 @@ class TestWindowDelegate : public CefWindowDelegate { // CefWindowDelegate methods: void OnWindowCreated(CefRefPtr window) override; void OnWindowDestroyed(CefRefPtr window) override; + void OnWindowFullscreenTransition(CefRefPtr window, + bool is_completed) override; bool IsFrameless(CefRefPtr window) override; CefRect GetInitialBounds(CefRefPtr window) override; + cef_show_state_t GetInitialShowState(CefRefPtr window) override; CefSize GetPreferredSize(CefRefPtr view) override; bool OnAccelerator(CefRefPtr window, int command_id) override; bool OnKeyEvent(CefRefPtr window, @@ -73,6 +81,9 @@ class TestWindowDelegate : public CefWindowDelegate { bool got_get_initial_bounds_ = false; bool got_get_preferred_size_ = false; + size_t fullscreen_transition_callback_count_ = 0; + size_t fullscreen_transition_complete_count_ = 0; + // Must be the last member. base::WeakPtrFactory weak_ptr_factory_; diff --git a/tests/ceftests/views/window_unittest.cc b/tests/ceftests/views/window_unittest.cc index 0c8d6b824..aa00d1f00 100644 --- a/tests/ceftests/views/window_unittest.cc +++ b/tests/ceftests/views/window_unittest.cc @@ -36,6 +36,13 @@ void ExpectCloseRects(const CefRect& expected, EXPECT_LE(abs(expected.height - actual.height), allowed_deviance); } +void ExpectClosePoints(const CefPoint& expected, + const CefPoint& actual, + int allowed_deviance) { + EXPECT_LE(abs(expected.x - actual.x), allowed_deviance); + EXPECT_LE(abs(expected.y - actual.y), allowed_deviance); +} + void WindowCreateImpl(CefRefPtr event) { auto config = std::make_unique(); TestWindowDelegate::RunTest(event, std::move(config)); @@ -47,23 +54,106 @@ void WindowCreateFramelessImpl(CefRefPtr event) { TestWindowDelegate::RunTest(event, std::move(config)); } -void RunWindowShow(CefRefPtr window) { - EXPECT_FALSE(window->IsVisible()); - EXPECT_FALSE(window->IsDrawn()); - window->Show(); - EXPECT_TRUE(window->IsVisible()); - EXPECT_TRUE(window->IsDrawn()); +void RunWindowShow(cef_show_state_t initial_show_state, + CefRefPtr window) { +#if defined(OS_MAC) + if (initial_show_state == CEF_SHOW_STATE_FULLSCREEN) { + // On MacOS, starting in fullscreen mode also shows the window on creation. + EXPECT_TRUE(window->IsVisible()); + EXPECT_TRUE(window->IsDrawn()); + } else +#endif + { + EXPECT_FALSE(window->IsVisible()); + EXPECT_FALSE(window->IsDrawn()); + window->Show(); + } + + if (initial_show_state == CEF_SHOW_STATE_MINIMIZED) { +#if !defined(OS_MAC) + // This result is a bit unexpected, but I guess the platform considers a + // window to be visible even when it's minimized. + EXPECT_TRUE(window->IsVisible()); + EXPECT_TRUE(window->IsDrawn()); +#else + EXPECT_FALSE(window->IsVisible()); + EXPECT_FALSE(window->IsDrawn()); +#endif + } else { + EXPECT_TRUE(window->IsVisible()); + EXPECT_TRUE(window->IsDrawn()); + } + + switch (initial_show_state) { + case CEF_SHOW_STATE_NORMAL: + EXPECT_FALSE(window->IsMaximized()); + EXPECT_FALSE(window->IsMinimized()); + EXPECT_FALSE(window->IsFullscreen()); + break; + case CEF_SHOW_STATE_MINIMIZED: + EXPECT_FALSE(window->IsMaximized()); +#if defined(OS_WIN) + // On MacOS, IsMinimized() state isn't reliable in this callback due to a + // timing issue between NativeWidgetMac::Minimize requesting the minimize + // state change (before this callback) and + // NativeWidgetMacNSWindowHost::OnWindowMiniaturizedChanged indicating the + // completed state change (after this callback). + // On Linux, there's likely a similar timing issue. + EXPECT_TRUE(window->IsMinimized()); +#endif + EXPECT_FALSE(window->IsFullscreen()); + break; + case CEF_SHOW_STATE_MAXIMIZED: +#if !defined(OS_LINUX) + // On Linux, there's likely a similar timing issue. + EXPECT_TRUE(window->IsMaximized()); +#endif + EXPECT_FALSE(window->IsMinimized()); + EXPECT_FALSE(window->IsFullscreen()); + break; + case CEF_SHOW_STATE_FULLSCREEN: + EXPECT_FALSE(window->IsMaximized()); + EXPECT_FALSE(window->IsMinimized()); + EXPECT_TRUE(window->IsFullscreen()); + break; + } } void WindowCreateWithOriginImpl(CefRefPtr event) { auto config = std::make_unique(); config->window_origin = {100, 200}; - config->on_window_created = base::BindOnce(RunWindowShow); + config->on_window_created = + base::BindOnce(RunWindowShow, config->initial_show_state); TestWindowDelegate::RunTest(event, std::move(config)); } -void RunWindowShowHide(CefRefPtr window) { - RunWindowShow(window); +void WindowCreateMinimizedImpl(CefRefPtr event) { + auto config = std::make_unique(); + config->initial_show_state = CEF_SHOW_STATE_MINIMIZED; + config->on_window_created = + base::BindOnce(RunWindowShow, config->initial_show_state); + TestWindowDelegate::RunTest(event, std::move(config)); +} + +void WindowCreateMaximizedImpl(CefRefPtr event) { + auto config = std::make_unique(); + config->initial_show_state = CEF_SHOW_STATE_MAXIMIZED; + config->on_window_created = + base::BindOnce(RunWindowShow, config->initial_show_state); + TestWindowDelegate::RunTest(event, std::move(config)); +} + +void WindowCreateFullscreenImpl(CefRefPtr event) { + auto config = std::make_unique(); + config->initial_show_state = CEF_SHOW_STATE_FULLSCREEN; + config->on_window_created = + base::BindOnce(RunWindowShow, config->initial_show_state); + TestWindowDelegate::RunTest(event, std::move(config)); +} + +void RunWindowShowHide(cef_show_state_t initial_show_state, + CefRefPtr window) { + RunWindowShow(initial_show_state, window); window->Hide(); EXPECT_FALSE(window->IsVisible()); EXPECT_FALSE(window->IsDrawn()); @@ -71,13 +161,15 @@ void RunWindowShowHide(CefRefPtr window) { void WindowShowHideImpl(CefRefPtr event) { auto config = std::make_unique(); - config->on_window_created = base::BindOnce(RunWindowShowHide); + config->on_window_created = + base::BindOnce(RunWindowShowHide, config->initial_show_state); TestWindowDelegate::RunTest(event, std::move(config)); } void WindowShowHideFramelessImpl(CefRefPtr event) { auto config = std::make_unique(); - config->on_window_created = base::BindOnce(RunWindowShowHide); + config->on_window_created = + base::BindOnce(RunWindowShowHide, config->initial_show_state); config->frameless = true; TestWindowDelegate::RunTest(event, std::move(config)); } @@ -146,9 +238,9 @@ void RunWindowLayoutAndCoords(CefRefPtr window) { point); point = CefPoint(0, 0); EXPECT_TRUE(view2->ConvertPointToScreen(point)); - EXPECT_EQ(CefPoint(client_bounds_in_screen.x, - client_bounds_in_screen.y + kWSize / 2), - point); + ExpectClosePoints(CefPoint(client_bounds_in_screen.x, + client_bounds_in_screen.y + kWSize / 2), + point, 1); // Test view from screen coordinate conversions. point = CefPoint(client_bounds_in_screen.x, client_bounds_in_screen.y); @@ -157,7 +249,7 @@ void RunWindowLayoutAndCoords(CefRefPtr window) { point = CefPoint(client_bounds_in_screen.x, client_bounds_in_screen.y + kWSize / 2); EXPECT_TRUE(view2->ConvertPointFromScreen(point)); - EXPECT_EQ(CefPoint(0, 0), point); + ExpectClosePoints(CefPoint(0, 0), point, 1); // Test view to window coordinate conversions. point = CefPoint(0, 0); @@ -165,7 +257,7 @@ void RunWindowLayoutAndCoords(CefRefPtr window) { EXPECT_EQ(CefPoint(0, 0), point); point = CefPoint(0, 0); EXPECT_TRUE(view2->ConvertPointToWindow(point)); - EXPECT_EQ(CefPoint(0, kWSize / 2), point); + ExpectClosePoints(CefPoint(0, kWSize / 2), point, 1); // Test view from window coordinate conversions. point = CefPoint(0, 0); @@ -173,23 +265,23 @@ void RunWindowLayoutAndCoords(CefRefPtr window) { EXPECT_EQ(CefPoint(0, 0), point); point = CefPoint(0, kWSize / 2); EXPECT_TRUE(view2->ConvertPointFromWindow(point)); - EXPECT_EQ(CefPoint(0, 0), point); + ExpectClosePoints(CefPoint(0, 0), point, 1); // Test view to view coordinate conversions. point = CefPoint(0, 0); EXPECT_TRUE(view1->ConvertPointToView(view2, point)); - EXPECT_EQ(CefPoint(0, -kWSize / 2), point); + ExpectClosePoints(CefPoint(0, -kWSize / 2), point, 1); point = CefPoint(0, 0); EXPECT_TRUE(view2->ConvertPointToView(view1, point)); - EXPECT_EQ(CefPoint(0, kWSize / 2), point); + ExpectClosePoints(CefPoint(0, kWSize / 2), point, 1); // Test view from view coordinate conversions. point = CefPoint(0, -kWSize / 2); EXPECT_TRUE(view1->ConvertPointFromView(view2, point)); - EXPECT_EQ(CefPoint(0, 0), point); + ExpectClosePoints(CefPoint(0, 0), point, 1); point = CefPoint(0, kWSize / 2); EXPECT_TRUE(view2->ConvertPointFromView(view1, point)); - EXPECT_EQ(CefPoint(0, 0), point); + ExpectClosePoints(CefPoint(0, 0), point, 1); CefRefPtr display = window->GetDisplay(); EXPECT_TRUE(display.get()); @@ -198,8 +290,8 @@ void RunWindowLayoutAndCoords(CefRefPtr window) { point = CefPoint(client_bounds_in_screen.x, client_bounds_in_screen.y); display->ConvertPointToPixels(point); display->ConvertPointFromPixels(point); - EXPECT_EQ(CefPoint(client_bounds_in_screen.x, client_bounds_in_screen.y), - point); + ExpectClosePoints( + CefPoint(client_bounds_in_screen.x, client_bounds_in_screen.y), point, 1); // We don't know what the pixel values will be, but they should be reversable. point = CefPoint(client_bounds_in_screen.x, client_bounds_in_screen.y); @@ -278,10 +370,15 @@ void VerifyMinimize(CefRefPtr window) { EXPECT_FALSE(window->IsMaximized()); EXPECT_FALSE(window->IsFullscreen()); +#if defined(OS_WIN) // This result is a bit unexpected, but I guess the platform considers a // window to be visible even when it's minimized. EXPECT_TRUE(window->IsVisible()); EXPECT_TRUE(window->IsDrawn()); +#else + EXPECT_FALSE(window->IsVisible()); + EXPECT_FALSE(window->IsDrawn()); +#endif window->Restore(); CefPostDelayedTask(TID_UI, base::BindOnce(VerifyRestore, window), @@ -316,28 +413,26 @@ void WindowMinimizeFramelessImpl(CefRefPtr event) { config->close_window = false; TestWindowDelegate::RunTest(event, std::move(config)); } - -void VerifyFullscreenExit(CefRefPtr window) { +void WindowFullscreenTransitionComplete(CefRefPtr window, + size_t count) { EXPECT_FALSE(window->IsMinimized()); + +#if defined(OS_MAC) + // On MacOS, IsMaximized() returns true when IsFullscreen() returns true. + EXPECT_EQ(window->IsFullscreen(), window->IsMaximized()); +#else EXPECT_FALSE(window->IsMaximized()); - EXPECT_FALSE(window->IsFullscreen()); - EXPECT_TRUE(window->IsVisible()); - EXPECT_TRUE(window->IsDrawn()); +#endif - // End the test by closing the Window. - window->Close(); -} + if (window->IsFullscreen()) { + EXPECT_EQ(1U, count); + window->SetFullscreen(false); + } else { + EXPECT_EQ(2U, count); -void VerifyFullscreen(CefRefPtr window) { - EXPECT_FALSE(window->IsMinimized()); - EXPECT_FALSE(window->IsMaximized()); - EXPECT_TRUE(window->IsFullscreen()); - EXPECT_TRUE(window->IsVisible()); - EXPECT_TRUE(window->IsDrawn()); - - window->SetFullscreen(false); - CefPostDelayedTask(TID_UI, base::BindOnce(VerifyFullscreenExit, window), - kStateDelayMS); + // End the test by closing the Window. + window->Close(); + } } void RunWindowFullscreen(CefRefPtr window) { @@ -350,13 +445,13 @@ void RunWindowFullscreen(CefRefPtr window) { EXPECT_TRUE(window->IsDrawn()); window->SetFullscreen(true); - CefPostDelayedTask(TID_UI, base::BindOnce(VerifyFullscreen, window), - kStateDelayMS); } void WindowFullscreenImpl(CefRefPtr event) { auto config = std::make_unique(); config->on_window_created = base::BindOnce(RunWindowFullscreen); + config->on_window_fullscreen_transition_complete = + base::BindRepeating(WindowFullscreenTransitionComplete); config->close_window = false; TestWindowDelegate::RunTest(event, std::move(config)); } @@ -364,6 +459,8 @@ void WindowFullscreenImpl(CefRefPtr event) { void WindowFullscreenFramelessImpl(CefRefPtr event) { auto config = std::make_unique(); config->on_window_created = base::BindOnce(RunWindowFullscreen); + config->on_window_fullscreen_transition_complete = + base::BindRepeating(WindowFullscreenTransitionComplete); config->frameless = true; config->close_window = false; TestWindowDelegate::RunTest(event, std::move(config)); @@ -505,6 +602,9 @@ void WindowAcceleratorImpl(CefRefPtr event) { WINDOW_TEST_ASYNC(WindowCreate) WINDOW_TEST_ASYNC(WindowCreateFrameless) WINDOW_TEST_ASYNC(WindowCreateWithOrigin) +WINDOW_TEST_ASYNC(WindowCreateMinimized) +WINDOW_TEST_ASYNC(WindowCreateMaximized) +WINDOW_TEST_ASYNC(WindowCreateFullscreen) WINDOW_TEST_ASYNC(WindowShowHide) WINDOW_TEST_ASYNC(WindowShowHideFrameless) WINDOW_TEST_ASYNC(WindowLayoutAndCoords)