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 #ifndef CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_VIEW_WIN_H_ 6 #define CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_VIEW_WIN_H_ 7 8 #include <atlbase.h> 9 #include <atlapp.h> 10 #include <atlcrack.h> 11 #include <atlctrls.h> 12 #include <atlmisc.h> 13 #include <tom.h> // For ITextDocument, a COM interface to CRichEditCtrl. 14 15 #include "base/memory/scoped_ptr.h" 16 #include "base/win/scoped_comptr.h" 17 #include "chrome/browser/ui/omnibox/omnibox_view.h" 18 #include "chrome/browser/ui/toolbar/toolbar_model.h" 19 #include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h" 20 #include "ui/base/ime/win/tsf_event_router.h" 21 #include "ui/base/models/simple_menu_model.h" 22 #include "ui/base/win/extra_sdk_defines.h" 23 #include "ui/base/window_open_disposition.h" 24 #include "ui/gfx/font_list.h" 25 26 class LocationBarView; 27 class OmniboxPopupView; 28 29 namespace views { 30 class MenuRunner; 31 class NativeViewHost; 32 class View; 33 } 34 35 // Provides the implementation of an edit control with a drop-down 36 // autocomplete box. The box itself is implemented in autocomplete_popup.cc 37 // This file implements the edit box and management for the popup. 38 class OmniboxViewWin 39 : public CWindowImpl<OmniboxViewWin, 40 CRichEditCtrl, 41 CWinTraits<WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | 42 ES_NOHIDESEL> >, 43 public CRichEditCommands<OmniboxViewWin>, 44 public ui::SimpleMenuModel::Delegate, 45 public ui::TSFEventRouterObserver, 46 public OmniboxView { 47 public: 48 struct State { 49 State(const CHARRANGE& selection, 50 const CHARRANGE& saved_selection_for_focus_change) 51 : selection(selection), 52 saved_selection_for_focus_change(saved_selection_for_focus_change) { 53 } 54 55 const CHARRANGE selection; 56 const CHARRANGE saved_selection_for_focus_change; 57 }; 58 59 DECLARE_WND_SUPERCLASS(L"Chrome_OmniboxView", MSFTEDIT_CLASS); 60 61 OmniboxViewWin(OmniboxEditController* controller, 62 ToolbarModel* toolbar_model, 63 LocationBarView* parent_view, 64 CommandUpdater* command_updater, 65 bool popup_window_mode, 66 const gfx::FontList& font_list, 67 int font_y_offset); 68 ~OmniboxViewWin(); 69 70 // Gets the relative window for the specified native view. 71 static gfx::NativeView GetRelativeWindowForNativeView( 72 gfx::NativeView edit_native_view); 73 74 views::View* parent_view() const; 75 76 // OmniboxView: 77 virtual void SaveStateToTab(content::WebContents* tab) OVERRIDE; 78 virtual void Update( 79 const content::WebContents* tab_for_state_restoring) OVERRIDE; 80 virtual void OpenMatch(const AutocompleteMatch& match, 81 WindowOpenDisposition disposition, 82 const GURL& alternate_nav_url, 83 size_t index) OVERRIDE; 84 virtual string16 GetText() const OVERRIDE; 85 virtual void SetUserText(const string16& text, 86 const string16& display_text, 87 bool update_popup) OVERRIDE; 88 virtual void SetWindowTextAndCaretPos(const string16& text, 89 size_t caret_pos, 90 bool update_popup, 91 bool notify_text_changed) OVERRIDE; 92 virtual void SetForcedQuery() OVERRIDE; 93 virtual bool IsSelectAll() const OVERRIDE; 94 virtual bool DeleteAtEndPressed() OVERRIDE; 95 virtual void GetSelectionBounds(string16::size_type* start, 96 string16::size_type* end) const OVERRIDE; 97 virtual void SelectAll(bool reversed) OVERRIDE; 98 virtual void RevertAll() OVERRIDE; 99 virtual void UpdatePopup() OVERRIDE; 100 virtual void SetFocus() OVERRIDE; 101 virtual void ApplyCaretVisibility() OVERRIDE; 102 virtual void OnTemporaryTextMaybeChanged( 103 const string16& display_text, 104 bool save_original_selection, 105 bool notify_text_changed) OVERRIDE; 106 virtual bool OnInlineAutocompleteTextMaybeChanged( 107 const string16& display_text, size_t user_text_length) OVERRIDE; 108 virtual void OnRevertTemporaryText() OVERRIDE; 109 virtual void OnBeforePossibleChange() OVERRIDE; 110 virtual bool OnAfterPossibleChange() OVERRIDE; 111 virtual gfx::NativeView GetNativeView() const OVERRIDE; 112 virtual gfx::NativeView GetRelativeWindowForPopup() const OVERRIDE; 113 virtual void SetGrayTextAutocompletion(const string16& suggestion) OVERRIDE; 114 virtual int TextWidth() const OVERRIDE; 115 virtual string16 GetGrayTextAutocompletion() const OVERRIDE; 116 virtual bool IsImeComposing() const OVERRIDE; 117 virtual int GetMaxEditWidth(int entry_width) const OVERRIDE; 118 virtual views::View* AddToView(views::View* parent) OVERRIDE; 119 virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE; 120 121 int GetPopupMaxYCoordinate(); 122 123 void SetDropHighlightPosition(int position); 124 int drop_highlight_position() const { return drop_highlight_position_; } 125 126 // Returns true if a drag a drop session was initiated by this edit. 127 bool in_drag() const { return in_drag_; } 128 129 // Moves the selected text to the specified position. 130 void MoveSelectedText(int new_position); 131 132 // Inserts the text at the specified position. 133 void InsertText(int position, const string16& text); 134 135 void set_force_hidden(bool force_hidden) { force_hidden_ = force_hidden; } 136 137 // Called before an accelerator is processed to give us a chance to override 138 // it. 139 bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event); 140 141 // Handler for external events passed in to us. The View that owns us may 142 // send us events that we should treat as if they were events on us. 143 void HandleExternalMsg(UINT msg, UINT flags, const CPoint& screen_point); 144 145 // CWindowImpl 146 BEGIN_MSG_MAP(OmniboxViewWin) 147 MSG_WM_CHAR(OnChar) 148 MSG_WM_CONTEXTMENU(OnContextMenu) 149 MSG_WM_COPY(OnCopy) 150 MSG_WM_CREATE(OnCreate) 151 MSG_WM_CUT(OnCut) 152 MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject) 153 MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeComposition) 154 MESSAGE_HANDLER_EX(WM_IME_ENDCOMPOSITION, OnImeEndComposition) 155 MESSAGE_HANDLER_EX(WM_IME_NOTIFY, OnImeNotify) 156 MESSAGE_HANDLER_EX(WM_TOUCH, OnTouchEvent) 157 MSG_WM_KEYDOWN(OnKeyDown) 158 MSG_WM_KEYUP(OnKeyUp) 159 MSG_WM_KILLFOCUS(OnKillFocus) 160 MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk) 161 MSG_WM_LBUTTONDOWN(OnLButtonDown) 162 MSG_WM_LBUTTONUP(OnLButtonUp) 163 MSG_WM_MBUTTONDBLCLK(OnMButtonDblClk) 164 MSG_WM_MBUTTONDOWN(OnMButtonDown) 165 MSG_WM_MBUTTONUP(OnMButtonUp) 166 MSG_WM_MOUSEACTIVATE(OnMouseActivate) 167 MSG_WM_MOUSEMOVE(OnMouseMove) 168 MSG_WM_MOUSEWHEEL(OnMouseWheel) 169 MSG_WM_PAINT(OnPaint) 170 MSG_WM_PASTE(OnPaste) 171 MSG_WM_RBUTTONDBLCLK(OnRButtonDblClk) 172 MSG_WM_RBUTTONDOWN(OnRButtonDown) 173 MSG_WM_RBUTTONUP(OnRButtonUp) 174 MSG_WM_SETFOCUS(OnSetFocus) 175 MSG_WM_SETTEXT(OnSetText) 176 MSG_WM_SYSCHAR(OnSysChar) // WM_SYSxxx == WM_xxx with ALT down 177 MSG_WM_SYSKEYDOWN(OnKeyDown) 178 MSG_WM_SYSKEYUP(OnKeyUp) 179 MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging) 180 DEFAULT_REFLECTION_HANDLER() // avoids black margin area 181 END_MSG_MAP() 182 183 // ui::SimpleMenuModel::Delegate 184 virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; 185 virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; 186 virtual bool GetAcceleratorForCommandId( 187 int command_id, 188 ui::Accelerator* accelerator) OVERRIDE; 189 virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE; 190 virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE; 191 virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE; 192 193 private: 194 enum MouseButton { 195 kLeft = 0, 196 kRight = 1, 197 }; 198 199 // This object freezes repainting of the edit until the object is destroyed. 200 // Some methods of the CRichEditCtrl draw synchronously to the screen. If we 201 // don't freeze, the user will see a rapid series of calls to these as 202 // flickers. 203 // 204 // Freezing the control while it is already frozen is permitted; the control 205 // will unfreeze once both freezes are released (the freezes stack). 206 class ScopedFreeze { 207 public: 208 ScopedFreeze(OmniboxViewWin* edit, ITextDocument* text_object_model); 209 ~ScopedFreeze(); 210 211 private: 212 OmniboxViewWin* const edit_; 213 ITextDocument* const text_object_model_; 214 215 DISALLOW_COPY_AND_ASSIGN(ScopedFreeze); 216 }; 217 218 class EditDropTarget; 219 friend class EditDropTarget; 220 221 // This object suspends placing any operations on the edit's undo stack until 222 // the object is destroyed. If we don't do this, some of the operations we 223 // perform behind the user's back will be undoable by the user, which feels 224 // bizarre and confusing. 225 class ScopedSuspendUndo { 226 public: 227 explicit ScopedSuspendUndo(ITextDocument* text_object_model); 228 ~ScopedSuspendUndo(); 229 230 private: 231 ITextDocument* const text_object_model_; 232 233 DISALLOW_COPY_AND_ASSIGN(ScopedSuspendUndo); 234 }; 235 236 // Replacement word-breaking proc for the rich edit control. 237 static int CALLBACK WordBreakProc(LPTSTR edit_text, 238 int current_pos, 239 int length, 240 int action); 241 242 // Returns true if |edit_text| starting at |current_pos| is "://". 243 static bool SchemeEnd(LPTSTR edit_text, int current_pos, int length); 244 245 // Message handlers 246 void OnChar(TCHAR ch, UINT repeat_count, UINT flags); 247 void OnContextMenu(HWND window, const CPoint& point); 248 void OnCopy(); 249 LRESULT OnCreate(const CREATESTRUCTW* create_struct); 250 void OnCut(); 251 LRESULT OnGetObject(UINT message, WPARAM wparam, LPARAM lparam); 252 LRESULT OnImeComposition(UINT message, WPARAM wparam, LPARAM lparam); 253 LRESULT OnImeEndComposition(UINT message, WPARAM wparam, LPARAM lparam); 254 LRESULT OnImeNotify(UINT message, WPARAM wparam, LPARAM lparam); 255 LRESULT OnTouchEvent(UINT message, WPARAM wparam, LPARAM lparam); 256 void OnKeyDown(TCHAR key, UINT repeat_count, UINT flags); 257 void OnKeyUp(TCHAR key, UINT repeat_count, UINT flags); 258 void OnKillFocus(HWND focus_wnd); 259 void OnLButtonDblClk(UINT keys, const CPoint& point); 260 void OnLButtonDown(UINT keys, const CPoint& point); 261 void OnLButtonUp(UINT keys, const CPoint& point); 262 void OnMButtonDblClk(UINT keys, const CPoint& point); 263 void OnMButtonDown(UINT keys, const CPoint& point); 264 void OnMButtonUp(UINT keys, const CPoint& point); 265 LRESULT OnMouseActivate(HWND window, UINT hit_test, UINT mouse_message); 266 void OnMouseMove(UINT keys, const CPoint& point); 267 BOOL OnMouseWheel(UINT flags, short delta, CPoint point); 268 void OnPaint(HDC bogus_hdc); 269 void OnPaste(); 270 void OnRButtonDblClk(UINT keys, const CPoint& point); 271 void OnRButtonDown(UINT keys, const CPoint& point); 272 void OnRButtonUp(UINT keys, const CPoint& point); 273 void OnSetFocus(HWND focus_wnd); 274 LRESULT OnSetText(const wchar_t* text); 275 void OnSysChar(TCHAR ch, UINT repeat_count, UINT flags); 276 void OnWindowPosChanging(WINDOWPOS* window_pos); 277 278 // Helper function for OnChar() and OnKeyDown() that handles keystrokes that 279 // could change the text in the edit. 280 void HandleKeystroke(UINT message, TCHAR key, UINT repeat_count, UINT flags); 281 282 // Helper functions for OnKeyDown() that handle accelerators applicable when 283 // we're not read-only and all the time, respectively. These return true if 284 // they handled the key. 285 bool OnKeyDownOnlyWritable(TCHAR key, UINT repeat_count, UINT flags); 286 bool OnKeyDownAllModes(TCHAR key, UINT repeat_count, UINT flags); 287 288 // Like GetSel(), but returns a range where |cpMin| will be larger than 289 // |cpMax| if the cursor is at the start rather than the end of the selection 290 // (in other words, tracks selection direction as well as offsets). 291 // Note the non-Google-style "non-const-ref" argument, which matches GetSel(). 292 void GetSelection(CHARRANGE& sel) const; 293 294 // Returns the currently selected text of the edit control. 295 string16 GetSelectedText() const; 296 297 // Like SetSel(), but respects the selection direction implied by |start| and 298 // |end|: if |end| < |start|, the effective cursor will be placed at the 299 // beginning of the selection. 300 void SetSelection(LONG start, LONG end); 301 302 // Like SetSelection(), but takes a CHARRANGE. 303 void SetSelectionRange(const CHARRANGE& sel) { 304 SetSelection(sel.cpMin, sel.cpMax); 305 } 306 307 // Places the caret at the given position. This clears any selection. 308 void PlaceCaretAt(size_t pos); 309 310 // Returns true if |sel| represents a forward or backward selection of all the 311 // text. 312 bool IsSelectAllForRange(const CHARRANGE& sel) const; 313 314 // Given an X coordinate in client coordinates, returns that coordinate 315 // clipped to be within the horizontal bounds of the visible text. 316 // 317 // This is used in our mouse handlers to work around quirky behaviors of the 318 // underlying CRichEditCtrl like not supporting triple-click when the user 319 // doesn't click on the text itself. 320 // 321 // |is_triple_click| should be true iff this is the third click of a triple 322 // click. Sadly, we need to clip slightly differently in this case. 323 LONG ClipXCoordToVisibleText(LONG x, bool is_triple_click) const; 324 325 virtual int GetOmniboxTextLength() const OVERRIDE; 326 327 // Parses the contents of the control for the scheme and the host name. 328 // Highlights the scheme in green or red depending on it security level. 329 // If a host name is found, it makes it visually stronger. 330 virtual void EmphasizeURLComponents() OVERRIDE; 331 332 // TSFEventRouter::Observer: 333 virtual void OnCandidateWindowCountChanged(size_t window_count) OVERRIDE; 334 virtual void OnTextUpdated(const ui::Range& composition_range) OVERRIDE; 335 336 // Erases the portion of the selection in the font's y-adjustment area. For 337 // some reason the edit draws the selection rect here even though it's not 338 // part of the font. 339 void EraseTopOfSelection(CDC* dc, 340 const CRect& client_rect, 341 const CRect& paint_clip_rect); 342 343 // Draws a slash across the scheme if desired. 344 void DrawSlashForInsecureScheme(HDC hdc, 345 const CRect& client_rect, 346 const CRect& paint_clip_rect); 347 348 // Renders the drop highlight. 349 void DrawDropHighlight(HDC hdc, 350 const CRect& client_rect, 351 const CRect& paint_clip_rect); 352 353 // Internally invoked whenever the text changes in some way. 354 void TextChanged() OVERRIDE; 355 356 // Getter for the text_object_model_. Note that the pointer returned here is 357 // only valid as long as the AutocompleteEdit is still alive. Also, if the 358 // underlying call fails, this may return NULL. 359 ITextDocument* GetTextObjectModel() const; 360 361 // Invoked during a mouse move. As necessary starts a drag and drop session. 362 void StartDragIfNecessary(const CPoint& point); 363 364 // Invoked during a mouse down. If the mouse location is over the selection 365 // this sets possible_drag_ to true to indicate a drag should start if the 366 // user moves the mouse far enough to start a drag. 367 void OnPossibleDrag(const CPoint& point); 368 369 // Redraws the necessary region for a drop highlight at the specified 370 // position. This does nothing if position is beyond the bounds of the 371 // text. 372 void RepaintDropHighlight(int position); 373 374 // Generates the context menu for the edit field. 375 void BuildContextMenu(); 376 377 void SelectAllIfNecessary(MouseButton button, const CPoint& point); 378 void TrackMousePosition(MouseButton button, const CPoint& point); 379 380 // Returns the sum of the left and right margins. 381 int GetHorizontalMargin() const; 382 383 // Returns the width in pixels needed to display |text|. 384 int WidthNeededToDisplay(const string16& text) const; 385 386 // Real implementation of OnAfterPossibleChange() method. 387 // If |force_text_changed| is true, then the text_changed code will always be 388 // triggerred no matter if the text is actually changed or not. 389 bool OnAfterPossibleChangeInternal(bool force_text_changed); 390 391 // Common implementation for performing a drop on the edit view. 392 int OnPerformDropImpl(const ui::DropTargetEvent& event, bool in_drag); 393 394 // Whether to show the menu item for copying the URL. 395 bool ShouldEnableCopyURL() const; 396 void CopyURL(); 397 398 // The handle to the RichEdit DLL. In the rare case where the user's system 399 // is missing this DLL (due to some kind of system corruption), the similar 400 // OmniboxViewViews is used instead; see Textfield::IsViewsTextfieldEnabled(). 401 static HMODULE loaded_library_module_; 402 403 scoped_ptr<OmniboxPopupView> popup_view_; 404 405 // The parent view for the edit, used to align the popup and for 406 // accessibility. 407 LocationBarView* location_bar_; 408 409 // When true, the location bar view is read only and also is has a slightly 410 // different presentation (font size / color). This is used for popups. 411 bool popup_window_mode_; 412 413 // True if we should prevent attempts to make the window visible when we 414 // handle WM_WINDOWPOSCHANGING. While toggling fullscreen mode, the main 415 // window is hidden, and if the edit is shown it will draw over the main 416 // window when that window reappears. 417 bool force_hidden_; 418 419 // Non-null when the edit is gaining focus from a left click. This is only 420 // needed between when WM_MOUSEACTIVATE and WM_LBUTTONDOWN get processed. It 421 // serves two purposes: first, by communicating to OnLButtonDown() that we're 422 // gaining focus from a left click, it allows us to work even with the 423 // inconsistent order in which various Windows messages get sent (see comments 424 // in OnMouseActivate()). Second, by holding the edit frozen, it ensures that 425 // when we process WM_SETFOCUS the edit won't first redraw itself with the 426 // caret at the beginning, and then have it blink to where the mouse cursor 427 // really is shortly afterward. 428 scoped_ptr<ScopedFreeze> gaining_focus_; 429 430 // When the user clicks to give us focus, we watch to see if they're clicking 431 // or dragging. When they're clicking, we select nothing until mouseup, then 432 // select all the text in the edit. During this process, tracking_click_[X] 433 // is true and click_point_[X] holds the original click location. 434 // At other times, tracking_click_[X] is false, and the contents of 435 // click_point_[X] should be ignored. The arrays hold the state for the 436 // left and right mouse buttons, and are indexed using the MouseButton enum. 437 bool tracking_click_[2]; 438 CPoint click_point_[2]; 439 440 // We need to know if the user triple-clicks, so track double click points 441 // and times so we can see if subsequent clicks are actually triple clicks. 442 bool tracking_double_click_; 443 CPoint double_click_point_; 444 DWORD double_click_time_; 445 446 // Used to discard unnecessary WM_MOUSEMOVE events after the first such 447 // unnecessary event. See detailed comments in OnMouseMove(). 448 bool can_discard_mousemove_; 449 450 // Used to prevent IME message handling in the midst of updating the edit 451 // text. See comments where this is used. 452 bool ignore_ime_messages_; 453 454 // Variables for tracking state before and after a possible change. 455 string16 text_before_change_; 456 CHARRANGE sel_before_change_; 457 458 // Set at the same time the model's original_* members are set, and valid in 459 // the same cases. 460 CHARRANGE original_selection_; 461 462 // Holds the user's selection across focus changes. cpMin holds -1 when 463 // there is no saved selection. 464 CHARRANGE saved_selection_for_focus_change_; 465 466 // Was the delete key pressed with an empty selection at the end of the edit? 467 bool delete_at_end_pressed_; 468 469 // The context menu for the edit. 470 scoped_ptr<ui::SimpleMenuModel> context_menu_contents_; 471 scoped_ptr<views::MenuRunner> context_menu_runner_; 472 473 // The font list to draw text in Omnibox. 474 gfx::FontList font_list_; 475 476 // Metrics about the font, which we keep so we don't need to recalculate them 477 // every time we paint. |font_y_adjustment_| is the number of pixels we need 478 // to shift the font vertically in order to make its baseline be at our 479 // desired baseline in the edit. 480 int font_x_height_; 481 int font_y_adjustment_; 482 483 // If true, indicates the mouse is down and if the mouse is moved enough we 484 // should start a drag. 485 bool possible_drag_; 486 487 // If true, we're in a call to DoDragDrop. 488 bool in_drag_; 489 490 // If true indicates we've run a drag and drop session. This is used to 491 // avoid starting two drag and drop sessions if the drag is canceled while 492 // the mouse is still down. 493 bool initiated_drag_; 494 495 // Position of the drop highlight. If this is -1, there is no drop highlight. 496 int drop_highlight_position_; 497 498 // True if the IME candidate window is open. When this is true, we want to 499 // avoid showing the popup. 500 bool ime_candidate_window_open_; 501 502 // Security UI-related data. 503 COLORREF background_color_; 504 ToolbarModel::SecurityLevel security_level_; 505 506 // This interface is useful for accessing the CRichEditCtrl at a low level. 507 mutable ITextDocument* text_object_model_; 508 509 // This contains the scheme char start and stop indexes that should be 510 // stricken-out when displaying an insecure scheme. 511 url_parse::Component insecure_scheme_component_; 512 513 // Instance of accessibility information and handling. 514 mutable base::win::ScopedComPtr<IAccessible> autocomplete_accessibility_; 515 516 // The native view host. 517 views::NativeViewHost* native_view_host_; 518 519 // TSF related event router. 520 scoped_ptr<ui::TSFEventRouter> tsf_event_router_; 521 522 DISALLOW_COPY_AND_ASSIGN(OmniboxViewWin); 523 }; 524 525 #endif // CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_VIEW_WIN_H_ 526