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