Skip to content

Commit

Permalink
chrome: Improve positioning of the "Find" widget (fixes #3461)
Browse files Browse the repository at this point in the history
The "Find" widget will be excluded from regions near the edges of the window
that contain overlays, draggable regions or titlebar.
  • Loading branch information
magreenblatt committed Apr 20, 2023
1 parent 17cab6d commit a39c2a0
Show file tree
Hide file tree
Showing 20 changed files with 630 additions and 151 deletions.
7 changes: 4 additions & 3 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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 += [
Expand All @@ -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 = [
Expand Down
3 changes: 3 additions & 0 deletions libcef/browser/browser_platform_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 3 additions & 0 deletions libcef/browser/browser_platform_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions libcef/browser/chrome/browser_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions libcef/browser/chrome/chrome_browser_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions libcef/browser/chrome/chrome_browser_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -35,13 +37,16 @@ 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_; }

private:
void SetBrowserView(CefRefPtr<CefBrowserViewImpl> browser_view);

CefWindowImpl* GetWindowImpl() const;

CefRefPtr<CefBrowserViewImpl> browser_view_;
};

Expand Down
102 changes: 102 additions & 0 deletions libcef/browser/geometry_util.cc
Original file line number Diff line number Diff line change
@@ -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;
}
29 changes: 29 additions & 0 deletions libcef/browser/geometry_util.h
Original file line number Diff line number Diff line change
@@ -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_
Loading

0 comments on commit a39c2a0

Please sign in to comment.