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.
This commit is contained in:
Marshall Greenblatt 2024-01-11 18:32:08 -05:00
parent 9ec3172ffa
commit b5d542d38d
16 changed files with 274 additions and 85 deletions

View File

@ -264,9 +264,6 @@ std::unique_ptr<CefMenuRunner> CefBrowserPlatformDelegate::CreateMenuRunner() {
return nullptr; return nullptr;
} }
void CefBrowserPlatformDelegate::UpdateFindBarBoundingBox(
gfx::Rect* bounds) const {}
bool CefBrowserPlatformDelegate::IsWindowless() const { bool CefBrowserPlatformDelegate::IsWindowless() const {
return false; return false;
} }

View File

@ -286,9 +286,6 @@ class CefBrowserPlatformDelegate {
// Create the platform-specific menu runner. // Create the platform-specific menu runner.
virtual std::unique_ptr<CefMenuRunner> CreateMenuRunner(); virtual std::unique_ptr<CefMenuRunner> 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 // Returns true if this delegate implements windowless rendering. May be
// called on multiple threads. // called on multiple threads.
virtual bool IsWindowless() const; virtual bool IsWindowless() const;

View File

@ -7,11 +7,11 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <optional>
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "chrome/browser/ui/page_action/page_action_icon_type.h" #include "chrome/browser/ui/page_action/page_action_icon_type.h"
#include "content/public/browser/web_contents_delegate.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 "third_party/skia/include/core/SkRegion.h"
#include "ui/base/window_open_disposition.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. // Optionally modify the bounding box for the Find bar.
virtual void UpdateFindBarBoundingBox(gfx::Rect* bounds) {} 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 // Same as RequestMediaAccessPermission but returning |callback| if the
// request is unhandled. // request is unhandled.
[[nodiscard]] virtual content::MediaResponseCallback [[nodiscard]] virtual content::MediaResponseCallback
@ -118,8 +121,8 @@ class BrowserDelegate : public content::WebContentsDelegate {
// Optionally override support for the specified window feature of type // Optionally override support for the specified window feature of type
// Browser::WindowFeature. // Browser::WindowFeature.
virtual absl::optional<bool> SupportsWindowFeature(int feature) const { virtual std::optional<bool> SupportsWindowFeature(int feature) const {
return absl::nullopt; return std::nullopt;
} }
// Returns true if draggable regions are supported. // 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. // Returns the draggable region, if any, relative to the web contents.
// Called from PictureInPictureBrowserFrameView::NonClientHitTest and // Called from PictureInPictureBrowserFrameView::NonClientHitTest and
// BrowserView::ShouldDescendIntoChildForEventHandling. // BrowserView::ShouldDescendIntoChildForEventHandling.
virtual const absl::optional<SkRegion> GetDraggableRegion() const { virtual const std::optional<SkRegion> GetDraggableRegion() const {
return absl::nullopt; return std::nullopt;
} }
// Set the draggable region relative to web contents. // Set the draggable region relative to web contents.

View File

@ -336,8 +336,16 @@ bool ChromeBrowserDelegate::IsToolbarButtonVisible(
} }
void ChromeBrowserDelegate::UpdateFindBarBoundingBox(gfx::Rect* bounds) { void ChromeBrowserDelegate::UpdateFindBarBoundingBox(gfx::Rect* bounds) {
if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) { if (auto cef_window_view = GetCefWindowView()) {
browser->platform_delegate()->UpdateFindBarBoundingBox(bounds); 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_; return *frameless_pip_;
} }
absl::optional<bool> ChromeBrowserDelegate::SupportsWindowFeature( std::optional<bool> ChromeBrowserDelegate::SupportsWindowFeature(
int feature) const { int feature) const {
// Override the default value from // Override the default value from
// Browser::PictureInPictureBrowserSupportsWindowFeature. // Browser::PictureInPictureBrowserSupportsWindowFeature.
@ -386,14 +394,14 @@ absl::optional<bool> ChromeBrowserDelegate::SupportsWindowFeature(
// Return false to hide titlebar and enable draggable regions. // Return false to hide titlebar and enable draggable regions.
return !SupportsFramelessPictureInPicture(); return !SupportsFramelessPictureInPicture();
} }
return absl::nullopt; return std::nullopt;
} }
bool ChromeBrowserDelegate::SupportsDraggableRegion() const { bool ChromeBrowserDelegate::SupportsDraggableRegion() const {
return SupportsFramelessPictureInPicture(); return SupportsFramelessPictureInPicture();
} }
const absl::optional<SkRegion> ChromeBrowserDelegate::GetDraggableRegion() const std::optional<SkRegion> ChromeBrowserDelegate::GetDraggableRegion()
const { const {
DCHECK(SupportsDraggableRegion()); DCHECK(SupportsDraggableRegion());
return draggable_region_; return draggable_region_;
@ -408,14 +416,11 @@ void ChromeBrowserDelegate::WindowFullscreenStateChanged() {
// Use a synchronous callback for notification on Windows/Linux. MacOS gets // Use a synchronous callback for notification on Windows/Linux. MacOS gets
// notified asynchronously via CefNativeWidgetMac callbacks. // notified asynchronously via CefNativeWidgetMac callbacks.
#if !BUILDFLAG(IS_MAC) #if !BUILDFLAG(IS_MAC)
if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) { if (auto cef_window_impl = GetCefWindowImpl()) {
if (auto chrome_browser_view = browser->chrome_browser_view()) { if (auto* delegate = cef_window_impl->delegate()) {
auto* cef_window = chrome_browser_view->cef_browser_view()->cef_window(); // Give the CefWindowDelegate a chance to handle the event.
if (auto* delegate = cef_window->delegate()) { delegate->OnWindowFullscreenTransition(cef_window_impl,
// Give the CefWindowDelegate a chance to handle the event. /*is_completed=*/true);
delegate->OnWindowFullscreenTransition(cef_window,
/*is_completed=*/true);
}
} }
} }
#endif #endif
@ -646,7 +651,7 @@ ChromeBrowserDelegate::CreateBrowserHostForPopup(
} }
CefBrowserContentsDelegate* ChromeBrowserDelegate::GetDelegateForWebContents( CefBrowserContentsDelegate* ChromeBrowserDelegate::GetDelegateForWebContents(
content::WebContents* web_contents) { content::WebContents* web_contents) const {
auto browser_host = auto browser_host =
ChromeBrowserHostImpl::GetBrowserForContents(web_contents); ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
if (browser_host) { if (browser_host) {
@ -655,6 +660,28 @@ CefBrowserContentsDelegate* ChromeBrowserDelegate::GetDelegateForWebContents(
return nullptr; 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<ChromeBrowserView*>(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 { namespace cef {
// static // static

View File

@ -16,6 +16,8 @@
class CefBrowserContentsDelegate; class CefBrowserContentsDelegate;
class CefRequestContextImpl; class CefRequestContextImpl;
class CefWindowImpl;
class CefWindowView;
class ChromeBrowserHostImpl; class ChromeBrowserHostImpl;
// Implementation of the cef::BrowserDelegate interface. Lifespan is controlled // 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 IsPageActionIconVisible(PageActionIconType icon_type) override;
bool IsToolbarButtonVisible(ToolbarButtonType button_type) override; bool IsToolbarButtonVisible(ToolbarButtonType button_type) override;
void UpdateFindBarBoundingBox(gfx::Rect* bounds) override; void UpdateFindBarBoundingBox(gfx::Rect* bounds) override;
void UpdateDialogTopInset(int* dialog_top_y) override;
[[nodiscard]] content::MediaResponseCallback RequestMediaAccessPermissionEx( [[nodiscard]] content::MediaResponseCallback RequestMediaAccessPermissionEx(
content::WebContents* web_contents, content::WebContents* web_contents,
const content::MediaStreamRequest& request, const content::MediaStreamRequest& request,
content::MediaResponseCallback callback) override; content::MediaResponseCallback callback) override;
absl::optional<bool> SupportsWindowFeature(int feature) const override; std::optional<bool> SupportsWindowFeature(int feature) const override;
bool SupportsDraggableRegion() const override; bool SupportsDraggableRegion() const override;
const absl::optional<SkRegion> GetDraggableRegion() const override; const std::optional<SkRegion> GetDraggableRegion() const override;
void UpdateDraggableRegion(const SkRegion& region) override; void UpdateDraggableRegion(const SkRegion& region) override;
void WindowFullscreenStateChanged() override; void WindowFullscreenStateChanged() override;
@ -137,19 +140,25 @@ class ChromeBrowserDelegate : public cef::BrowserDelegate {
CefRefPtr<ChromeBrowserHostImpl> opener); CefRefPtr<ChromeBrowserHostImpl> opener);
CefBrowserContentsDelegate* GetDelegateForWebContents( CefBrowserContentsDelegate* GetDelegateForWebContents(
content::WebContents* web_contents); content::WebContents* web_contents) const;
bool SupportsFramelessPictureInPicture() 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_; Browser* const browser_;
base::WeakPtr<ChromeBrowserHostImpl> opener_host_; base::WeakPtr<ChromeBrowserHostImpl> opener_host_;
// Used when creating a new browser host. // Used when creating a new browser host.
const CefBrowserCreateParams create_params_; const CefBrowserCreateParams create_params_;
absl::optional<bool> show_status_bubble_; std::optional<bool> show_status_bubble_;
absl::optional<SkRegion> draggable_region_; std::optional<SkRegion> draggable_region_;
mutable absl::optional<bool> frameless_pip_; mutable std::optional<bool> frameless_pip_;
std::unique_ptr<CefShowDevToolsParams> pending_show_devtools_params_; std::unique_ptr<CefShowDevToolsParams> pending_show_devtools_params_;
}; };

View File

@ -93,8 +93,15 @@ CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForGlobalId(
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForBrowser( CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForBrowser(
const Browser* browser) { const Browser* browser) {
REQUIRE_CHROME_RUNTIME(); REQUIRE_CHROME_RUNTIME();
return GetBrowserForContents( // Return the ChromeBrowserHostImpl that is currently active.
browser->tab_strip_model()->GetActiveWebContents()); // 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; ChromeBrowserHostImpl::~ChromeBrowserHostImpl() = default;

View File

@ -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 { bool CefBrowserPlatformDelegateChromeViews::IsViewsHosted() const {
return true; return true;
} }

View File

@ -37,7 +37,6 @@ class CefBrowserPlatformDelegateChromeViews
bool is_devtools) override; bool is_devtools) override;
void PopupBrowserCreated(CefBrowserHostBase* new_browser, void PopupBrowserCreated(CefBrowserHostBase* new_browser,
bool is_devtools) override; bool is_devtools) override;
void UpdateFindBarBoundingBox(gfx::Rect* bounds) const override;
bool IsViewsHosted() const override; bool IsViewsHosted() const override;
CefRefPtr<CefBrowserViewImpl> browser_view() const { return browser_view_; } CefRefPtr<CefBrowserViewImpl> browser_view() const { return browser_view_; }

View File

@ -141,7 +141,7 @@ bool CefBrowserViewImpl::HandleKeyboardEvent(
} }
// Give the CefWindowDelegate a chance to handle the event. // 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; CefKeyEvent cef_event;
if (browser_util::GetCefKeyEvent(event, cef_event) && if (browser_util::GetCefKeyEvent(event, cef_event) &&
window_impl->OnKeyEvent(cef_event)) { window_impl->OnKeyEvent(cef_event)) {
@ -316,7 +316,11 @@ ChromeBrowserView* CefBrowserViewImpl::chrome_browser_view() const {
return static_cast<ChromeBrowserView*>(root_view()); return static_cast<ChromeBrowserView*>(root_view());
} }
CefWindowImpl* CefBrowserViewImpl::cef_window() const { CefWindowImpl* CefBrowserViewImpl::cef_window_impl() const {
// Same implementation as GetWindow().
if (!root_view()) {
return nullptr;
}
CefRefPtr<CefWindow> window = CefRefPtr<CefWindow> window =
view_util::GetWindowFor(root_view()->GetWidget()); view_util::GetWindowFor(root_view()->GetWidget());
return static_cast<CefWindowImpl*>(window.get()); return static_cast<CefWindowImpl*>(window.get());

View File

@ -85,7 +85,7 @@ class CefBrowserViewImpl
ChromeBrowserView* chrome_browser_view() const; ChromeBrowserView* chrome_browser_view() const;
// Return the CefWindowImpl hosting this object. // Return the CefWindowImpl hosting this object.
CefWindowImpl* cef_window() const; CefWindowImpl* cef_window_impl() const;
private: private:
// Create a new implementation object. // Create a new implementation object.

View File

@ -278,6 +278,7 @@ void CefOverlayViewHost::SetOverlayBounds(const gfx::Rect& bounds) {
view_->SetSize(bounds_.size()); view_->SetSize(bounds_.size());
} }
widget_->SetBounds(bounds_); widget_->SetBounds(bounds_);
window_view_->OnOverlayBoundsChanged();
bounds_changing_ = false; bounds_changing_ = false;
} }

View File

@ -137,7 +137,7 @@ void CefWindowImpl::ShowAsBrowserModalDialog(
static_cast<CefBrowserViewImpl*>(browser_view.get()); static_cast<CefBrowserViewImpl*>(browser_view.get());
// |browser_view| must belong to the host widget. // |browser_view| must belong to the host widget.
auto* host_widget = static_cast<CefWindowView*>(root_view())->host_widget(); auto* host_widget = cef_window_view()->host_widget();
CHECK(host_widget && CHECK(host_widget &&
browser_view_impl->root_view()->GetWidget() == host_widget); browser_view_impl->root_view()->GetWidget() == host_widget);
@ -739,6 +739,10 @@ void CefWindowImpl::RemoveAllAccelerators() {
focus_manager->UnregisterAccelerators(this); focus_manager->UnregisterAccelerators(this);
} }
CefWindowView* CefWindowImpl::cef_window_view() const {
return static_cast<CefWindowView*>(root_view());
}
CefWindowImpl::CefWindowImpl(CefRefPtr<CefWindowDelegate> delegate) CefWindowImpl::CefWindowImpl(CefRefPtr<CefWindowDelegate> delegate)
: ParentClass(delegate) {} : ParentClass(delegate) {}
@ -747,7 +751,7 @@ CefWindowView* CefWindowImpl::CreateRootView() {
} }
void CefWindowImpl::InitializeRootView() { void CefWindowImpl::InitializeRootView() {
static_cast<CefWindowView*>(root_view())->Initialize(); cef_window_view()->Initialize();
} }
void CefWindowImpl::CreateWidget(gfx::AcceleratedWidget parent_widget) { void CefWindowImpl::CreateWidget(gfx::AcceleratedWidget parent_widget) {

View File

@ -133,6 +133,8 @@ class CefWindowImpl
cef_menu_anchor_position_t anchor_position); cef_menu_anchor_position_t anchor_position);
void MenuClosed(); void MenuClosed();
CefWindowView* cef_window_view() const;
views::Widget* widget() const { return widget_; } views::Widget* widget() const { return widget_; }
bool initialized() const { return initialized_; } bool initialized() const { return initialized_; }

View File

@ -92,7 +92,7 @@ class NativeFrameViewEx : public views::NativeFrameView {
} }
if (!view_->IsFrameless()) { 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)); 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( void CefWindowView::SetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) { const std::vector<CefDraggableRegion>& regions) {
if (regions.empty() && !draggable_region_) {
// Still empty.
return;
}
InvalidateExclusionRegions();
if (regions.empty()) { if (regions.empty()) {
if (draggable_region_) { draggable_region_.reset();
draggable_region_.reset(nullptr);
}
draggable_rects_.clear(); draggable_rects_.clear();
return; return;
} }
@ -854,6 +865,10 @@ void CefWindowView::SetDraggableRegions(
} }
} }
void CefWindowView::OnOverlayBoundsChanged() {
InvalidateExclusionRegions();
}
views::NonClientFrameView* CefWindowView::GetNonClientFrameView() const { views::NonClientFrameView* CefWindowView::GetNonClientFrameView() const {
const views::Widget* widget = GetWidget(); const views::Widget* widget = GetWidget();
if (!widget) { if (!widget) {
@ -865,7 +880,8 @@ views::NonClientFrameView* CefWindowView::GetNonClientFrameView() const {
return widget->non_client_view()->frame_view(); 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. // Max distance from the edges of |bounds| to qualify for subtraction.
const int kMaxDistance = 10; const int kMaxDistance = 10;
@ -878,16 +894,8 @@ void CefWindowView::UpdateFindBarBoundingBox(gfx::Rect* bounds) const {
*bounds = SubtractOverlayFromBoundingBox(*bounds, rect, kMaxDistance); *bounds = SubtractOverlayFromBoundingBox(*bounds, rect, kMaxDistance);
} }
if (auto titlebar_height = GetTitlebarHeight()) { if (auto titlebar_height = GetTitlebarHeight(add_titlebar_height)) {
gfx::Insets inset; 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) { if (add_titlebar_height) {
inset.set_top(*titlebar_height); inset.set_top(*titlebar_height);
} else if (bounds->y() < *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 { views::Widget* CefWindowView::host_widget() const {
if (host_widget_destruction_observer_) { if (host_widget_destruction_observer_) {
return host_widget_destruction_observer_->widget(); return host_widget_destruction_observer_->widget();
@ -907,7 +955,7 @@ views::Widget* CefWindowView::host_widget() const {
return nullptr; return nullptr;
} }
absl::optional<float> CefWindowView::GetTitlebarHeight() const { std::optional<float> CefWindowView::GetTitlebarHeight(bool required) const {
if (cef_delegate()) { if (cef_delegate()) {
float title_bar_height = 0; float title_bar_height = 0;
const bool has_title_bar_height = const bool has_title_bar_height =
@ -918,7 +966,7 @@ absl::optional<float> CefWindowView::GetTitlebarHeight() const {
} }
#if BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_MAC)
if (!is_frameless_) { if (required) {
// For framed windows on macOS we must include the titlebar height in the // For framed windows on macOS we must include the titlebar height in the
// UpdateFindBarBoundingBox() calculation. // UpdateFindBarBoundingBox() calculation.
return view_util::GetNSWindowTitleBarHeight( return view_util::GetNSWindowTitleBarHeight(
@ -926,5 +974,5 @@ absl::optional<float> CefWindowView::GetTitlebarHeight() const {
} }
#endif #endif
return absl::nullopt; return std::nullopt;
} }

View File

@ -6,6 +6,7 @@
#define CEF_LIBCEF_BROWSER_VIEWS_WINDOW_VIEW_H_ #define CEF_LIBCEF_BROWSER_VIEWS_WINDOW_VIEW_H_
#pragma once #pragma once
#include <optional>
#include <vector> #include <vector>
#include "include/views/cef_window.h" #include "include/views/cef_window.h"
@ -112,13 +113,19 @@ class CefWindowView
void SetDraggableRegions(const std::vector<CefDraggableRegion>& regions); void SetDraggableRegions(const std::vector<CefDraggableRegion>& regions);
SkRegion* draggable_region() const { return draggable_region_.get(); } SkRegion* draggable_region() const { return draggable_region_.get(); }
// Called from CefOverlayViewHost::SetOverlayBounds().
void OnOverlayBoundsChanged();
// Returns the NonClientFrameView for this Window. May be nullptr. // Returns the NonClientFrameView for this Window. May be nullptr.
views::NonClientFrameView* GetNonClientFrameView() const; views::NonClientFrameView* GetNonClientFrameView() const;
// Optionally modify the bounding box for the Chrome Find bar. // Optionally modify the bounding box for the Chrome Find bar.
void UpdateFindBarBoundingBox(gfx::Rect* bounds) const; void UpdateFindBarBoundingBox(gfx::Rect* bounds) const;
absl::optional<float> GetTitlebarHeight() const; // Optionally modify the top inset for Chrome dialogs.
void UpdateDialogTopInset(int* dialog_top_y) const;
std::optional<float> GetTitlebarHeight(bool required) const;
bool IsFrameless() const { return is_frameless_; } bool IsFrameless() const { return is_frameless_; }
// The Widget that hosts us, if we're a modal dialog. May return nullptr // The Widget that hosts us, if we're a modal dialog. May return nullptr
@ -130,6 +137,9 @@ class CefWindowView
void DeleteDelegate(); void DeleteDelegate();
void MoveOverlaysIfNecessary(); void MoveOverlaysIfNecessary();
void InvalidateExclusionRegions();
void UpdateBoundingBox(gfx::Rect* bounds, bool add_titlebar_height) const;
// Not owned by this object. // Not owned by this object.
Delegate* window_delegate_; Delegate* window_delegate_;
@ -144,6 +154,9 @@ class CefWindowView
std::unique_ptr<SkRegion> draggable_region_; std::unique_ptr<SkRegion> draggable_region_;
std::vector<gfx::Rect> draggable_rects_; std::vector<gfx::Rect> 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. // Tracks the Widget that hosts us, if we're a modal dialog.
std::unique_ptr<WidgetDestructionObserver> host_widget_destruction_observer_; std::unique_ptr<WidgetDestructionObserver> host_widget_destruction_observer_;

View File

@ -363,7 +363,7 @@ index 0c231b6ac5b01..6b5af98e18e42 100644
BrowserFrame(const BrowserFrame&) = delete; BrowserFrame(const BrowserFrame&) = delete;
BrowserFrame& operator=(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 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
+++ chrome/browser/ui/views/frame/browser_view.cc +++ chrome/browser/ui/views/frame/browser_view.cc
@@ -343,11 +343,10 @@ using content::NativeWebKeyboardEvent; @@ -343,11 +343,10 @@ using content::NativeWebKeyboardEvent;
@ -381,7 +381,22 @@ index 4273a5f004935..a46cdb993474b 100644
#if BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS_ASH)
// UMA histograms that record animation smoothness for tab loading animation. // 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: // BrowserView, public:
@ -404,7 +419,7 @@ index 4273a5f004935..a46cdb993474b 100644
// Store the actions so that the access is available for other classes. // Store the actions so that the access is available for other classes.
if (features::IsSidePanelPinningEnabled()) { if (features::IsSidePanelPinningEnabled()) {
browser_->SetUserData(BrowserActions::UserDataKey(), browser_->SetUserData(BrowserActions::UserDataKey(),
@@ -963,8 +972,15 @@ BrowserView::BrowserView(std::unique_ptr<Browser> browser) @@ -963,8 +980,15 @@ BrowserView::BrowserView(std::unique_ptr<Browser> browser)
contents_container->SetLayoutManager(std::make_unique<ContentsLayoutManager>( contents_container->SetLayoutManager(std::make_unique<ContentsLayoutManager>(
devtools_web_view_, contents_web_view_)); devtools_web_view_, contents_web_view_));
@ -422,7 +437,7 @@ index 4273a5f004935..a46cdb993474b 100644
contents_separator_ = contents_separator_ =
top_container_->AddChildView(std::make_unique<ContentsSeparator>()); top_container_->AddChildView(std::make_unique<ContentsSeparator>());
@@ -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 // 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. // 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 // Stop the animation timer explicitly here to avoid running it in a nested
// message loop, which may run by Browser destructor. // 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. // child views and it is an observer for avatar toolbar button if any.
autofill_bubble_handler_.reset(); 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 // The TabStrip attaches a listener to the model. Make sure we shut down the
// TabStrip first so that it can cleanly remove the listener. // 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 // `SidePanelUI::RemoveSidePanelUIForBrowser()` deletes the
// SidePanelCoordinator. // SidePanelCoordinator.
@ -457,7 +472,7 @@ index 4273a5f004935..a46cdb993474b 100644
} }
// static // static
@@ -1950,9 +1972,14 @@ void BrowserView::OnExclusiveAccessUserInput() { @@ -1950,9 +1980,14 @@ void BrowserView::OnExclusiveAccessUserInput() {
bool BrowserView::ShouldHideUIForFullscreen() const { bool BrowserView::ShouldHideUIForFullscreen() const {
// Immersive mode needs UI for the slide-down top panel. // Immersive mode needs UI for the slide-down top panel.
@ -473,7 +488,7 @@ index 4273a5f004935..a46cdb993474b 100644
return frame_->GetFrameView()->ShouldHideTopUIForFullscreen(); return frame_->GetFrameView()->ShouldHideTopUIForFullscreen();
} }
@@ -3065,7 +3092,8 @@ DownloadShelf* BrowserView::GetDownloadShelf() { @@ -3065,7 +3100,8 @@ DownloadShelf* BrowserView::GetDownloadShelf() {
} }
DownloadBubbleUIController* BrowserView::GetDownloadBubbleUIController() { DownloadBubbleUIController* BrowserView::GetDownloadBubbleUIController() {
@ -483,7 +498,7 @@ index 4273a5f004935..a46cdb993474b 100644
if (auto* download_button = toolbar_button_provider_->GetDownloadButton()) if (auto* download_button = toolbar_button_provider_->GetDownloadButton())
return download_button->bubble_controller(); return download_button->bubble_controller();
return nullptr; return nullptr;
@@ -3616,7 +3644,8 @@ void BrowserView::ReparentTopContainerForEndOfImmersive() { @@ -3616,7 +3652,8 @@ void BrowserView::ReparentTopContainerForEndOfImmersive() {
if (top_container()->parent() == this) if (top_container()->parent() == this)
return; return;
@ -493,7 +508,7 @@ index 4273a5f004935..a46cdb993474b 100644
top_container()->DestroyLayer(); top_container()->DestroyLayer();
AddChildViewAt(top_container(), 0); AddChildViewAt(top_container(), 0);
EnsureFocusOrder(); EnsureFocusOrder();
@@ -4078,11 +4107,38 @@ void BrowserView::GetAccessiblePanes(std::vector<views::View*>* panes) { @@ -4078,11 +4115,38 @@ void BrowserView::GetAccessiblePanes(std::vector<views::View*>* panes) {
bool BrowserView::ShouldDescendIntoChildForEventHandling( bool BrowserView::ShouldDescendIntoChildForEventHandling(
gfx::NativeView child, gfx::NativeView child,
const gfx::Point& location) { const gfx::Point& location) {
@ -534,7 +549,7 @@ index 4273a5f004935..a46cdb993474b 100644
// Draggable regions are defined relative to the web contents. // Draggable regions are defined relative to the web contents.
gfx::Point point_in_contents_web_view_coords(location); gfx::Point point_in_contents_web_view_coords(location);
views::View::ConvertPointToTarget(GetWidget()->GetRootView(), 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 // Draggable regions should be ignored for clicks into any browser view's
// owned widgets, for example alerts, permission prompts or find bar. // 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.x(),
point_in_contents_web_view_coords.y()) || point_in_contents_web_view_coords.y()) ||
WidgetOwnedByAnchorContainsPoint(point_in_contents_web_view_coords); 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? // TODO(jamescook): Why was this in the middle of layout code?
toolbar_->location_bar()->omnibox_view()->SetFocusBehavior( toolbar_->location_bar()->omnibox_view()->SetFocusBehavior(
@ -556,7 +571,7 @@ index 4273a5f004935..a46cdb993474b 100644
#if BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_CHROMEOS_ASH)
// In chromeOS ash we round the bottom two corners of the browser frame by // 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()); SetThemeProfileForWindow(GetNativeWindow(), browser_->profile());
#endif #endif
@ -568,7 +583,7 @@ index 4273a5f004935..a46cdb993474b 100644
toolbar_->Init(); toolbar_->Init();
// TODO(pbos): Investigate whether the side panels should be creatable when // 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(); EnsureFocusOrder();
@ -584,7 +599,7 @@ index 4273a5f004935..a46cdb993474b 100644
using_native_frame_ = frame_->ShouldUseNativeFrame(); using_native_frame_ = frame_->ShouldUseNativeFrame();
MaybeInitializeWebUITabStrip(); 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. // Undo our anti-jankiness hacks and force a re-layout.
in_process_fullscreen_ = false; in_process_fullscreen_ = false;
ToolbarSizeChanged(false); ToolbarSizeChanged(false);
@ -594,7 +609,7 @@ index 4273a5f004935..a46cdb993474b 100644
} }
bool BrowserView::ShouldUseImmersiveFullscreenForUrl(const GURL& url) const { bool BrowserView::ShouldUseImmersiveFullscreenForUrl(const GURL& url) const {
@@ -5147,6 +5207,8 @@ Profile* BrowserView::GetProfile() { @@ -5147,6 +5215,8 @@ Profile* BrowserView::GetProfile() {
} }
void BrowserView::UpdateUIForTabFullscreen() { void BrowserView::UpdateUIForTabFullscreen() {
@ -603,7 +618,7 @@ index 4273a5f004935..a46cdb993474b 100644
frame()->GetFrameView()->UpdateFullscreenTopUI(); frame()->GetFrameView()->UpdateFullscreenTopUI();
} }
@@ -5169,6 +5231,8 @@ void BrowserView::HideDownloadShelf() { @@ -5169,6 +5239,8 @@ void BrowserView::HideDownloadShelf() {
} }
bool BrowserView::CanUserExitFullscreen() const { bool BrowserView::CanUserExitFullscreen() const {
@ -644,7 +659,7 @@ index 2e4054890db75..1a518ba936fd1 100644
// Do not friend BrowserViewLayout. Use the BrowserViewLayoutDelegate // Do not friend BrowserViewLayout. Use the BrowserViewLayoutDelegate
// interface to keep these two classes decoupled and testable. // 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 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
+++ chrome/browser/ui/views/frame/browser_view_layout.cc +++ chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -48,6 +48,10 @@ @@ -48,6 +48,10 @@
@ -658,7 +673,67 @@ index 5e39a622e391e..e0b67a6902182 100644
using views::View; using views::View;
using web_modal::ModalDialogHostObserver; using web_modal::ModalDialogHostObserver;
using web_modal::WebContentsModalDialogHost; 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) { int BrowserViewLayout::LayoutToolbar(int top) {
TRACE_EVENT0("ui", "BrowserViewLayout::LayoutToolbar"); TRACE_EVENT0("ui", "BrowserViewLayout::LayoutToolbar");
@ -672,6 +747,18 @@ index 5e39a622e391e..e0b67a6902182 100644
int browser_view_width = vertical_layout_rect_.width(); int browser_view_width = vertical_layout_rect_.width();
bool toolbar_visible = delegate_->IsToolbarVisible(); bool toolbar_visible = delegate_->IsToolbarVisible();
int height = toolbar_visible ? toolbar_->GetPreferredSize().height() : 0; 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 diff --git chrome/browser/ui/views/frame/contents_web_view.cc chrome/browser/ui/views/frame/contents_web_view.cc
index 8267a265a8e10..ee08f18e96a34 100644 index 8267a265a8e10..ee08f18e96a34 100644
--- chrome/browser/ui/views/frame/contents_web_view.cc --- chrome/browser/ui/views/frame/contents_web_view.cc