blob: 2a028e9b3a6174efe4f0801499082c7af526c052 [file] [log] [blame]
// Copyright (c) 2012 The Chromium 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 <stddef.h>
#include <memory>
#include <set>
#include <string>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/scoped_observer.h"
#include "build/build_config.h"
#include "components/omnibox/browser/omnibox_view.h"
#include "components/search_engines/template_url_service_observer.h"
#include "ui/base/window_open_disposition.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_observer.h"
#include "ui/gfx/range/range.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/textfield/textfield_controller.h"
#if defined(OS_CHROMEOS)
#include "ui/base/ime/chromeos/input_method_manager.h"
class LocationBarView;
class OmniboxClient;
class OmniboxPopupContentsView;
namespace content {
class WebContents;
} // namespace content
namespace gfx {
class RenderText;
namespace send_tab_to_self {
class SendTabToSelfSubMenuModel;
namespace ui {
class OSExchangeData;
} // namespace ui
// Views-implementation of OmniboxView.
class OmniboxViewViews : public OmniboxView,
public views::Textfield,
#if defined(OS_CHROMEOS)
public chromeos::input_method::InputMethodManager::
public views::TextfieldController,
public ui::CompositorObserver,
public TemplateURLServiceObserver {
// The internal view class name.
static const char kViewClassName[];
OmniboxViewViews(OmniboxEditController* controller,
std::unique_ptr<OmniboxClient> client,
bool popup_window_mode,
LocationBarView* location_bar,
const gfx::FontList& font_list);
~OmniboxViewViews() override;
// Initialize, create the underlying views, etc.
void Init();
// Exposes the RenderText for tests.
#if defined(UNIT_TEST)
gfx::RenderText* GetRenderText() {
return views::Textfield::GetRenderText();
// For use when switching tabs, this saves the current state onto the tab so
// that it can be restored during a later call to Update().
void SaveStateToTab(content::WebContents* tab);
// Called when the window's active tab changes.
void OnTabChanged(const content::WebContents* web_contents);
// Called to clear the saved state for |web_contents|.
void ResetTabState(content::WebContents* web_contents);
// Installs the placeholder text with the name of the current default search
// provider. For example, if Google is the default search provider, this shows
// "Search Google or type a URL" when the Omnibox is empty and unfocused.
void InstallPlaceholderText();
// Indicates if the cursor is at one end of the input. Requires that both
// ends of the selection reside there.
bool SelectionAtBeginning() const;
bool SelectionAtEnd() const;
// Returns the width in pixels needed to display the current text. The
// returned value includes margins.
int GetTextWidth() const;
// Returns the omnibox's width in pixels.
int GetWidth() const;
// OmniboxView:
void EmphasizeURLComponents() override;
void Update() override;
base::string16 GetText() const override;
using OmniboxView::SetUserText;
void SetUserText(const base::string16& text,
bool update_popup) override;
void SetWindowTextAndCaretPos(const base::string16& text,
size_t caret_pos,
bool update_popup,
bool notify_text_changed) override;
void EnterKeywordModeForDefaultSearchProvider() override;
bool IsSelectAll() const override;
void GetSelectionBounds(base::string16::size_type* start,
base::string16::size_type* end) const override;
void SelectAll(bool reversed) override;
void RevertAll() override;
void SetFocus() override;
bool IsImeComposing() const override;
gfx::NativeView GetRelativeWindowForPopup() const override;
bool IsImeShowingPopup() const override;
// views::Textfield:
gfx::Size GetMinimumSize() const override;
void OnPaint(gfx::Canvas* canvas) override;
void ExecuteCommand(int command_id, int event_flags) override;
ui::TextInputType GetTextInputType() const override;
void AddedToWidget() override;
void RemovedFromWidget() override;
bool ShouldDoLearning() override;
base::string16 GetLabelForCommandId(int command_id) const override;
bool IsCommandIdEnabled(int command_id) const override;
// For testing only.
OmniboxPopupContentsView* GetPopupContentsViewForTesting() const {
return popup_view_.get();
// views::Textfield:
bool IsDropCursorForInsertion() const override;
// TODO(tommycli): Remove the rest of these friends after porting these
// browser tests to unit tests.
FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, CloseOmniboxPopupOnTextDrag);
FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, FriendlyAccessibleLabel);
FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, DoNotNavigateOnDrop);
class PathFadeAnimation;
enum class UnelisionGesture {
// Update the field with |text| and set the selection.
void SetTextAndSelectedRange(const base::string16& text,
const gfx::Range& range);
// Returns the selected text.
base::string16 GetSelectedText() const;
// Paste text from the clipboard into the omnibox.
// Textfields implementation of Paste() pastes the contents of the clipboard
// as is. We want to strip whitespace and other things (see GetClipboardText()
// for details). The function invokes OnBefore/AfterPossibleChange() as
// necessary.
void OnPaste();
// Handle keyword hint tab-to-search and tabbing through dropdown results.
bool HandleEarlyTabActions(const ui::KeyEvent& event);
void ClearAccessibilityLabel();
void SetAccessibilityLabel(const base::string16& display_text,
const AutocompleteMatch& match);
// Selects the whole omnibox contents as a result of the user gesture. This
// may also unapply steady state elisions depending on user preferences.
void SelectAllForUserGesture();
// Returns true if the user text was updated with the full URL (without
// steady-state elisions). |gesture| is the user gesture causing unelision.
bool UnapplySteadyStateElisions(UnelisionGesture gesture);
// Informs if text and UI direction match (otherwise what "at end" means must
// flip.)
bool TextAndUIDirectionMatch() const;
// Helper function for MaybeFocusTabButton() and MaybeUnfocusTabButton().
bool SelectedSuggestionHasTabMatch() const;
// Like SelectionAtEnd(), but accounts for RTL.
bool DirectionAwareSelectionAtEnd() const;
// Attempts to either focus or unfocus the tab switch button (tests if all
// conditions are met and makes necessary subroutine call) and returns
// whether it succeeded.
bool MaybeFocusTabButton();
bool MaybeUnfocusTabButton();
// OmniboxView:
void SetCaretPos(size_t caret_pos) override;
void UpdatePopup() override;
void ApplyCaretVisibility() override;
void OnTemporaryTextMaybeChanged(const base::string16& display_text,
const AutocompleteMatch& match,
bool save_original_selection,
bool notify_text_changed) override;
bool OnInlineAutocompleteTextMaybeChanged(const base::string16& display_text,
size_t user_text_length) override;
void OnInlineAutocompleteTextCleared() override;
void OnRevertTemporaryText(const base::string16& display_text,
const AutocompleteMatch& match) override;
void OnBeforePossibleChange() override;
bool OnAfterPossibleChange(bool allow_keyword_ui_change) override;
gfx::NativeView GetNativeView() const override;
void ShowVirtualKeyboardIfEnabled() override;
void HideImeIfNeeded() override;
int GetOmniboxTextLength() const override;
void SetEmphasis(bool emphasize, const gfx::Range& range) override;
void UpdateSchemeStyle(const gfx::Range& range) override;
// views::View
void OnMouseMoved(const ui::MouseEvent& event) override;
void OnMouseExited(const ui::MouseEvent& event) override;
// views::Textfield:
bool IsItemForCommandIdDynamic(int command_id) const override;
const char* GetClassName() const override;
bool OnMousePressed(const ui::MouseEvent& event) override;
bool OnMouseDragged(const ui::MouseEvent& event) override;
void OnMouseReleased(const ui::MouseEvent& event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
void AboutToRequestFocusFromTabTraversal(bool reverse) override;
bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
bool HandleAccessibleAction(const ui::AXActionData& action_data) override;
void OnFocus() override;
void OnBlur() override;
base::string16 GetSelectionClipboardText() const override;
void DoInsertChar(base::char16 ch) override;
bool IsTextEditCommandEnabled(ui::TextEditCommand command) const override;
void ExecuteTextEditCommand(ui::TextEditCommand command) override;
bool ShouldShowPlaceholderText() const override;
// chromeos::input_method::InputMethodManager::CandidateWindowObserver:
#if defined(OS_CHROMEOS)
void CandidateWindowOpened(
chromeos::input_method::InputMethodManager* manager) override;
void CandidateWindowClosed(
chromeos::input_method::InputMethodManager* manager) override;
// views::TextfieldController:
void ContentsChanged(views::Textfield* sender,
const base::string16& new_contents) override;
bool HandleKeyEvent(views::Textfield* sender,
const ui::KeyEvent& key_event) override;
void OnBeforeUserAction(views::Textfield* sender) override;
void OnAfterUserAction(views::Textfield* sender) override;
void OnAfterCutOrCopy(ui::ClipboardType clipboard_type) override;
void OnWriteDragData(ui::OSExchangeData* data) override;
void OnGetDragOperationsForTextfield(int* drag_operations) override;
void AppendDropFormats(
int* formats,
std::set<ui::ClipboardFormatType>* format_types) override;
int OnDrop(const ui::OSExchangeData& data) override;
void UpdateContextMenu(ui::SimpleMenuModel* menu_contents) override;
// ui::CompositorObserver:
void OnCompositingDidCommit(ui::Compositor* compositor) override;
void OnCompositingStarted(ui::Compositor* compositor,
base::TimeTicks start_time) override;
void OnCompositingEnded(ui::Compositor* compositor) override;
void OnCompositingShuttingDown(ui::Compositor* compositor) override;
// TemplateURLServiceObserver:
void OnTemplateURLServiceChanged() override;
// When true, the location bar view is read only and also is has a slightly
// different presentation (smaller font size). This is used for popups.
bool popup_window_mode_;
std::unique_ptr<OmniboxPopupContentsView> popup_view_;
// Animation used to fade out the path under some elision settings.
std::unique_ptr<PathFadeAnimation> path_fade_animation_;
// Selection persisted across temporary text changes, like popup suggestions.
gfx::Range saved_temporary_selection_;
// Holds the user's selection across focus changes. There is only a saved
// selection if this range IsValid().
gfx::Range saved_selection_for_focus_change_;
// Tracking state before and after a possible change.
State state_before_change_;
bool ime_composing_before_change_ = false;
// |location_bar_view_| can be NULL in tests.
LocationBarView* location_bar_view_;
#if defined(OS_CHROMEOS)
// True if the IME candidate window is open. When this is true, we want to
// avoid showing the popup. So far, the candidate window is detected only
// on Chrome OS.
bool ime_candidate_window_open_ = false;
// True if any mouse button is currently depressed.
bool is_mouse_pressed_ = false;
// Applies a minimum threshold to drag events after unelision. Because the
// text shifts after unelision, we don't want unintentional mouse drags to
// change the selection.
bool filter_drag_events_for_unelision_ = false;
// Should we select all the text when we see the mouse button get released?
// We select in response to a click that focuses the omnibox, but we defer
// until release, setting this variable back to false if we saw a drag, to
// allow the user to select just a portion of the text.
bool select_all_on_mouse_release_ = false;
// Indicates if we want to select all text in the omnibox when we get a
// GESTURE_TAP. We want to select all only when the textfield is not in focus
// and gets a tap. So we use this variable to remember focus state before tap.
bool select_all_on_gesture_tap_ = false;
// The time of the first character insert operation that has not yet been
// painted. Used to measure omnibox responsiveness with a histogram.
base::TimeTicks insert_char_time_;
// The state machine for logging the Omnibox.CharTypedToRepaintLatency
// histogram.
enum {
NOT_ACTIVE, // Not currently tracking a char typed event.
CHAR_TYPED, // Character was typed.
ON_PAINT_CALLED, // Character was typed and OnPaint() called.
COMPOSITING_COMMIT, // Compositing was committed after OnPaint().
COMPOSITING_STARTED, // Compositing was started.
} latency_histogram_state_;
// The currently selected match, if any, with additional labelling text
// such as the document title and the type of search, for example:
// "Google location from bookmark", or
// "cats are liquid search suggestion".
base::string16 friendly_suggestion_text_;
// The number of added labelling characters before editable text begins.
// For example, "Google location from history",
// this is set to 7 (the length of "Google ").
int friendly_suggestion_text_prefix_length_;
ScopedObserver<ui::Compositor, ui::CompositorObserver>
ScopedObserver<TemplateURLService, TemplateURLServiceObserver>
// Send tab to self submenu.