autocomplete_edit_view_win.cc revision 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7
1// Copyright (c) 2010 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#include "chrome/browser/autocomplete/autocomplete_edit_view_win.h"
6
7#include <algorithm>
8#include <locale>
9#include <string>
10
11#include <richedit.h>
12#include <textserv.h>
13
14#include "app/clipboard/clipboard.h"
15#include "app/clipboard/scoped_clipboard_writer.h"
16#include "app/keyboard_codes.h"
17#include "app/l10n_util.h"
18#include "app/l10n_util_win.h"
19#include "app/os_exchange_data.h"
20#include "app/os_exchange_data_provider_win.h"
21#include "app/win_util.h"
22#include "app/win/drag_source.h"
23#include "app/win/drop_target.h"
24#include "app/win/iat_patch_function.h"
25#include "base/auto_reset.h"
26#include "base/basictypes.h"
27#include "base/i18n/rtl.h"
28#include "base/lazy_instance.h"
29#include "base/ref_counted.h"
30#include "base/string_util.h"
31#include "base/utf_string_conversions.h"
32#include "chrome/app/chrome_command_ids.h"
33#include "chrome/browser/autocomplete/autocomplete_accessibility.h"
34#include "chrome/browser/autocomplete/autocomplete_match.h"
35#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
36#include "chrome/browser/autocomplete/keyword_provider.h"
37#include "chrome/browser/browser_process.h"
38#include "chrome/browser/command_updater.h"
39#include "chrome/browser/metrics/user_metrics.h"
40#include "chrome/browser/net/url_fixer_upper.h"
41#include "chrome/browser/profile.h"
42#include "chrome/browser/search_engines/template_url.h"
43#include "chrome/browser/search_engines/template_url_model.h"
44#include "chrome/browser/tab_contents/tab_contents.h"
45#include "chrome/browser/views/location_bar/location_bar_view.h"
46#include "chrome/common/notification_service.h"
47#include "googleurl/src/url_util.h"
48#include "gfx/canvas.h"
49#include "gfx/canvas_skia.h"
50#include "grit/generated_resources.h"
51#include "net/base/escape.h"
52#include "skia/ext/skia_utils_win.h"
53#include "views/drag_utils.h"
54#include "views/focus/focus_util_win.h"
55#include "views/widget/widget.h"
56
57#pragma comment(lib, "oleacc.lib")  // Needed for accessibility support.
58#pragma comment(lib, "riched20.lib")  // Needed for the richedit control.
59
60///////////////////////////////////////////////////////////////////////////////
61// AutocompleteEditModel
62
63namespace {
64
65// EditDropTarget is the IDropTarget implementation installed on
66// AutocompleteEditViewWin. EditDropTarget prefers URL over plain text. A drop
67// of a URL replaces all the text of the edit and navigates immediately to the
68// URL. A drop of plain text from the same edit either copies or moves the
69// selected text, and a drop of plain text from a source other than the edit
70// does a paste and go.
71class EditDropTarget : public app::win::DropTarget {
72 public:
73  explicit EditDropTarget(AutocompleteEditViewWin* edit);
74
75 protected:
76  virtual DWORD OnDragEnter(IDataObject* data_object,
77                            DWORD key_state,
78                            POINT cursor_position,
79                            DWORD effect);
80  virtual DWORD OnDragOver(IDataObject* data_object,
81                           DWORD key_state,
82                           POINT cursor_position,
83                           DWORD effect);
84  virtual void OnDragLeave(IDataObject* data_object);
85  virtual DWORD OnDrop(IDataObject* data_object,
86                       DWORD key_state,
87                       POINT cursor_position,
88                       DWORD effect);
89
90 private:
91  // If dragging a string, the drop highlight position of the edit is reset
92  // based on the mouse position.
93  void UpdateDropHighlightPosition(const POINT& cursor_screen_position);
94
95  // Resets the visual drop indicates we install on the edit.
96  void ResetDropHighlights();
97
98  // The edit we're the drop target for.
99  AutocompleteEditViewWin* edit_;
100
101  // If true, the drag session contains a URL.
102  bool drag_has_url_;
103
104  // If true, the drag session contains a string. If drag_has_url_ is true,
105  // this is false regardless of whether the clipboard has a string.
106  bool drag_has_string_;
107
108  DISALLOW_COPY_AND_ASSIGN(EditDropTarget);
109};
110
111// A helper method for determining a valid DROPEFFECT given the allowed
112// DROPEFFECTS.  We prefer copy over link.
113DWORD CopyOrLinkDropEffect(DWORD effect) {
114  if (effect & DROPEFFECT_COPY)
115    return DROPEFFECT_COPY;
116  if (effect & DROPEFFECT_LINK)
117    return DROPEFFECT_LINK;
118  return DROPEFFECT_NONE;
119}
120
121EditDropTarget::EditDropTarget(AutocompleteEditViewWin* edit)
122    : app::win::DropTarget(edit->m_hWnd),
123      edit_(edit),
124      drag_has_url_(false),
125      drag_has_string_(false) {
126}
127
128DWORD EditDropTarget::OnDragEnter(IDataObject* data_object,
129                                  DWORD key_state,
130                                  POINT cursor_position,
131                                  DWORD effect) {
132  OSExchangeData os_data(new OSExchangeDataProviderWin(data_object));
133  drag_has_url_ = os_data.HasURL();
134  drag_has_string_ = !drag_has_url_ && os_data.HasString();
135  if (drag_has_url_) {
136    if (edit_->in_drag()) {
137      // The edit we're associated with originated the drag. No point in
138      // allowing the user to drop back on us.
139      drag_has_url_ = false;
140    }
141    // NOTE: it would be nice to visually show all the text is going to
142    // be replaced by selecting all, but this caused painting problems. In
143    // particular the flashing caret would appear outside the edit! For now
144    // we stick with no visual indicator other than that shown own the mouse
145    // cursor.
146  }
147  return OnDragOver(data_object, key_state, cursor_position, effect);
148}
149
150DWORD EditDropTarget::OnDragOver(IDataObject* data_object,
151                                 DWORD key_state,
152                                 POINT cursor_position,
153                                 DWORD effect) {
154  if (drag_has_url_)
155    return CopyOrLinkDropEffect(effect);
156
157  if (drag_has_string_) {
158    UpdateDropHighlightPosition(cursor_position);
159    if (edit_->drop_highlight_position() == -1 && edit_->in_drag())
160      return DROPEFFECT_NONE;
161    if (edit_->in_drag()) {
162      // The edit we're associated with originated the drag.  Do the normal drag
163      // behavior.
164      DCHECK((effect & DROPEFFECT_COPY) && (effect & DROPEFFECT_MOVE));
165      return (key_state & MK_CONTROL) ? DROPEFFECT_COPY : DROPEFFECT_MOVE;
166    }
167    // Our edit didn't originate the drag, only allow link or copy.
168    return CopyOrLinkDropEffect(effect);
169  }
170
171  return DROPEFFECT_NONE;
172}
173
174void EditDropTarget::OnDragLeave(IDataObject* data_object) {
175  ResetDropHighlights();
176}
177
178DWORD EditDropTarget::OnDrop(IDataObject* data_object,
179                             DWORD key_state,
180                             POINT cursor_position,
181                             DWORD effect) {
182  OSExchangeData os_data(new OSExchangeDataProviderWin(data_object));
183
184  if (drag_has_url_) {
185    GURL url;
186    std::wstring title;
187    if (os_data.GetURLAndTitle(&url, &title)) {
188      edit_->SetUserText(UTF8ToWide(url.spec()));
189      edit_->model()->AcceptInput(CURRENT_TAB, true);
190      return CopyOrLinkDropEffect(effect);
191    }
192  } else if (drag_has_string_) {
193    int string_drop_position = edit_->drop_highlight_position();
194    std::wstring text;
195    if ((string_drop_position != -1 || !edit_->in_drag()) &&
196        os_data.GetString(&text)) {
197      DCHECK(string_drop_position == -1 ||
198             ((string_drop_position >= 0) &&
199              (string_drop_position <= edit_->GetTextLength())));
200      const DWORD drop_operation =
201          OnDragOver(data_object, key_state, cursor_position, effect);
202      if (edit_->in_drag()) {
203        if (drop_operation == DROPEFFECT_MOVE)
204          edit_->MoveSelectedText(string_drop_position);
205        else
206          edit_->InsertText(string_drop_position, text);
207      } else {
208        edit_->PasteAndGo(CollapseWhitespace(text, true));
209      }
210      ResetDropHighlights();
211      return drop_operation;
212    }
213  }
214
215  ResetDropHighlights();
216
217  return DROPEFFECT_NONE;
218}
219
220void EditDropTarget::UpdateDropHighlightPosition(
221    const POINT& cursor_screen_position) {
222  if (drag_has_string_) {
223    POINT client_position = cursor_screen_position;
224    ScreenToClient(edit_->m_hWnd, &client_position);
225    int drop_position = edit_->CharFromPos(client_position);
226    if (edit_->in_drag()) {
227      // Our edit originated the drag, don't allow a drop if over the selected
228      // region.
229      LONG sel_start, sel_end;
230      edit_->GetSel(sel_start, sel_end);
231      if ((sel_start != sel_end) && (drop_position >= sel_start) &&
232          (drop_position <= sel_end))
233        drop_position = -1;
234    } else {
235      // A drop from a source other than the edit replaces all the text, so
236      // we don't show the drop location. See comment in OnDragEnter as to why
237      // we don't try and select all here.
238      drop_position = -1;
239    }
240    edit_->SetDropHighlightPosition(drop_position);
241  }
242}
243
244void EditDropTarget::ResetDropHighlights() {
245  if (drag_has_string_)
246    edit_->SetDropHighlightPosition(-1);
247}
248
249// The AutocompleteEditState struct contains enough information about the
250// AutocompleteEditModel and AutocompleteEditViewWin to save/restore a user's
251// typing, caret position, etc. across tab changes.  We explicitly don't
252// preserve things like whether the popup was open as this might be weird.
253struct AutocompleteEditState {
254  AutocompleteEditState(const AutocompleteEditModel::State model_state,
255                        const AutocompleteEditViewWin::State view_state)
256      : model_state(model_state),
257        view_state(view_state) {
258  }
259
260  const AutocompleteEditModel::State model_state;
261  const AutocompleteEditViewWin::State view_state;
262};
263
264}  // namespace
265
266///////////////////////////////////////////////////////////////////////////////
267// Helper classes
268
269AutocompleteEditViewWin::ScopedFreeze::ScopedFreeze(
270    AutocompleteEditViewWin* edit,
271    ITextDocument* text_object_model)
272    : edit_(edit),
273      text_object_model_(text_object_model) {
274  // Freeze the screen.
275  if (text_object_model_) {
276    long count;
277    text_object_model_->Freeze(&count);
278  }
279}
280
281AutocompleteEditViewWin::ScopedFreeze::~ScopedFreeze() {
282  // Unfreeze the screen.
283  // NOTE: If this destructor is reached while the edit is being destroyed (for
284  // example, because we double-clicked the edit of a popup and caused it to
285  // transform to an unconstrained window), it will no longer have an HWND, and
286  // text_object_model_ may point to a destroyed object, so do nothing here.
287  if (edit_->IsWindow() && text_object_model_) {
288    long count;
289    text_object_model_->Unfreeze(&count);
290    if (count == 0) {
291      // We need to UpdateWindow() here instead of InvalidateRect() because, as
292      // far as I can tell, the edit likes to synchronously erase its background
293      // when unfreezing, thus requiring us to synchronously redraw if we don't
294      // want flicker.
295      edit_->UpdateWindow();
296    }
297  }
298}
299
300AutocompleteEditViewWin::ScopedSuspendUndo::ScopedSuspendUndo(
301    ITextDocument* text_object_model)
302    : text_object_model_(text_object_model) {
303  // Suspend Undo processing.
304  if (text_object_model_)
305    text_object_model_->Undo(tomSuspend, NULL);
306}
307
308AutocompleteEditViewWin::ScopedSuspendUndo::~ScopedSuspendUndo() {
309  // Resume Undo processing.
310  if (text_object_model_)
311    text_object_model_->Undo(tomResume, NULL);
312}
313
314///////////////////////////////////////////////////////////////////////////////
315// AutocompleteEditViewWin
316
317namespace {
318
319// These are used to hook the CRichEditCtrl's calls to BeginPaint() and
320// EndPaint() and provide a memory DC instead.  See OnPaint().
321HWND edit_hwnd = NULL;
322PAINTSTRUCT paint_struct;
323
324// Intercepted method for BeginPaint(). Must use __stdcall convention.
325HDC WINAPI BeginPaintIntercept(HWND hWnd, LPPAINTSTRUCT lpPaint) {
326  if (!edit_hwnd || (hWnd != edit_hwnd))
327    return ::BeginPaint(hWnd, lpPaint);
328
329  *lpPaint = paint_struct;
330  return paint_struct.hdc;
331}
332
333// Intercepted method for EndPaint(). Must use __stdcall convention.
334BOOL WINAPI EndPaintIntercept(HWND hWnd, const PAINTSTRUCT* lpPaint) {
335  return (edit_hwnd && (hWnd == edit_hwnd)) ?
336      true : ::EndPaint(hWnd, lpPaint);
337}
338
339// Returns a lazily initialized property bag accessor for saving our state in a
340// TabContents.
341PropertyAccessor<AutocompleteEditState>* GetStateAccessor() {
342  static PropertyAccessor<AutocompleteEditState> state;
343  return &state;
344}
345
346class PaintPatcher {
347 public:
348  PaintPatcher() : refcount_(0) { }
349  ~PaintPatcher() { DCHECK(refcount_ == 0); }
350
351  void RefPatch() {
352    if (refcount_ == 0) {
353      DCHECK(!begin_paint_.is_patched());
354      DCHECK(!end_paint_.is_patched());
355      begin_paint_.Patch(L"riched20.dll", "user32.dll", "BeginPaint",
356                         &BeginPaintIntercept);
357      end_paint_.Patch(L"riched20.dll", "user32.dll", "EndPaint",
358                       &EndPaintIntercept);
359    }
360    ++refcount_;
361  }
362
363  void DerefPatch() {
364    DCHECK(begin_paint_.is_patched());
365    DCHECK(end_paint_.is_patched());
366    --refcount_;
367    if (refcount_ == 0) {
368      begin_paint_.Unpatch();
369      end_paint_.Unpatch();
370    }
371  }
372
373 private:
374  size_t refcount_;
375  app::win::IATPatchFunction begin_paint_;
376  app::win::IATPatchFunction end_paint_;
377
378  DISALLOW_COPY_AND_ASSIGN(PaintPatcher);
379};
380
381base::LazyInstance<PaintPatcher> g_paint_patcher(base::LINKER_INITIALIZED);
382
383// twips are a unit of type measurement, and RichEdit controls use them
384// to set offsets.
385const int kTwipsPerInch = 1440;
386
387}  // namespace
388
389AutocompleteEditViewWin::AutocompleteEditViewWin(
390    const gfx::Font& font,
391    AutocompleteEditController* controller,
392    ToolbarModel* toolbar_model,
393    views::View* parent_view,
394    HWND hwnd,
395    Profile* profile,
396    CommandUpdater* command_updater,
397    bool popup_window_mode,
398    const views::View* location_bar)
399    : model_(new AutocompleteEditModel(this, controller, profile)),
400      popup_view_(new AutocompletePopupContentsView(font, this, model_.get(),
401                                                    profile, location_bar)),
402      controller_(controller),
403      parent_view_(parent_view),
404      toolbar_model_(toolbar_model),
405      command_updater_(command_updater),
406      popup_window_mode_(popup_window_mode),
407      force_hidden_(false),
408      tracking_click_(),
409      tracking_double_click_(false),
410      double_click_time_(0),
411      can_discard_mousemove_(false),
412      ignore_ime_messages_(false),
413      font_(font),
414      possible_drag_(false),
415      in_drag_(false),
416      initiated_drag_(false),
417      drop_highlight_position_(-1),
418      background_color_(skia::SkColorToCOLORREF(LocationBarView::GetColor(
419          ToolbarModel::NONE, LocationBarView::BACKGROUND))),
420      security_level_(ToolbarModel::NONE),
421      text_object_model_(NULL) {
422  // Dummy call to a function exported by riched20.dll to ensure it sets up an
423  // import dependency on the dll.
424  CreateTextServices(NULL, NULL, NULL);
425
426  model_->SetPopupModel(popup_view_->GetModel());
427
428  saved_selection_for_focus_change_.cpMin = -1;
429
430  g_paint_patcher.Pointer()->RefPatch();
431
432  Create(hwnd, 0, 0, 0, l10n_util::GetExtendedStyles());
433  SetReadOnly(popup_window_mode_);
434  SetFont(font_.GetNativeFont());
435
436  // NOTE: Do not use SetWordBreakProcEx() here, that is no longer supported as
437  // of Rich Edit 2.0 onward.
438  SendMessage(m_hWnd, EM_SETWORDBREAKPROC, 0,
439              reinterpret_cast<LPARAM>(&WordBreakProc));
440
441  // Get the metrics for the font.
442  HDC dc = ::GetDC(NULL);
443  SelectObject(dc, font_.GetNativeFont());
444  TEXTMETRIC tm = {0};
445  GetTextMetrics(dc, &tm);
446  const float kXHeightRatio = 0.7f;  // The ratio of a font's x-height to its
447                                     // cap height.  Sadly, Windows doesn't
448                                     // provide a true value for a font's
449                                     // x-height in its text metrics, so we
450                                     // approximate.
451  font_x_height_ = static_cast<int>((static_cast<float>(font_.GetBaseline() -
452      tm.tmInternalLeading) * kXHeightRatio) + 0.5);
453  // The distance from the top of the field to the desired baseline of the
454  // rendered text.
455  const int kTextBaseline = popup_window_mode_ ? 15 : 18;
456  font_y_adjustment_ = kTextBaseline - font_.GetBaseline();
457
458  // Get the number of twips per pixel, which we need below to offset our text
459  // by the desired number of pixels.
460  const long kTwipsPerPixel = kTwipsPerInch / GetDeviceCaps(dc, LOGPIXELSY);
461  ::ReleaseDC(NULL, dc);
462
463  // Set the default character style -- adjust to our desired baseline.
464  CHARFORMAT cf = {0};
465  cf.dwMask = CFM_OFFSET;
466  cf.yOffset = -font_y_adjustment_ * kTwipsPerPixel;
467  SetDefaultCharFormat(cf);
468
469  SetBackgroundColor(background_color_);
470
471  // By default RichEdit has a drop target. Revoke it so that we can install our
472  // own. Revoke takes care of deleting the existing one.
473  RevokeDragDrop(m_hWnd);
474
475  // Register our drop target. RichEdit appears to invoke RevokeDropTarget when
476  // done so that we don't have to explicitly.
477  if (!popup_window_mode_) {
478    scoped_refptr<EditDropTarget> drop_target = new EditDropTarget(this);
479    RegisterDragDrop(m_hWnd, drop_target.get());
480  }
481}
482
483AutocompleteEditViewWin::~AutocompleteEditViewWin() {
484  NotificationService::current()->Notify(
485      NotificationType::AUTOCOMPLETE_EDIT_DESTROYED,
486      Source<AutocompleteEditViewWin>(this),
487      NotificationService::NoDetails());
488
489  // Explicitly release the text object model now that we're done with it, and
490  // before we free the library. If the library gets unloaded before this
491  // released, it becomes garbage.
492  text_object_model_->Release();
493
494  // We balance our reference count and unpatch when the last instance has
495  // been destroyed.  This prevents us from relying on the AtExit or static
496  // destructor sequence to do our unpatching, which is generally fragile.
497  g_paint_patcher.Pointer()->DerefPatch();
498}
499
500int AutocompleteEditViewWin::TextWidth() {
501  return WidthNeededToDisplay(GetText());
502}
503
504int AutocompleteEditViewWin::WidthOfTextAfterCursor() {
505  CHARRANGE selection;
506  GetSelection(selection);
507  const int start = std::max(0, static_cast<int>(selection.cpMax - 1));
508  return WidthNeededToDisplay(GetText().substr(start));
509 }
510
511gfx::Font AutocompleteEditViewWin::GetFont() {
512  return font_;
513}
514
515void AutocompleteEditViewWin::SaveStateToTab(TabContents* tab) {
516  DCHECK(tab);
517
518  const AutocompleteEditModel::State model_state(
519      model_->GetStateForTabSwitch());
520
521  CHARRANGE selection;
522  GetSelection(selection);
523  GetStateAccessor()->SetProperty(tab->property_bag(),
524      AutocompleteEditState(
525          model_state,
526          State(selection, saved_selection_for_focus_change_)));
527}
528
529void AutocompleteEditViewWin::Update(
530    const TabContents* tab_for_state_restoring) {
531  const bool visibly_changed_permanent_text =
532      model_->UpdatePermanentText(toolbar_model_->GetText());
533
534  const ToolbarModel::SecurityLevel security_level =
535      toolbar_model_->GetSecurityLevel();
536  const bool changed_security_level = (security_level != security_level_);
537
538  // Bail early when no visible state will actually change (prevents an
539  // unnecessary ScopedFreeze, and thus UpdateWindow()).
540  if (!changed_security_level && !visibly_changed_permanent_text &&
541      !tab_for_state_restoring)
542    return;
543
544  // Update our local state as desired.  We set security_level_ here so it will
545  // already be correct before we get to any RevertAll()s below and use it.
546  security_level_ = security_level;
547
548  // When we're switching to a new tab, restore its state, if any.
549  ScopedFreeze freeze(this, GetTextObjectModel());
550  if (tab_for_state_restoring) {
551    // Make sure we reset our own state first.  The new tab may not have any
552    // saved state, or it may not have had input in progress, in which case we
553    // won't overwrite all our local state.
554    RevertAll();
555
556    const AutocompleteEditState* state = GetStateAccessor()->GetProperty(
557        tab_for_state_restoring->property_bag());
558    if (state) {
559      model_->RestoreState(state->model_state);
560
561      // Restore user's selection.  We do this after restoring the user_text
562      // above so we're selecting in the correct string.
563      SetSelectionRange(state->view_state.selection);
564      saved_selection_for_focus_change_ =
565          state->view_state.saved_selection_for_focus_change;
566    }
567  } else if (visibly_changed_permanent_text) {
568    // Not switching tabs, just updating the permanent text.  (In the case where
569    // we _were_ switching tabs, the RevertAll() above already drew the new
570    // permanent text.)
571
572    // Tweak: if the edit was previously nonempty and had all the text selected,
573    // select all the new text.  This makes one particular case better: the
574    // user clicks in the box to change it right before the permanent URL is
575    // changed.  Since the new URL is still fully selected, the user's typing
576    // will replace the edit contents as they'd intended.
577    //
578    // NOTE: The selection can be longer than the text length if the edit is in
579    // in rich text mode and the user has selected the "phantom newline" at the
580    // end, so use ">=" instead of "==" to see if all the text is selected.  In
581    // theory we prevent this case from ever occurring, but this is still safe.
582    CHARRANGE sel;
583    GetSelection(sel);
584    const bool was_reversed = (sel.cpMin > sel.cpMax);
585    const bool was_sel_all = (sel.cpMin != sel.cpMax) &&
586      IsSelectAllForRange(sel);
587
588    RevertAll();
589
590    if (was_sel_all)
591      SelectAll(was_reversed);
592  } else if (changed_security_level) {
593    // Only the security style changed, nothing else.  Redraw our text using it.
594    EmphasizeURLComponents();
595  }
596}
597
598void AutocompleteEditViewWin::OpenURL(const GURL& url,
599                                      WindowOpenDisposition disposition,
600                                      PageTransition::Type transition,
601                                      const GURL& alternate_nav_url,
602                                      size_t selected_line,
603                                      const std::wstring& keyword) {
604  if (!url.is_valid())
605    return;
606
607  // When we navigate, we first revert to the unedited state, then if necessary
608  // synchronously change the permanent text to the new URL.  If we don't freeze
609  // here, the user could potentially see a flicker of the current URL before
610  // the new one reappears, which would look glitchy.
611  ScopedFreeze freeze(this, GetTextObjectModel());
612  model_->OpenURL(url, disposition, transition, alternate_nav_url,
613                  selected_line, keyword);
614}
615
616std::wstring AutocompleteEditViewWin::GetText() const {
617  const int len = GetTextLength() + 1;
618  std::wstring str;
619  GetWindowText(WriteInto(&str, len), len);
620  return str;
621}
622
623bool AutocompleteEditViewWin::IsEditingOrEmpty() const {
624  return model_->user_input_in_progress() || (GetTextLength() == 0);
625}
626
627int AutocompleteEditViewWin::GetIcon() const {
628  return IsEditingOrEmpty() ?
629      AutocompleteMatch::TypeToIcon(model_->CurrentTextType()) :
630      toolbar_model_->GetIcon();
631}
632
633void AutocompleteEditViewWin::SetUserText(const std::wstring& text) {
634  SetUserText(text, text, true);
635}
636
637void AutocompleteEditViewWin::SetUserText(const std::wstring& text,
638                                          const std::wstring& display_text,
639                                          bool update_popup) {
640  ScopedFreeze freeze(this, GetTextObjectModel());
641  model_->SetUserText(text);
642  saved_selection_for_focus_change_.cpMin = -1;
643  SetWindowTextAndCaretPos(display_text, display_text.length());
644  if (update_popup)
645    UpdatePopup();
646  TextChanged();
647}
648
649void AutocompleteEditViewWin::SetWindowTextAndCaretPos(const std::wstring& text,
650                                                       size_t caret_pos) {
651  SetWindowText(text.c_str());
652  PlaceCaretAt(caret_pos);
653}
654
655void AutocompleteEditViewWin::ReplaceSelection(const string16& text) {
656  CHARRANGE selection;
657  GetSel(selection);
658  if (selection.cpMin == selection.cpMax && text.empty())
659    return;
660
661  const std::wstring w_text(UTF16ToWide(text));
662  ScopedFreeze freeze(this, GetTextObjectModel());
663  OnBeforePossibleChange();
664  ReplaceSel(w_text.c_str(), TRUE);
665  SetSelection(selection.cpMin, selection.cpMin + w_text.size());
666  OnAfterPossibleChange();
667}
668
669void AutocompleteEditViewWin::SetForcedQuery() {
670  const std::wstring current_text(GetText());
671  const size_t start = current_text.find_first_not_of(kWhitespaceWide);
672  if (start == std::wstring::npos || (current_text[start] != '?'))
673    SetUserText(L"?");
674  else
675    SetSelection(current_text.length(), start + 1);
676}
677
678bool AutocompleteEditViewWin::IsSelectAll() {
679  CHARRANGE selection;
680  GetSel(selection);
681  return IsSelectAllForRange(selection);
682}
683
684void AutocompleteEditViewWin::GetSelectionBounds(std::wstring::size_type* start,
685                                                 std::wstring::size_type* end) {
686  CHARRANGE selection;
687  GetSel(selection);
688  *start = static_cast<size_t>(selection.cpMin);
689  *end = static_cast<size_t>(selection.cpMax);
690}
691
692void AutocompleteEditViewWin::SelectAll(bool reversed) {
693  if (reversed)
694    SetSelection(GetTextLength(), 0);
695  else
696    SetSelection(0, GetTextLength());
697}
698
699void AutocompleteEditViewWin::RevertAll() {
700  ScopedFreeze freeze(this, GetTextObjectModel());
701  ClosePopup();
702  model_->Revert();
703  saved_selection_for_focus_change_.cpMin = -1;
704  TextChanged();
705}
706
707void AutocompleteEditViewWin::UpdatePopup() {
708  ScopedFreeze freeze(this, GetTextObjectModel());
709  model_->SetInputInProgress(true);
710
711  if (!model_->has_focus()) {
712    // When we're in the midst of losing focus, don't rerun autocomplete.  This
713    // can happen when losing focus causes the IME to cancel/finalize a
714    // composition.  We still want to note that user input is in progress, we
715    // just don't want to do anything else.
716    //
717    // Note that in this case the ScopedFreeze above was unnecessary; however,
718    // we're inside the callstack of OnKillFocus(), which has already frozen the
719    // edit, so this will never result in an unnecessary UpdateWindow() call.
720    return;
721  }
722
723  // Figure out whether the user is trying to compose something in an IME.
724  bool ime_composing = false;
725  HIMC context = ImmGetContext(m_hWnd);
726  if (context) {
727    ime_composing = !!ImmGetCompositionString(context, GCS_COMPSTR, NULL, 0);
728    ImmReleaseContext(m_hWnd, context);
729  }
730
731  // Don't inline autocomplete when:
732  //   * The user is deleting text
733  //   * The caret/selection isn't at the end of the text
734  //   * The user has just pasted in something that replaced all the text
735  //   * The user is trying to compose something in an IME
736  CHARRANGE sel;
737  GetSel(sel);
738  model_->StartAutocomplete(sel.cpMax != sel.cpMin,
739                            (sel.cpMax < GetTextLength()) || ime_composing);
740}
741
742void AutocompleteEditViewWin::ClosePopup() {
743  if (popup_view_->GetModel()->IsOpen())
744    controller_->OnAutocompleteWillClosePopup();
745
746  popup_view_->GetModel()->StopAutocomplete();
747}
748
749void AutocompleteEditViewWin::SetFocus() {
750  ::SetFocus(m_hWnd);
751  parent_view_->
752      NotifyAccessibilityEvent(AccessibilityTypes::EVENT_FOCUS, false);
753}
754
755IAccessible* AutocompleteEditViewWin::GetIAccessible() {
756  if (!autocomplete_accessibility_) {
757    CComObject<AutocompleteAccessibility>* accessibility = NULL;
758    if (!SUCCEEDED(CComObject<AutocompleteAccessibility>::CreateInstance(
759            &accessibility)) || !accessibility)
760      return NULL;
761
762    // Wrap the created object in a smart pointer so it won't leak.
763    ScopedComPtr<IAccessible> accessibility_comptr(accessibility);
764    if (!SUCCEEDED(accessibility->Initialize(this)))
765      return NULL;
766
767    // Copy to the class smart pointer, and notify that an instance of
768    // IAccessible was allocated for m_hWnd.
769    autocomplete_accessibility_ = accessibility_comptr;
770    NotifyWinEvent(EVENT_OBJECT_CREATE, m_hWnd, OBJID_CLIENT, CHILDID_SELF);
771  }
772  // Detach to leave ref counting to the caller.
773  return autocomplete_accessibility_.Detach();
774}
775
776void AutocompleteEditViewWin::SetDropHighlightPosition(int position) {
777  if (drop_highlight_position_ != position) {
778    RepaintDropHighlight(drop_highlight_position_);
779    drop_highlight_position_ = position;
780    RepaintDropHighlight(drop_highlight_position_);
781  }
782}
783
784void AutocompleteEditViewWin::MoveSelectedText(int new_position) {
785  const std::wstring selected_text(GetSelectedText());
786  CHARRANGE sel;
787  GetSel(sel);
788  DCHECK((sel.cpMax != sel.cpMin) && (new_position >= 0) &&
789         (new_position <= GetTextLength()));
790
791  ScopedFreeze freeze(this, GetTextObjectModel());
792  OnBeforePossibleChange();
793
794  // Nuke the selected text.
795  ReplaceSel(L"", TRUE);
796
797  // And insert it into the new location.
798  if (new_position >= sel.cpMin)
799    new_position -= (sel.cpMax - sel.cpMin);
800  PlaceCaretAt(new_position);
801  ReplaceSel(selected_text.c_str(), TRUE);
802
803  OnAfterPossibleChange();
804}
805
806void AutocompleteEditViewWin::InsertText(int position,
807                                         const std::wstring& text) {
808  DCHECK((position >= 0) && (position <= GetTextLength()));
809  ScopedFreeze freeze(this, GetTextObjectModel());
810  OnBeforePossibleChange();
811  SetSelection(position, position);
812  ReplaceSel(text.c_str());
813  OnAfterPossibleChange();
814}
815
816void AutocompleteEditViewWin::OnTemporaryTextMaybeChanged(
817    const std::wstring& display_text,
818    bool save_original_selection) {
819  if (save_original_selection)
820    GetSelection(original_selection_);
821
822  // Set new text and cursor position.  Sometimes this does extra work (e.g.
823  // when the new text and the old text are identical), but it's only called
824  // when the user manually changes the selected line in the popup, so that's
825  // not really a problem.  Also, even when the text hasn't changed we'd want to
826  // update the caret, because if the user had the cursor in the middle of the
827  // text and then arrowed to another entry with the same text, we'd still want
828  // to move the caret.
829  ScopedFreeze freeze(this, GetTextObjectModel());
830  SetWindowTextAndCaretPos(display_text, display_text.length());
831  TextChanged();
832}
833
834bool AutocompleteEditViewWin::OnInlineAutocompleteTextMaybeChanged(
835    const std::wstring& display_text,
836    size_t user_text_length) {
837  // Update the text and selection.  Because this can be called repeatedly while
838  // typing, we've careful not to freeze the edit unless we really need to.
839  // Also, unlike in the temporary text case above, here we don't want to update
840  // the caret/selection unless we have to, since this might make the user's
841  // caret position change without warning during typing.
842  if (display_text == GetText())
843    return false;
844
845  ScopedFreeze freeze(this, GetTextObjectModel());
846  SetWindowText(display_text.c_str());
847  // Set a reversed selection to keep the caret in the same position, which
848  // avoids scrolling the user's text.
849  SetSelection(static_cast<LONG>(display_text.length()),
850               static_cast<LONG>(user_text_length));
851  TextChanged();
852  return true;
853}
854
855void AutocompleteEditViewWin::OnRevertTemporaryText() {
856  SetSelectionRange(original_selection_);
857  TextChanged();
858}
859
860void AutocompleteEditViewWin::OnBeforePossibleChange() {
861  // Record our state.
862  text_before_change_ = GetText();
863  GetSelection(sel_before_change_);
864}
865
866bool AutocompleteEditViewWin::OnAfterPossibleChange() {
867  // Prevent the user from selecting the "phantom newline" at the end of the
868  // edit.  If they try, we just silently move the end of the selection back to
869  // the end of the real text.
870  CHARRANGE new_sel;
871  GetSelection(new_sel);
872  const int length = GetTextLength();
873  if ((new_sel.cpMin > length) || (new_sel.cpMax > length)) {
874    if (new_sel.cpMin > length)
875      new_sel.cpMin = length;
876    if (new_sel.cpMax > length)
877      new_sel.cpMax = length;
878    SetSelectionRange(new_sel);
879  }
880  const bool selection_differs = (new_sel.cpMin != sel_before_change_.cpMin) ||
881      (new_sel.cpMax != sel_before_change_.cpMax);
882  const bool at_end_of_edit =
883      (new_sel.cpMin == length) && (new_sel.cpMax == length);
884
885  // See if the text or selection have changed since OnBeforePossibleChange().
886  const std::wstring new_text(GetText());
887  const bool text_differs = (new_text != text_before_change_);
888
889  // When the user has deleted text, we don't allow inline autocomplete.  Make
890  // sure to not flag cases like selecting part of the text and then pasting
891  // (or typing) the prefix of that selection.  (We detect these by making
892  // sure the caret, which should be after any insertion, hasn't moved
893  // forward of the old selection start.)
894  const bool just_deleted_text =
895      (text_before_change_.length() > new_text.length()) &&
896      (new_sel.cpMin <= std::min(sel_before_change_.cpMin,
897                                 sel_before_change_.cpMax));
898
899
900  const bool something_changed = model_->OnAfterPossibleChange(new_text,
901      selection_differs, text_differs, just_deleted_text, at_end_of_edit);
902
903  if (selection_differs)
904    controller_->OnSelectionBoundsChanged();
905
906  if (something_changed && text_differs)
907    TextChanged();
908
909  if (text_differs) {
910    // Note that a TEXT_CHANGED event implies that the cursor/selection
911    // probably changed too, so we don't need to send both.
912    parent_view_->NotifyAccessibilityEvent(
913        AccessibilityTypes::EVENT_TEXT_CHANGED);
914  } else if (selection_differs) {
915    // Notify assistive technology that the cursor or selection changed.
916    parent_view_->NotifyAccessibilityEvent(
917        AccessibilityTypes::EVENT_SELECTION_CHANGED);
918  }
919
920  return something_changed;
921}
922
923gfx::NativeView AutocompleteEditViewWin::GetNativeView() const {
924  return m_hWnd;
925}
926
927CommandUpdater* AutocompleteEditViewWin::GetCommandUpdater() {
928  return command_updater_;
929}
930
931void AutocompleteEditViewWin::PasteAndGo(const std::wstring& text) {
932  if (CanPasteAndGo(text))
933    model_->PasteAndGo();
934}
935
936bool AutocompleteEditViewWin::SkipDefaultKeyEventProcessing(
937    const views::KeyEvent& e) {
938  app::KeyboardCode key = e.GetKeyCode();
939  // We don't process ALT + numpad digit as accelerators, they are used for
940  // entering special characters.  We do translate alt-home.
941  if (e.IsAltDown() && (key != app::VKEY_HOME) &&
942      win_util::IsNumPadDigit(key, e.IsExtendedKey()))
943    return true;
944
945  // Skip accelerators for key combinations omnibox wants to crack. This list
946  // should be synced with OnKeyDownOnlyWritable() (but for tab which is dealt
947  // with above in LocationBarView::SkipDefaultKeyEventProcessing).
948  //
949  // We cannot return true for all keys because we still need to handle some
950  // accelerators (e.g., F5 for reload the page should work even when the
951  // Omnibox gets focused).
952  switch (key) {
953    case app::VKEY_ESCAPE: {
954      ScopedFreeze freeze(this, GetTextObjectModel());
955      return model_->OnEscapeKeyPressed();
956    }
957
958    case app::VKEY_RETURN:
959      return true;
960
961    case app::VKEY_UP:
962    case app::VKEY_DOWN:
963      return !e.IsAltDown();
964
965    case app::VKEY_DELETE:
966    case app::VKEY_INSERT:
967      return !e.IsAltDown() && e.IsShiftDown() && !e.IsControlDown();
968
969    case app::VKEY_X:
970    case app::VKEY_V:
971      return !e.IsAltDown() && e.IsControlDown();
972
973    case app::VKEY_BACK:
974    case app::VKEY_OEM_PLUS:
975      return true;
976
977    default:
978      return false;
979  }
980}
981
982void AutocompleteEditViewWin::HandleExternalMsg(UINT msg,
983                                                UINT flags,
984                                                const CPoint& screen_point) {
985  if (msg == WM_CAPTURECHANGED) {
986    SendMessage(msg, 0, NULL);
987    return;
988  }
989
990  CPoint client_point(screen_point);
991  ::MapWindowPoints(NULL, m_hWnd, &client_point, 1);
992  SendMessage(msg, flags, MAKELPARAM(client_point.x, client_point.y));
993}
994
995bool AutocompleteEditViewWin::IsCommandIdChecked(int command_id) const {
996  return false;
997}
998
999bool AutocompleteEditViewWin::IsCommandIdEnabled(int command_id) const {
1000  switch (command_id) {
1001    case IDS_UNDO:         return !!CanUndo();
1002    case IDC_CUT:          return !!CanCut();
1003    case IDC_COPY:         return !!CanCopy();
1004    case IDC_PASTE:        return !!CanPaste();
1005    case IDS_PASTE_AND_GO: return CanPasteAndGo(GetClipboardText());
1006    case IDS_SELECT_ALL:   return !!CanSelectAll();
1007    case IDS_EDIT_SEARCH_ENGINES:
1008      return command_updater_->IsCommandEnabled(IDC_EDIT_SEARCH_ENGINES);
1009    default:
1010      NOTREACHED();
1011      return false;
1012  }
1013}
1014
1015bool AutocompleteEditViewWin::GetAcceleratorForCommandId(
1016    int command_id,
1017    menus::Accelerator* accelerator) {
1018  return parent_view_->GetWidget()->GetAccelerator(command_id, accelerator);
1019}
1020
1021bool AutocompleteEditViewWin::IsLabelForCommandIdDynamic(int command_id) const {
1022  // No need to change the default IDS_PASTE_AND_GO label unless this is a
1023  // search.
1024  return command_id == IDS_PASTE_AND_GO;
1025}
1026
1027std::wstring AutocompleteEditViewWin::GetLabelForCommandId(
1028    int command_id) const {
1029  DCHECK(command_id == IDS_PASTE_AND_GO);
1030  return l10n_util::GetString(model_->is_paste_and_search() ?
1031      IDS_PASTE_AND_SEARCH : IDS_PASTE_AND_GO);
1032}
1033
1034void AutocompleteEditViewWin::ExecuteCommand(int command_id) {
1035  ScopedFreeze freeze(this, GetTextObjectModel());
1036  if (command_id == IDS_PASTE_AND_GO) {
1037    // This case is separate from the switch() below since we don't want to wrap
1038    // it in OnBefore/AfterPossibleChange() calls.
1039    model_->PasteAndGo();
1040    return;
1041  }
1042
1043  OnBeforePossibleChange();
1044  switch (command_id) {
1045    case IDS_UNDO:
1046      Undo();
1047      break;
1048
1049    case IDC_CUT:
1050      Cut();
1051      break;
1052
1053    case IDC_COPY:
1054      Copy();
1055      break;
1056
1057    case IDC_PASTE:
1058      Paste();
1059      break;
1060
1061    case IDS_SELECT_ALL:
1062      SelectAll(false);
1063      break;
1064
1065    case IDS_EDIT_SEARCH_ENGINES:
1066      command_updater_->ExecuteCommand(IDC_EDIT_SEARCH_ENGINES);
1067      break;
1068
1069    default:
1070      NOTREACHED();
1071      break;
1072  }
1073  OnAfterPossibleChange();
1074}
1075
1076// static
1077int CALLBACK AutocompleteEditViewWin::WordBreakProc(LPTSTR edit_text,
1078                                                    int current_pos,
1079                                                    int num_bytes,
1080                                                    int action) {
1081  // TODO(pkasting): http://b/1111308 We should let other people, like ICU and
1082  // GURL, do the work for us here instead of writing all this ourselves.
1083
1084  // Sadly, even though the MSDN docs claim that the third parameter here is a
1085  // number of characters, they lie.  It's a number of bytes.
1086  const int length = num_bytes / sizeof(wchar_t);
1087
1088  // With no clear guidance from the MSDN docs on how to handle "not found" in
1089  // the "find the nearest xxx..." cases below, I cap the return values at
1090  // [0, length].  Since one of these (0) is also a valid position, the return
1091  // values are thus ambiguous :(
1092  switch (action) {
1093    // Find nearest character before current position that begins a word.
1094    case WB_LEFT:
1095    case WB_MOVEWORDLEFT: {
1096      if (current_pos < 2) {
1097        // Either current_pos == 0, so we have a "not found" case and return 0,
1098        // or current_pos == 1, and the only character before this position is
1099        // at 0.
1100        return 0;
1101      }
1102
1103      // Look for a delimiter before the previous character; the previous word
1104      // starts immediately after.  (If we looked for a delimiter before the
1105      // current character, we could stop on the immediate prior character,
1106      // which would mean we'd return current_pos -- which isn't "before the
1107      // current position".)
1108      const int prev_delim =
1109          WordBreakProc(edit_text, current_pos - 1, num_bytes, WB_LEFTBREAK);
1110
1111      if ((prev_delim == 0) &&
1112          !WordBreakProc(edit_text, 0, num_bytes, WB_ISDELIMITER)) {
1113        // Got back 0, but position 0 isn't a delimiter.  This was a "not
1114        // found" 0, so return one of our own.
1115        return 0;
1116      }
1117
1118      return prev_delim + 1;
1119    }
1120
1121    // Find nearest character after current position that begins a word.
1122    case WB_RIGHT:
1123    case WB_MOVEWORDRIGHT: {
1124      if (WordBreakProc(edit_text, current_pos, num_bytes, WB_ISDELIMITER)) {
1125        // The current character is a delimiter, so the next character starts
1126        // a new word.  Done.
1127        return current_pos + 1;
1128      }
1129
1130      // Look for a delimiter after the current character; the next word starts
1131      // immediately after.
1132      const int next_delim =
1133          WordBreakProc(edit_text, current_pos, num_bytes, WB_RIGHTBREAK);
1134      if (next_delim == length) {
1135        // Didn't find a delimiter.  Return length to signal "not found".
1136        return length;
1137      }
1138
1139      return next_delim + 1;
1140    }
1141
1142    // Determine if the current character delimits words.
1143    case WB_ISDELIMITER:
1144      return !!(WordBreakProc(edit_text, current_pos, num_bytes, WB_CLASSIFY) &
1145                WBF_BREAKLINE);
1146
1147    // Return the classification of the current character.
1148    case WB_CLASSIFY:
1149      if (IsWhitespace(edit_text[current_pos])) {
1150        // Whitespace normally breaks words, but the MSDN docs say that we must
1151        // not break on the CRs in a "CR, LF" or a "CR, CR, LF" sequence.  Just
1152        // check for an arbitrarily long sequence of CRs followed by LF and
1153        // report "not a delimiter" for the current CR in that case.
1154        while ((current_pos < (length - 1)) &&
1155               (edit_text[current_pos] == 0x13)) {
1156          if (edit_text[++current_pos] == 0x10)
1157            return WBF_ISWHITE;
1158        }
1159        return WBF_BREAKLINE | WBF_ISWHITE;
1160      }
1161
1162      // Punctuation normally breaks words, but the first two characters in
1163      // "://" (end of scheme) should not be breaks, so that "http://" will be
1164      // treated as one word.
1165      if (ispunct(edit_text[current_pos], std::locale()) &&
1166          !SchemeEnd(edit_text, current_pos, length) &&
1167          !SchemeEnd(edit_text, current_pos - 1, length))
1168        return WBF_BREAKLINE;
1169
1170      // Normal character, no flags.
1171      return 0;
1172
1173    // Finds nearest delimiter before current position.
1174    case WB_LEFTBREAK:
1175      for (int i = current_pos - 1; i >= 0; --i) {
1176        if (WordBreakProc(edit_text, i, num_bytes, WB_ISDELIMITER))
1177          return i;
1178      }
1179      return 0;
1180
1181    // Finds nearest delimiter after current position.
1182    case WB_RIGHTBREAK:
1183      for (int i = current_pos + 1; i < length; ++i) {
1184        if (WordBreakProc(edit_text, i, num_bytes, WB_ISDELIMITER))
1185          return i;
1186      }
1187      return length;
1188  }
1189
1190  NOTREACHED();
1191  return 0;
1192}
1193
1194// static
1195bool AutocompleteEditViewWin::SchemeEnd(LPTSTR edit_text,
1196                                        int current_pos,
1197                                        int length) {
1198  return (current_pos >= 0) &&
1199         ((length - current_pos) > 2) &&
1200         (edit_text[current_pos] == ':') &&
1201         (edit_text[current_pos + 1] == '/') &&
1202         (edit_text[current_pos + 2] == '/');
1203}
1204
1205void AutocompleteEditViewWin::OnChar(TCHAR ch, UINT repeat_count, UINT flags) {
1206  // Don't let alt-enter beep.  Not sure this is necessary, as the standard
1207  // alt-enter will hit DiscardWMSysChar() and get thrown away, and
1208  // ctrl-alt-enter doesn't seem to reach here for some reason?  At least not on
1209  // my system... still, this is harmless and maybe necessary in other locales.
1210  if (ch == VK_RETURN && (flags & KF_ALTDOWN))
1211    return;
1212
1213  // Escape is processed in OnKeyDown.  Don't let any WM_CHAR messages propagate
1214  // as we don't want the RichEdit to do anything funky.
1215  if (ch == VK_ESCAPE && !(flags & KF_ALTDOWN))
1216    return;
1217
1218  if (ch == VK_TAB) {
1219    // Don't add tabs to the input.
1220    return;
1221  }
1222
1223  HandleKeystroke(GetCurrentMessage()->message, ch, repeat_count, flags);
1224}
1225
1226void AutocompleteEditViewWin::OnContextMenu(HWND window, const CPoint& point) {
1227  BuildContextMenu();
1228  if (point.x == -1 || point.y == -1) {
1229    POINT p;
1230    GetCaretPos(&p);
1231    MapWindowPoints(HWND_DESKTOP, &p, 1);
1232    context_menu_->RunContextMenuAt(gfx::Point(p));
1233  } else {
1234    context_menu_->RunContextMenuAt(gfx::Point(point));
1235  }
1236}
1237
1238void AutocompleteEditViewWin::OnCopy() {
1239  std::wstring text(GetSelectedText());
1240  if (text.empty())
1241    return;
1242
1243  CHARRANGE sel;
1244  GURL url;
1245  bool write_url = false;
1246  GetSel(sel);
1247  // GetSel() doesn't preserve selection direction, so sel.cpMin will always be
1248  // the smaller value.
1249  model_->AdjustTextForCopy(sel.cpMin, IsSelectAll(), &text, &url, &write_url);
1250  ScopedClipboardWriter scw(g_browser_process->clipboard());
1251  scw.WriteText(text);
1252  if (write_url) {
1253    scw.WriteBookmark(text, url.spec());
1254    scw.WriteHyperlink(EscapeForHTML(text), url.spec());
1255  }
1256}
1257
1258void AutocompleteEditViewWin::OnCut() {
1259  OnCopy();
1260
1261  // This replace selection will have no effect (even on the undo stack) if the
1262  // current selection is empty.
1263  ReplaceSel(L"", true);
1264}
1265
1266LRESULT AutocompleteEditViewWin::OnGetObject(UINT uMsg,
1267                                             WPARAM wparam,
1268                                             LPARAM lparam) {
1269  // Accessibility readers will send an OBJID_CLIENT message.
1270  if (lparam == OBJID_CLIENT) {
1271    // Re-attach for internal re-usage of accessibility pointer.
1272    autocomplete_accessibility_.Attach(GetIAccessible());
1273
1274    if (autocomplete_accessibility_) {
1275      return LresultFromObject(IID_IAccessible, wparam,
1276                               autocomplete_accessibility_);
1277    }
1278  }
1279  return 0;
1280}
1281
1282LRESULT AutocompleteEditViewWin::OnImeComposition(UINT message,
1283                                                  WPARAM wparam,
1284                                                  LPARAM lparam) {
1285  if (ignore_ime_messages_) {
1286    // This message was sent while we're in the middle of meddling with the
1287    // underlying edit control.  If we handle it below, OnAfterPossibleChange()
1288    // can get bogus text for the edit, and rerun autocomplete, destructively
1289    // modifying the result set that we're in the midst of using.  For example,
1290    // if SetWindowTextAndCaretPos() was called due to the user clicking an
1291    // entry in the popup, we're in the middle of executing SetSelectedLine(),
1292    // and changing the results can cause checkfailures.
1293    return DefWindowProc(message, wparam, lparam);
1294  }
1295
1296  ScopedFreeze freeze(this, GetTextObjectModel());
1297  OnBeforePossibleChange();
1298  LRESULT result = DefWindowProc(message, wparam, lparam);
1299
1300  // Some IMEs insert whitespace characters instead of input characters while
1301  // they are composing text, and trimming these whitespace characters at the
1302  // beginning of this control (in OnAfterPossibleChange()) prevents users from
1303  // inputting text on these IMEs.
1304  // To prevent this problem, we should not start auto-complete if the
1305  // composition string starts with whitespace characters.
1306  // (When we type a space key to insert a whitespace character, IMEs don't
1307  // insert the whitespace character to their composition string but their
1308  // result string. So, this code doesn't prevent us from updating autocomplete
1309  // when we insert a whitespace character.)
1310  if (lparam & GCS_COMPSTR) {
1311    std::wstring text;
1312    HIMC context = ImmGetContext(m_hWnd);
1313    if (context) {
1314      int size = ImmGetCompositionString(context, GCS_COMPSTR, NULL, 0);
1315      if (size > 0) {
1316        wchar_t* text_data = WriteInto(&text, size / sizeof(wchar_t) + 1);
1317        if (text_data)
1318          ImmGetCompositionString(context, GCS_COMPSTR, text_data, size);
1319      }
1320      ImmReleaseContext(m_hWnd, context);
1321    }
1322    if (!text.empty() && IsWhitespace(text[0]))
1323      return result;
1324  }
1325
1326  if (!OnAfterPossibleChange() && (lparam & GCS_RESULTSTR)) {
1327    // The result string changed, but the text in the popup didn't actually
1328    // change.  This means the user finalized the composition.  Rerun
1329    // autocomplete so that we can now trigger inline autocomplete if
1330    // applicable.
1331    //
1332    // Note that if we're in the midst of losing focus, UpdatePopup() won't
1333    // actually rerun autocomplete, but will just set local state correctly.
1334    UpdatePopup();
1335  }
1336  return result;
1337}
1338
1339LRESULT AutocompleteEditViewWin::OnImeNotify(UINT message,
1340                                             WPARAM wparam,
1341                                             LPARAM lparam) {
1342  // NOTE: I'm not sure this is ever reached with |ignore_ime_messages_| set,
1343  // but if it is, the safe thing to do is to only call DefWindowProc().
1344  if (!ignore_ime_messages_ && (wparam == IMN_SETOPENSTATUS)) {
1345    // A user has activated (or deactivated) IMEs (but not started a
1346    // composition).
1347    // Some IMEs get confused when we accept keywords while they are composing
1348    // text. To prevent this situation, we accept keywords when an IME is
1349    // activated.
1350    HIMC imm_context = ImmGetContext(m_hWnd);
1351    if (imm_context) {
1352      if (ImmGetOpenStatus(imm_context) &&
1353          model_->is_keyword_hint() && !model_->keyword().empty()) {
1354        ScopedFreeze freeze(this, GetTextObjectModel());
1355        model_->AcceptKeyword();
1356      }
1357      ImmReleaseContext(m_hWnd, imm_context);
1358    }
1359  }
1360  return DefWindowProc(message, wparam, lparam);
1361}
1362
1363void AutocompleteEditViewWin::OnKeyDown(TCHAR key,
1364                                        UINT repeat_count,
1365                                        UINT flags) {
1366  if (OnKeyDownAllModes(key, repeat_count, flags))
1367    return;
1368
1369  // Make sure that we handle system key events like Alt-F4.
1370  if (popup_window_mode_) {
1371    DefWindowProc(GetCurrentMessage()->message, key, MAKELPARAM(repeat_count,
1372                                                                flags));
1373    return;
1374  }
1375
1376  if (OnKeyDownOnlyWritable(key, repeat_count, flags))
1377    return;
1378
1379  // CRichEditCtrl changes its text on WM_KEYDOWN instead of WM_CHAR for many
1380  // different keys (backspace, ctrl-v, ...), so we call this in both cases.
1381  HandleKeystroke(GetCurrentMessage()->message, key, repeat_count, flags);
1382}
1383
1384void AutocompleteEditViewWin::OnKeyUp(TCHAR key,
1385                                      UINT repeat_count,
1386                                      UINT flags) {
1387  if (key == VK_CONTROL)
1388    model_->OnControlKeyChanged(false);
1389
1390  // On systems with RTL input languages, ctrl+shift toggles the reading order
1391  // (depending on which shift key is pressed). But by default the CRichEditCtrl
1392  // only changes the current reading order, and as soon as the user deletes all
1393  // the text, or we call SetWindowText(), it reverts to the "default" order.
1394  // To work around this, if the user hits ctrl+shift, we pass it to
1395  // DefWindowProc() while the edit is empty, which toggles the default reading
1396  // order; then we restore the user's input.
1397  if (!(flags & KF_ALTDOWN) &&
1398      (((key == VK_CONTROL) && (GetKeyState(VK_SHIFT) < 0)) ||
1399       ((key == VK_SHIFT) && (GetKeyState(VK_CONTROL) < 0)))) {
1400    ScopedFreeze freeze(this, GetTextObjectModel());
1401
1402    std::wstring saved_text(GetText());
1403    CHARRANGE saved_sel;
1404    GetSelection(saved_sel);
1405
1406    SetWindowText(L"");
1407
1408    DefWindowProc(WM_KEYUP, key, MAKELPARAM(repeat_count, flags));
1409
1410    SetWindowText(saved_text.c_str());
1411    SetSelectionRange(saved_sel);
1412    return;
1413  }
1414
1415  SetMsgHandled(false);
1416}
1417
1418void AutocompleteEditViewWin::OnKillFocus(HWND focus_wnd) {
1419  if (m_hWnd == focus_wnd) {
1420    // Focus isn't actually leaving.
1421    SetMsgHandled(false);
1422    return;
1423  }
1424
1425  // This must be invoked before ClosePopup.
1426  controller_->OnAutocompleteLosingFocus(focus_wnd);
1427
1428  // Close the popup.
1429  ClosePopup();
1430
1431  // Save the user's existing selection to restore it later.
1432  GetSelection(saved_selection_for_focus_change_);
1433
1434  // Tell the model to reset itself.
1435  model_->OnKillFocus();
1436
1437  // Let the CRichEditCtrl do its default handling.  This will complete any
1438  // in-progress IME composition.  We must do this after setting has_focus_ to
1439  // false so that UpdatePopup() will know not to rerun autocomplete.
1440  ScopedFreeze freeze(this, GetTextObjectModel());
1441  DefWindowProc(WM_KILLFOCUS, reinterpret_cast<WPARAM>(focus_wnd), 0);
1442
1443  // Cancel any user selection and scroll the text back to the beginning of the
1444  // URL.  We have to do this after calling DefWindowProc() because otherwise
1445  // an in-progress IME composition will be completed at the new caret position,
1446  // resulting in the string jumping unexpectedly to the front of the edit.
1447  PlaceCaretAt(0);
1448}
1449
1450void AutocompleteEditViewWin::OnLButtonDblClk(UINT keys, const CPoint& point) {
1451  // Save the double click info for later triple-click detection.
1452  tracking_double_click_ = true;
1453  double_click_point_ = point;
1454  double_click_time_ = GetCurrentMessage()->time;
1455  possible_drag_ = false;
1456
1457  // Modifying the selection counts as accepting any inline autocompletion, so
1458  // track "changes" made by clicking the mouse button.
1459  ScopedFreeze freeze(this, GetTextObjectModel());
1460  OnBeforePossibleChange();
1461  DefWindowProc(WM_LBUTTONDBLCLK, keys,
1462                MAKELPARAM(ClipXCoordToVisibleText(point.x, false), point.y));
1463  OnAfterPossibleChange();
1464
1465  gaining_focus_.reset();  // See NOTE in OnMouseActivate().
1466}
1467
1468void AutocompleteEditViewWin::OnLButtonDown(UINT keys, const CPoint& point) {
1469  TrackMousePosition(kLeft, point);
1470  if (gaining_focus_.get()) {
1471    // When Chrome was already the activated app, we haven't reached
1472    // OnSetFocus() yet.  When we get there, don't restore the saved selection,
1473    // since it will just screw up the user's interaction with the edit.
1474    saved_selection_for_focus_change_.cpMin = -1;
1475
1476    // Crazy hack: In this particular case, the CRichEditCtrl seems to have an
1477    // internal flag that discards the next WM_LBUTTONDOWN without processing
1478    // it, so that clicks on the edit when its owning app is not activated are
1479    // eaten rather than processed (despite whatever the return value of
1480    // DefWindowProc(WM_MOUSEACTIVATE, ...) may say).  This behavior is
1481    // confusing and we want the click to be treated normally.  So, to reset the
1482    // CRichEditCtrl's internal flag, we pass it an extra WM_LBUTTONDOWN here
1483    // (as well as a matching WM_LBUTTONUP, just in case we'd be confusing some
1484    // kind of state tracking otherwise).
1485    DefWindowProc(WM_LBUTTONDOWN, keys, MAKELPARAM(point.x, point.y));
1486    DefWindowProc(WM_LBUTTONUP, keys, MAKELPARAM(point.x, point.y));
1487  }
1488
1489  // Check for triple click, then reset tracker.  Should be safe to subtract
1490  // double_click_time_ from the current message's time even if the timer has
1491  // wrapped in between.
1492  const bool is_triple_click = tracking_double_click_ &&
1493      win_util::IsDoubleClick(double_click_point_, point,
1494                              GetCurrentMessage()->time - double_click_time_);
1495  tracking_double_click_ = false;
1496
1497  if (!gaining_focus_.get() && !is_triple_click)
1498    OnPossibleDrag(point);
1499
1500
1501  // Modifying the selection counts as accepting any inline autocompletion, so
1502  // track "changes" made by clicking the mouse button.
1503  ScopedFreeze freeze(this, GetTextObjectModel());
1504  OnBeforePossibleChange();
1505  DefWindowProc(WM_LBUTTONDOWN, keys,
1506                MAKELPARAM(ClipXCoordToVisibleText(point.x, is_triple_click),
1507                           point.y));
1508  OnAfterPossibleChange();
1509
1510  gaining_focus_.reset();
1511}
1512
1513void AutocompleteEditViewWin::OnLButtonUp(UINT keys, const CPoint& point) {
1514  // default processing should happen first so we can see the result of the
1515  // selection
1516  ScopedFreeze freeze(this, GetTextObjectModel());
1517  DefWindowProc(WM_LBUTTONUP, keys,
1518                MAKELPARAM(ClipXCoordToVisibleText(point.x, false), point.y));
1519
1520  SelectAllIfNecessary(kLeft, point);
1521
1522  tracking_click_[kLeft] = false;
1523
1524  possible_drag_ = false;
1525}
1526
1527void AutocompleteEditViewWin::OnMButtonDblClk(UINT /*keys*/,
1528                                              const CPoint& /*point*/) {
1529  gaining_focus_.reset();  // See NOTE in OnMouseActivate().
1530
1531  // By default, the edit responds to middle-clicks by capturing the mouse and
1532  // ignoring all subsequent events until it receives another click (of any of
1533  // the left, middle, or right buttons).  This bizarre behavior is not only
1534  // useless but can cause the UI to appear unresponsive if a user accidentally
1535  // middle-clicks the edit (instead of a tab above it), so we purposefully eat
1536  // this message (instead of calling SetMsgHandled(false)) to avoid triggering
1537  // this.
1538}
1539
1540void AutocompleteEditViewWin::OnMButtonDown(UINT /*keys*/,
1541                                            const CPoint& /*point*/) {
1542  tracking_double_click_ = false;
1543
1544  // See note in OnMButtonDblClk above.
1545}
1546
1547void AutocompleteEditViewWin::OnMButtonUp(UINT /*keys*/,
1548                                          const CPoint& /*point*/) {
1549  possible_drag_ = false;
1550
1551  // See note in OnMButtonDblClk above.
1552}
1553
1554LRESULT AutocompleteEditViewWin::OnMouseActivate(HWND window,
1555                                                 UINT hit_test,
1556                                                 UINT mouse_message) {
1557  // First, give other handlers a chance to handle the message to see if we are
1558  // actually going to activate and gain focus.
1559  LRESULT result = DefWindowProc(WM_MOUSEACTIVATE,
1560                                 reinterpret_cast<WPARAM>(window),
1561                                 MAKELPARAM(hit_test, mouse_message));
1562  // Check if we're getting focus from a click.  We have to do this here rather
1563  // than in OnXButtonDown() since in many scenarios OnSetFocus() will be
1564  // reached before OnXButtonDown(), preventing us from detecting this properly
1565  // there.  Also in those cases, we need to already know in OnSetFocus() that
1566  // we should not restore the saved selection.
1567  if (!model_->has_focus() &&
1568      ((mouse_message == WM_LBUTTONDOWN || mouse_message == WM_RBUTTONDOWN)) &&
1569      (result == MA_ACTIVATE)) {
1570    DCHECK(!gaining_focus_.get());
1571    gaining_focus_.reset(new ScopedFreeze(this, GetTextObjectModel()));
1572    // NOTE: Despite |mouse_message| being WM_XBUTTONDOWN here, we're not
1573    // guaranteed to call OnXButtonDown() later!  Specifically, if this is the
1574    // second click of a double click, we'll reach here but later call
1575    // OnXButtonDblClk().  Make sure |gaining_focus_| gets reset both places,
1576    // or we'll have visual glitchiness and then DCHECK failures.
1577
1578    // Don't restore saved selection, it will just screw up our interaction
1579    // with this edit.
1580    saved_selection_for_focus_change_.cpMin = -1;
1581  }
1582  return result;
1583}
1584
1585void AutocompleteEditViewWin::OnMouseMove(UINT keys, const CPoint& point) {
1586  if (possible_drag_) {
1587    StartDragIfNecessary(point);
1588    // Don't fall through to default mouse handling, otherwise a second
1589    // drag session may start.
1590    return;
1591  }
1592
1593  if (tracking_click_[kLeft] && !win_util::IsDrag(click_point_[kLeft], point))
1594    return;
1595
1596  tracking_click_[kLeft] = false;
1597
1598  // Return quickly if this can't change the selection/cursor, so we don't
1599  // create a ScopedFreeze (and thus do an UpdateWindow()) on every
1600  // WM_MOUSEMOVE.
1601  if (!(keys & MK_LBUTTON)) {
1602    DefWindowProc(WM_MOUSEMOVE, keys, MAKELPARAM(point.x, point.y));
1603    return;
1604  }
1605
1606  // Clamp the selection to the visible text so the user can't drag to select
1607  // the "phantom newline".  In theory we could achieve this by clipping the X
1608  // coordinate, but in practice the edit seems to behave nondeterministically
1609  // with similar sequences of clipped input coordinates fed to it.  Maybe it's
1610  // reading the mouse cursor position directly?
1611  //
1612  // This solution has a minor visual flaw, however: if there's a visible cursor
1613  // at the edge of the text (only true when there's no selection), dragging the
1614  // mouse around outside that edge repaints the cursor on every WM_MOUSEMOVE
1615  // instead of allowing it to blink normally.  To fix this, we special-case
1616  // this exact case and discard the WM_MOUSEMOVE messages instead of passing
1617  // them along.
1618  //
1619  // But even this solution has a flaw!  (Argh.)  In the case where the user has
1620  // a selection that starts at the edge of the edit, and proceeds to the middle
1621  // of the edit, and the user is dragging back past the start edge to remove
1622  // the selection, there's a redraw problem where the change between having the
1623  // last few bits of text still selected and having nothing selected can be
1624  // slow to repaint (which feels noticeably strange).  This occurs if you only
1625  // let the edit receive a single WM_MOUSEMOVE past the edge of the text.  I
1626  // think on each WM_MOUSEMOVE the edit is repainting its previous state, then
1627  // updating its internal variables to the new state but not repainting.  To
1628  // fix this, we allow one more WM_MOUSEMOVE through after the selection has
1629  // supposedly been shrunk to nothing; this makes the edit redraw the selection
1630  // quickly so it feels smooth.
1631  CHARRANGE selection;
1632  GetSel(selection);
1633  const bool possibly_can_discard_mousemove =
1634      (selection.cpMin == selection.cpMax) &&
1635      (((selection.cpMin == 0) &&
1636        (ClipXCoordToVisibleText(point.x, false) > point.x)) ||
1637       ((selection.cpMin == GetTextLength()) &&
1638        (ClipXCoordToVisibleText(point.x, false) < point.x)));
1639  if (!can_discard_mousemove_ || !possibly_can_discard_mousemove) {
1640    can_discard_mousemove_ = possibly_can_discard_mousemove;
1641    ScopedFreeze freeze(this, GetTextObjectModel());
1642    OnBeforePossibleChange();
1643    // Force the Y coordinate to the center of the clip rect.  The edit
1644    // behaves strangely when the cursor is dragged vertically: if the cursor
1645    // is in the middle of the text, drags inside the clip rect do nothing,
1646    // and drags outside the clip rect act as if the cursor jumped to the
1647    // left edge of the text.  When the cursor is at the right edge, drags of
1648    // just a few pixels vertically end up selecting the "phantom newline"...
1649    // sometimes.
1650    RECT r;
1651    GetRect(&r);
1652    DefWindowProc(WM_MOUSEMOVE, keys,
1653                  MAKELPARAM(point.x, (r.bottom - r.top) / 2));
1654    OnAfterPossibleChange();
1655  }
1656}
1657
1658void AutocompleteEditViewWin::OnPaint(HDC bogus_hdc) {
1659  // We need to paint over the top of the edit.  If we simply let the edit do
1660  // its default painting, then do ours into the window DC, the screen is
1661  // updated in between and we can get flicker.  To avoid this, we force the
1662  // edit to paint into a memory DC, which we also paint onto, then blit the
1663  // whole thing to the screen.
1664
1665  // Don't paint if not necessary.
1666  CRect paint_clip_rect;
1667  if (!GetUpdateRect(&paint_clip_rect, true))
1668    return;
1669
1670  // Begin painting, and create a memory DC for the edit to paint into.
1671  CPaintDC paint_dc(m_hWnd);
1672  CDC memory_dc(CreateCompatibleDC(paint_dc));
1673  CRect rect;
1674  GetClientRect(&rect);
1675  // NOTE: This next call uses |paint_dc| instead of |memory_dc| because
1676  // |memory_dc| contains a 1x1 monochrome bitmap by default, which will cause
1677  // |memory_bitmap| to be monochrome, which isn't what we want.
1678  CBitmap memory_bitmap(CreateCompatibleBitmap(paint_dc, rect.Width(),
1679                                               rect.Height()));
1680  HBITMAP old_bitmap = memory_dc.SelectBitmap(memory_bitmap);
1681
1682  // Tell our intercept functions to supply our memory DC to the edit when it
1683  // tries to call BeginPaint().
1684  //
1685  // The sane way to do this would be to use WM_PRINTCLIENT to ask the edit to
1686  // paint into our desired DC.  Unfortunately, the Rich Edit 3.0 that ships
1687  // with Windows 2000/XP/Vista doesn't handle WM_PRINTCLIENT correctly; it
1688  // treats it just like WM_PAINT and calls BeginPaint(), ignoring our provided
1689  // DC.  The Rich Edit 6.0 that ships with Office 2007 handles this better, but
1690  // has other issues, and we can't redistribute that DLL anyway.  So instead,
1691  // we use this scary hack.
1692  //
1693  // NOTE: It's possible to get nested paint calls (!) (try setting the
1694  // permanent URL to something longer than the edit width, then selecting the
1695  // contents of the edit, typing a character, and hitting <esc>), so we can't
1696  // DCHECK(!edit_hwnd_) here.  Instead, just save off the old HWND, which most
1697  // of the time will be NULL.
1698  HWND old_edit_hwnd = edit_hwnd;
1699  edit_hwnd = m_hWnd;
1700  paint_struct = paint_dc.m_ps;
1701  paint_struct.hdc = memory_dc;
1702  DefWindowProc(WM_PAINT, reinterpret_cast<WPARAM>(bogus_hdc), 0);
1703
1704  // Make the selection look better.
1705  EraseTopOfSelection(&memory_dc, rect, paint_clip_rect);
1706
1707  // Draw a slash through the scheme if this is insecure.
1708  if (insecure_scheme_component_.is_nonempty())
1709    DrawSlashForInsecureScheme(memory_dc, rect, paint_clip_rect);
1710
1711  // Draw the drop highlight.
1712  if (drop_highlight_position_ != -1)
1713    DrawDropHighlight(memory_dc, rect, paint_clip_rect);
1714
1715  // Blit the memory DC to the actual paint DC and clean up.
1716  BitBlt(paint_dc, rect.left, rect.top, rect.Width(), rect.Height(), memory_dc,
1717         rect.left, rect.top, SRCCOPY);
1718  memory_dc.SelectBitmap(old_bitmap);
1719  edit_hwnd = old_edit_hwnd;
1720}
1721
1722void AutocompleteEditViewWin::OnPaste() {
1723  // Replace the selection if we have something to paste.
1724  const std::wstring text(GetClipboardText());
1725  if (!text.empty()) {
1726    // If this paste will be replacing all the text, record that, so we can do
1727    // different behaviors in such a case.
1728    if (IsSelectAll())
1729      model_->on_paste_replacing_all();
1730    // Force a Paste operation to trigger the text_changed code in
1731    // OnAfterPossibleChange(), even if identical contents are pasted into the
1732    // text box.
1733    text_before_change_.clear();
1734    ReplaceSel(text.c_str(), true);
1735  }
1736}
1737
1738void AutocompleteEditViewWin::OnRButtonDblClk(UINT /*keys*/,
1739                                              const CPoint& /*point*/) {
1740  gaining_focus_.reset();  // See NOTE in OnMouseActivate().
1741  SetMsgHandled(false);
1742}
1743
1744void AutocompleteEditViewWin::OnRButtonDown(UINT /*keys*/,
1745                                            const CPoint& point) {
1746  TrackMousePosition(kRight, point);
1747  tracking_double_click_ = false;
1748  possible_drag_ = false;
1749  gaining_focus_.reset();
1750  SetMsgHandled(false);
1751}
1752
1753void AutocompleteEditViewWin::OnRButtonUp(UINT /*keys*/, const CPoint& point) {
1754  SelectAllIfNecessary(kRight, point);
1755  tracking_click_[kRight] = false;
1756  SetMsgHandled(false);
1757}
1758
1759void AutocompleteEditViewWin::OnSetFocus(HWND focus_wnd) {
1760  views::FocusManager* focus_manager = parent_view_->GetFocusManager();
1761  if (focus_manager) {
1762    // Notify the FocusManager that the focused view is now the location bar
1763    // (our parent view).
1764    focus_manager->SetFocusedView(parent_view_);
1765  } else {
1766    NOTREACHED();
1767  }
1768
1769  model_->OnSetFocus(GetKeyState(VK_CONTROL) < 0);
1770
1771  // Restore saved selection if available.
1772  if (saved_selection_for_focus_change_.cpMin != -1) {
1773    SetSelectionRange(saved_selection_for_focus_change_);
1774    saved_selection_for_focus_change_.cpMin = -1;
1775  }
1776
1777  SetMsgHandled(false);
1778}
1779
1780LRESULT AutocompleteEditViewWin::OnSetText(const wchar_t* text) {
1781  // Ignore all IME messages while we process this WM_SETTEXT message.
1782  // When SetWindowText() is called while an IME is composing text, the IME
1783  // calls SendMessage() to send a WM_IME_COMPOSITION message. When we receive
1784  // this WM_IME_COMPOSITION message, we update the omnibox and may call
1785  // SetWindowText() again. To stop this recursive message-handler call, we
1786  // stop updating the omnibox while we process a WM_SETTEXT message.
1787  // We wouldn't need to do this update anyway, because either we're in the
1788  // middle of updating the omnibox already or the caller of SetWindowText()
1789  // is going to update the omnibox next.
1790  AutoReset<bool> auto_reset_ignore_ime_messages(&ignore_ime_messages_, true);
1791  return DefWindowProc(WM_SETTEXT, 0, reinterpret_cast<LPARAM>(text));
1792}
1793
1794void AutocompleteEditViewWin::OnSysChar(TCHAR ch,
1795                                        UINT repeat_count,
1796                                        UINT flags) {
1797  // Nearly all alt-<xxx> combos result in beeping rather than doing something
1798  // useful, so we discard most.  Exceptions:
1799  //   * ctrl-alt-<xxx>, which is sometimes important, generates WM_CHAR instead
1800  //     of WM_SYSCHAR, so it doesn't need to be handled here.
1801  //   * alt-space gets translated by the default WM_SYSCHAR handler to a
1802  //     WM_SYSCOMMAND to open the application context menu, so we need to allow
1803  //     it through.
1804  if (ch == VK_SPACE)
1805    SetMsgHandled(false);
1806}
1807
1808void AutocompleteEditViewWin::OnWindowPosChanging(WINDOWPOS* window_pos) {
1809  if (force_hidden_)
1810    window_pos->flags &= ~SWP_SHOWWINDOW;
1811  SetMsgHandled(true);
1812}
1813
1814BOOL AutocompleteEditViewWin::OnMouseWheel(UINT flags,
1815                                           short delta,
1816                                           CPoint point) {
1817  // Forward the mouse-wheel message to the window under the mouse.
1818  if (!views::RerouteMouseWheel(m_hWnd, MAKEWPARAM(flags, delta),
1819                                MAKELPARAM(point.x, point.y)))
1820    SetMsgHandled(false);
1821  return 0;
1822}
1823
1824void AutocompleteEditViewWin::HandleKeystroke(UINT message,
1825                                              TCHAR key,
1826                                              UINT repeat_count,
1827                                              UINT flags) {
1828  ScopedFreeze freeze(this, GetTextObjectModel());
1829  OnBeforePossibleChange();
1830
1831  if (key == app::VKEY_HOME || key == app::VKEY_END) {
1832    // DefWindowProc() might reset the keyboard layout when it receives a
1833    // keydown event for VKEY_HOME or VKEY_END. When the window was created
1834    // with WS_EX_LAYOUTRTL and the current keyboard layout is not a RTL one,
1835    // if the input text is pure LTR text, the layout changes to the first RTL
1836    // keyboard layout in keyboard layout queue; if the input text is
1837    // bidirectional text, the layout changes to the keyboard layout of the
1838    // first RTL character in input text. When the window was created without
1839    // WS_EX_LAYOUTRTL and the current keyboard layout is not a LTR one, if the
1840    // input text is pure RTL text, the layout changes to English; if the input
1841    // text is bidirectional text, the layout changes to the keyboard layout of
1842    // the first LTR character in input text. Such keyboard layout change
1843    // behavior is surprising and inconsistent with keyboard behavior
1844    // elsewhere, so reset the layout in this case.
1845    HKL layout = GetKeyboardLayout(0);
1846    DefWindowProc(message, key, MAKELPARAM(repeat_count, flags));
1847    ActivateKeyboardLayout(layout, KLF_REORDER);
1848  } else {
1849    DefWindowProc(message, key, MAKELPARAM(repeat_count, flags));
1850  }
1851
1852  // CRichEditCtrl automatically turns on IMF_AUTOKEYBOARD when the user
1853  // inputs an RTL character, making it difficult for the user to control
1854  // what language is set as they type. Force this off to make the edit's
1855  // behavior more stable.
1856  const int lang_options = SendMessage(EM_GETLANGOPTIONS, 0, 0);
1857  if (lang_options & IMF_AUTOKEYBOARD)
1858    SendMessage(EM_SETLANGOPTIONS, 0, lang_options & ~IMF_AUTOKEYBOARD);
1859
1860  OnAfterPossibleChange();
1861}
1862
1863bool AutocompleteEditViewWin::OnKeyDownOnlyWritable(TCHAR key,
1864                                                    UINT repeat_count,
1865                                                    UINT flags) {
1866  // NOTE: Annoyingly, ctrl-alt-<key> generates WM_KEYDOWN rather than
1867  // WM_SYSKEYDOWN, so we need to check (flags & KF_ALTDOWN) in various places
1868  // in this function even with a WM_SYSKEYDOWN handler.
1869
1870  // If adding a new key that could possibly be an accelerator then you'll need
1871  // to update LocationBarView::SkipDefaultKeyEventProcessing() as well.
1872  int count = repeat_count;
1873  switch (key) {
1874    case VK_RIGHT:
1875      // TODO(sky): figure out RTL.
1876      if (base::i18n::IsRTL())
1877        return false;
1878      {
1879        CHARRANGE selection;
1880        GetSel(selection);
1881        return (selection.cpMin == selection.cpMax) &&
1882            (selection.cpMin == GetTextLength()) &&
1883            controller_->OnCommitSuggestedText(GetText());
1884      }
1885
1886    case VK_RETURN:
1887      model_->AcceptInput((flags & KF_ALTDOWN) ?
1888          NEW_FOREGROUND_TAB : CURRENT_TAB, false);
1889      return true;
1890
1891    case VK_PRIOR:
1892    case VK_NEXT:
1893      count = model_->result().size();
1894      // FALL THROUGH
1895    case VK_UP:
1896    case VK_DOWN:
1897      // Ignore alt + numpad, but treat alt + (non-numpad) like (non-numpad).
1898      if ((flags & KF_ALTDOWN) && !(flags & KF_EXTENDED))
1899        return false;
1900
1901      model_->OnUpOrDownKeyPressed(((key == VK_PRIOR) || (key == VK_UP)) ?
1902          -count : count);
1903      return true;
1904
1905    // Hijacking Editing Commands
1906    //
1907    // We hijack the keyboard short-cuts for Cut, Copy, and Paste here so that
1908    // they go through our clipboard routines.  This allows us to be smarter
1909    // about how we interact with the clipboard and avoid bugs in the
1910    // CRichEditCtrl.  If we didn't hijack here, the edit control would handle
1911    // these internally with sending the WM_CUT, WM_COPY, or WM_PASTE messages.
1912    //
1913    // Cut:   Shift-Delete and Ctrl-x are treated as cut.  Ctrl-Shift-Delete and
1914    //        Ctrl-Shift-x are not treated as cut even though the underlying
1915    //        CRichTextEdit would treat them as such.
1916    // Copy:  Ctrl-Insert and Ctrl-c is treated as copy.  Shift-Ctrl-c is not.
1917    //        (This is handled in OnKeyDownAllModes().)
1918    // Paste: Shift-Insert and Ctrl-v are treated as paste.  Ctrl-Shift-Insert
1919    //        and Ctrl-Shift-v are not.
1920    //
1921    // This behavior matches most, but not all Windows programs, and largely
1922    // conforms to what users expect.
1923
1924    case VK_DELETE:
1925      if ((flags & KF_ALTDOWN) || GetKeyState(VK_SHIFT) >= 0)
1926        return false;
1927      if (GetKeyState(VK_CONTROL) >= 0) {
1928        // Cut text if possible.
1929        CHARRANGE selection;
1930        GetSel(selection);
1931        if (selection.cpMin != selection.cpMax) {
1932          ScopedFreeze freeze(this, GetTextObjectModel());
1933          OnBeforePossibleChange();
1934          Cut();
1935          OnAfterPossibleChange();
1936        } else {
1937          AutocompletePopupModel* popup_model = popup_view_->GetModel();
1938          if (popup_model->IsOpen()) {
1939            // This is a bit overloaded, but we hijack Shift-Delete in this
1940            // case to delete the current item from the pop-up.  We prefer
1941            // cutting to this when possible since that's the behavior more
1942            // people expect from Shift-Delete, and it's more commonly useful.
1943            popup_model->TryDeletingCurrentItem();
1944          }
1945        }
1946      }
1947      return true;
1948
1949    case 'X':
1950      if ((flags & KF_ALTDOWN) || (GetKeyState(VK_CONTROL) >= 0))
1951        return false;
1952      if (GetKeyState(VK_SHIFT) >= 0) {
1953        ScopedFreeze freeze(this, GetTextObjectModel());
1954        OnBeforePossibleChange();
1955        Cut();
1956        OnAfterPossibleChange();
1957      }
1958      return true;
1959
1960    case VK_INSERT:
1961      // Ignore insert by itself, so we don't turn overtype mode on/off.
1962      if (!(flags & KF_ALTDOWN) && (GetKeyState(VK_SHIFT) >= 0) &&
1963          (GetKeyState(VK_CONTROL) >= 0))
1964        return true;
1965      // FALL THROUGH
1966    case 'V':
1967      if ((flags & KF_ALTDOWN) ||
1968          (GetKeyState((key == 'V') ? VK_CONTROL : VK_SHIFT) >= 0))
1969        return false;
1970      if (GetKeyState((key == 'V') ? VK_SHIFT : VK_CONTROL) >= 0) {
1971        ScopedFreeze freeze(this, GetTextObjectModel());
1972        OnBeforePossibleChange();
1973        Paste();
1974        OnAfterPossibleChange();
1975      }
1976      return true;
1977
1978    case VK_BACK: {
1979      if ((flags & KF_ALTDOWN) || model_->is_keyword_hint() ||
1980          model_->keyword().empty())
1981        return false;
1982
1983      {
1984        CHARRANGE selection;
1985        GetSel(selection);
1986        if ((selection.cpMin != selection.cpMax) || (selection.cpMin != 0))
1987          return false;
1988      }
1989
1990      // We're showing a keyword and the user pressed backspace at the beginning
1991      // of the text. Delete the selected keyword.
1992      ScopedFreeze freeze(this, GetTextObjectModel());
1993      model_->ClearKeyword(GetText());
1994      return true;
1995    }
1996
1997    case VK_TAB: {
1998      if (model_->is_keyword_hint() && !model_->keyword().empty()) {
1999        // Accept the keyword.
2000        ScopedFreeze freeze(this, GetTextObjectModel());
2001        model_->AcceptKeyword();
2002      }
2003      return true;
2004    }
2005
2006    case 0xbb:  // Ctrl-'='.  Triggers subscripting (even in plain text mode).
2007                // We don't use VK_OEM_PLUS in case the macro isn't defined.
2008                // (e.g., we don't have this symbol in embeded environment).
2009      return true;
2010
2011    default:
2012      return false;
2013  }
2014}
2015
2016bool AutocompleteEditViewWin::OnKeyDownAllModes(TCHAR key,
2017                                                UINT repeat_count,
2018                                                UINT flags) {
2019  // See KF_ALTDOWN comment atop OnKeyDownOnlyWritable().
2020
2021  switch (key) {
2022    case VK_CONTROL:
2023      model_->OnControlKeyChanged(true);
2024      return false;
2025
2026    case VK_INSERT:
2027    case 'C':
2028      // See more detailed comments in OnKeyDownOnlyWritable().
2029      if ((flags & KF_ALTDOWN) || (GetKeyState(VK_CONTROL) >= 0))
2030        return false;
2031      if (GetKeyState(VK_SHIFT) >= 0)
2032        Copy();
2033      return true;
2034
2035    default:
2036      return false;
2037  }
2038}
2039
2040void AutocompleteEditViewWin::GetSelection(CHARRANGE& sel) const {
2041  GetSel(sel);
2042
2043  // See if we need to reverse the direction of the selection.
2044  ITextDocument* const text_object_model = GetTextObjectModel();
2045  if (!text_object_model)
2046    return;
2047  ScopedComPtr<ITextSelection> selection;
2048  const HRESULT hr = text_object_model->GetSelection(selection.Receive());
2049  DCHECK(hr == S_OK);
2050  long flags;
2051  selection->GetFlags(&flags);
2052  if (flags & tomSelStartActive)
2053    std::swap(sel.cpMin, sel.cpMax);
2054}
2055
2056std::wstring AutocompleteEditViewWin::GetSelectedText() const {
2057  // Figure out the length of the selection.
2058  CHARRANGE sel;
2059  GetSel(sel);
2060
2061  // Grab the selected text.
2062  std::wstring str;
2063  GetSelText(WriteInto(&str, sel.cpMax - sel.cpMin + 1));
2064  return str;
2065}
2066
2067void AutocompleteEditViewWin::SetSelection(LONG start, LONG end) {
2068  SetSel(start, end);
2069
2070  if (start <= end)
2071    return;
2072
2073  // We need to reverse the direction of the selection.
2074  ITextDocument* const text_object_model = GetTextObjectModel();
2075  if (!text_object_model)
2076    return;
2077  ScopedComPtr<ITextSelection> selection;
2078  const HRESULT hr = text_object_model->GetSelection(selection.Receive());
2079  DCHECK(hr == S_OK);
2080  selection->SetFlags(tomSelStartActive);
2081}
2082
2083void AutocompleteEditViewWin::PlaceCaretAt(std::wstring::size_type pos) {
2084  SetSelection(static_cast<LONG>(pos), static_cast<LONG>(pos));
2085}
2086
2087bool AutocompleteEditViewWin::IsSelectAllForRange(const CHARRANGE& sel) const {
2088  const int text_length = GetTextLength();
2089  return ((sel.cpMin == 0) && (sel.cpMax >= text_length)) ||
2090      ((sel.cpMax == 0) && (sel.cpMin >= text_length));
2091}
2092
2093LONG AutocompleteEditViewWin::ClipXCoordToVisibleText(
2094    LONG x, bool is_triple_click) const {
2095  // Clip the X coordinate to the left edge of the text. Careful:
2096  // PosFromChar(0) may return a negative X coordinate if the beginning of the
2097  // text has scrolled off the edit, so don't go past the clip rect's edge.
2098  PARAFORMAT2 pf2;
2099  GetParaFormat(pf2);
2100  // Calculation of the clipped coordinate is more complicated if the paragraph
2101  // layout is RTL layout, or if there is RTL characters inside the LTR layout
2102  // paragraph.
2103  const bool ltr_text_in_ltr_layout = !(pf2.wEffects & PFE_RTLPARA) &&
2104      !base::i18n::StringContainsStrongRTLChars(GetText());
2105  const int length = GetTextLength();
2106  RECT r;
2107  GetRect(&r);
2108  // The values returned by PosFromChar() seem to refer always
2109  // to the left edge of the character's bounding box.
2110  const LONG first_position_x = PosFromChar(0).x;
2111  LONG min_x = first_position_x;
2112  if (!ltr_text_in_ltr_layout) {
2113    for (int i = 1; i < length; ++i)
2114      min_x = std::min(min_x, PosFromChar(i).x);
2115  }
2116  const LONG left_bound = std::max(r.left, min_x);
2117  // PosFromChar(length) is a phantom character past the end of the text. It is
2118  // not necessarily a right bound; in RTL controls it may be a left bound. So
2119  // treat it as a right bound only if it is to the right of the first
2120  // character.
2121  LONG right_bound = r.right;
2122  LONG end_position_x = PosFromChar(length).x;
2123  if (end_position_x >= first_position_x) {
2124    right_bound = std::min(right_bound, end_position_x);  // LTR case.
2125  }
2126  // For trailing characters that are 2 pixels wide of less (like "l" in some
2127  // fonts), we have a problem:
2128  //   * Clicks on any pixel within the character will place the cursor before
2129  //     the character.
2130  //   * Clicks on the pixel just after the character will not allow triple-
2131  //     click to work properly (true for any last character width).
2132  // So, we move to the last pixel of the character when this is a
2133  // triple-click, and moving to one past the last pixel in all other
2134  // scenarios.  This way, all clicks that can move the cursor will place it at
2135  // the end of the text, but triple-click will still work.
2136  if (x < left_bound) {
2137    return (is_triple_click && ltr_text_in_ltr_layout) ? left_bound - 1 :
2138                                                         left_bound;
2139  }
2140  if ((length == 0) || (x < right_bound))
2141    return x;
2142  return is_triple_click ? (right_bound - 1) : right_bound;
2143}
2144
2145void AutocompleteEditViewWin::EmphasizeURLComponents() {
2146  ITextDocument* const text_object_model = GetTextObjectModel();
2147  ScopedFreeze freeze(this, text_object_model);
2148  ScopedSuspendUndo suspend_undo(text_object_model);
2149
2150  // Save the selection.
2151  CHARRANGE saved_sel;
2152  GetSelection(saved_sel);
2153
2154  // See whether the contents are a URL with a non-empty host portion, which we
2155  // should emphasize.  To check for a URL, rather than using the type returned
2156  // by Parse(), ask the model, which will check the desired page transition for
2157  // this input.  This can tell us whether an UNKNOWN input string is going to
2158  // be treated as a search or a navigation, and is the same method the Paste
2159  // And Go system uses.
2160  url_parse::Component scheme, host;
2161  AutocompleteInput::ParseForEmphasizeComponents(
2162      GetText(), model_->GetDesiredTLD(), &scheme, &host);
2163  const bool emphasize = model_->CurrentTextIsURL() && (host.len > 0);
2164
2165  // Set the baseline emphasis.
2166  CHARFORMAT cf = {0};
2167  cf.dwMask = CFM_COLOR;
2168  // If we're going to emphasize parts of the text, then the baseline state
2169  // should be "de-emphasized".  If not, then everything should be rendered in
2170  // the standard text color.
2171  cf.crTextColor = skia::SkColorToCOLORREF(LocationBarView::GetColor(
2172      security_level_,
2173      emphasize ? LocationBarView::DEEMPHASIZED_TEXT : LocationBarView::TEXT));
2174  // NOTE: Don't use SetDefaultCharFormat() instead of the below; that sets the
2175  // format that will get applied to text added in the future, not to text
2176  // already in the edit.
2177  SelectAll(false);
2178  SetSelectionCharFormat(cf);
2179
2180  if (emphasize) {
2181    // We've found a host name, give it more emphasis.
2182    cf.crTextColor = skia::SkColorToCOLORREF(LocationBarView::GetColor(
2183        security_level_, LocationBarView::TEXT));
2184    SetSelection(host.begin, host.end());
2185    SetSelectionCharFormat(cf);
2186  }
2187
2188  // Emphasize the scheme for security UI display purposes (if necessary).
2189  insecure_scheme_component_.reset();
2190  if (!model_->user_input_in_progress() && scheme.is_nonempty() &&
2191      (security_level_ != ToolbarModel::NONE)) {
2192    if (security_level_ == ToolbarModel::SECURITY_ERROR) {
2193      insecure_scheme_component_.begin = scheme.begin;
2194      insecure_scheme_component_.len = scheme.len;
2195    }
2196    cf.crTextColor = skia::SkColorToCOLORREF(LocationBarView::GetColor(
2197        security_level_, LocationBarView::SECURITY_TEXT));
2198    SetSelection(scheme.begin, scheme.end());
2199    SetSelectionCharFormat(cf);
2200  }
2201
2202  // Restore the selection.
2203  SetSelectionRange(saved_sel);
2204}
2205
2206void AutocompleteEditViewWin::EraseTopOfSelection(
2207    CDC* dc, const CRect& client_rect, const CRect& paint_clip_rect) {
2208  // Find the area we care about painting.   We could calculate the rect
2209  // containing just the selected portion, but there's no harm in simply erasing
2210  // the whole top of the client area, and at least once I saw us manage to
2211  // select the "phantom newline" briefly, which looks very weird if not clipped
2212  // off at the same height.
2213  CRect erase_rect(client_rect.left, client_rect.top, client_rect.right,
2214                   client_rect.top + font_y_adjustment_);
2215  erase_rect.IntersectRect(erase_rect, paint_clip_rect);
2216
2217  // Erase to the background color.
2218  if (!erase_rect.IsRectNull())
2219    dc->FillSolidRect(&erase_rect, background_color_);
2220}
2221
2222void AutocompleteEditViewWin::DrawSlashForInsecureScheme(
2223    HDC hdc,
2224    const CRect& client_rect,
2225    const CRect& paint_clip_rect) {
2226  DCHECK(insecure_scheme_component_.is_nonempty());
2227
2228  // Calculate the rect, in window coordinates, containing the portion of the
2229  // scheme where we'll be drawing the slash.  Vertically, we draw across one
2230  // x-height of text, plus an additional 3 stroke diameters (the stroke width
2231  // plus a half-stroke width of space between the stroke and the text, both
2232  // above and below the text).
2233  const int font_top = client_rect.top + font_y_adjustment_;
2234  const SkScalar kStrokeWidthPixels = SkIntToScalar(2);
2235  const int kAdditionalSpaceOutsideFont =
2236      static_cast<int>(ceil(kStrokeWidthPixels * 1.5f));
2237  const CRect scheme_rect(PosFromChar(insecure_scheme_component_.begin).x,
2238                          font_top + font_.GetBaseline() - font_x_height_ -
2239                              kAdditionalSpaceOutsideFont,
2240                          PosFromChar(insecure_scheme_component_.end()).x,
2241                          font_top + font_.GetBaseline() +
2242                              kAdditionalSpaceOutsideFont);
2243
2244  // Clip to the portion we care about and translate to canvas coordinates
2245  // (see the canvas creation below) for use later.
2246  CRect canvas_clip_rect, canvas_paint_clip_rect;
2247  canvas_clip_rect.IntersectRect(scheme_rect, client_rect);
2248  canvas_paint_clip_rect.IntersectRect(canvas_clip_rect, paint_clip_rect);
2249  if (canvas_paint_clip_rect.IsRectNull())
2250    return;  // We don't need to paint any of this region, so just bail early.
2251  canvas_clip_rect.OffsetRect(-scheme_rect.left, -scheme_rect.top);
2252  canvas_paint_clip_rect.OffsetRect(-scheme_rect.left, -scheme_rect.top);
2253
2254  // Create a paint context for drawing the antialiased stroke.
2255  SkPaint paint;
2256  paint.setAntiAlias(true);
2257  paint.setStrokeWidth(kStrokeWidthPixels);
2258  paint.setStrokeCap(SkPaint::kRound_Cap);
2259
2260  // Create a canvas as large as |scheme_rect| to do our drawing, and initialize
2261  // it to fully transparent so any antialiasing will look nice when painted
2262  // atop the edit.
2263  gfx::CanvasSkia canvas(scheme_rect.Width(), scheme_rect.Height(), false);
2264  canvas.getDevice()->accessBitmap(true).eraseARGB(0, 0, 0, 0);
2265
2266  // Calculate the start and end of the stroke, which are just the lower left
2267  // and upper right corners of the canvas, inset by the radius of the endcap
2268  // so we don't clip the endcap off.
2269  const SkScalar kEndCapRadiusPixels = kStrokeWidthPixels / SkIntToScalar(2);
2270  const SkPoint start_point = {
2271      kEndCapRadiusPixels,
2272      SkIntToScalar(scheme_rect.Height()) - kEndCapRadiusPixels };
2273  const SkPoint end_point = {
2274      SkIntToScalar(scheme_rect.Width()) - kEndCapRadiusPixels,
2275      kEndCapRadiusPixels };
2276
2277  // Calculate the selection rectangle in canvas coordinates, which we'll use
2278  // to clip the stroke so we can draw the unselected and selected portions.
2279  CHARRANGE sel;
2280  GetSel(sel);
2281  const SkRect selection_rect = {
2282      SkIntToScalar(PosFromChar(sel.cpMin).x - scheme_rect.left),
2283      SkIntToScalar(0),
2284      SkIntToScalar(PosFromChar(sel.cpMax).x - scheme_rect.left),
2285      SkIntToScalar(scheme_rect.Height()) };
2286
2287  // Draw the unselected portion of the stroke.
2288  canvas.save();
2289  if (selection_rect.isEmpty() ||
2290      canvas.clipRect(selection_rect, SkRegion::kDifference_Op)) {
2291    paint.setColor(LocationBarView::GetColor(security_level_,
2292                                             LocationBarView::SECURITY_TEXT));
2293    canvas.drawLine(start_point.fX, start_point.fY,
2294                    end_point.fX, end_point.fY, paint);
2295  }
2296  canvas.restore();
2297
2298  // Draw the selected portion of the stroke.
2299  if (!selection_rect.isEmpty() && canvas.clipRect(selection_rect)) {
2300    paint.setColor(LocationBarView::GetColor(security_level_,
2301                                             LocationBarView::SELECTED_TEXT));
2302    canvas.drawLine(start_point.fX, start_point.fY,
2303                    end_point.fX, end_point.fY, paint);
2304  }
2305
2306  // Now copy what we drew to the target HDC.
2307  canvas.getTopPlatformDevice().drawToHDC(hdc,
2308      scheme_rect.left + canvas_paint_clip_rect.left - canvas_clip_rect.left,
2309      std::max(scheme_rect.top, client_rect.top) + canvas_paint_clip_rect.top -
2310          canvas_clip_rect.top, &canvas_paint_clip_rect);
2311}
2312
2313void AutocompleteEditViewWin::DrawDropHighlight(
2314    HDC hdc, const CRect& client_rect, const CRect& paint_clip_rect) {
2315  DCHECK(drop_highlight_position_ != -1);
2316
2317  const int highlight_y = client_rect.top + font_y_adjustment_;
2318  const int highlight_x = PosFromChar(drop_highlight_position_).x - 1;
2319  const CRect highlight_rect(highlight_x,
2320                             highlight_y,
2321                             highlight_x + 1,
2322                             highlight_y + font_.GetHeight());
2323
2324  // Clip the highlight to the region being painted.
2325  CRect clip_rect;
2326  clip_rect.IntersectRect(highlight_rect, paint_clip_rect);
2327  if (clip_rect.IsRectNull())
2328    return;
2329
2330  HGDIOBJ last_pen = SelectObject(hdc, CreatePen(PS_SOLID, 1, RGB(0, 0, 0)));
2331  MoveToEx(hdc, clip_rect.left, clip_rect.top, NULL);
2332  LineTo(hdc, clip_rect.left, clip_rect.bottom);
2333  DeleteObject(SelectObject(hdc, last_pen));
2334}
2335
2336void AutocompleteEditViewWin::TextChanged() {
2337  ScopedFreeze freeze(this, GetTextObjectModel());
2338  EmphasizeURLComponents();
2339  controller_->OnChanged();
2340}
2341
2342std::wstring AutocompleteEditViewWin::GetClipboardText() const {
2343  // Try text format.
2344  Clipboard* clipboard = g_browser_process->clipboard();
2345  if (clipboard->IsFormatAvailable(Clipboard::GetPlainTextWFormatType(),
2346                                   Clipboard::BUFFER_STANDARD)) {
2347    std::wstring text;
2348    clipboard->ReadText(Clipboard::BUFFER_STANDARD, &text);
2349
2350    // Note: Unlike in the find popup and textfield view, here we completely
2351    // remove whitespace strings containing newlines.  We assume users are
2352    // most likely pasting in URLs that may have been split into multiple
2353    // lines in terminals, email programs, etc., and so linebreaks indicate
2354    // completely bogus whitespace that would just cause the input to be
2355    // invalid.
2356    return CollapseWhitespace(text, true);
2357  }
2358
2359  // Try bookmark format.
2360  //
2361  // It is tempting to try bookmark format first, but the URL we get out of a
2362  // bookmark has been cannonicalized via GURL.  This means if a user copies
2363  // and pastes from the URL bar to itself, the text will get fixed up and
2364  // cannonicalized, which is not what the user expects.  By pasting in this
2365  // order, we are sure to paste what the user copied.
2366  if (clipboard->IsFormatAvailable(Clipboard::GetUrlWFormatType(),
2367                                   Clipboard::BUFFER_STANDARD)) {
2368    std::string url_str;
2369    clipboard->ReadBookmark(NULL, &url_str);
2370    // pass resulting url string through GURL to normalize
2371    GURL url(url_str);
2372    if (url.is_valid())
2373      return UTF8ToWide(url.spec());
2374  }
2375
2376  return std::wstring();
2377}
2378
2379bool AutocompleteEditViewWin::CanPasteAndGo(const std::wstring& text) const {
2380  return !popup_window_mode_ && model_->CanPasteAndGo(text);
2381}
2382
2383ITextDocument* AutocompleteEditViewWin::GetTextObjectModel() const {
2384  if (!text_object_model_) {
2385    // This is lazily initialized, instead of being initialized in the
2386    // constructor, in order to avoid hurting startup performance.
2387    ScopedComPtr<IRichEditOle, NULL> ole_interface;
2388    ole_interface.Attach(GetOleInterface());
2389    if (ole_interface) {
2390      ole_interface.QueryInterface(
2391          __uuidof(ITextDocument),
2392          reinterpret_cast<void**>(&text_object_model_));
2393    }
2394  }
2395  return text_object_model_;
2396}
2397
2398void AutocompleteEditViewWin::StartDragIfNecessary(const CPoint& point) {
2399  if (initiated_drag_ || !win_util::IsDrag(click_point_[kLeft], point))
2400    return;
2401
2402  OSExchangeData data;
2403
2404  DWORD supported_modes = DROPEFFECT_COPY;
2405
2406  CHARRANGE sel;
2407  GetSelection(sel);
2408
2409  // We're about to start a drag session, but the edit is expecting a mouse up
2410  // that it uses to reset internal state.  If we don't send a mouse up now,
2411  // when the mouse moves back into the edit the edit will reset the selection.
2412  // So, we send the event now which resets the selection.  We then restore the
2413  // selection and start the drag.  We always send lbuttonup as otherwise we
2414  // might trigger a context menu (right up).  This seems scary, but doesn't
2415  // seem to cause problems.
2416  {
2417    ScopedFreeze freeze(this, GetTextObjectModel());
2418    DefWindowProc(WM_LBUTTONUP, 0,
2419                  MAKELPARAM(click_point_[kLeft].x, click_point_[kLeft].y));
2420    SetSelectionRange(sel);
2421  }
2422
2423  const std::wstring start_text(GetText());
2424  std::wstring text_to_write(GetSelectedText());
2425  GURL url;
2426  bool write_url;
2427  const bool is_all_selected = IsSelectAllForRange(sel);
2428
2429  // |sel| was set by GetSelection(), which preserves selection direction, so
2430  // sel.cpMin may not be the smaller value.
2431  model()->AdjustTextForCopy(std::min(sel.cpMin, sel.cpMax), is_all_selected,
2432                             &text_to_write, &url, &write_url);
2433
2434  if (write_url) {
2435    std::wstring title;
2436    SkBitmap favicon;
2437    if (is_all_selected)
2438      model_->GetDataForURLExport(&url, &title, &favicon);
2439    drag_utils::SetURLAndDragImage(url, title, favicon, &data);
2440    supported_modes |= DROPEFFECT_LINK;
2441    UserMetrics::RecordAction(UserMetricsAction("Omnibox_DragURL"),
2442                              model_->profile());
2443  } else {
2444    supported_modes |= DROPEFFECT_MOVE;
2445    UserMetrics::RecordAction(UserMetricsAction("Omnibox_DragString"),
2446                              model_->profile());
2447  }
2448
2449  data.SetString(text_to_write);
2450
2451  scoped_refptr<app::win::DragSource> drag_source(new app::win::DragSource);
2452  DWORD dropped_mode;
2453  AutoReset<bool> auto_reset_in_drag(&in_drag_, true);
2454  if (DoDragDrop(OSExchangeDataProviderWin::GetIDataObject(data), drag_source,
2455                 supported_modes, &dropped_mode) == DRAGDROP_S_DROP) {
2456    if ((dropped_mode == DROPEFFECT_MOVE) && (start_text == GetText())) {
2457      ScopedFreeze freeze(this, GetTextObjectModel());
2458      OnBeforePossibleChange();
2459      SetSelectionRange(sel);
2460      ReplaceSel(L"", true);
2461      OnAfterPossibleChange();
2462    }
2463    // else case, not a move or it was a move and the drop was on us.
2464    // If the drop was on us, EditDropTarget took care of the move so that
2465    // we don't have to delete the text.
2466    possible_drag_ = false;
2467  } else {
2468    // Drag was canceled or failed. The mouse may still be down and
2469    // over us, in which case we need possible_drag_ to remain true so
2470    // that we don't forward mouse move events to the edit which will
2471    // start another drag.
2472    //
2473    // NOTE: we didn't use mouse capture during the mouse down as DoDragDrop
2474    // does its own capture.
2475    CPoint cursor_location;
2476    GetCursorPos(&cursor_location);
2477
2478    CRect client_rect;
2479    GetClientRect(&client_rect);
2480
2481    CPoint client_origin_on_screen(client_rect.left, client_rect.top);
2482    ClientToScreen(&client_origin_on_screen);
2483    client_rect.MoveToXY(client_origin_on_screen.x,
2484                         client_origin_on_screen.y);
2485    possible_drag_ = (client_rect.PtInRect(cursor_location) &&
2486                      ((GetKeyState(VK_LBUTTON) != 0) ||
2487                       (GetKeyState(VK_MBUTTON) != 0) ||
2488                       (GetKeyState(VK_RBUTTON) != 0)));
2489  }
2490
2491  initiated_drag_ = true;
2492  tracking_click_[kLeft] = false;
2493}
2494
2495void AutocompleteEditViewWin::OnPossibleDrag(const CPoint& point) {
2496  if (possible_drag_)
2497    return;
2498
2499  click_point_[kLeft] = point;
2500  initiated_drag_ = false;
2501
2502  CHARRANGE selection;
2503  GetSel(selection);
2504  if (selection.cpMin != selection.cpMax) {
2505    const POINT min_sel_location(PosFromChar(selection.cpMin));
2506    const POINT max_sel_location(PosFromChar(selection.cpMax));
2507    // NOTE: we don't consider the y location here as we always pass a
2508    // y-coordinate in the middle to the default handler which always triggers
2509    // a drag regardless of the y-coordinate.
2510    possible_drag_ = (point.x >= min_sel_location.x) &&
2511                     (point.x < max_sel_location.x);
2512  }
2513}
2514
2515void AutocompleteEditViewWin::RepaintDropHighlight(int position) {
2516  if ((position != -1) && (position <= GetTextLength())) {
2517    const POINT min_loc(PosFromChar(position));
2518    const RECT highlight_bounds = {min_loc.x - 1, font_y_adjustment_,
2519        min_loc.x + 2, font_.GetHeight() + font_y_adjustment_};
2520    InvalidateRect(&highlight_bounds, false);
2521  }
2522}
2523
2524void AutocompleteEditViewWin::BuildContextMenu() {
2525  if (context_menu_contents_.get())
2526    return;
2527
2528  context_menu_contents_.reset(new menus::SimpleMenuModel(this));
2529  // Set up context menu.
2530  if (popup_window_mode_) {
2531    context_menu_contents_->AddItemWithStringId(IDC_COPY, IDS_COPY);
2532  } else {
2533    context_menu_contents_->AddItemWithStringId(IDS_UNDO, IDS_UNDO);
2534    context_menu_contents_->AddSeparator();
2535    context_menu_contents_->AddItemWithStringId(IDC_CUT, IDS_CUT);
2536    context_menu_contents_->AddItemWithStringId(IDC_COPY, IDS_COPY);
2537    context_menu_contents_->AddItemWithStringId(IDC_PASTE, IDS_PASTE);
2538    // GetContextualLabel() will override this next label with the
2539    // IDS_PASTE_AND_SEARCH label as needed.
2540    context_menu_contents_->AddItemWithStringId(IDS_PASTE_AND_GO,
2541                                                IDS_PASTE_AND_GO);
2542    context_menu_contents_->AddSeparator();
2543    context_menu_contents_->AddItemWithStringId(IDS_SELECT_ALL, IDS_SELECT_ALL);
2544    context_menu_contents_->AddSeparator();
2545    context_menu_contents_->AddItemWithStringId(IDS_EDIT_SEARCH_ENGINES,
2546                                                IDS_EDIT_SEARCH_ENGINES);
2547  }
2548  context_menu_.reset(new views::Menu2(context_menu_contents_.get()));
2549}
2550
2551void AutocompleteEditViewWin::SelectAllIfNecessary(MouseButton button,
2552                                                   const CPoint& point) {
2553  // When the user has clicked and released to give us focus, select all.
2554  if (tracking_click_[button] &&
2555      !win_util::IsDrag(click_point_[button], point)) {
2556    // Select all in the reverse direction so as not to scroll the caret
2557    // into view and shift the contents jarringly.
2558    SelectAll(true);
2559    possible_drag_ = false;
2560  }
2561}
2562
2563void AutocompleteEditViewWin::TrackMousePosition(MouseButton button,
2564                                                 const CPoint& point) {
2565  if (gaining_focus_.get()) {
2566    // This click is giving us focus, so we need to track how much the mouse
2567    // moves to see if it's a drag or just a click. Clicks should select all
2568    // the text.
2569    tracking_click_[button] = true;
2570    click_point_[button] = point;
2571  }
2572}
2573
2574int AutocompleteEditViewWin::GetHorizontalMargin() {
2575  RECT rect;
2576  GetRect(&rect);
2577  RECT client_rect;
2578  GetClientRect(&client_rect);
2579  return (rect.left - client_rect.left) + (client_rect.right - rect.right);
2580}
2581
2582int AutocompleteEditViewWin::WidthNeededToDisplay(const std::wstring& text) {
2583  // Use font_.GetStringWidth() instead of
2584  // PosFromChar(location_entry_->GetTextLength()) because PosFromChar() is
2585  // apparently buggy. In both LTR UI and RTL UI with left-to-right layout,
2586  // PosFromChar(i) might return 0 when i is greater than 1.
2587  return font_.GetStringWidth(text) + GetHorizontalMargin();
2588}
2589