1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // This file defines the interface class OmniboxView.  Each toolkit will
6 // implement the edit view differently, so that code is inherently platform
7 // specific.  However, the OmniboxEditModel needs to do some communication with
8 // the view.  Since the model is shared between platforms, we need to define an
9 // interface that all view implementations will share.
10 
11 #ifndef COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_VIEW_H_
12 #define COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_VIEW_H_
13 
14 #include <stddef.h>
15 
16 #include <memory>
17 #include <string>
18 
19 #include "base/gtest_prod_util.h"
20 #include "base/strings/string16.h"
21 #include "base/strings/string_util.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "components/omnibox/browser/autocomplete_match.h"
24 #include "components/omnibox/browser/omnibox_client.h"
25 #include "third_party/skia/include/core/SkColor.h"
26 #include "ui/base/models/image_model.h"
27 #include "ui/base/window_open_disposition.h"
28 #include "ui/gfx/image/image_skia.h"
29 #include "ui/gfx/native_widget_types.h"
30 #include "ui/gfx/range/range.h"
31 
32 class GURL;
33 class OmniboxEditController;
34 class OmniboxViewMacTest;
35 class OmniboxEditModel;
36 
37 class OmniboxView {
38  public:
39   using IconFetchedCallback = base::OnceCallback<void(const gfx::Image& icon)>;
40 
41   // Represents the changes between two State objects.  This is used by the
42   // model to determine how its internal state should be updated after the view
43   // state changes.  See OmniboxEditModel::OnAfterPossibleChange().
44   struct StateChanges {
45     // |old_text| and |new_text| are not owned.
46     const base::string16* old_text;
47     const base::string16* new_text;
48     size_t new_sel_start;
49     size_t new_sel_end;
50     bool selection_differs;
51     bool text_differs;
52     bool keyword_differs;
53     bool just_deleted_text;
54   };
55 
56   virtual ~OmniboxView();
57   OmniboxView(const OmniboxView&) = delete;
58   OmniboxView& operator=(const OmniboxView&) = delete;
59 
60   // Used by the automation system for getting at the model from the view.
model()61   OmniboxEditModel* model() { return model_.get(); }
model()62   const OmniboxEditModel* model() const { return model_.get(); }
63 
64   // Called when any relevant state changes other than changing tabs.
65   virtual void Update() = 0;
66 
67   // Asks the browser to load the specified match, using the supplied
68   // disposition. |alternate_nav_url|, if non-empty, contains the
69   // alternate navigation URL for for this match. See comments on
70   // AutocompleteResult::GetAlternateNavURL().
71   //
72   // |pasted_text| should only be set if this call is due to a
73   // Paste-And-Go/Search action.
74   //
75   // |selected_line| is passed to SendOpenNotification(); see comments there.
76   //
77   // This may close the popup.
78   virtual void OpenMatch(const AutocompleteMatch& match,
79                          WindowOpenDisposition disposition,
80                          const GURL& alternate_nav_url,
81                          const base::string16& pasted_text,
82                          size_t selected_line,
83                          base::TimeTicks match_selection_timestamp);
84 
85   // Returns the current text of the edit control, which could be the
86   // "temporary" text set by the popup, the "permanent" text set by the
87   // browser, or just whatever the user has currently typed.
88   virtual base::string16 GetText() const = 0;
89 
90   // |true| if the user is in the process of editing the field, or if
91   // the field is empty.
92   bool IsEditingOrEmpty() const;
93 
94   // Returns the icon to display as the location icon. If a favicon is
95   // available, |on_icon_fetched| may be called later asynchronously.
96   ui::ImageModel GetIcon(int dip_size,
97                          SkColor color,
98                          IconFetchedCallback on_icon_fetched) const;
99 
100   // The user text is the text the user has manually keyed in.  When present,
101   // this is shown in preference to the permanent text; hitting escape will
102   // revert to the permanent text.
103   void SetUserText(const base::string16& text);
104   virtual void SetUserText(const base::string16& text,
105                            bool update_popup);
106 
107   // Sets the window text and the caret position. |notify_text_changed| is true
108   // if the model should be notified of the change. If rich autocompletion is
109   // enabled, |additional_text| is displayed in a non-editable views::Label
110   // adjacent to the omnibox.
111   virtual void SetWindowTextAndCaretPos(const base::string16& text,
112                                         size_t caret_pos,
113                                         bool update_popup,
114                                         bool notify_text_changed) = 0;
115 
116   // Sets the caret position. Removes any selection. Clamps the requested caret
117   // position to the length of the current text.
118   virtual void SetCaretPos(size_t caret_pos) = 0;
119 
120   // Sets the omnibox adjacent additional text label in the location bar view.
121   virtual void SetAdditionalText(const base::string16& text) = 0;
122 
123   // Transitions the user into keyword mode with their default search provider,
124   // preserving and selecting the user's text if they already typed in a query.
125   virtual void EnterKeywordModeForDefaultSearchProvider() = 0;
126 
127   // Returns true if all text is selected. Returns false if there is no text.
128   virtual bool IsSelectAll() const = 0;
129 
130   // Fills |start| and |end| with the indexes of the current selection's bounds.
131   // It is not guaranteed that |*start < *end|, as the selection can be
132   // directed.  If there is no selection, |start| and |end| will both be equal
133   // to the current cursor position.
134   virtual void GetSelectionBounds(size_t* start, size_t* end) const = 0;
135 
136   // Returns the sum of all selections' lengths. This is used to detect when
137   // the user has deleted text, and therefore, their input should not be
138   // autocompleted.
139   virtual size_t GetAllSelectionsLength() const = 0;
140 
141   // Selects all the text in the edit.  Use this in place of SetSelAll() to
142   // avoid selecting the "phantom newline" at the end of the edit.
143   virtual void SelectAll(bool reversed) = 0;
144 
145   // Reverts the edit and popup back to their unedited state (permanent text
146   // showing, popup closed, no user input in progress).
147   virtual void RevertAll();
148 
149   // Updates the autocomplete popup and other state after the text has been
150   // changed by the user.
151   virtual void UpdatePopup() = 0;
152 
153   // Closes the autocomplete popup, if it's open. The name |ClosePopup|
154   // conflicts with the OSX class override as that has a base class that also
155   // defines a method with that name.
156   virtual void CloseOmniboxPopup();
157 
158   // Sets the focus to the omnibox. |is_user_initiated| is true when the user
159   // explicitly focused the omnibox, and false when the omnibox was
160   // automatically focused (like for browser startup or NTP load).
161   virtual void SetFocus(bool is_user_initiated) = 0;
162 
163   // Shows or hides the caret based on whether the model's is_caret_visible() is
164   // true.
165   virtual void ApplyCaretVisibility() = 0;
166 
167   // Updates the accessibility state by enunciating any on-focus text.
SetAccessibilityLabel(const base::string16 & display_text,const AutocompleteMatch & match,bool notify_text_changed)168   virtual void SetAccessibilityLabel(const base::string16& display_text,
169                                      const AutocompleteMatch& match,
170                                      bool notify_text_changed) {}
171 
172   // Called when the temporary text in the model may have changed.
173   // |display_text| is the new text to show; |match_type| is the type of the
174   // match the new text came from. |save_original_selection| is true when there
175   // wasn't previously a temporary text and thus we need to save off the user's
176   // existing selection. |notify_text_changed| is true if the model should be
177   // notified of the change.
178   virtual void OnTemporaryTextMaybeChanged(const base::string16& display_text,
179                                            const AutocompleteMatch& match,
180                                            bool save_original_selection,
181                                            bool notify_text_changed) = 0;
182 
183   // Called when the inline autocomplete text in the model may have changed.
184   // |display_text| is the new text to show. |selection| indicates the
185   // autocompleted portions which should be selected. |user_text_length| is the
186   // length of the user input portion of the text (not including the
187   // autocompletion).
188   virtual void OnInlineAutocompleteTextMaybeChanged(
189       const base::string16& display_text,
190       std::vector<gfx::Range> selections,
191       size_t user_text_length) = 0;
192 
193   // Called when the inline autocomplete text in the model has been cleared.
194   virtual void OnInlineAutocompleteTextCleared() = 0;
195 
196   // Called when the temporary text has been reverted by the user.  This will
197   // reset the user's original selection.
198   virtual void OnRevertTemporaryText(const base::string16& display_text,
199                                      const AutocompleteMatch& match) = 0;
200 
201   // Checkpoints the current edit state before an operation that might trigger
202   // a new autocomplete run to open or modify the popup. Call this before
203   // user-initiated edit actions that trigger autocomplete, but *not* for
204   // automatic changes to the textfield that should not affect autocomplete.
205   virtual void OnBeforePossibleChange() = 0;
206   // OnAfterPossibleChange() returns true if there was a change that caused it
207   // to call UpdatePopup().  If |allow_keyword_ui_change| is false, we
208   // prevent alterations to the keyword UI state (enabled vs. disabled).
209   virtual bool OnAfterPossibleChange(bool allow_keyword_ui_change) = 0;
210 
211   // Returns the gfx::NativeView of the edit view.
212   virtual gfx::NativeView GetNativeView() const = 0;
213 
214   // Gets the relative window for the pop up window of OmniboxPopupView. The pop
215   // up window will be shown under the relative window. When an IME is attached
216   // to the rich edit control, the IME window is the relative window. Otherwise,
217   // the top-most window is the relative window.
218   virtual gfx::NativeView GetRelativeWindowForPopup() const = 0;
219 
220   // Returns true if the user is composing something in an IME.
221   virtual bool IsImeComposing() const = 0;
222 
223   // Returns true if we know for sure that an IME is showing a popup window,
224   // which may overlap the omnibox's popup window.
225   virtual bool IsImeShowingPopup() const;
226 
227   // Display a virtual keyboard or alternate input view if enabled.
228   virtual void ShowVirtualKeyboardIfEnabled();
229 
230   // Hides a virtual keyboard or alternate input view if enabled.
231   virtual void HideImeIfNeeded();
232 
233   // Returns true if the view is displaying UI that indicates that query
234   // refinement will take place when the user selects the current match.  For
235   // search matches, this will cause the omnibox to search over the existing
236   // corpus (e.g. Images) rather than start a new Web search.  This method will
237   // only ever return true on mobile ports.
238   virtual bool IsIndicatingQueryRefinement() const;
239 
240   // Returns |text| with any leading javascript schemas stripped.
241   static base::string16 StripJavascriptSchemas(const base::string16& text);
242 
243   // Automatically collapses internal whitespace as follows:
244   // * Leading and trailing whitespace are often copied accidentally and rarely
245   //   affect behavior, so they are stripped.  If this collapses the whole
246   //   string, returns a space, since pasting nothing feels broken.
247   // * Internal whitespace sequences not containing CR/LF may be integral to the
248   //   meaning of the string and are preserved exactly.  The presence of any of
249   //   these also suggests the input is more likely a search than a navigation,
250   //   which affects the next bullet.
251   // * Internal whitespace sequences containing CR/LF have likely been split
252   //   across lines by terminals, email programs, etc., and are collapsed.  If
253   //   there are any internal non-CR/LF whitespace sequences, the input is more
254   //   likely search data (e.g. street addresses), so collapse these to a single
255   //   space.  If not, the input might be a navigation (e.g. a line-broken URL),
256   //   so collapse these away entirely.
257   //
258   // Finally, calls StripJavascriptSchemas() on the resulting string.
259   static base::string16 SanitizeTextForPaste(const base::string16& text);
260 
261  protected:
262   // Tracks important state that may change between OnBeforePossibleChange() and
263   // OnAfterPossibleChange().
264   struct State {
265     base::string16 text;
266     base::string16 keyword;
267     bool is_keyword_selected;
268     size_t sel_start;
269     size_t sel_end;
270     size_t all_sel_length;
271 
272     State();
273     State(const State& state);
274   };
275 
276   OmniboxView(OmniboxEditController* controller,
277               std::unique_ptr<OmniboxClient> client);
278 
279   // Fills |state| with the current text state.
280   void GetState(State* state);
281 
282   // Returns the delta between |before| and |after|.
283   StateChanges GetStateChanges(const State& before,
284                                           const State& after);
285 
286   // Internally invoked whenever the text changes in some way.
287   virtual void TextChanged();
288 
289   // Return the number of characters in the current buffer. The name
290   // |GetTextLength| can't be used as the Windows override of this class
291   // inherits from a class that defines a method with that name.
292   virtual int GetOmniboxTextLength() const = 0;
293 
294   // Try to parse the current text as a URL and colorize the components.
295   virtual void EmphasizeURLComponents() = 0;
296 
controller()297   OmniboxEditController* controller() { return controller_; }
controller()298   const OmniboxEditController* controller() const { return controller_; }
299 
300   // Marks part (or, if |range| is invalid, all) of the current text as
301   // emphasized or de-emphasized, by changing its color.
302   virtual void SetEmphasis(bool emphasize, const gfx::Range& range) = 0;
303 
304   // Sets the color and strikethrough state for |range|, which represents the
305   // current scheme, based on the current security state.  Schemes are displayed
306   // in different ways for different security levels.
307   virtual void UpdateSchemeStyle(const gfx::Range& range) = 0;
308 
309   // Parses |display_text|, then invokes SetEmphasis() and UpdateSchemeStyle()
310   // appropriately. If the text is a query string, there is no scheme, and
311   // everything is emphasized equally, whereas for URLs the scheme may be styled
312   // based on the current security state, with parts of the URL de-emphasized to
313   // draw attention to whatever best represents the "identity" of the current
314   // URL.
315   void UpdateTextStyle(const base::string16& display_text,
316                        const bool text_is_url,
317                        const AutocompleteSchemeClassifier& classifier);
318 
319  private:
320   friend class OmniboxViewMacTest;
321   friend class TestOmniboxView;
322 
323   // |model_| can be NULL in tests.
324   std::unique_ptr<OmniboxEditModel> model_;
325   OmniboxEditController* controller_;
326 };
327 
328 #endif  // COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_VIEW_H_
329