chrome: Improve positioning of the "Find" widget (fixes #3461)
The "Find" widget will be excluded from regions near the edges of the window that contain overlays, draggable regions or titlebar.
This commit is contained in:
parent
17cab6d955
commit
a39c2a0068
7
BUILD.gn
7
BUILD.gn
|
@ -385,12 +385,13 @@ source_set("libcef_static_unittested") {
|
|||
sources = [
|
||||
"libcef/browser/devtools/devtools_util.cc",
|
||||
"libcef/browser/devtools/devtools_util.h",
|
||||
"libcef/browser/screen_util.h",
|
||||
"libcef/browser/screen_util.cc",
|
||||
"libcef/browser/geometry_util.h",
|
||||
"libcef/browser/geometry_util.cc",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//base",
|
||||
"//ui/gfx/geometry",
|
||||
]
|
||||
|
||||
configs += [
|
||||
|
@ -406,7 +407,7 @@ test("libcef_static_unittests") {
|
|||
|
||||
sources = [
|
||||
"libcef/browser/devtools/devtools_util_unittest.cc",
|
||||
"libcef/browser/screen_util_unittest.cc",
|
||||
"libcef/browser/geometry_util_unittest.cc",
|
||||
]
|
||||
|
||||
deps = [
|
||||
|
|
|
@ -241,6 +241,9 @@ std::unique_ptr<CefMenuRunner> CefBrowserPlatformDelegate::CreateMenuRunner() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void CefBrowserPlatformDelegate::UpdateFindBarBoundingBox(
|
||||
gfx::Rect* bounds) const {}
|
||||
|
||||
bool CefBrowserPlatformDelegate::IsWindowless() const {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -286,6 +286,9 @@ class CefBrowserPlatformDelegate {
|
|||
// Create the platform-specific menu runner.
|
||||
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
|
||||
// called on multiple threads.
|
||||
virtual bool IsWindowless() const;
|
||||
|
|
|
@ -92,6 +92,9 @@ class BrowserDelegate : public content::WebContentsDelegate {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Optionally modify the bounding box for the Find bar.
|
||||
virtual void UpdateFindBarBoundingBox(gfx::Rect* bounds) {}
|
||||
|
||||
// Same as RequestMediaAccessPermission but returning |callback| if the
|
||||
// request is unhandled.
|
||||
[[nodiscard]] virtual content::MediaResponseCallback
|
||||
|
|
|
@ -176,6 +176,12 @@ bool ChromeBrowserDelegate::IsToolbarButtonVisible(
|
|||
return true;
|
||||
}
|
||||
|
||||
void ChromeBrowserDelegate::UpdateFindBarBoundingBox(gfx::Rect* bounds) {
|
||||
if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) {
|
||||
browser->platform_delegate()->UpdateFindBarBoundingBox(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
content::MediaResponseCallback
|
||||
ChromeBrowserDelegate::RequestMediaAccessPermissionEx(
|
||||
content::WebContents* web_contents,
|
||||
|
|
|
@ -60,6 +60,7 @@ class ChromeBrowserDelegate : public cef::BrowserDelegate {
|
|||
bool IsAppMenuItemEnabled(int command_id) override;
|
||||
bool IsPageActionIconVisible(PageActionIconType icon_type) override;
|
||||
bool IsToolbarButtonVisible(ToolbarButtonType button_type) override;
|
||||
void UpdateFindBarBoundingBox(gfx::Rect* bounds) override;
|
||||
[[nodiscard]] content::MediaResponseCallback RequestMediaAccessPermissionEx(
|
||||
content::WebContents* web_contents,
|
||||
const content::MediaStreamRequest& request,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h"
|
||||
|
||||
#include "include/views/cef_window.h"
|
||||
#include "libcef/browser/views/window_impl.h"
|
||||
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
@ -170,6 +171,23 @@ 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;
|
||||
}
|
||||
|
||||
CefWindowImpl* CefBrowserPlatformDelegateChromeViews::GetWindowImpl() const {
|
||||
if (auto* widget = GetWindowWidget()) {
|
||||
CefRefPtr<CefWindow> window = view_util::GetWindowFor(widget);
|
||||
return static_cast<CefWindowImpl*>(window.get());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "libcef/browser/chrome/browser_platform_delegate_chrome.h"
|
||||
#include "libcef/browser/views/browser_view_impl.h"
|
||||
|
||||
class CefWindowImpl;
|
||||
|
||||
// Implementation of Chrome-based browser functionality.
|
||||
class CefBrowserPlatformDelegateChromeViews
|
||||
: public CefBrowserPlatformDelegateChrome {
|
||||
|
@ -35,6 +37,7 @@ 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<CefBrowserViewImpl> browser_view() const { return browser_view_; }
|
||||
|
@ -42,6 +45,8 @@ class CefBrowserPlatformDelegateChromeViews
|
|||
private:
|
||||
void SetBrowserView(CefRefPtr<CefBrowserViewImpl> browser_view);
|
||||
|
||||
CefWindowImpl* GetWindowImpl() const;
|
||||
|
||||
CefRefPtr<CefBrowserViewImpl> browser_view_;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "libcef/browser/geometry_util.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "ui/gfx/geometry/rect.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kMinWidth = 0;
|
||||
constexpr int kMinHeight = 0;
|
||||
|
||||
// Makes sure that line segment lies entirely between min and max.
|
||||
int clamp_segment_start(int start, int len, int min, int max) {
|
||||
start = std::clamp(start, min, max);
|
||||
const int end = start + len;
|
||||
const int excess = end - max;
|
||||
|
||||
if (excess > 0) {
|
||||
start = start - excess;
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
gfx::Rect MakeVisibleOnScreenRect(const gfx::Rect& rect,
|
||||
const gfx::Rect& screen) {
|
||||
const int width = std::clamp(rect.width(), kMinWidth, screen.width());
|
||||
const int height = std::clamp(rect.height(), kMinHeight, screen.height());
|
||||
|
||||
const int right_border = screen.x() + screen.width();
|
||||
const int x = clamp_segment_start(rect.x(), width, screen.x(), right_border);
|
||||
|
||||
const int bottom_border = screen.y() + screen.height();
|
||||
const int y =
|
||||
clamp_segment_start(rect.y(), height, screen.y(), bottom_border);
|
||||
|
||||
return gfx::Rect(x, y, width, height);
|
||||
}
|
||||
|
||||
gfx::Rect SubtractOverlayFromBoundingBox(const gfx::Rect& bounds,
|
||||
const gfx::Rect& overlay,
|
||||
int max_distance) {
|
||||
if (overlay.Contains(bounds)) {
|
||||
// Early exit; |bounds| is completely inside |overlay|.
|
||||
return bounds;
|
||||
}
|
||||
|
||||
// Portion of |overlay| that is inside |bounds|.
|
||||
auto overlap = overlay;
|
||||
overlap.Intersect(bounds);
|
||||
if (overlap.IsEmpty()) {
|
||||
// Early exit; |bounds| and |overlay| don't intersect.
|
||||
return bounds;
|
||||
}
|
||||
|
||||
gfx::Insets insets;
|
||||
|
||||
if (overlap.width() >= overlap.height()) {
|
||||
// Wide overlay; maybe inset |bounds| in the Y direction.
|
||||
const int delta_top = overlap.y() - bounds.y();
|
||||
const int delta_bottom =
|
||||
bounds.y() + bounds.height() - overlap.y() - overlap.height();
|
||||
|
||||
// Inset from the closest side that meets |max_distance| requirements.
|
||||
if (delta_top <= delta_bottom && delta_top <= max_distance) {
|
||||
// Inset from the top.
|
||||
insets.set_top(delta_top + overlap.height());
|
||||
} else if (delta_bottom <= max_distance) {
|
||||
// Inset from the bottom.
|
||||
insets.set_bottom(delta_bottom + overlap.height());
|
||||
}
|
||||
} else {
|
||||
// Tall overlay; maybe inset |bounds| in the X direction.
|
||||
const int delta_left = overlap.x() - bounds.x();
|
||||
const int delta_right =
|
||||
bounds.x() + bounds.width() - overlap.x() - overlap.width();
|
||||
|
||||
// Inset from the closest side that meets |max_distance| requirements.
|
||||
if (delta_left <= delta_right && delta_left <= max_distance) {
|
||||
// Inset from the left.
|
||||
insets.set_left(delta_left + overlap.width());
|
||||
} else if (delta_right <= max_distance) {
|
||||
// Inset from the right.
|
||||
insets.set_right(delta_right + overlap.width());
|
||||
}
|
||||
}
|
||||
|
||||
if (insets.IsEmpty()) {
|
||||
// |overlay| is too far inside |bounds| to trigger insets.
|
||||
return bounds;
|
||||
}
|
||||
|
||||
auto result = bounds;
|
||||
result.Inset(insets);
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#ifndef CEF_LIBCEF_BROWSER_GEOMETRY_UTIL_H_
|
||||
#define CEF_LIBCEF_BROWSER_GEOMETRY_UTIL_H_
|
||||
#pragma once
|
||||
|
||||
namespace gfx {
|
||||
class Rect;
|
||||
}
|
||||
|
||||
// Create a new rectangle from the input |rect| rectangle that is fully visible
|
||||
// on provided |screen_rect| screen. The width and height of the resulting
|
||||
// rectangle are clamped to the screen width and height respectively if they
|
||||
// would overflow.
|
||||
gfx::Rect MakeVisibleOnScreenRect(const gfx::Rect& rect,
|
||||
const gfx::Rect& screen);
|
||||
|
||||
// Possibly subtract |overlay| from |bounds|. We only want to subtract overlays
|
||||
// that are inside |bounds| and close to the edges, so |max_distance| is the
|
||||
// maximum allowed distance between |overlay| and |bounds| extents in order to
|
||||
// trigger the subtraction. Subtraction will occur from the closest edge. If
|
||||
// distances are otherwise equal then top will be preferred followed by left.
|
||||
gfx::Rect SubtractOverlayFromBoundingBox(const gfx::Rect& bounds,
|
||||
const gfx::Rect& overlay,
|
||||
int max_distance);
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_GEOMETRY_UTIL_H_
|
|
@ -0,0 +1,352 @@
|
|||
// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "cef/libcef/browser/geometry_util.h"
|
||||
#include "tests/gtest/include/gtest/gtest.h"
|
||||
|
||||
#include "ui/gfx/geometry/rect.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kScreenWidth = 1024;
|
||||
constexpr int kScreenHeight = 768;
|
||||
const gfx::Rect kMainScreen(0, 0, kScreenWidth, kScreenHeight);
|
||||
const gfx::Rect kLeftScreen(-1024, 0, kScreenWidth, kScreenHeight);
|
||||
|
||||
#define EXPECT_RECT_EQ(rect1, rect2) \
|
||||
EXPECT_EQ(rect1.x(), rect2.x()); \
|
||||
EXPECT_EQ(rect1.y(), rect2.y()); \
|
||||
EXPECT_EQ(rect1.width(), rect2.width()); \
|
||||
EXPECT_EQ(rect1.height(), rect2.height())
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(GeometryUtil, MakeVisibleOnScreenRect_RectSizeIsBiggerThanScreen) {
|
||||
const gfx::Rect rect{400, 500, 1500, 800};
|
||||
|
||||
auto result = MakeVisibleOnScreenRect(rect, kMainScreen);
|
||||
|
||||
EXPECT_EQ(result.x(), 0);
|
||||
EXPECT_EQ(result.width(), kMainScreen.width());
|
||||
EXPECT_EQ(result.y(), 0);
|
||||
EXPECT_EQ(result.height(), kMainScreen.height());
|
||||
}
|
||||
|
||||
TEST(GeometryUtil, MakeVisibleOnScreenRect_RightBorderIsOutsideTheScreen) {
|
||||
const gfx::Rect rect{600, 400, 500, 300};
|
||||
|
||||
auto result = MakeVisibleOnScreenRect(rect, kMainScreen);
|
||||
|
||||
EXPECT_EQ(result.x(), 524);
|
||||
EXPECT_EQ(result.width(), rect.width());
|
||||
EXPECT_EQ(result.y(), rect.y());
|
||||
EXPECT_EQ(result.height(), rect.height());
|
||||
}
|
||||
|
||||
TEST(GeometryUtil, MakeVisibleOnScreenRect_LeftBorderIsOutsideTheScreen) {
|
||||
const gfx::Rect rect{-400, 400, 500, 300};
|
||||
|
||||
auto result = MakeVisibleOnScreenRect(rect, kMainScreen);
|
||||
|
||||
EXPECT_EQ(result.x(), 0);
|
||||
EXPECT_EQ(result.width(), rect.width());
|
||||
EXPECT_EQ(result.y(), rect.y());
|
||||
EXPECT_EQ(result.height(), rect.height());
|
||||
}
|
||||
|
||||
TEST(GeometryUtil, MakeVisibleOnScreenRect_BottomBorderIsOutsideTheScreen) {
|
||||
const gfx::Rect rect{600, 500, 300, 300};
|
||||
|
||||
auto result = MakeVisibleOnScreenRect(rect, kMainScreen);
|
||||
|
||||
EXPECT_EQ(result.x(), 600);
|
||||
EXPECT_EQ(result.width(), rect.width());
|
||||
EXPECT_EQ(result.y(), 468);
|
||||
EXPECT_EQ(result.height(), rect.height());
|
||||
}
|
||||
|
||||
TEST(GeometryUtil, MakeVisibleOnScreenRect_RectIsVisibleOnTheLeftScreen) {
|
||||
const gfx::Rect rect{-500, 300, 300, 300};
|
||||
|
||||
auto result = MakeVisibleOnScreenRect(rect, kLeftScreen);
|
||||
|
||||
EXPECT_RECT_EQ(result, rect);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil, MakeVisibleOnScreenRect_RectSizeIsBiggerThanLeftScreen) {
|
||||
const gfx::Rect rect{-500, 300, 3000, 3000};
|
||||
|
||||
auto result = MakeVisibleOnScreenRect(rect, kLeftScreen);
|
||||
|
||||
EXPECT_RECT_EQ(result, kLeftScreen);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil, SubtractOverlayFromBoundingBox_Square_NoIntersect_NoInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{0, 0, 10, 10};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 10);
|
||||
|
||||
EXPECT_RECT_EQ(bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil, SubtractOverlayFromBoundingBox_Square_Contains_NoInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{5, 5, 85, 85};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 10);
|
||||
|
||||
EXPECT_RECT_EQ(bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil, SubtractOverlayFromBoundingBox_Square_AllClose_TopInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{12, 12, 76, 76};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
// When all sides are close, inset from the top.
|
||||
const gfx::Rect expected_bounds{10, 88, 80, 2};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_Square_TopAndLeftClose_TopInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{12, 12, 30, 30};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
// When top and left sides are close, inset from the top.
|
||||
const gfx::Rect expected_bounds{10, 42, 80, 48};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_Square_TopAndRightClose_TopInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{58, 12, 30, 30};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
// When top and right sides are close, inset from the top.
|
||||
const gfx::Rect expected_bounds{10, 42, 80, 48};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_Square_BottomAndLeftClose_BottomInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{12, 58, 30, 30};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
// When bottom and left sides are close, inset from the botom.
|
||||
const gfx::Rect expected_bounds{10, 10, 80, 48};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_Square_BottomAndRightClose_BottomInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{58, 58, 30, 30};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
// When bottom and right sides are close, inset from the botom.
|
||||
const gfx::Rect expected_bounds{10, 10, 80, 48};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_WideRect_TopAndLeftExact_TopInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{10, 10, 10, 5};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 0);
|
||||
|
||||
const gfx::Rect expected_bounds{10, 15, 80, 75};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_WideRect_TopIntersectLeftExact_TopInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{10, 7, 10, 5};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
const gfx::Rect expected_bounds{10, 12, 80, 78};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_WideRect_TopInsideLeftExact_TopInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{10, 12, 10, 5};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
const gfx::Rect expected_bounds{10, 17, 80, 73};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_WideRect_TopTooFarInsideLeftExact_NoInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{10, 16, 10, 5};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
EXPECT_RECT_EQ(bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil, SubtractOverlayFromBoundingBox_WideRect_Oversized_TopInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{5, 5, 85, 10};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 10);
|
||||
|
||||
const gfx::Rect expected_bounds{10, 15, 80, 75};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_WideRect_BottomAndLeftExact_BottomInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{10, 85, 10, 5};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 0);
|
||||
|
||||
const gfx::Rect expected_bounds{10, 10, 80, 75};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(
|
||||
GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_WideRect_BottomInsideLeftExact_BottomInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{10, 83, 10, 5};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
const gfx::Rect expected_bounds{10, 10, 80, 73};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(
|
||||
GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_WideRect_BottomIntersectLeftExact_BottomInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{10, 87, 10, 5};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
const gfx::Rect expected_bounds{10, 10, 80, 77};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(
|
||||
GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_WideRect_BottomTooFarInsideLeftExact_NoInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{10, 77, 10, 5};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
EXPECT_RECT_EQ(bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_WideRect_Oversized_BottomInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{5, 85, 85, 10};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 10);
|
||||
|
||||
const gfx::Rect expected_bounds{10, 10, 80, 75};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_TallRect_TopAndLeftExact_LeftInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{10, 10, 5, 10};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 0);
|
||||
|
||||
const gfx::Rect expected_bounds{15, 10, 75, 80};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_TallRect_TopExactLeftIntersect_LeftInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{7, 10, 5, 10};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
const gfx::Rect expected_bounds{12, 10, 78, 80};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_TallRect_TopExactLeftInside_LeftInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{12, 10, 5, 10};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
const gfx::Rect expected_bounds{17, 10, 73, 80};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_TallRect_TopExactLeftTooFarInside_NoInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{16, 10, 5, 10};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
EXPECT_RECT_EQ(bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil, SubtractOverlayFromBoundingBox_TallRect_Oversize_LeftInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{5, 5, 10, 85};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 10);
|
||||
|
||||
const gfx::Rect expected_bounds{15, 10, 75, 80};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_TallRect_TopAndRightExact_RightInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{85, 10, 5, 10};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 0);
|
||||
|
||||
const gfx::Rect expected_bounds{10, 10, 75, 80};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_TallRect_TopExactRightInside_RightInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{83, 10, 5, 10};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
const gfx::Rect expected_bounds{10, 10, 73, 80};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(
|
||||
GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_TallRect_TopExactRightIntersect_RightInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{87, 10, 5, 10};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
const gfx::Rect expected_bounds{10, 10, 77, 80};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
||||
|
||||
TEST(
|
||||
GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_TallRect_TopExactRightTooFarInside_NoInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{77, 10, 5, 10};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 5);
|
||||
|
||||
EXPECT_RECT_EQ(bounds, result);
|
||||
}
|
||||
|
||||
TEST(GeometryUtil,
|
||||
SubtractOverlayFromBoundingBox_TallRect_Oversize_RightInset) {
|
||||
const gfx::Rect bounds{10, 10, 80, 80};
|
||||
const gfx::Rect overlay{85, 5, 10, 85};
|
||||
auto result = SubtractOverlayFromBoundingBox(bounds, overlay, 10);
|
||||
|
||||
const gfx::Rect expected_bounds{10, 10, 75, 80};
|
||||
EXPECT_RECT_EQ(expected_bounds, result);
|
||||
}
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
|
||||
#include "libcef/browser/context.h"
|
||||
#include "libcef/browser/geometry_util.h"
|
||||
#include "libcef/browser/native/window_delegate_view.h"
|
||||
#include "libcef/browser/screen_util.h"
|
||||
#include "libcef/browser/thread_util.h"
|
||||
|
||||
#include "base/base_paths_win.h"
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "libcef/browser/screen_util.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "ui/gfx/geometry/rect.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kMinWidth = 0;
|
||||
constexpr int kMinHeight = 0;
|
||||
|
||||
// Makes sure that line segment lies entirely between min and max.
|
||||
int clamp_segment_start(int start, int len, int min, int max) {
|
||||
start = std::clamp(start, min, max);
|
||||
const int end = start + len;
|
||||
const int excess = end - max;
|
||||
|
||||
if (excess > 0) {
|
||||
start = start - excess;
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
gfx::Rect MakeVisibleOnScreenRect(const gfx::Rect& rect,
|
||||
const gfx::Rect& screen) {
|
||||
const int width = std::clamp(rect.width(), kMinWidth, screen.width());
|
||||
const int height = std::clamp(rect.height(), kMinHeight, screen.height());
|
||||
|
||||
const int right_border = screen.x() + screen.width();
|
||||
const int x = clamp_segment_start(rect.x(), width, screen.x(), right_border);
|
||||
|
||||
const int bottom_border = screen.y() + screen.height();
|
||||
const int y =
|
||||
clamp_segment_start(rect.y(), height, screen.y(), bottom_border);
|
||||
|
||||
return gfx::Rect(x, y, width, height);
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#ifndef CEF_LIBCEF_BROWSER_SCREEN_UTIL_H_
|
||||
#define CEF_LIBCEF_BROWSER_SCREEN_UTIL_H_
|
||||
#pragma once
|
||||
|
||||
namespace gfx {
|
||||
class Rect;
|
||||
}
|
||||
|
||||
// Create a new rectangle from the input |rect| rectangle that is fully visible
|
||||
// on provided |screen_rect| screen. The width and height of the resulting
|
||||
// rectangle are clamped to the screen width and height respectively if they
|
||||
// would overflow.
|
||||
gfx::Rect MakeVisibleOnScreenRect(const gfx::Rect& rect,
|
||||
const gfx::Rect& screen);
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_SCREEN_UTIL_H_
|
|
@ -1,83 +0,0 @@
|
|||
// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "cef/libcef/browser/screen_util.h"
|
||||
#include "tests/gtest/include/gtest/gtest.h"
|
||||
|
||||
#include "ui/gfx/geometry/rect.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kScreenWidth = 1024;
|
||||
constexpr int kScreenHeight = 768;
|
||||
const gfx::Rect kMainScreen(0, 0, kScreenWidth, kScreenHeight);
|
||||
const gfx::Rect kLeftScreen(-1024, 0, kScreenWidth, kScreenHeight);
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(MakeVisibleOnScreenRect, RectSizeIsBiggerThanScreen) {
|
||||
const gfx::Rect rect{400, 500, 1500, 800};
|
||||
|
||||
auto result = MakeVisibleOnScreenRect(rect, kMainScreen);
|
||||
|
||||
EXPECT_EQ(result.x(), 0);
|
||||
EXPECT_EQ(result.width(), kMainScreen.width());
|
||||
EXPECT_EQ(result.y(), 0);
|
||||
EXPECT_EQ(result.height(), kMainScreen.height());
|
||||
}
|
||||
|
||||
TEST(MakeVisibleOnScreenRect, RightBorderIsOutsideTheScreen) {
|
||||
const gfx::Rect rect{600, 400, 500, 300};
|
||||
|
||||
auto result = MakeVisibleOnScreenRect(rect, kMainScreen);
|
||||
|
||||
EXPECT_EQ(result.x(), 524);
|
||||
EXPECT_EQ(result.width(), rect.width());
|
||||
EXPECT_EQ(result.y(), rect.y());
|
||||
EXPECT_EQ(result.height(), rect.height());
|
||||
}
|
||||
|
||||
TEST(MakeVisibleOnScreenRect, LeftBorderIsOutsideTheScreen) {
|
||||
const gfx::Rect rect{-400, 400, 500, 300};
|
||||
|
||||
auto result = MakeVisibleOnScreenRect(rect, kMainScreen);
|
||||
|
||||
EXPECT_EQ(result.x(), 0);
|
||||
EXPECT_EQ(result.width(), rect.width());
|
||||
EXPECT_EQ(result.y(), rect.y());
|
||||
EXPECT_EQ(result.height(), rect.height());
|
||||
}
|
||||
|
||||
TEST(MakeVisibleOnScreenRect, BottomBorderIsOutsideTheScreen) {
|
||||
const gfx::Rect rect{600, 500, 300, 300};
|
||||
|
||||
auto result = MakeVisibleOnScreenRect(rect, kMainScreen);
|
||||
|
||||
EXPECT_EQ(result.x(), 600);
|
||||
EXPECT_EQ(result.width(), rect.width());
|
||||
EXPECT_EQ(result.y(), 468);
|
||||
EXPECT_EQ(result.height(), rect.height());
|
||||
}
|
||||
|
||||
TEST(MakeVisibleOnScreenRect, RectIsVisibleOnTheLeftScreen) {
|
||||
const gfx::Rect rect{-500, 300, 300, 300};
|
||||
|
||||
auto result = MakeVisibleOnScreenRect(rect, kLeftScreen);
|
||||
|
||||
EXPECT_EQ(result.x(), rect.x());
|
||||
EXPECT_EQ(result.width(), rect.width());
|
||||
EXPECT_EQ(result.y(), rect.y());
|
||||
EXPECT_EQ(result.height(), rect.height());
|
||||
}
|
||||
|
||||
TEST(MakeVisibleOnScreenRect, RectSizeIsBiggerThanLeftScreen) {
|
||||
const gfx::Rect rect{-500, 300, 3000, 3000};
|
||||
|
||||
auto result = MakeVisibleOnScreenRect(rect, kLeftScreen);
|
||||
|
||||
EXPECT_EQ(result.x(), kLeftScreen.x());
|
||||
EXPECT_EQ(result.width(), kLeftScreen.width());
|
||||
EXPECT_EQ(result.y(), kLeftScreen.y());
|
||||
EXPECT_EQ(result.height(), kLeftScreen.height());
|
||||
}
|
|
@ -161,6 +161,10 @@ views::NativeWidget* CreateNativeWidget(
|
|||
void SetHostView(views::Widget* widget, views::View* host_view);
|
||||
views::View* GetHostView(views::Widget* widget);
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
float GetNSWindowTitleBarHeight(views::Widget* widget);
|
||||
#endif
|
||||
|
||||
} // namespace view_util
|
||||
|
||||
#endif // CEF_LIBCEF_BROWSER_VIEWS_VIEW_UTIL_H_
|
||||
|
|
|
@ -17,6 +17,9 @@ namespace {
|
|||
|
||||
constexpr char kNativeHostViewKey[] = "CefNativeHostViewKey";
|
||||
|
||||
// For Venura 13.3.1.
|
||||
constexpr float kDefaultTitleBarHeight = 30;
|
||||
|
||||
} // namespace
|
||||
|
||||
gfx::NativeWindow GetNativeWindow(views::Widget* widget) {
|
||||
|
@ -67,4 +70,13 @@ views::View* GetHostView(views::Widget* widget) {
|
|||
widget->GetNativeWindowProperty(kNativeHostViewKey));
|
||||
}
|
||||
|
||||
float GetNSWindowTitleBarHeight(views::Widget* widget) {
|
||||
if (auto window = GetNativeWindow(widget)) {
|
||||
NSWindow* nswindow = window.GetNativeNSWindow();
|
||||
return nswindow.frame.size.height -
|
||||
[nswindow contentRectForFrameRect:nswindow.frame].size.height;
|
||||
}
|
||||
return kDefaultTitleBarHeight;
|
||||
}
|
||||
|
||||
} // namespace view_util
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "libcef/browser/views/window_view.h"
|
||||
|
||||
#include "libcef/browser/chrome/views/chrome_browser_frame.h"
|
||||
#include "libcef/browser/geometry_util.h"
|
||||
#include "libcef/browser/image_impl.h"
|
||||
#include "libcef/browser/views/window_impl.h"
|
||||
#include "libcef/features/runtime.h"
|
||||
|
@ -638,6 +639,7 @@ void CefWindowView::SetDraggableRegions(
|
|||
if (draggable_region_) {
|
||||
draggable_region_.reset(nullptr);
|
||||
}
|
||||
draggable_rects_.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -648,6 +650,11 @@ void CefWindowView::SetDraggableRegions(
|
|||
region.bounds.x + region.bounds.width,
|
||||
region.bounds.y + region.bounds.height},
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
|
||||
if (region.draggable) {
|
||||
draggable_rects_.push_back({region.bounds.x, region.bounds.y,
|
||||
region.bounds.width, region.bounds.height});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -661,3 +668,60 @@ views::NonClientFrameView* CefWindowView::GetNonClientFrameView() const {
|
|||
}
|
||||
return widget->non_client_view()->frame_view();
|
||||
}
|
||||
|
||||
void CefWindowView::UpdateFindBarBoundingBox(gfx::Rect* bounds) const {
|
||||
// Max distance from the edges of |bounds| to qualify for subtraction.
|
||||
const int kMaxDistance = 10;
|
||||
|
||||
for (auto& overlay_host : overlay_hosts_) {
|
||||
*bounds = SubtractOverlayFromBoundingBox(*bounds, overlay_host->bounds(),
|
||||
kMaxDistance);
|
||||
}
|
||||
|
||||
for (auto& rect : draggable_rects_) {
|
||||
*bounds = SubtractOverlayFromBoundingBox(*bounds, rect, kMaxDistance);
|
||||
}
|
||||
|
||||
if (auto titlebar_height = GetTitlebarHeight()) {
|
||||
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) {
|
||||
inset.set_top(*titlebar_height - bounds->y());
|
||||
}
|
||||
|
||||
if (!inset.IsEmpty()) {
|
||||
bounds->Inset(inset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
absl::optional<float> CefWindowView::GetTitlebarHeight() const {
|
||||
if (cef_delegate()) {
|
||||
float title_bar_height = 0;
|
||||
const bool has_title_bar_height =
|
||||
cef_delegate()->GetTitlebarHeight(GetCefWindow(), &title_bar_height);
|
||||
if (has_title_bar_height) {
|
||||
return title_bar_height;
|
||||
}
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
if (!is_frameless_) {
|
||||
// For framed windows on macOS we must include the titlebar height in the
|
||||
// UpdateFindBarBoundingBox() calculation.
|
||||
return view_util::GetNSWindowTitleBarHeight(
|
||||
const_cast<views::Widget*>(GetWidget()));
|
||||
}
|
||||
#endif
|
||||
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
|
|
@ -113,12 +113,17 @@ class CefWindowView
|
|||
// 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;
|
||||
|
||||
private:
|
||||
// Called when removed from the Widget and before |this| is deleted.
|
||||
void DeleteDelegate();
|
||||
|
||||
void MoveOverlaysIfNecessary();
|
||||
|
||||
absl::optional<float> GetTitlebarHeight() const;
|
||||
|
||||
// Not owned by this object.
|
||||
Delegate* window_delegate_;
|
||||
|
||||
|
@ -130,6 +135,7 @@ class CefWindowView
|
|||
CefRefPtr<CefImage> window_app_icon_;
|
||||
|
||||
std::unique_ptr<SkRegion> draggable_region_;
|
||||
std::vector<gfx::Rect> draggable_rects_;
|
||||
|
||||
// Hosts for overlay widgets.
|
||||
std::vector<std::unique_ptr<CefOverlayViewHost>> overlay_hosts_;
|
||||
|
|
|
@ -216,6 +216,23 @@ index 26545b0cee2c1..118cf0df456d6 100644
|
|||
private:
|
||||
friend class ::MockAppMenuModel;
|
||||
|
||||
diff --git chrome/browser/ui/views/find_bar_host.cc chrome/browser/ui/views/find_bar_host.cc
|
||||
index 8ac822b917399..7a7e6fd15bdd9 100644
|
||||
--- chrome/browser/ui/views/find_bar_host.cc
|
||||
+++ chrome/browser/ui/views/find_bar_host.cc
|
||||
@@ -412,6 +412,12 @@ void FindBarHost::GetWidgetBounds(gfx::Rect* bounds) {
|
||||
// The BrowserView does Layout for the components that we care about
|
||||
// positioning relative to, so we ask it to tell us where we should go.
|
||||
*bounds = browser_view()->GetFindBarBoundingBox();
|
||||
+
|
||||
+#if BUILDFLAG(ENABLE_CEF)
|
||||
+ if (browser_view()->browser() && browser_view()->browser()->cef_delegate()) {
|
||||
+ browser_view()->browser()->cef_delegate()->UpdateFindBarBoundingBox(bounds);
|
||||
+ }
|
||||
+#endif
|
||||
}
|
||||
|
||||
void FindBarHost::RegisterAccelerators() {
|
||||
diff --git chrome/browser/ui/views/frame/browser_frame.cc chrome/browser/ui/views/frame/browser_frame.cc
|
||||
index 8da09b8c01c3f..d4f2a855bb8e8 100644
|
||||
--- chrome/browser/ui/views/frame/browser_frame.cc
|
||||
|
|
Loading…
Reference in New Issue