From b5d542d38d022676c30b923762955cab358c0984 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Thu, 11 Jan 2024 18:32:08 -0500 Subject: [PATCH] chrome: Improve positioning of dialogs (fixes #3628) Dialogs will be excluded from regions near the top of the window that contain overlays, draggable regions or titlebar. --- libcef/browser/browser_platform_delegate.cc | 3 - libcef/browser/browser_platform_delegate.h | 3 - libcef/browser/chrome/browser_delegate.h | 13 +- .../browser/chrome/chrome_browser_delegate.cc | 55 ++++++-- .../browser/chrome/chrome_browser_delegate.h | 21 ++- .../chrome/chrome_browser_host_impl.cc | 11 +- .../browser_platform_delegate_chrome_views.cc | 9 -- .../browser_platform_delegate_chrome_views.h | 1 - libcef/browser/views/browser_view_impl.cc | 8 +- libcef/browser/views/browser_view_impl.h | 2 +- libcef/browser/views/overlay_view_host.cc | 1 + libcef/browser/views/window_impl.cc | 8 +- libcef/browser/views/window_impl.h | 2 + libcef/browser/views/window_view.cc | 82 +++++++++--- libcef/browser/views/window_view.h | 15 ++- patch/patches/chrome_runtime_views.patch | 125 +++++++++++++++--- 16 files changed, 274 insertions(+), 85 deletions(-) diff --git a/libcef/browser/browser_platform_delegate.cc b/libcef/browser/browser_platform_delegate.cc index a06db2bdb..92ec8cd1c 100644 --- a/libcef/browser/browser_platform_delegate.cc +++ b/libcef/browser/browser_platform_delegate.cc @@ -264,9 +264,6 @@ std::unique_ptr CefBrowserPlatformDelegate::CreateMenuRunner() { return nullptr; } -void CefBrowserPlatformDelegate::UpdateFindBarBoundingBox( - gfx::Rect* bounds) const {} - bool CefBrowserPlatformDelegate::IsWindowless() const { return false; } diff --git a/libcef/browser/browser_platform_delegate.h b/libcef/browser/browser_platform_delegate.h index 7c0e366ae..f675b4829 100644 --- a/libcef/browser/browser_platform_delegate.h +++ b/libcef/browser/browser_platform_delegate.h @@ -286,9 +286,6 @@ class CefBrowserPlatformDelegate { // Create the platform-specific menu runner. virtual std::unique_ptr CreateMenuRunner(); - // Optionally modify the bounding box for the Chrome Find bar. - virtual void UpdateFindBarBoundingBox(gfx::Rect* bounds) const; - // Returns true if this delegate implements windowless rendering. May be // called on multiple threads. virtual bool IsWindowless() const; diff --git a/libcef/browser/chrome/browser_delegate.h b/libcef/browser/chrome/browser_delegate.h index 5e9b53dda..92a0c0bb4 100644 --- a/libcef/browser/chrome/browser_delegate.h +++ b/libcef/browser/chrome/browser_delegate.h @@ -7,11 +7,11 @@ #pragma once #include +#include #include "base/memory/scoped_refptr.h" #include "chrome/browser/ui/page_action/page_action_icon_type.h" #include "content/public/browser/web_contents_delegate.h" -#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/skia/include/core/SkRegion.h" #include "ui/base/window_open_disposition.h" @@ -107,6 +107,9 @@ class BrowserDelegate : public content::WebContentsDelegate { // Optionally modify the bounding box for the Find bar. virtual void UpdateFindBarBoundingBox(gfx::Rect* bounds) {} + // Optionally modify the top inset for dialogs. + virtual void UpdateDialogTopInset(int* dialog_top_y) {} + // Same as RequestMediaAccessPermission but returning |callback| if the // request is unhandled. [[nodiscard]] virtual content::MediaResponseCallback @@ -118,8 +121,8 @@ class BrowserDelegate : public content::WebContentsDelegate { // Optionally override support for the specified window feature of type // Browser::WindowFeature. - virtual absl::optional SupportsWindowFeature(int feature) const { - return absl::nullopt; + virtual std::optional SupportsWindowFeature(int feature) const { + return std::nullopt; } // Returns true if draggable regions are supported. @@ -128,8 +131,8 @@ class BrowserDelegate : public content::WebContentsDelegate { // Returns the draggable region, if any, relative to the web contents. // Called from PictureInPictureBrowserFrameView::NonClientHitTest and // BrowserView::ShouldDescendIntoChildForEventHandling. - virtual const absl::optional GetDraggableRegion() const { - return absl::nullopt; + virtual const std::optional GetDraggableRegion() const { + return std::nullopt; } // Set the draggable region relative to web contents. diff --git a/libcef/browser/chrome/chrome_browser_delegate.cc b/libcef/browser/chrome/chrome_browser_delegate.cc index 083073fb1..2049d655f 100644 --- a/libcef/browser/chrome/chrome_browser_delegate.cc +++ b/libcef/browser/chrome/chrome_browser_delegate.cc @@ -336,8 +336,16 @@ bool ChromeBrowserDelegate::IsToolbarButtonVisible( } void ChromeBrowserDelegate::UpdateFindBarBoundingBox(gfx::Rect* bounds) { - if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) { - browser->platform_delegate()->UpdateFindBarBoundingBox(bounds); + if (auto cef_window_view = GetCefWindowView()) { + cef_window_view->UpdateFindBarBoundingBox(bounds); + } +} + +void ChromeBrowserDelegate::UpdateDialogTopInset(int* dialog_top_y) { + // This may be called during Browser initialization (before Tab/WebContents + // creation), so we can't route through the ChromeBrowserHostImpl. + if (auto cef_window_view = GetCefWindowView()) { + cef_window_view->UpdateDialogTopInset(dialog_top_y); } } @@ -377,7 +385,7 @@ bool ChromeBrowserDelegate::SupportsFramelessPictureInPicture() const { return *frameless_pip_; } -absl::optional ChromeBrowserDelegate::SupportsWindowFeature( +std::optional ChromeBrowserDelegate::SupportsWindowFeature( int feature) const { // Override the default value from // Browser::PictureInPictureBrowserSupportsWindowFeature. @@ -386,14 +394,14 @@ absl::optional ChromeBrowserDelegate::SupportsWindowFeature( // Return false to hide titlebar and enable draggable regions. return !SupportsFramelessPictureInPicture(); } - return absl::nullopt; + return std::nullopt; } bool ChromeBrowserDelegate::SupportsDraggableRegion() const { return SupportsFramelessPictureInPicture(); } -const absl::optional ChromeBrowserDelegate::GetDraggableRegion() +const std::optional ChromeBrowserDelegate::GetDraggableRegion() const { DCHECK(SupportsDraggableRegion()); return draggable_region_; @@ -408,14 +416,11 @@ 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); - } + if (auto cef_window_impl = GetCefWindowImpl()) { + if (auto* delegate = cef_window_impl->delegate()) { + // Give the CefWindowDelegate a chance to handle the event. + delegate->OnWindowFullscreenTransition(cef_window_impl, + /*is_completed=*/true); } } #endif @@ -646,7 +651,7 @@ ChromeBrowserDelegate::CreateBrowserHostForPopup( } CefBrowserContentsDelegate* ChromeBrowserDelegate::GetDelegateForWebContents( - content::WebContents* web_contents) { + content::WebContents* web_contents) const { auto browser_host = ChromeBrowserHostImpl::GetBrowserForContents(web_contents); if (browser_host) { @@ -655,6 +660,28 @@ CefBrowserContentsDelegate* ChromeBrowserDelegate::GetDelegateForWebContents( return nullptr; } +bool ChromeBrowserDelegate::IsViewsHosted() const { + return create_params_.browser_view != nullptr || + create_params_.popup_with_views_hosted_opener; +} + +CefWindowImpl* ChromeBrowserDelegate::GetCefWindowImpl() const { + if (IsViewsHosted()) { + if (auto chrome_browser_view = + static_cast(browser_->window())) { + return chrome_browser_view->cef_browser_view()->cef_window_impl(); + } + } + return nullptr; +} + +CefWindowView* ChromeBrowserDelegate::GetCefWindowView() const { + if (auto cef_window_impl = GetCefWindowImpl()) { + return cef_window_impl->cef_window_view(); + } + return nullptr; +} + namespace cef { // static diff --git a/libcef/browser/chrome/chrome_browser_delegate.h b/libcef/browser/chrome/chrome_browser_delegate.h index c25a95c5b..6b721ec5b 100644 --- a/libcef/browser/chrome/chrome_browser_delegate.h +++ b/libcef/browser/chrome/chrome_browser_delegate.h @@ -16,6 +16,8 @@ class CefBrowserContentsDelegate; class CefRequestContextImpl; +class CefWindowImpl; +class CefWindowView; class ChromeBrowserHostImpl; // Implementation of the cef::BrowserDelegate interface. Lifespan is controlled @@ -69,13 +71,14 @@ class ChromeBrowserDelegate : public cef::BrowserDelegate { bool IsPageActionIconVisible(PageActionIconType icon_type) override; bool IsToolbarButtonVisible(ToolbarButtonType button_type) override; void UpdateFindBarBoundingBox(gfx::Rect* bounds) override; + void UpdateDialogTopInset(int* dialog_top_y) override; [[nodiscard]] content::MediaResponseCallback RequestMediaAccessPermissionEx( content::WebContents* web_contents, const content::MediaStreamRequest& request, content::MediaResponseCallback callback) override; - absl::optional SupportsWindowFeature(int feature) const override; + std::optional SupportsWindowFeature(int feature) const override; bool SupportsDraggableRegion() const override; - const absl::optional GetDraggableRegion() const override; + const std::optional GetDraggableRegion() const override; void UpdateDraggableRegion(const SkRegion& region) override; void WindowFullscreenStateChanged() override; @@ -137,19 +140,25 @@ class ChromeBrowserDelegate : public cef::BrowserDelegate { CefRefPtr opener); CefBrowserContentsDelegate* GetDelegateForWebContents( - content::WebContents* web_contents); + content::WebContents* web_contents) const; bool SupportsFramelessPictureInPicture() const; + bool IsViewsHosted() const; + + // Will return nullptr if the Browser is not Views-hosted. + CefWindowImpl* GetCefWindowImpl() const; + CefWindowView* GetCefWindowView() const; + Browser* const browser_; base::WeakPtr opener_host_; // Used when creating a new browser host. const CefBrowserCreateParams create_params_; - absl::optional show_status_bubble_; - absl::optional draggable_region_; - mutable absl::optional frameless_pip_; + std::optional show_status_bubble_; + std::optional draggable_region_; + mutable std::optional frameless_pip_; std::unique_ptr pending_show_devtools_params_; }; diff --git a/libcef/browser/chrome/chrome_browser_host_impl.cc b/libcef/browser/chrome/chrome_browser_host_impl.cc index e402994de..1f13364c7 100644 --- a/libcef/browser/chrome/chrome_browser_host_impl.cc +++ b/libcef/browser/chrome/chrome_browser_host_impl.cc @@ -93,8 +93,15 @@ CefRefPtr ChromeBrowserHostImpl::GetBrowserForGlobalId( CefRefPtr ChromeBrowserHostImpl::GetBrowserForBrowser( const Browser* browser) { REQUIRE_CHROME_RUNTIME(); - return GetBrowserForContents( - browser->tab_strip_model()->GetActiveWebContents()); + // Return the ChromeBrowserHostImpl that is currently active. + // Views-hosted Browsers will contain a single ChromeBrowserHostImpl. + // Otherwise, there will be a ChromeBrowserHostImpl per Tab/WebContents. + // |contents| may be nullptr during Browser initialization or destruction. + auto contents = browser->tab_strip_model()->GetActiveWebContents(); + if (!contents) { + return nullptr; + } + return GetBrowserForContents(contents); } ChromeBrowserHostImpl::~ChromeBrowserHostImpl() = default; diff --git a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc index 78f1d8491..25c24bf51 100644 --- a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc +++ b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc @@ -195,15 +195,6 @@ void CefBrowserPlatformDelegateChromeViews::PopupBrowserCreated( } } -void CefBrowserPlatformDelegateChromeViews::UpdateFindBarBoundingBox( - gfx::Rect* bounds) const { - if (auto* window_impl = GetWindowImpl()) { - if (window_impl->root_view()) { - window_impl->root_view()->UpdateFindBarBoundingBox(bounds); - } - } -} - bool CefBrowserPlatformDelegateChromeViews::IsViewsHosted() const { return true; } diff --git a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h index f27ba881d..ffd4c58c4 100644 --- a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h +++ b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h @@ -37,7 +37,6 @@ class CefBrowserPlatformDelegateChromeViews bool is_devtools) override; void PopupBrowserCreated(CefBrowserHostBase* new_browser, bool is_devtools) override; - void UpdateFindBarBoundingBox(gfx::Rect* bounds) const override; bool IsViewsHosted() const override; CefRefPtr browser_view() const { return browser_view_; } diff --git a/libcef/browser/views/browser_view_impl.cc b/libcef/browser/views/browser_view_impl.cc index ddce105d0..8897cd117 100644 --- a/libcef/browser/views/browser_view_impl.cc +++ b/libcef/browser/views/browser_view_impl.cc @@ -141,7 +141,7 @@ bool CefBrowserViewImpl::HandleKeyboardEvent( } // Give the CefWindowDelegate a chance to handle the event. - if (auto* window_impl = cef_window()) { + if (auto* window_impl = cef_window_impl()) { CefKeyEvent cef_event; if (browser_util::GetCefKeyEvent(event, cef_event) && window_impl->OnKeyEvent(cef_event)) { @@ -316,7 +316,11 @@ ChromeBrowserView* CefBrowserViewImpl::chrome_browser_view() const { return static_cast(root_view()); } -CefWindowImpl* CefBrowserViewImpl::cef_window() const { +CefWindowImpl* CefBrowserViewImpl::cef_window_impl() const { + // Same implementation as GetWindow(). + if (!root_view()) { + return nullptr; + } CefRefPtr window = view_util::GetWindowFor(root_view()->GetWidget()); return static_cast(window.get()); diff --git a/libcef/browser/views/browser_view_impl.h b/libcef/browser/views/browser_view_impl.h index 74562806b..bada6bf90 100644 --- a/libcef/browser/views/browser_view_impl.h +++ b/libcef/browser/views/browser_view_impl.h @@ -85,7 +85,7 @@ class CefBrowserViewImpl ChromeBrowserView* chrome_browser_view() const; // Return the CefWindowImpl hosting this object. - CefWindowImpl* cef_window() const; + CefWindowImpl* cef_window_impl() const; private: // Create a new implementation object. diff --git a/libcef/browser/views/overlay_view_host.cc b/libcef/browser/views/overlay_view_host.cc index 8dd687e4c..acbb93e7c 100644 --- a/libcef/browser/views/overlay_view_host.cc +++ b/libcef/browser/views/overlay_view_host.cc @@ -278,6 +278,7 @@ void CefOverlayViewHost::SetOverlayBounds(const gfx::Rect& bounds) { view_->SetSize(bounds_.size()); } widget_->SetBounds(bounds_); + window_view_->OnOverlayBoundsChanged(); bounds_changing_ = false; } diff --git a/libcef/browser/views/window_impl.cc b/libcef/browser/views/window_impl.cc index b98d27bf3..7f8092536 100644 --- a/libcef/browser/views/window_impl.cc +++ b/libcef/browser/views/window_impl.cc @@ -137,7 +137,7 @@ void CefWindowImpl::ShowAsBrowserModalDialog( static_cast(browser_view.get()); // |browser_view| must belong to the host widget. - auto* host_widget = static_cast(root_view())->host_widget(); + auto* host_widget = cef_window_view()->host_widget(); CHECK(host_widget && browser_view_impl->root_view()->GetWidget() == host_widget); @@ -739,6 +739,10 @@ void CefWindowImpl::RemoveAllAccelerators() { focus_manager->UnregisterAccelerators(this); } +CefWindowView* CefWindowImpl::cef_window_view() const { + return static_cast(root_view()); +} + CefWindowImpl::CefWindowImpl(CefRefPtr delegate) : ParentClass(delegate) {} @@ -747,7 +751,7 @@ CefWindowView* CefWindowImpl::CreateRootView() { } void CefWindowImpl::InitializeRootView() { - static_cast(root_view())->Initialize(); + cef_window_view()->Initialize(); } void CefWindowImpl::CreateWidget(gfx::AcceleratedWidget parent_widget) { diff --git a/libcef/browser/views/window_impl.h b/libcef/browser/views/window_impl.h index a207bdf42..4129fb021 100644 --- a/libcef/browser/views/window_impl.h +++ b/libcef/browser/views/window_impl.h @@ -133,6 +133,8 @@ class CefWindowImpl cef_menu_anchor_position_t anchor_position); void MenuClosed(); + CefWindowView* cef_window_view() const; + views::Widget* widget() const { return widget_; } bool initialized() const { return initialized_; } diff --git a/libcef/browser/views/window_view.cc b/libcef/browser/views/window_view.cc index a94622bca..f3cb5972f 100644 --- a/libcef/browser/views/window_view.cc +++ b/libcef/browser/views/window_view.cc @@ -92,7 +92,7 @@ class NativeFrameViewEx : public views::NativeFrameView { } if (!view_->IsFrameless()) { - if (auto titlebar_height = view_->GetTitlebarHeight()) { + if (auto titlebar_height = view_->GetTitlebarHeight(/*required=*/true)) { window_bounds.Inset(gfx::Insets::TLBR(-(*titlebar_height), 0, 0, 0)); } } @@ -829,12 +829,23 @@ void CefWindowView::MoveOverlaysIfNecessary() { } } +void CefWindowView::InvalidateExclusionRegions() { + if (last_dialog_top_inset_ != -1) { + last_dialog_top_y_ = last_dialog_top_inset_ = -1; + } +} + void CefWindowView::SetDraggableRegions( const std::vector& regions) { + if (regions.empty() && !draggable_region_) { + // Still empty. + return; + } + + InvalidateExclusionRegions(); + if (regions.empty()) { - if (draggable_region_) { - draggable_region_.reset(nullptr); - } + draggable_region_.reset(); draggable_rects_.clear(); return; } @@ -854,6 +865,10 @@ void CefWindowView::SetDraggableRegions( } } +void CefWindowView::OnOverlayBoundsChanged() { + InvalidateExclusionRegions(); +} + views::NonClientFrameView* CefWindowView::GetNonClientFrameView() const { const views::Widget* widget = GetWidget(); if (!widget) { @@ -865,7 +880,8 @@ views::NonClientFrameView* CefWindowView::GetNonClientFrameView() const { return widget->non_client_view()->frame_view(); } -void CefWindowView::UpdateFindBarBoundingBox(gfx::Rect* bounds) const { +void CefWindowView::UpdateBoundingBox(gfx::Rect* bounds, + bool add_titlebar_height) const { // Max distance from the edges of |bounds| to qualify for subtraction. const int kMaxDistance = 10; @@ -878,16 +894,8 @@ void CefWindowView::UpdateFindBarBoundingBox(gfx::Rect* bounds) const { *bounds = SubtractOverlayFromBoundingBox(*bounds, rect, kMaxDistance); } - if (auto titlebar_height = GetTitlebarHeight()) { + if (auto titlebar_height = GetTitlebarHeight(add_titlebar_height)) { gfx::Insets inset; - -#if BUILDFLAG(IS_MAC) - // For framed windows on macOS we must add the titlebar height. - const bool add_titlebar_height = !is_frameless_; -#else - const bool add_titlebar_height = false; -#endif - if (add_titlebar_height) { inset.set_top(*titlebar_height); } else if (bounds->y() < *titlebar_height) { @@ -900,6 +908,46 @@ void CefWindowView::UpdateFindBarBoundingBox(gfx::Rect* bounds) const { } } +void CefWindowView::UpdateFindBarBoundingBox(gfx::Rect* bounds) const { +#if BUILDFLAG(IS_MAC) + // For framed windows on macOS we must add the titlebar height. + const bool add_titlebar_height = !is_frameless_; +#else + const bool add_titlebar_height = false; +#endif + + UpdateBoundingBox(bounds, add_titlebar_height); +} + +void CefWindowView::UpdateDialogTopInset(int* dialog_top_y) const { + if (*dialog_top_y == last_dialog_top_y_ && last_dialog_top_inset_ != -1) { + // Return the cached value. + *dialog_top_y = last_dialog_top_inset_; + return; + } + + const views::Widget* widget = GetWidget(); + if (!widget) { + return; + } + + gfx::Rect bounds(widget->GetSize()); + if (*dialog_top_y > 0) { + // Start with the value computed in + // BrowserViewLayout::LayoutBookmarkAndInfoBars. + gfx::Insets inset; + inset.set_top(*dialog_top_y); + bounds.Inset(inset); + } + + UpdateBoundingBox(&bounds, /*add_titlebar_height=*/false); + + last_dialog_top_y_ = *dialog_top_y; + last_dialog_top_inset_ = bounds.y(); + + *dialog_top_y = bounds.y(); +} + views::Widget* CefWindowView::host_widget() const { if (host_widget_destruction_observer_) { return host_widget_destruction_observer_->widget(); @@ -907,7 +955,7 @@ views::Widget* CefWindowView::host_widget() const { return nullptr; } -absl::optional CefWindowView::GetTitlebarHeight() const { +std::optional CefWindowView::GetTitlebarHeight(bool required) const { if (cef_delegate()) { float title_bar_height = 0; const bool has_title_bar_height = @@ -918,7 +966,7 @@ absl::optional CefWindowView::GetTitlebarHeight() const { } #if BUILDFLAG(IS_MAC) - if (!is_frameless_) { + if (required) { // For framed windows on macOS we must include the titlebar height in the // UpdateFindBarBoundingBox() calculation. return view_util::GetNSWindowTitleBarHeight( @@ -926,5 +974,5 @@ absl::optional CefWindowView::GetTitlebarHeight() const { } #endif - return absl::nullopt; + return std::nullopt; } diff --git a/libcef/browser/views/window_view.h b/libcef/browser/views/window_view.h index 882acd569..1689878a7 100644 --- a/libcef/browser/views/window_view.h +++ b/libcef/browser/views/window_view.h @@ -6,6 +6,7 @@ #define CEF_LIBCEF_BROWSER_VIEWS_WINDOW_VIEW_H_ #pragma once +#include #include #include "include/views/cef_window.h" @@ -112,13 +113,19 @@ class CefWindowView void SetDraggableRegions(const std::vector& regions); SkRegion* draggable_region() const { return draggable_region_.get(); } + // Called from CefOverlayViewHost::SetOverlayBounds(). + void OnOverlayBoundsChanged(); + // Returns the NonClientFrameView for this Window. May be nullptr. views::NonClientFrameView* GetNonClientFrameView() const; // Optionally modify the bounding box for the Chrome Find bar. void UpdateFindBarBoundingBox(gfx::Rect* bounds) const; - absl::optional GetTitlebarHeight() const; + // Optionally modify the top inset for Chrome dialogs. + void UpdateDialogTopInset(int* dialog_top_y) const; + + std::optional GetTitlebarHeight(bool required) const; bool IsFrameless() const { return is_frameless_; } // The Widget that hosts us, if we're a modal dialog. May return nullptr @@ -130,6 +137,9 @@ class CefWindowView void DeleteDelegate(); void MoveOverlaysIfNecessary(); + void InvalidateExclusionRegions(); + + void UpdateBoundingBox(gfx::Rect* bounds, bool add_titlebar_height) const; // Not owned by this object. Delegate* window_delegate_; @@ -144,6 +154,9 @@ class CefWindowView std::unique_ptr draggable_region_; std::vector draggable_rects_; + mutable int last_dialog_top_y_ = -1; + mutable int last_dialog_top_inset_ = -1; + // Tracks the Widget that hosts us, if we're a modal dialog. std::unique_ptr host_widget_destruction_observer_; diff --git a/patch/patches/chrome_runtime_views.patch b/patch/patches/chrome_runtime_views.patch index 80408da6d..9f3f8e392 100644 --- a/patch/patches/chrome_runtime_views.patch +++ b/patch/patches/chrome_runtime_views.patch @@ -363,7 +363,7 @@ index 0c231b6ac5b01..6b5af98e18e42 100644 BrowserFrame(const BrowserFrame&) = delete; BrowserFrame& operator=(const BrowserFrame&) = delete; diff --git chrome/browser/ui/views/frame/browser_view.cc chrome/browser/ui/views/frame/browser_view.cc -index 4273a5f004935..a46cdb993474b 100644 +index 4273a5f004935..55f2782c262e4 100644 --- chrome/browser/ui/views/frame/browser_view.cc +++ chrome/browser/ui/views/frame/browser_view.cc @@ -343,11 +343,10 @@ using content::NativeWebKeyboardEvent; @@ -381,7 +381,22 @@ index 4273a5f004935..a46cdb993474b 100644 #if BUILDFLAG(IS_CHROMEOS_ASH) // UMA histograms that record animation smoothness for tab loading animation. -@@ -862,11 +861,21 @@ class BrowserView::AccessibilityModeObserver : public ui::AXModeObserver { +@@ -701,6 +700,14 @@ class BrowserViewLayoutDelegateImpl : public BrowserViewLayoutDelegate { + return browser_view_->frame()->GetTopInset() - browser_view_->y(); + } + ++ void UpdateDialogTopInsetInBrowserView(int* dialog_top_y) const override { ++#if BUILDFLAG(ENABLE_CEF) ++ if (auto cef_delegate = browser_view_->browser_->cef_delegate()) { ++ cef_delegate->UpdateDialogTopInset(dialog_top_y); ++ } ++#endif ++ } ++ + bool IsToolbarVisible() const override { + return browser_view_->IsToolbarVisible(); + } +@@ -862,11 +869,21 @@ class BrowserView::AccessibilityModeObserver : public ui::AXModeObserver { /////////////////////////////////////////////////////////////////////////////// // BrowserView, public: @@ -404,7 +419,7 @@ index 4273a5f004935..a46cdb993474b 100644 // Store the actions so that the access is available for other classes. if (features::IsSidePanelPinningEnabled()) { browser_->SetUserData(BrowserActions::UserDataKey(), -@@ -963,8 +972,15 @@ BrowserView::BrowserView(std::unique_ptr browser) +@@ -963,8 +980,15 @@ BrowserView::BrowserView(std::unique_ptr browser) contents_container->SetLayoutManager(std::make_unique( devtools_web_view_, contents_web_view_)); @@ -422,7 +437,7 @@ index 4273a5f004935..a46cdb993474b 100644 contents_separator_ = top_container_->AddChildView(std::make_unique()); -@@ -1038,7 +1054,9 @@ BrowserView::~BrowserView() { +@@ -1038,7 +1062,9 @@ BrowserView::~BrowserView() { // All the tabs should have been destroyed already. If we were closed by the // OS with some tabs than the NativeBrowserFrame should have destroyed them. @@ -432,7 +447,7 @@ index 4273a5f004935..a46cdb993474b 100644 // Stop the animation timer explicitly here to avoid running it in a nested // message loop, which may run by Browser destructor. -@@ -1052,12 +1070,14 @@ BrowserView::~BrowserView() { +@@ -1052,12 +1078,14 @@ BrowserView::~BrowserView() { // child views and it is an observer for avatar toolbar button if any. autofill_bubble_handler_.reset(); @@ -447,7 +462,7 @@ index 4273a5f004935..a46cdb993474b 100644 // The TabStrip attaches a listener to the model. Make sure we shut down the // TabStrip first so that it can cleanly remove the listener. -@@ -1075,7 +1095,9 @@ BrowserView::~BrowserView() { +@@ -1075,7 +1103,9 @@ BrowserView::~BrowserView() { // `SidePanelUI::RemoveSidePanelUIForBrowser()` deletes the // SidePanelCoordinator. @@ -457,7 +472,7 @@ index 4273a5f004935..a46cdb993474b 100644 } // static -@@ -1950,9 +1972,14 @@ void BrowserView::OnExclusiveAccessUserInput() { +@@ -1950,9 +1980,14 @@ void BrowserView::OnExclusiveAccessUserInput() { bool BrowserView::ShouldHideUIForFullscreen() const { // Immersive mode needs UI for the slide-down top panel. @@ -473,7 +488,7 @@ index 4273a5f004935..a46cdb993474b 100644 return frame_->GetFrameView()->ShouldHideTopUIForFullscreen(); } -@@ -3065,7 +3092,8 @@ DownloadShelf* BrowserView::GetDownloadShelf() { +@@ -3065,7 +3100,8 @@ DownloadShelf* BrowserView::GetDownloadShelf() { } DownloadBubbleUIController* BrowserView::GetDownloadBubbleUIController() { @@ -483,7 +498,7 @@ index 4273a5f004935..a46cdb993474b 100644 if (auto* download_button = toolbar_button_provider_->GetDownloadButton()) return download_button->bubble_controller(); return nullptr; -@@ -3616,7 +3644,8 @@ void BrowserView::ReparentTopContainerForEndOfImmersive() { +@@ -3616,7 +3652,8 @@ void BrowserView::ReparentTopContainerForEndOfImmersive() { if (top_container()->parent() == this) return; @@ -493,7 +508,7 @@ index 4273a5f004935..a46cdb993474b 100644 top_container()->DestroyLayer(); AddChildViewAt(top_container(), 0); EnsureFocusOrder(); -@@ -4078,11 +4107,38 @@ void BrowserView::GetAccessiblePanes(std::vector* panes) { +@@ -4078,11 +4115,38 @@ void BrowserView::GetAccessiblePanes(std::vector* panes) { bool BrowserView::ShouldDescendIntoChildForEventHandling( gfx::NativeView child, const gfx::Point& location) { @@ -534,7 +549,7 @@ index 4273a5f004935..a46cdb993474b 100644 // Draggable regions are defined relative to the web contents. gfx::Point point_in_contents_web_view_coords(location); views::View::ConvertPointToTarget(GetWidget()->GetRootView(), -@@ -4091,7 +4147,7 @@ bool BrowserView::ShouldDescendIntoChildForEventHandling( +@@ -4091,7 +4155,7 @@ bool BrowserView::ShouldDescendIntoChildForEventHandling( // Draggable regions should be ignored for clicks into any browser view's // owned widgets, for example alerts, permission prompts or find bar. @@ -543,7 +558,7 @@ index 4273a5f004935..a46cdb993474b 100644 point_in_contents_web_view_coords.x(), point_in_contents_web_view_coords.y()) || WidgetOwnedByAnchorContainsPoint(point_in_contents_web_view_coords); -@@ -4199,8 +4255,10 @@ void BrowserView::Layout() { +@@ -4199,8 +4263,10 @@ void BrowserView::Layout() { // TODO(jamescook): Why was this in the middle of layout code? toolbar_->location_bar()->omnibox_view()->SetFocusBehavior( @@ -556,7 +571,7 @@ index 4273a5f004935..a46cdb993474b 100644 #if BUILDFLAG(IS_CHROMEOS_ASH) // In chromeOS ash we round the bottom two corners of the browser frame by -@@ -4278,6 +4336,11 @@ void BrowserView::AddedToWidget() { +@@ -4278,6 +4344,11 @@ void BrowserView::AddedToWidget() { SetThemeProfileForWindow(GetNativeWindow(), browser_->profile()); #endif @@ -568,7 +583,7 @@ index 4273a5f004935..a46cdb993474b 100644 toolbar_->Init(); // TODO(pbos): Investigate whether the side panels should be creatable when -@@ -4326,13 +4389,9 @@ void BrowserView::AddedToWidget() { +@@ -4326,13 +4397,9 @@ void BrowserView::AddedToWidget() { EnsureFocusOrder(); @@ -584,7 +599,7 @@ index 4273a5f004935..a46cdb993474b 100644 using_native_frame_ = frame_->ShouldUseNativeFrame(); MaybeInitializeWebUITabStrip(); -@@ -4749,7 +4808,8 @@ void BrowserView::ProcessFullscreen(bool fullscreen, +@@ -4749,7 +4816,8 @@ void BrowserView::ProcessFullscreen(bool fullscreen, // Undo our anti-jankiness hacks and force a re-layout. in_process_fullscreen_ = false; ToolbarSizeChanged(false); @@ -594,7 +609,7 @@ index 4273a5f004935..a46cdb993474b 100644 } bool BrowserView::ShouldUseImmersiveFullscreenForUrl(const GURL& url) const { -@@ -5147,6 +5207,8 @@ Profile* BrowserView::GetProfile() { +@@ -5147,6 +5215,8 @@ Profile* BrowserView::GetProfile() { } void BrowserView::UpdateUIForTabFullscreen() { @@ -603,7 +618,7 @@ index 4273a5f004935..a46cdb993474b 100644 frame()->GetFrameView()->UpdateFullscreenTopUI(); } -@@ -5169,6 +5231,8 @@ void BrowserView::HideDownloadShelf() { +@@ -5169,6 +5239,8 @@ void BrowserView::HideDownloadShelf() { } bool BrowserView::CanUserExitFullscreen() const { @@ -644,7 +659,7 @@ index 2e4054890db75..1a518ba936fd1 100644 // Do not friend BrowserViewLayout. Use the BrowserViewLayoutDelegate // interface to keep these two classes decoupled and testable. diff --git chrome/browser/ui/views/frame/browser_view_layout.cc chrome/browser/ui/views/frame/browser_view_layout.cc -index 5e39a622e391e..e0b67a6902182 100644 +index 5e39a622e391e..1d4504370305f 100644 --- chrome/browser/ui/views/frame/browser_view_layout.cc +++ chrome/browser/ui/views/frame/browser_view_layout.cc @@ -48,6 +48,10 @@ @@ -658,7 +673,67 @@ index 5e39a622e391e..e0b67a6902182 100644 using views::View; using web_modal::ModalDialogHostObserver; using web_modal::WebContentsModalDialogHost; -@@ -583,6 +587,13 @@ int BrowserViewLayout::LayoutWebUITabStrip(int top) { +@@ -92,6 +96,10 @@ class BrowserViewLayout::WebContentsModalDialogHostViews + observer.OnHostDestroying(); + } + ++ bool HasObservers() const { ++ return !observer_list_.empty(); ++ } ++ + void NotifyPositionRequiresUpdate() { + for (ModalDialogHostObserver& observer : observer_list_) + observer.OnPositionRequiresUpdate(); +@@ -102,7 +110,7 @@ class BrowserViewLayout::WebContentsModalDialogHostViews + views::View* view = browser_view_layout_->contents_container_; + gfx::Rect rect = view->ConvertRectToWidget(view->GetLocalBounds()); + const int middle_x = rect.x() + rect.width() / 2; +- const int top = browser_view_layout_->dialog_top_y_; ++ const int top = GetDialogTopY(); + return gfx::Point(middle_x - size.width() / 2, top); + } + +@@ -117,7 +125,7 @@ class BrowserViewLayout::WebContentsModalDialogHostViews + gfx::Size GetMaximumDialogSize() override { + views::View* view = browser_view_layout_->contents_container_; + gfx::Rect content_area = view->ConvertRectToWidget(view->GetLocalBounds()); +- const int top = browser_view_layout_->dialog_top_y_; ++ const int top = GetDialogTopY(); + return gfx::Size(content_area.width(), content_area.bottom() - top); + } + +@@ -131,6 +139,13 @@ class BrowserViewLayout::WebContentsModalDialogHostViews + return GetHostWidget()->GetNativeView(); + } + ++ int GetDialogTopY() const { ++ int dialog_top_y = browser_view_layout_->dialog_top_y_; ++ browser_view_layout_->delegate_->UpdateDialogTopInsetInBrowserView( ++ &dialog_top_y); ++ return dialog_top_y; ++ } ++ + // Add/remove observer. + void AddObserver(ModalDialogHostObserver* observer) override { + observer_list_.AddObserver(observer); +@@ -441,6 +456,8 @@ void BrowserViewLayout::Layout(views::View* browser_view) { + if (exclusive_access_bubble) + exclusive_access_bubble->RepositionIfVisible(); + ++ // Avoid unnecessary calls to UpdateDialogTopInsetInBrowserView(). ++ if (dialog_host_->HasObservers()) { + // Adjust any hosted dialogs if the browser's dialog hosting bounds changed. + const gfx::Rect dialog_bounds(dialog_host_->GetDialogPosition(gfx::Size()), + dialog_host_->GetMaximumDialogSize()); +@@ -454,6 +471,7 @@ void BrowserViewLayout::Layout(views::View* browser_view) { + latest_dialog_bounds_in_screen_ = dialog_bounds_in_screen; + dialog_host_->NotifyPositionRequiresUpdate(); + } ++ } + } + + // Return the preferred size which is the size required to give each +@@ -583,6 +601,13 @@ int BrowserViewLayout::LayoutWebUITabStrip(int top) { int BrowserViewLayout::LayoutToolbar(int top) { TRACE_EVENT0("ui", "BrowserViewLayout::LayoutToolbar"); @@ -672,6 +747,18 @@ index 5e39a622e391e..e0b67a6902182 100644 int browser_view_width = vertical_layout_rect_.width(); bool toolbar_visible = delegate_->IsToolbarVisible(); int height = toolbar_visible ? toolbar_->GetPreferredSize().height() : 0; +diff --git chrome/browser/ui/views/frame/browser_view_layout_delegate.h chrome/browser/ui/views/frame/browser_view_layout_delegate.h +index 29ad5517bd3c9..b0fe093467abc 100644 +--- chrome/browser/ui/views/frame/browser_view_layout_delegate.h ++++ chrome/browser/ui/views/frame/browser_view_layout_delegate.h +@@ -28,6 +28,7 @@ class BrowserViewLayoutDelegate { + const gfx::Rect& available_space, + views::Label& window_title_label) const = 0; + virtual int GetTopInsetInBrowserView() const = 0; ++ virtual void UpdateDialogTopInsetInBrowserView(int* dialog_top_y) const = 0; + virtual bool IsToolbarVisible() const = 0; + virtual bool IsBookmarkBarVisible() const = 0; + virtual bool IsContentsSeparatorEnabled() const = 0; diff --git chrome/browser/ui/views/frame/contents_web_view.cc chrome/browser/ui/views/frame/contents_web_view.cc index 8267a265a8e10..ee08f18e96a34 100644 --- chrome/browser/ui/views/frame/contents_web_view.cc