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