blob: 66429fb4f9db1fb673a67e870a8a2dab1f9f4641 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_FIND_BAR_HOST_H_
#define CHROME_BROWSER_UI_VIEWS_FIND_BAR_HOST_H_
#include <memory>
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/ui/find_bar/find_bar.h"
#include "chrome/browser/ui/find_bar/find_bar_controller.h"
#include "chrome/browser/ui/views/find_bar_owner.h"
#include "chrome/browser/ui/views/find_bar_view.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_ui_types.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/focus/external_focus_tracker.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/widget/widget_delegate.h"
class BrowserView;
class FindBarController;
class FindInPageTest;
namespace find_in_page {
class FindNotificationDetails;
}
namespace views {
class Widget;
}
////////////////////////////////////////////////////////////////////////////////
//
// The FindBarHost implements the container widget for the find-in-page
// functionality. It is responsible for showing, hiding, closing, and moving the
// widget if needed, for example if the widget is obscuring the selection
// results. It also receives notifications about the search results and
// communicates that to the view. There is one FindBarHost per BrowserView, and
// its state is updated whenever the selected Tab is changed. The FindBarHost is
// created when the BrowserView is attached to the frame's Widget for the first
// time.
//
////////////////////////////////////////////////////////////////////////////////
class FindBarHost : public FindBar,
public FindBarTesting,
public views::FocusChangeListener,
public ui::AcceleratorTarget,
public views::AnimationDelegateViews,
public views::WidgetDelegate {
public:
explicit FindBarHost(FindBarOwner* find_bar_owner);
FindBarHost(const FindBarHost&) = delete;
FindBarHost& operator=(const FindBarHost&) = delete;
~FindBarHost() override;
// Forwards selected key events to the renderer. This is useful to make sure
// that arrow keys and PageUp and PageDown result in scrolling, instead of
// being eaten because the FindBar has focus. Returns true if the keystroke
// was forwarded, false if not.
bool MaybeForwardKeyEventToWebpage(const ui::KeyEvent& key_event);
// Returns true if the find bar view is visible, or false otherwise.
bool IsVisible() const;
FindBarOwner* find_bar_owner() { return find_bar_owner_; }
#if BUILDFLAG(IS_MAC)
// Get the host widget.
views::Widget* GetHostWidget() override;
#endif
// FindBar implementation:
FindBarController* GetFindBarController() const override;
void SetFindBarController(FindBarController* find_bar_controller) override;
void Show(bool animate, bool focus) override;
void Hide(bool animate) override;
void SetFocusAndSelection() override;
void ClearResults(
const find_in_page::FindNotificationDetails& results) override;
void StopAnimation() override;
void MoveWindowIfNecessary() override;
void SetFindTextAndSelectedRange(const std::u16string& find_text,
const gfx::Range& selected_range) override;
std::u16string_view GetFindText() const override;
gfx::Range GetSelectedRange() const override;
void UpdateUIForFindResult(
const find_in_page::FindNotificationDetails& result,
const std::u16string& find_text) override;
void AudibleAlert() override;
bool IsFindBarVisible() const override;
void RestoreSavedFocus() override;
bool HasGlobalFindPasteboard() const override;
void UpdateFindBarForChangedWebContents() override;
const FindBarTesting* GetFindBarTesting() const override;
bool HasFocus() const override;
// Overridden from ui::AcceleratorTarget
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
bool CanHandleAccelerators() const override;
// FindBarTesting implementation:
bool GetFindBarWindowInfo(gfx::Point* position,
bool* fully_visible) const override;
std::u16string_view GetFindSelectedText() const override;
std::u16string_view GetMatchCountText() const override;
int GetContentsWidth() const override;
size_t GetAudibleAlertCount() const override;
// views::WidgetDelegate:
std::u16string GetAccessibleWindowTitle() const override;
FindBarView* GetFindBarViewForTesting();
static void SetEnableAnimationsForTesting(bool enable_animations);
private:
friend class FindInPageTest;
friend class LegacyFindInPageTest;
// Return the current web contents.
content::WebContents* web_contents() {
return find_bar_controller_ ? find_bar_controller_->web_contents()
: nullptr;
}
// Allows implementation to tweak widget position.
void GetWidgetPositionNative(gfx::Rect* avoid_overlapping_rect);
// If the find bar obscures the search results we need to move the window. To
// do that we need to know what is selected on the page. We simply calculate
// where it would be if we place it on the left of the selection and if it
// doesn't fit on the screen we try the right side. The parameter
// |selection_rect| is expected to have coordinates relative to the top of
// the web page area.
void MoveWindowIfNecessaryWithRect(const gfx::Rect& selection_rect);
// Saves the focus tracker for potential restoration later during a
// WebContents change.
void SaveFocusTracker();
// Takes the focus tracker from a WebContents and restores it to the
// FindBarHost. If no focus tracker is set, creates one.
void RestoreOrCreateFocusTracker();
// Call when the find bar gains or loses focus on current tab. Used to restore
// focus state in tab switching. i.e. the focus state should not change after
// switching away and then back to the current tab.
void SetFindBarIsFocusedOnCurrentTab(bool focused);
// Called when `is_visible_` changes.
void OnVisibilityChanged();
// Registers this class as the handler for when Escape is pressed. Once we
// loose focus we will unregister Escape and (any accelerators the derived
// classes registers by using overrides of RegisterAccelerators). See also:
// SetFocusChangeListener().
void RegisterAccelerators();
// When we lose focus, we unregister all accelerator handlers. See also:
// SetFocusChangeListener().
void UnregisterAccelerators();
// Returns the rectangle representing where to position the find bar. It uses
// GetDialogBounds and positions itself within that, either to the left (if an
// InfoBar is present) or to the right (no InfoBar). If
// |avoid_overlapping_rect| is specified, the return value will be a rectangle
// located immediately to the left of |avoid_overlapping_rect|, as long as
// there is enough room for the dialog to draw within the bounds. If not, the
// dialog position returned will overlap |avoid_overlapping_rect|.
// Note: |avoid_overlapping_rect| is expected to use coordinates relative to
// the top of the page area, (it will be converted to coordinates relative to
// the top of the browser window, when comparing against the dialog
// coordinates). The returned value is relative to the browser window.
gfx::Rect GetDialogPosition(gfx::Rect avoid_overlapping_rect);
// Moves the dialog window to the provided location, moves it to top in the
// z-order (HWND_TOP, not HWND_TOPMOST) and shows the window (if hidden).
void SetDialogPosition(const gfx::Rect& new_pos);
// views::FocusChangeListener:
void OnWillChangeFocus(views::View* focused_before,
views::View* focused_now) override;
// views::AnimationDelegateViews:
void AnimationProgressed(const gfx::Animation* animation) override;
void AnimationEnded(const gfx::Animation* animation) override;
// Our view, which is responsible for drawing the UI.
raw_ptr<FindBarView, DanglingUntriaged> view_ = nullptr;
// The animation class to use when opening the FindBar widget.
std::unique_ptr<gfx::SlideAnimation> animation_;
// Host is the Widget implementation that is created and maintained by the
// find bar. It contains the find bar view.
std::unique_ptr<views::Widget> host_;
// A pointer back to the owning controller.
raw_ptr<FindBarController> find_bar_controller_ = nullptr;
// The number of audible alerts issued.
size_t audible_alerts_ = 0;
// A flag to manually manage visibility. GTK/X11 is asynchronous and
// the state of the widget can be out of sync.
bool is_visible_ = false;
// The FindBarOwner that created us.
const raw_ptr<FindBarOwner, DanglingUntriaged> find_bar_owner_;
// The focus manager we register with to keep track of focus changes.
raw_ptr<views::FocusManager, DanglingUntriaged> focus_manager_ = nullptr;
// True if the accelerator target for Esc key is registered.
bool esc_accel_target_registered_ = false;
// Tracks and stores the last focused view which is not the FindBarHost's view
// or any of its children. Used to restore focus once the FindBarHost's view
// is closed.
std::unique_ptr<views::ExternalFocusTracker> focus_tracker_;
// Observation over the host's FocusManager.
base::ScopedObservation<views::FocusManager, views::FocusChangeListener>
focus_manager_observation_{this};
};
#endif // CHROME_BROWSER_UI_VIEWS_FIND_BAR_HOST_H_