1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/views/controls/textfield/textfield.h"
6
7#include <string>
8
9#include "base/debug/trace_event.h"
10#include "grit/ui_strings.h"
11#include "ui/accessibility/ax_view_state.h"
12#include "ui/base/clipboard/scoped_clipboard_writer.h"
13#include "ui/base/cursor/cursor.h"
14#include "ui/base/dragdrop/drag_drop_types.h"
15#include "ui/base/dragdrop/drag_utils.h"
16#include "ui/base/resource/resource_bundle.h"
17#include "ui/base/ui_base_switches_util.h"
18#include "ui/compositor/scoped_animation_duration_scale_mode.h"
19#include "ui/events/event.h"
20#include "ui/events/keycodes/keyboard_codes.h"
21#include "ui/gfx/canvas.h"
22#include "ui/gfx/display.h"
23#include "ui/gfx/insets.h"
24#include "ui/gfx/screen.h"
25#include "ui/native_theme/native_theme.h"
26#include "ui/views/background.h"
27#include "ui/views/controls/focusable_border.h"
28#include "ui/views/controls/label.h"
29#include "ui/views/controls/menu/menu_runner.h"
30#include "ui/views/controls/native/native_view_host.h"
31#include "ui/views/controls/textfield/textfield_controller.h"
32#include "ui/views/drag_utils.h"
33#include "ui/views/ime/input_method.h"
34#include "ui/views/metrics.h"
35#include "ui/views/native_cursor.h"
36#include "ui/views/painter.h"
37#include "ui/views/views_delegate.h"
38#include "ui/views/widget/widget.h"
39
40#if defined(OS_WIN)
41#include "base/win/win_util.h"
42#endif
43
44#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
45#include "base/strings/utf_string_conversions.h"
46#include "ui/events/linux/text_edit_command_auralinux.h"
47#include "ui/events/linux/text_edit_key_bindings_delegate_auralinux.h"
48#endif
49
50namespace views {
51
52namespace {
53
54// Default placeholder text color.
55const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY;
56
57const int kNoCommand = 0;
58
59void ConvertRectToScreen(const View* src, gfx::Rect* r) {
60  DCHECK(src);
61
62  gfx::Point new_origin = r->origin();
63  View::ConvertPointToScreen(src, &new_origin);
64  r->set_origin(new_origin);
65}
66
67// Get the drag selection timer delay, respecting animation scaling for testing.
68int GetDragSelectionDelay() {
69  switch (ui::ScopedAnimationDurationScaleMode::duration_scale_mode()) {
70      case ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION: return 100;
71      case ui::ScopedAnimationDurationScaleMode::FAST_DURATION:   return 25;
72      case ui::ScopedAnimationDurationScaleMode::SLOW_DURATION:   return 400;
73      case ui::ScopedAnimationDurationScaleMode::ZERO_DURATION:   return 0;
74    }
75  return 100;
76}
77
78// Get the default command for a given key |event| and selection state.
79int GetCommandForKeyEvent(const ui::KeyEvent& event, bool has_selection) {
80  if (event.type() != ui::ET_KEY_PRESSED || event.IsUnicodeKeyCode())
81    return kNoCommand;
82
83  const bool shift = event.IsShiftDown();
84  const bool control = event.IsControlDown();
85  const bool alt = event.IsAltDown() || event.IsAltGrDown();
86  switch (event.key_code()) {
87    case ui::VKEY_Z:
88      if (control && !shift && !alt)
89        return IDS_APP_UNDO;
90      return (control && shift && !alt) ? IDS_APP_REDO : kNoCommand;
91    case ui::VKEY_Y:
92      return (control && !alt) ? IDS_APP_REDO : kNoCommand;
93    case ui::VKEY_A:
94      return (control && !alt) ? IDS_APP_SELECT_ALL : kNoCommand;
95    case ui::VKEY_X:
96      return (control && !alt) ? IDS_APP_CUT : kNoCommand;
97    case ui::VKEY_C:
98      return (control && !alt) ? IDS_APP_COPY : kNoCommand;
99    case ui::VKEY_V:
100      return (control && !alt) ? IDS_APP_PASTE : kNoCommand;
101    case ui::VKEY_RIGHT:
102      // Ignore alt+right, which may be a browser navigation shortcut.
103      if (alt)
104        return kNoCommand;
105      if (!shift)
106        return control ? IDS_MOVE_WORD_RIGHT : IDS_MOVE_RIGHT;
107      return control ? IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION :
108                        IDS_MOVE_RIGHT_AND_MODIFY_SELECTION;
109    case ui::VKEY_LEFT:
110      // Ignore alt+left, which may be a browser navigation shortcut.
111      if (alt)
112        return kNoCommand;
113      if (!shift)
114        return control ? IDS_MOVE_WORD_LEFT : IDS_MOVE_LEFT;
115      return control ? IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION :
116                        IDS_MOVE_LEFT_AND_MODIFY_SELECTION;
117    case ui::VKEY_HOME:
118      return shift ? IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION :
119                      IDS_MOVE_TO_BEGINNING_OF_LINE;
120    case ui::VKEY_END:
121      return shift ? IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION :
122                      IDS_MOVE_TO_END_OF_LINE;
123    case ui::VKEY_BACK:
124      if (!control || has_selection)
125        return IDS_DELETE_BACKWARD;
126#if defined(OS_LINUX)
127      // Only erase by line break on Linux and ChromeOS.
128      if (shift)
129        return IDS_DELETE_TO_BEGINNING_OF_LINE;
130#endif
131      return IDS_DELETE_WORD_BACKWARD;
132    case ui::VKEY_DELETE:
133      if (!control || has_selection)
134        return (shift && has_selection) ? IDS_APP_CUT : IDS_DELETE_FORWARD;
135#if defined(OS_LINUX)
136      // Only erase by line break on Linux and ChromeOS.
137      if (shift)
138        return IDS_DELETE_TO_END_OF_LINE;
139#endif
140      return IDS_DELETE_WORD_FORWARD;
141    case ui::VKEY_INSERT:
142      if (control && !shift)
143        return IDS_APP_COPY;
144      return (shift && !control) ? IDS_APP_PASTE : kNoCommand;
145    default:
146      return kNoCommand;
147  }
148}
149
150#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
151// Convert a custom text edit |command| to the equivalent views command ID.
152int GetViewsCommand(const ui::TextEditCommandAuraLinux& command, bool rtl) {
153  const bool select = command.extend_selection();
154  switch (command.command_id()) {
155    case ui::TextEditCommandAuraLinux::COPY:
156      return IDS_APP_COPY;
157    case ui::TextEditCommandAuraLinux::CUT:
158      return IDS_APP_CUT;
159    case ui::TextEditCommandAuraLinux::DELETE_BACKWARD:
160      return IDS_DELETE_BACKWARD;
161    case ui::TextEditCommandAuraLinux::DELETE_FORWARD:
162      return IDS_DELETE_FORWARD;
163    case ui::TextEditCommandAuraLinux::DELETE_TO_BEGINING_OF_LINE:
164    case ui::TextEditCommandAuraLinux::DELETE_TO_BEGINING_OF_PARAGRAPH:
165      return IDS_DELETE_TO_BEGINNING_OF_LINE;
166    case ui::TextEditCommandAuraLinux::DELETE_TO_END_OF_LINE:
167    case ui::TextEditCommandAuraLinux::DELETE_TO_END_OF_PARAGRAPH:
168      return IDS_DELETE_TO_END_OF_LINE;
169    case ui::TextEditCommandAuraLinux::DELETE_WORD_BACKWARD:
170      return IDS_DELETE_WORD_BACKWARD;
171    case ui::TextEditCommandAuraLinux::DELETE_WORD_FORWARD:
172      return IDS_DELETE_WORD_FORWARD;
173    case ui::TextEditCommandAuraLinux::INSERT_TEXT:
174      return kNoCommand;
175    case ui::TextEditCommandAuraLinux::MOVE_BACKWARD:
176      if (rtl)
177        return select ? IDS_MOVE_RIGHT_AND_MODIFY_SELECTION : IDS_MOVE_RIGHT;
178      return select ? IDS_MOVE_LEFT_AND_MODIFY_SELECTION : IDS_MOVE_LEFT;
179    case ui::TextEditCommandAuraLinux::MOVE_DOWN:
180      return IDS_MOVE_DOWN;
181    case ui::TextEditCommandAuraLinux::MOVE_FORWARD:
182      if (rtl)
183        return select ? IDS_MOVE_LEFT_AND_MODIFY_SELECTION : IDS_MOVE_LEFT;
184      return select ? IDS_MOVE_RIGHT_AND_MODIFY_SELECTION : IDS_MOVE_RIGHT;
185    case ui::TextEditCommandAuraLinux::MOVE_LEFT:
186      return select ? IDS_MOVE_LEFT_AND_MODIFY_SELECTION : IDS_MOVE_LEFT;
187    case ui::TextEditCommandAuraLinux::MOVE_PAGE_DOWN:
188    case ui::TextEditCommandAuraLinux::MOVE_PAGE_UP:
189      return kNoCommand;
190    case ui::TextEditCommandAuraLinux::MOVE_RIGHT:
191      return select ? IDS_MOVE_RIGHT_AND_MODIFY_SELECTION : IDS_MOVE_RIGHT;
192    case ui::TextEditCommandAuraLinux::MOVE_TO_BEGINING_OF_DOCUMENT:
193    case ui::TextEditCommandAuraLinux::MOVE_TO_BEGINING_OF_LINE:
194    case ui::TextEditCommandAuraLinux::MOVE_TO_BEGINING_OF_PARAGRAPH:
195      return select ? IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION :
196                      IDS_MOVE_TO_BEGINNING_OF_LINE;
197    case ui::TextEditCommandAuraLinux::MOVE_TO_END_OF_DOCUMENT:
198    case ui::TextEditCommandAuraLinux::MOVE_TO_END_OF_LINE:
199    case ui::TextEditCommandAuraLinux::MOVE_TO_END_OF_PARAGRAPH:
200      return select ? IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION :
201                      IDS_MOVE_TO_END_OF_LINE;
202    case ui::TextEditCommandAuraLinux::MOVE_UP:
203      return IDS_MOVE_UP;
204    case ui::TextEditCommandAuraLinux::MOVE_WORD_BACKWARD:
205      if (rtl) {
206        return select ? IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION :
207                        IDS_MOVE_WORD_RIGHT;
208      }
209      return select ? IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION :
210                      IDS_MOVE_WORD_LEFT;
211    case ui::TextEditCommandAuraLinux::MOVE_WORD_FORWARD:
212      if (rtl) {
213        return select ? IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION :
214                        IDS_MOVE_WORD_LEFT;
215      }
216      return select ? IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION :
217                      IDS_MOVE_WORD_RIGHT;
218    case ui::TextEditCommandAuraLinux::MOVE_WORD_LEFT:
219      return select ? IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION :
220                      IDS_MOVE_WORD_LEFT;
221    case ui::TextEditCommandAuraLinux::MOVE_WORD_RIGHT:
222      return select ? IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION :
223                      IDS_MOVE_WORD_RIGHT;
224    case ui::TextEditCommandAuraLinux::PASTE:
225      return IDS_APP_PASTE;
226    case ui::TextEditCommandAuraLinux::SELECT_ALL:
227      return IDS_APP_SELECT_ALL;
228    case ui::TextEditCommandAuraLinux::SET_MARK:
229    case ui::TextEditCommandAuraLinux::UNSELECT:
230    case ui::TextEditCommandAuraLinux::INVALID_COMMAND:
231      return kNoCommand;
232  }
233  return kNoCommand;
234}
235#endif
236
237}  // namespace
238
239// static
240const char Textfield::kViewClassName[] = "Textfield";
241
242// static
243size_t Textfield::GetCaretBlinkMs() {
244  static const size_t default_value = 500;
245#if defined(OS_WIN)
246  static const size_t system_value = ::GetCaretBlinkTime();
247  if (system_value != 0)
248    return (system_value == INFINITE) ? 0 : system_value;
249#endif
250  return default_value;
251}
252
253Textfield::Textfield()
254    : model_(new TextfieldModel(this)),
255      controller_(NULL),
256      read_only_(false),
257      default_width_in_chars_(0),
258      use_default_text_color_(true),
259      use_default_background_color_(true),
260      use_default_selection_text_color_(true),
261      use_default_selection_background_color_(true),
262      text_color_(SK_ColorBLACK),
263      background_color_(SK_ColorWHITE),
264      selection_text_color_(SK_ColorWHITE),
265      selection_background_color_(SK_ColorBLUE),
266      placeholder_text_color_(kDefaultPlaceholderTextColor),
267      text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
268      performing_user_action_(false),
269      skip_input_method_cancel_composition_(false),
270      cursor_visible_(false),
271      drop_cursor_visible_(false),
272      initiating_drag_(false),
273      aggregated_clicks_(0),
274      weak_ptr_factory_(this) {
275  set_context_menu_controller(this);
276  set_drag_controller(this);
277  SetBorder(scoped_ptr<Border>(new FocusableBorder()));
278  SetFocusable(true);
279
280  if (ViewsDelegate::views_delegate) {
281    password_reveal_duration_ = ViewsDelegate::views_delegate->
282        GetDefaultTextfieldObscuredRevealDuration();
283  }
284}
285
286Textfield::~Textfield() {}
287
288void Textfield::SetReadOnly(bool read_only) {
289  // Update read-only without changing the focusable state (or active, etc.).
290  read_only_ = read_only;
291  if (GetInputMethod())
292    GetInputMethod()->OnTextInputTypeChanged(this);
293  SetColor(GetTextColor());
294  UpdateBackgroundColor();
295}
296
297void Textfield::SetTextInputType(ui::TextInputType type) {
298  GetRenderText()->SetObscured(type == ui::TEXT_INPUT_TYPE_PASSWORD);
299  text_input_type_ = type;
300  OnCaretBoundsChanged();
301  if (GetInputMethod())
302    GetInputMethod()->OnTextInputTypeChanged(this);
303  SchedulePaint();
304}
305
306void Textfield::SetText(const base::string16& new_text) {
307  model_->SetText(new_text);
308  OnCaretBoundsChanged();
309  SchedulePaint();
310  NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true);
311}
312
313void Textfield::AppendText(const base::string16& new_text) {
314  if (new_text.empty())
315    return;
316  model_->Append(new_text);
317  OnCaretBoundsChanged();
318  SchedulePaint();
319}
320
321void Textfield::InsertOrReplaceText(const base::string16& new_text) {
322  if (new_text.empty())
323    return;
324  model_->InsertText(new_text);
325  OnCaretBoundsChanged();
326  SchedulePaint();
327}
328
329base::i18n::TextDirection Textfield::GetTextDirection() const {
330  return GetRenderText()->GetTextDirection();
331}
332
333base::string16 Textfield::GetSelectedText() const {
334  return model_->GetSelectedText();
335}
336
337void Textfield::SelectAll(bool reversed) {
338  model_->SelectAll(reversed);
339  UpdateSelectionClipboard();
340  UpdateAfterChange(false, true);
341}
342
343void Textfield::ClearSelection() {
344  model_->ClearSelection();
345  UpdateAfterChange(false, true);
346}
347
348bool Textfield::HasSelection() const {
349  return !GetSelectedRange().is_empty();
350}
351
352SkColor Textfield::GetTextColor() const {
353  if (!use_default_text_color_)
354    return text_color_;
355
356  return GetNativeTheme()->GetSystemColor(read_only() ?
357      ui::NativeTheme::kColorId_TextfieldReadOnlyColor :
358      ui::NativeTheme::kColorId_TextfieldDefaultColor);
359}
360
361void Textfield::SetTextColor(SkColor color) {
362  text_color_ = color;
363  use_default_text_color_ = false;
364  SetColor(color);
365}
366
367void Textfield::UseDefaultTextColor() {
368  use_default_text_color_ = true;
369  SetColor(GetTextColor());
370}
371
372SkColor Textfield::GetBackgroundColor() const {
373  if (!use_default_background_color_)
374    return background_color_;
375
376  return GetNativeTheme()->GetSystemColor(read_only() ?
377      ui::NativeTheme::kColorId_TextfieldReadOnlyBackground :
378      ui::NativeTheme::kColorId_TextfieldDefaultBackground);
379}
380
381void Textfield::SetBackgroundColor(SkColor color) {
382  background_color_ = color;
383  use_default_background_color_ = false;
384  UpdateBackgroundColor();
385}
386
387void Textfield::UseDefaultBackgroundColor() {
388  use_default_background_color_ = true;
389  UpdateBackgroundColor();
390}
391
392SkColor Textfield::GetSelectionTextColor() const {
393  return use_default_selection_text_color_ ?
394      GetNativeTheme()->GetSystemColor(
395          ui::NativeTheme::kColorId_TextfieldSelectionColor) :
396      selection_text_color_;
397}
398
399void Textfield::SetSelectionTextColor(SkColor color) {
400  selection_text_color_ = color;
401  use_default_selection_text_color_ = false;
402  GetRenderText()->set_selection_color(GetSelectionTextColor());
403  SchedulePaint();
404}
405
406void Textfield::UseDefaultSelectionTextColor() {
407  use_default_selection_text_color_ = true;
408  GetRenderText()->set_selection_color(GetSelectionTextColor());
409  SchedulePaint();
410}
411
412SkColor Textfield::GetSelectionBackgroundColor() const {
413  return use_default_selection_background_color_ ?
414      GetNativeTheme()->GetSystemColor(
415          ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused) :
416      selection_background_color_;
417}
418
419void Textfield::SetSelectionBackgroundColor(SkColor color) {
420  selection_background_color_ = color;
421  use_default_selection_background_color_ = false;
422  GetRenderText()->set_selection_background_focused_color(
423      GetSelectionBackgroundColor());
424  SchedulePaint();
425}
426
427void Textfield::UseDefaultSelectionBackgroundColor() {
428  use_default_selection_background_color_ = true;
429  GetRenderText()->set_selection_background_focused_color(
430      GetSelectionBackgroundColor());
431  SchedulePaint();
432}
433
434bool Textfield::GetCursorEnabled() const {
435  return GetRenderText()->cursor_enabled();
436}
437
438void Textfield::SetCursorEnabled(bool enabled) {
439  GetRenderText()->SetCursorEnabled(enabled);
440}
441
442const gfx::FontList& Textfield::GetFontList() const {
443  return GetRenderText()->font_list();
444}
445
446void Textfield::SetFontList(const gfx::FontList& font_list) {
447  GetRenderText()->SetFontList(font_list);
448  OnCaretBoundsChanged();
449  PreferredSizeChanged();
450}
451
452base::string16 Textfield::GetPlaceholderText() const {
453  return placeholder_text_;
454}
455
456gfx::HorizontalAlignment Textfield::GetHorizontalAlignment() const {
457  return GetRenderText()->horizontal_alignment();
458}
459
460void Textfield::SetHorizontalAlignment(gfx::HorizontalAlignment alignment) {
461  GetRenderText()->SetHorizontalAlignment(alignment);
462}
463
464void Textfield::ShowImeIfNeeded() {
465  if (enabled() && !read_only())
466    GetInputMethod()->ShowImeIfNeeded();
467}
468
469bool Textfield::IsIMEComposing() const {
470  return model_->HasCompositionText();
471}
472
473const gfx::Range& Textfield::GetSelectedRange() const {
474  return GetRenderText()->selection();
475}
476
477void Textfield::SelectRange(const gfx::Range& range) {
478  model_->SelectRange(range);
479  UpdateAfterChange(false, true);
480}
481
482const gfx::SelectionModel& Textfield::GetSelectionModel() const {
483  return GetRenderText()->selection_model();
484}
485
486void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) {
487  model_->SelectSelectionModel(sel);
488  UpdateAfterChange(false, true);
489}
490
491size_t Textfield::GetCursorPosition() const {
492  return model_->GetCursorPosition();
493}
494
495void Textfield::SetColor(SkColor value) {
496  GetRenderText()->SetColor(value);
497  SchedulePaint();
498}
499
500void Textfield::ApplyColor(SkColor value, const gfx::Range& range) {
501  GetRenderText()->ApplyColor(value, range);
502  SchedulePaint();
503}
504
505void Textfield::SetStyle(gfx::TextStyle style, bool value) {
506  GetRenderText()->SetStyle(style, value);
507  SchedulePaint();
508}
509
510void Textfield::ApplyStyle(gfx::TextStyle style,
511                           bool value,
512                           const gfx::Range& range) {
513  GetRenderText()->ApplyStyle(style, value, range);
514  SchedulePaint();
515}
516
517void Textfield::ClearEditHistory() {
518  model_->ClearEditHistory();
519}
520
521void Textfield::SetAccessibleName(const base::string16& name) {
522  accessible_name_ = name;
523}
524
525void Textfield::ExecuteCommand(int command_id) {
526  ExecuteCommand(command_id, ui::EF_NONE);
527}
528
529void Textfield::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
530  focus_painter_ = focus_painter.Pass();
531}
532
533bool Textfield::HasTextBeingDragged() {
534  return initiating_drag_;
535}
536
537////////////////////////////////////////////////////////////////////////////////
538// Textfield, View overrides:
539
540int Textfield::GetBaseline() const {
541  return GetInsets().top() + GetRenderText()->GetBaseline();
542}
543
544gfx::Size Textfield::GetPreferredSize() const {
545  const gfx::Insets& insets = GetInsets();
546  return gfx::Size(GetFontList().GetExpectedTextWidth(default_width_in_chars_) +
547                   insets.width(), GetFontList().GetHeight() + insets.height());
548}
549
550const char* Textfield::GetClassName() const {
551  return kViewClassName;
552}
553
554gfx::NativeCursor Textfield::GetCursor(const ui::MouseEvent& event) {
555  bool in_selection = GetRenderText()->IsPointInSelection(event.location());
556  bool drag_event = event.type() == ui::ET_MOUSE_DRAGGED;
557  bool text_cursor = !initiating_drag_ && (drag_event || !in_selection);
558  return text_cursor ? GetNativeIBeamCursor() : gfx::kNullCursor;
559}
560
561bool Textfield::OnMousePressed(const ui::MouseEvent& event) {
562  TrackMouseClicks(event);
563
564  if (!controller_ || !controller_->HandleMouseEvent(this, event)) {
565    if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) {
566      RequestFocus();
567      ShowImeIfNeeded();
568    }
569
570    if (event.IsOnlyLeftMouseButton()) {
571      OnBeforeUserAction();
572      initiating_drag_ = false;
573      switch (aggregated_clicks_) {
574        case 0:
575          if (GetRenderText()->IsPointInSelection(event.location()))
576            initiating_drag_ = true;
577          else
578            MoveCursorTo(event.location(), event.IsShiftDown());
579          break;
580        case 1:
581          model_->MoveCursorTo(event.location(), false);
582          model_->SelectWord();
583          UpdateAfterChange(false, true);
584          double_click_word_ = GetRenderText()->selection();
585          break;
586        case 2:
587          SelectAll(false);
588          break;
589        default:
590          NOTREACHED();
591      }
592      OnAfterUserAction();
593    }
594
595#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
596    if (event.IsOnlyMiddleMouseButton()) {
597      if (GetRenderText()->IsPointInSelection(event.location())) {
598        OnBeforeUserAction();
599        ClearSelection();
600        ui::ScopedClipboardWriter(
601            ui::Clipboard::GetForCurrentThread(),
602            ui::CLIPBOARD_TYPE_SELECTION).WriteText(base::string16());
603        OnAfterUserAction();
604      } else if(!read_only()) {
605        PasteSelectionClipboard(event);
606      }
607    }
608#endif
609  }
610
611  return true;
612}
613
614bool Textfield::OnMouseDragged(const ui::MouseEvent& event) {
615  last_drag_location_ = event.location();
616
617  // Don't adjust the cursor on a potential drag and drop, or if the mouse
618  // movement from the last mouse click does not exceed the drag threshold.
619  if (initiating_drag_ || !event.IsOnlyLeftMouseButton() ||
620      !ExceededDragThreshold(last_drag_location_ - last_click_location_)) {
621    return true;
622  }
623
624  // A timer is used to continuously scroll while selecting beyond side edges.
625  if ((event.location().x() > 0 && event.location().x() < size().width()) ||
626      GetDragSelectionDelay() == 0) {
627    drag_selection_timer_.Stop();
628    SelectThroughLastDragLocation();
629  } else if (!drag_selection_timer_.IsRunning()) {
630    drag_selection_timer_.Start(
631        FROM_HERE, base::TimeDelta::FromMilliseconds(GetDragSelectionDelay()),
632        this, &Textfield::SelectThroughLastDragLocation);
633  }
634
635  return true;
636}
637
638void Textfield::OnMouseReleased(const ui::MouseEvent& event) {
639  OnBeforeUserAction();
640  drag_selection_timer_.Stop();
641  // Cancel suspected drag initiations, the user was clicking in the selection.
642  if (initiating_drag_)
643    MoveCursorTo(event.location(), false);
644  initiating_drag_ = false;
645  UpdateSelectionClipboard();
646  OnAfterUserAction();
647}
648
649bool Textfield::OnKeyPressed(const ui::KeyEvent& event) {
650  bool handled = controller_ && controller_->HandleKeyEvent(this, event);
651
652#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
653  ui::TextEditKeyBindingsDelegateAuraLinux* delegate =
654      ui::GetTextEditKeyBindingsDelegate();
655  std::vector<ui::TextEditCommandAuraLinux> commands;
656  if (!handled && delegate && delegate->MatchEvent(event, &commands)) {
657    const bool rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
658    for (size_t i = 0; i < commands.size(); ++i) {
659      const int command = GetViewsCommand(commands[i], rtl);
660      if (IsCommandIdEnabled(command)) {
661        ExecuteCommand(command);
662        handled = true;
663      }
664    }
665    return handled;
666  }
667#endif
668
669  const int command = GetCommandForKeyEvent(event, HasSelection());
670  if (!handled && IsCommandIdEnabled(command)) {
671    ExecuteCommand(command);
672    handled = true;
673  }
674  return handled;
675}
676
677ui::TextInputClient* Textfield::GetTextInputClient() {
678  return read_only_ ? NULL : this;
679}
680
681void Textfield::OnGestureEvent(ui::GestureEvent* event) {
682  switch (event->type()) {
683    case ui::ET_GESTURE_TAP_DOWN:
684      OnBeforeUserAction();
685      RequestFocus();
686      ShowImeIfNeeded();
687
688      // We don't deselect if the point is in the selection
689      // because TAP_DOWN may turn into a LONG_PRESS.
690      if (!GetRenderText()->IsPointInSelection(event->location()))
691        MoveCursorTo(event->location(), false);
692      OnAfterUserAction();
693      event->SetHandled();
694      break;
695    case ui::ET_GESTURE_SCROLL_UPDATE:
696      OnBeforeUserAction();
697      MoveCursorTo(event->location(), true);
698      OnAfterUserAction();
699      event->SetHandled();
700      break;
701    case ui::ET_GESTURE_SCROLL_END:
702    case ui::ET_SCROLL_FLING_START:
703      CreateTouchSelectionControllerAndNotifyIt();
704      event->SetHandled();
705      break;
706    case ui::ET_GESTURE_TAP:
707      if (event->details().tap_count() == 1) {
708        CreateTouchSelectionControllerAndNotifyIt();
709      } else {
710        DestroyTouchSelection();
711        OnBeforeUserAction();
712        SelectAll(false);
713        OnAfterUserAction();
714        event->SetHandled();
715      }
716#if defined(OS_WIN)
717      if (!read_only())
718        base::win::DisplayVirtualKeyboard();
719#endif
720      break;
721    case ui::ET_GESTURE_LONG_PRESS:
722      // If long press happens outside selection, select word and show context
723      // menu (If touch selection is enabled, context menu is shown by the
724      // |touch_selection_controller_|, hence we mark the event handled.
725      // Otherwise, the regular context menu will be shown by views).
726      // If long press happens in selected text and touch drag drop is enabled,
727      // we will turn off touch selection (if one exists) and let views do drag
728      // drop.
729      if (!GetRenderText()->IsPointInSelection(event->location())) {
730        OnBeforeUserAction();
731        model_->SelectWord();
732        touch_selection_controller_.reset(
733            ui::TouchSelectionController::create(this));
734        UpdateAfterChange(false, true);
735        OnAfterUserAction();
736        if (touch_selection_controller_)
737          event->SetHandled();
738      } else if (switches::IsTouchDragDropEnabled()) {
739        initiating_drag_ = true;
740        DestroyTouchSelection();
741      } else {
742        if (!touch_selection_controller_)
743          CreateTouchSelectionControllerAndNotifyIt();
744        if (touch_selection_controller_)
745          event->SetHandled();
746      }
747      return;
748    case ui::ET_GESTURE_LONG_TAP:
749      if (!touch_selection_controller_)
750        CreateTouchSelectionControllerAndNotifyIt();
751
752      // If touch selection is enabled, the context menu on long tap will be
753      // shown by the |touch_selection_controller_|, hence we mark the event
754      // handled so views does not try to show context menu on it.
755      if (touch_selection_controller_)
756        event->SetHandled();
757      break;
758    default:
759      return;
760  }
761}
762
763void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) {
764  SelectAll(false);
765}
766
767bool Textfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
768#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
769  // Skip any accelerator handling that conflicts with custom keybindings.
770  ui::TextEditKeyBindingsDelegateAuraLinux* delegate =
771      ui::GetTextEditKeyBindingsDelegate();
772  std::vector<ui::TextEditCommandAuraLinux> commands;
773  if (delegate && delegate->MatchEvent(event, &commands)) {
774    const bool rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
775    for (size_t i = 0; i < commands.size(); ++i)
776      if (IsCommandIdEnabled(GetViewsCommand(commands[i], rtl)))
777        return true;
778  }
779#endif
780
781  // Skip backspace accelerator handling; editable textfields handle this key.
782  // Also skip processing Windows [Alt]+<num-pad digit> Unicode alt-codes.
783  const bool is_backspace = event.key_code() == ui::VKEY_BACK;
784  return (is_backspace && !read_only()) || event.IsUnicodeKeyCode();
785}
786
787bool Textfield::GetDropFormats(
788    int* formats,
789    std::set<OSExchangeData::CustomFormat>* custom_formats) {
790  if (!enabled() || read_only())
791    return false;
792  // TODO(msw): Can we support URL, FILENAME, etc.?
793  *formats = ui::OSExchangeData::STRING;
794  if (controller_)
795    controller_->AppendDropFormats(formats, custom_formats);
796  return true;
797}
798
799bool Textfield::CanDrop(const OSExchangeData& data) {
800  int formats;
801  std::set<OSExchangeData::CustomFormat> custom_formats;
802  GetDropFormats(&formats, &custom_formats);
803  return enabled() && !read_only() &&
804      data.HasAnyFormat(formats, custom_formats);
805}
806
807int Textfield::OnDragUpdated(const ui::DropTargetEvent& event) {
808  DCHECK(CanDrop(event.data()));
809  gfx::RenderText* render_text = GetRenderText();
810  const gfx::Range& selection = render_text->selection();
811  drop_cursor_position_ = render_text->FindCursorPosition(event.location());
812  bool in_selection = !selection.is_empty() &&
813      selection.Contains(gfx::Range(drop_cursor_position_.caret_pos()));
814  drop_cursor_visible_ = !in_selection;
815  // TODO(msw): Pan over text when the user drags to the visible text edge.
816  OnCaretBoundsChanged();
817  SchedulePaint();
818
819  if (initiating_drag_) {
820    if (in_selection)
821      return ui::DragDropTypes::DRAG_NONE;
822    return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY :
823                                   ui::DragDropTypes::DRAG_MOVE;
824  }
825  return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
826}
827
828void Textfield::OnDragExited() {
829  drop_cursor_visible_ = false;
830  SchedulePaint();
831}
832
833int Textfield::OnPerformDrop(const ui::DropTargetEvent& event) {
834  DCHECK(CanDrop(event.data()));
835  drop_cursor_visible_ = false;
836
837  if (controller_) {
838    int drag_operation = controller_->OnDrop(event.data());
839    if (drag_operation != ui::DragDropTypes::DRAG_NONE)
840      return drag_operation;
841  }
842
843  gfx::RenderText* render_text = GetRenderText();
844  DCHECK(!initiating_drag_ ||
845         !render_text->IsPointInSelection(event.location()));
846  OnBeforeUserAction();
847  skip_input_method_cancel_composition_ = true;
848
849  gfx::SelectionModel drop_destination_model =
850      render_text->FindCursorPosition(event.location());
851  base::string16 new_text;
852  event.data().GetString(&new_text);
853
854  // Delete the current selection for a drag and drop within this view.
855  const bool move = initiating_drag_ && !event.IsControlDown() &&
856                    event.source_operations() & ui::DragDropTypes::DRAG_MOVE;
857  if (move) {
858    // Adjust the drop destination if it is on or after the current selection.
859    size_t pos = drop_destination_model.caret_pos();
860    pos -= render_text->selection().Intersect(gfx::Range(0, pos)).length();
861    model_->DeleteSelectionAndInsertTextAt(new_text, pos);
862  } else {
863    model_->MoveCursorTo(drop_destination_model);
864    // Drop always inserts text even if the textfield is not in insert mode.
865    model_->InsertText(new_text);
866  }
867  skip_input_method_cancel_composition_ = false;
868  UpdateAfterChange(true, true);
869  OnAfterUserAction();
870  return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY;
871}
872
873void Textfield::OnDragDone() {
874  initiating_drag_ = false;
875  drop_cursor_visible_ = false;
876}
877
878void Textfield::GetAccessibleState(ui::AXViewState* state) {
879  state->role = ui::AX_ROLE_TEXT_FIELD;
880  state->name = accessible_name_;
881  if (read_only())
882    state->AddStateFlag(ui::AX_STATE_READ_ONLY);
883  if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD)
884    state->AddStateFlag(ui::AX_STATE_PROTECTED);
885  state->value = text();
886
887  const gfx::Range range = GetSelectedRange();
888  state->selection_start = range.start();
889  state->selection_end = range.end();
890
891  if (!read_only()) {
892    state->set_value_callback =
893        base::Bind(&Textfield::AccessibilitySetValue,
894                   weak_ptr_factory_.GetWeakPtr());
895  }
896}
897
898void Textfield::OnBoundsChanged(const gfx::Rect& previous_bounds) {
899  GetRenderText()->SetDisplayRect(GetContentsBounds());
900  OnCaretBoundsChanged();
901}
902
903void Textfield::OnEnabledChanged() {
904  View::OnEnabledChanged();
905  if (GetInputMethod())
906    GetInputMethod()->OnTextInputTypeChanged(this);
907  SchedulePaint();
908}
909
910void Textfield::OnPaint(gfx::Canvas* canvas) {
911  OnPaintBackground(canvas);
912  PaintTextAndCursor(canvas);
913  OnPaintBorder(canvas);
914}
915
916void Textfield::OnFocus() {
917  GetRenderText()->set_focused(true);
918  cursor_visible_ = true;
919  SchedulePaint();
920  GetInputMethod()->OnFocus();
921  OnCaretBoundsChanged();
922
923  const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
924  if (caret_blink_ms != 0) {
925    cursor_repaint_timer_.Start(FROM_HERE,
926        base::TimeDelta::FromMilliseconds(caret_blink_ms), this,
927        &Textfield::UpdateCursor);
928  }
929
930  View::OnFocus();
931  SchedulePaint();
932}
933
934void Textfield::OnBlur() {
935  GetRenderText()->set_focused(false);
936  GetInputMethod()->OnBlur();
937  cursor_repaint_timer_.Stop();
938  if (cursor_visible_) {
939    cursor_visible_ = false;
940    RepaintCursor();
941  }
942
943  DestroyTouchSelection();
944
945  // Border typically draws focus indicator.
946  SchedulePaint();
947}
948
949gfx::Point Textfield::GetKeyboardContextMenuLocation() {
950  return GetCaretBounds().bottom_right();
951}
952
953void Textfield::OnNativeThemeChanged(const ui::NativeTheme* theme) {
954  gfx::RenderText* render_text = GetRenderText();
955  render_text->SetColor(GetTextColor());
956  UpdateBackgroundColor();
957  render_text->set_cursor_color(GetTextColor());
958  render_text->set_selection_color(GetSelectionTextColor());
959  render_text->set_selection_background_focused_color(
960      GetSelectionBackgroundColor());
961}
962
963////////////////////////////////////////////////////////////////////////////////
964// Textfield, TextfieldModel::Delegate overrides:
965
966void Textfield::OnCompositionTextConfirmedOrCleared() {
967  if (!skip_input_method_cancel_composition_)
968    GetInputMethod()->CancelComposition(this);
969}
970
971////////////////////////////////////////////////////////////////////////////////
972// Textfield, ContextMenuController overrides:
973
974void Textfield::ShowContextMenuForView(View* source,
975                                       const gfx::Point& point,
976                                       ui::MenuSourceType source_type) {
977  UpdateContextMenu();
978  ignore_result(context_menu_runner_->RunMenuAt(
979      GetWidget(),
980      NULL,
981      gfx::Rect(point, gfx::Size()),
982      MENU_ANCHOR_TOPLEFT,
983      source_type,
984      MenuRunner::HAS_MNEMONICS | MenuRunner::CONTEXT_MENU));
985}
986
987////////////////////////////////////////////////////////////////////////////////
988// Textfield, DragController overrides:
989
990void Textfield::WriteDragDataForView(View* sender,
991                                     const gfx::Point& press_pt,
992                                     OSExchangeData* data) {
993  const base::string16& selected_text(GetSelectedText());
994  data->SetString(selected_text);
995  Label label(selected_text, GetFontList());
996  label.SetBackgroundColor(GetBackgroundColor());
997  label.set_subpixel_rendering_enabled(false);
998  gfx::Size size(label.GetPreferredSize());
999  gfx::NativeView native_view = GetWidget()->GetNativeView();
1000  gfx::Display display = gfx::Screen::GetScreenFor(native_view)->
1001      GetDisplayNearestWindow(native_view);
1002  size.SetToMin(gfx::Size(display.size().width(), height()));
1003  label.SetBoundsRect(gfx::Rect(size));
1004  scoped_ptr<gfx::Canvas> canvas(
1005      GetCanvasForDragImage(GetWidget(), label.size()));
1006  label.SetEnabledColor(GetTextColor());
1007#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1008  // Desktop Linux Aura does not yet support transparency in drag images.
1009  canvas->DrawColor(GetBackgroundColor());
1010#endif
1011  label.Paint(canvas.get(), views::CullSet());
1012  const gfx::Vector2d kOffset(-15, 0);
1013  drag_utils::SetDragImageOnDataObject(*canvas, kOffset, data);
1014  if (controller_)
1015    controller_->OnWriteDragData(data);
1016}
1017
1018int Textfield::GetDragOperationsForView(View* sender, const gfx::Point& p) {
1019  int drag_operations = ui::DragDropTypes::DRAG_COPY;
1020  if (!enabled() || text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD ||
1021      !GetRenderText()->IsPointInSelection(p)) {
1022    drag_operations = ui::DragDropTypes::DRAG_NONE;
1023  } else if (sender == this && !read_only()) {
1024    drag_operations =
1025        ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY;
1026  }
1027  if (controller_)
1028    controller_->OnGetDragOperationsForTextfield(&drag_operations);
1029  return drag_operations;
1030}
1031
1032bool Textfield::CanStartDragForView(View* sender,
1033                                    const gfx::Point& press_pt,
1034                                    const gfx::Point& p) {
1035  return initiating_drag_ && GetRenderText()->IsPointInSelection(press_pt);
1036}
1037
1038////////////////////////////////////////////////////////////////////////////////
1039// Textfield, ui::TouchEditable overrides:
1040
1041void Textfield::SelectRect(const gfx::Point& start, const gfx::Point& end) {
1042  if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
1043    return;
1044
1045  gfx::SelectionModel start_caret = GetRenderText()->FindCursorPosition(start);
1046  gfx::SelectionModel end_caret = GetRenderText()->FindCursorPosition(end);
1047  gfx::SelectionModel selection(
1048      gfx::Range(start_caret.caret_pos(), end_caret.caret_pos()),
1049      end_caret.caret_affinity());
1050
1051  OnBeforeUserAction();
1052  SelectSelectionModel(selection);
1053  OnAfterUserAction();
1054}
1055
1056void Textfield::MoveCaretTo(const gfx::Point& point) {
1057  SelectRect(point, point);
1058}
1059
1060void Textfield::GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) {
1061  gfx::RenderText* render_text = GetRenderText();
1062  const gfx::SelectionModel& sel = render_text->selection_model();
1063  gfx::SelectionModel start_sel =
1064      render_text->GetSelectionModelForSelectionStart();
1065  *p1 = render_text->GetCursorBounds(start_sel, true);
1066  *p2 = render_text->GetCursorBounds(sel, true);
1067}
1068
1069gfx::Rect Textfield::GetBounds() {
1070  return GetLocalBounds();
1071}
1072
1073gfx::NativeView Textfield::GetNativeView() const {
1074  return GetWidget()->GetNativeView();
1075}
1076
1077void Textfield::ConvertPointToScreen(gfx::Point* point) {
1078  View::ConvertPointToScreen(this, point);
1079}
1080
1081void Textfield::ConvertPointFromScreen(gfx::Point* point) {
1082  View::ConvertPointFromScreen(this, point);
1083}
1084
1085bool Textfield::DrawsHandles() {
1086  return false;
1087}
1088
1089void Textfield::OpenContextMenu(const gfx::Point& anchor) {
1090  DestroyTouchSelection();
1091  ShowContextMenu(anchor, ui::MENU_SOURCE_TOUCH_EDIT_MENU);
1092}
1093
1094void Textfield::DestroyTouchSelection() {
1095  touch_selection_controller_.reset();
1096}
1097
1098////////////////////////////////////////////////////////////////////////////////
1099// Textfield, ui::SimpleMenuModel::Delegate overrides:
1100
1101bool Textfield::IsCommandIdChecked(int command_id) const {
1102  return true;
1103}
1104
1105bool Textfield::IsCommandIdEnabled(int command_id) const {
1106  base::string16 result;
1107  bool editable = !read_only();
1108  bool readable = text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD;
1109  switch (command_id) {
1110    case IDS_APP_UNDO:
1111      return editable && model_->CanUndo();
1112    case IDS_APP_REDO:
1113      return editable && model_->CanRedo();
1114    case IDS_APP_CUT:
1115      return editable && readable && model_->HasSelection();
1116    case IDS_APP_COPY:
1117      return readable && model_->HasSelection();
1118    case IDS_APP_PASTE:
1119      ui::Clipboard::GetForCurrentThread()->ReadText(
1120          ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
1121      return editable && !result.empty();
1122    case IDS_APP_DELETE:
1123      return editable && model_->HasSelection();
1124    case IDS_APP_SELECT_ALL:
1125      return !text().empty();
1126    case IDS_DELETE_FORWARD:
1127    case IDS_DELETE_BACKWARD:
1128    case IDS_DELETE_TO_BEGINNING_OF_LINE:
1129    case IDS_DELETE_TO_END_OF_LINE:
1130    case IDS_DELETE_WORD_BACKWARD:
1131    case IDS_DELETE_WORD_FORWARD:
1132      return editable;
1133    case IDS_MOVE_LEFT:
1134    case IDS_MOVE_LEFT_AND_MODIFY_SELECTION:
1135    case IDS_MOVE_RIGHT:
1136    case IDS_MOVE_RIGHT_AND_MODIFY_SELECTION:
1137    case IDS_MOVE_WORD_LEFT:
1138    case IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION:
1139    case IDS_MOVE_WORD_RIGHT:
1140    case IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION:
1141    case IDS_MOVE_TO_BEGINNING_OF_LINE:
1142    case IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION:
1143    case IDS_MOVE_TO_END_OF_LINE:
1144    case IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION:
1145      return true;
1146    default:
1147      return false;
1148  }
1149}
1150
1151bool Textfield::GetAcceleratorForCommandId(int command_id,
1152                                           ui::Accelerator* accelerator) {
1153  return false;
1154}
1155
1156void Textfield::ExecuteCommand(int command_id, int event_flags) {
1157  DestroyTouchSelection();
1158  if (!IsCommandIdEnabled(command_id))
1159    return;
1160
1161  bool text_changed = false;
1162  bool cursor_changed = false;
1163  bool rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
1164  gfx::VisualCursorDirection begin = rtl ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT;
1165  gfx::VisualCursorDirection end = rtl ? gfx::CURSOR_LEFT : gfx::CURSOR_RIGHT;
1166  gfx::SelectionModel selection_model = GetSelectionModel();
1167
1168  OnBeforeUserAction();
1169  switch (command_id) {
1170    case IDS_APP_UNDO:
1171      text_changed = cursor_changed = model_->Undo();
1172      break;
1173    case IDS_APP_REDO:
1174      text_changed = cursor_changed = model_->Redo();
1175      break;
1176    case IDS_APP_CUT:
1177      text_changed = cursor_changed = Cut();
1178      break;
1179    case IDS_APP_COPY:
1180      Copy();
1181      break;
1182    case IDS_APP_PASTE:
1183      text_changed = cursor_changed = Paste();
1184      break;
1185    case IDS_APP_DELETE:
1186      text_changed = cursor_changed = model_->Delete();
1187      break;
1188    case IDS_APP_SELECT_ALL:
1189      SelectAll(false);
1190      break;
1191    case IDS_DELETE_BACKWARD:
1192      text_changed = cursor_changed = model_->Backspace();
1193      break;
1194    case IDS_DELETE_FORWARD:
1195      text_changed = cursor_changed = model_->Delete();
1196      break;
1197    case IDS_DELETE_TO_END_OF_LINE:
1198      model_->MoveCursor(gfx::LINE_BREAK, end, true);
1199      text_changed = cursor_changed = model_->Delete();
1200      break;
1201    case IDS_DELETE_TO_BEGINNING_OF_LINE:
1202      model_->MoveCursor(gfx::LINE_BREAK, begin, true);
1203      text_changed = cursor_changed = model_->Backspace();
1204      break;
1205    case IDS_DELETE_WORD_BACKWARD:
1206      model_->MoveCursor(gfx::WORD_BREAK, begin, true);
1207      text_changed = cursor_changed = model_->Backspace();
1208      break;
1209    case IDS_DELETE_WORD_FORWARD:
1210      model_->MoveCursor(gfx::WORD_BREAK, end, true);
1211      text_changed = cursor_changed = model_->Delete();
1212      break;
1213    case IDS_MOVE_LEFT:
1214      model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false);
1215      break;
1216    case IDS_MOVE_LEFT_AND_MODIFY_SELECTION:
1217      model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true);
1218      break;
1219    case IDS_MOVE_RIGHT:
1220      model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false);
1221      break;
1222    case IDS_MOVE_RIGHT_AND_MODIFY_SELECTION:
1223      model_->MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true);
1224      break;
1225    case IDS_MOVE_WORD_LEFT:
1226      model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, false);
1227      break;
1228    case IDS_MOVE_WORD_LEFT_AND_MODIFY_SELECTION:
1229      model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true);
1230      break;
1231    case IDS_MOVE_WORD_RIGHT:
1232      model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false);
1233      break;
1234    case IDS_MOVE_WORD_RIGHT_AND_MODIFY_SELECTION:
1235      model_->MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true);
1236      break;
1237    case IDS_MOVE_TO_BEGINNING_OF_LINE:
1238      model_->MoveCursor(gfx::LINE_BREAK, begin, false);
1239      break;
1240    case IDS_MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION:
1241      model_->MoveCursor(gfx::LINE_BREAK, begin, true);
1242      break;
1243    case IDS_MOVE_TO_END_OF_LINE:
1244      model_->MoveCursor(gfx::LINE_BREAK, end, false);
1245      break;
1246    case IDS_MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION:
1247      model_->MoveCursor(gfx::LINE_BREAK, end, true);
1248      break;
1249    default:
1250      NOTREACHED();
1251      break;
1252  }
1253
1254  cursor_changed |= GetSelectionModel() != selection_model;
1255  if (cursor_changed)
1256    UpdateSelectionClipboard();
1257  UpdateAfterChange(text_changed, cursor_changed);
1258  OnAfterUserAction();
1259}
1260
1261////////////////////////////////////////////////////////////////////////////////
1262// Textfield, ui::TextInputClient overrides:
1263
1264void Textfield::SetCompositionText(const ui::CompositionText& composition) {
1265  if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
1266    return;
1267
1268  OnBeforeUserAction();
1269  skip_input_method_cancel_composition_ = true;
1270  model_->SetCompositionText(composition);
1271  skip_input_method_cancel_composition_ = false;
1272  UpdateAfterChange(true, true);
1273  OnAfterUserAction();
1274}
1275
1276void Textfield::ConfirmCompositionText() {
1277  if (!model_->HasCompositionText())
1278    return;
1279
1280  OnBeforeUserAction();
1281  skip_input_method_cancel_composition_ = true;
1282  model_->ConfirmCompositionText();
1283  skip_input_method_cancel_composition_ = false;
1284  UpdateAfterChange(true, true);
1285  OnAfterUserAction();
1286}
1287
1288void Textfield::ClearCompositionText() {
1289  if (!model_->HasCompositionText())
1290    return;
1291
1292  OnBeforeUserAction();
1293  skip_input_method_cancel_composition_ = true;
1294  model_->CancelCompositionText();
1295  skip_input_method_cancel_composition_ = false;
1296  UpdateAfterChange(true, true);
1297  OnAfterUserAction();
1298}
1299
1300void Textfield::InsertText(const base::string16& new_text) {
1301  // TODO(suzhe): Filter invalid characters.
1302  if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || new_text.empty())
1303    return;
1304
1305  OnBeforeUserAction();
1306  skip_input_method_cancel_composition_ = true;
1307  if (GetRenderText()->insert_mode())
1308    model_->InsertText(new_text);
1309  else
1310    model_->ReplaceText(new_text);
1311  skip_input_method_cancel_composition_ = false;
1312  UpdateAfterChange(true, true);
1313  OnAfterUserAction();
1314}
1315
1316void Textfield::InsertChar(base::char16 ch, int flags) {
1317  const int kControlModifierMask = ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN |
1318                                   ui::EF_COMMAND_DOWN | ui::EF_ALTGR_DOWN |
1319                                   ui::EF_MOD3_DOWN;
1320
1321  // Filter out all control characters, including tab and new line characters,
1322  // and all characters with Alt modifier. But allow characters with the AltGr
1323  // modifier. On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a
1324  // different flag that we don't care about.
1325  const bool should_insert_char =
1326      ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) &&
1327      (flags & kControlModifierMask) != ui::EF_ALT_DOWN;
1328  if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || !should_insert_char)
1329    return;
1330
1331  OnBeforeUserAction();
1332  skip_input_method_cancel_composition_ = true;
1333  if (GetRenderText()->insert_mode())
1334    model_->InsertChar(ch);
1335  else
1336    model_->ReplaceChar(ch);
1337  skip_input_method_cancel_composition_ = false;
1338
1339  UpdateAfterChange(true, true);
1340  OnAfterUserAction();
1341
1342  if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD &&
1343      password_reveal_duration_ != base::TimeDelta()) {
1344    const size_t change_offset = model_->GetCursorPosition();
1345    DCHECK_GT(change_offset, 0u);
1346    RevealPasswordChar(change_offset - 1);
1347  }
1348}
1349
1350gfx::NativeWindow Textfield::GetAttachedWindow() const {
1351  // Imagine the following hierarchy.
1352  //   [NativeWidget A] - FocusManager
1353  //     [View]
1354  //     [NativeWidget B]
1355  //       [View]
1356  //         [View X]
1357  // An important thing is that [NativeWidget A] owns Win32 input focus even
1358  // when [View X] is logically focused by FocusManager. As a result, an Win32
1359  // IME may want to interact with the native view of [NativeWidget A] rather
1360  // than that of [NativeWidget B]. This is why we need to call
1361  // GetTopLevelWidget() here.
1362  return GetWidget()->GetTopLevelWidget()->GetNativeWindow();
1363}
1364
1365ui::TextInputType Textfield::GetTextInputType() const {
1366  if (read_only() || !enabled())
1367    return ui::TEXT_INPUT_TYPE_NONE;
1368  return text_input_type_;
1369}
1370
1371ui::TextInputMode Textfield::GetTextInputMode() const {
1372  return ui::TEXT_INPUT_MODE_DEFAULT;
1373}
1374
1375bool Textfield::CanComposeInline() const {
1376  return true;
1377}
1378
1379gfx::Rect Textfield::GetCaretBounds() const {
1380  gfx::Rect rect = GetRenderText()->GetUpdatedCursorBounds();
1381  ConvertRectToScreen(this, &rect);
1382  return rect;
1383}
1384
1385bool Textfield::GetCompositionCharacterBounds(uint32 index,
1386                                              gfx::Rect* rect) const {
1387  DCHECK(rect);
1388  if (!HasCompositionText())
1389    return false;
1390  gfx::RenderText* render_text = GetRenderText();
1391  const gfx::Range& composition_range = render_text->GetCompositionRange();
1392  DCHECK(!composition_range.is_empty());
1393
1394  size_t text_index = composition_range.start() + index;
1395  if (composition_range.end() <= text_index)
1396    return false;
1397  if (!render_text->IsValidCursorIndex(text_index)) {
1398    text_index = render_text->IndexOfAdjacentGrapheme(
1399        text_index, gfx::CURSOR_BACKWARD);
1400  }
1401  if (text_index < composition_range.start())
1402    return false;
1403  const gfx::SelectionModel caret(text_index, gfx::CURSOR_BACKWARD);
1404  *rect = render_text->GetCursorBounds(caret, false);
1405  ConvertRectToScreen(this, rect);
1406  return true;
1407}
1408
1409bool Textfield::HasCompositionText() const {
1410  return model_->HasCompositionText();
1411}
1412
1413bool Textfield::GetTextRange(gfx::Range* range) const {
1414  if (!ImeEditingAllowed())
1415    return false;
1416
1417  model_->GetTextRange(range);
1418  return true;
1419}
1420
1421bool Textfield::GetCompositionTextRange(gfx::Range* range) const {
1422  if (!ImeEditingAllowed())
1423    return false;
1424
1425  model_->GetCompositionTextRange(range);
1426  return true;
1427}
1428
1429bool Textfield::GetSelectionRange(gfx::Range* range) const {
1430  if (!ImeEditingAllowed())
1431    return false;
1432  *range = GetRenderText()->selection();
1433  return true;
1434}
1435
1436bool Textfield::SetSelectionRange(const gfx::Range& range) {
1437  if (!ImeEditingAllowed() || !range.IsValid())
1438    return false;
1439  OnBeforeUserAction();
1440  SelectRange(range);
1441  OnAfterUserAction();
1442  return true;
1443}
1444
1445bool Textfield::DeleteRange(const gfx::Range& range) {
1446  if (!ImeEditingAllowed() || range.is_empty())
1447    return false;
1448
1449  OnBeforeUserAction();
1450  model_->SelectRange(range);
1451  if (model_->HasSelection()) {
1452    model_->DeleteSelection();
1453    UpdateAfterChange(true, true);
1454  }
1455  OnAfterUserAction();
1456  return true;
1457}
1458
1459bool Textfield::GetTextFromRange(const gfx::Range& range,
1460                                 base::string16* range_text) const {
1461  if (!ImeEditingAllowed() || !range.IsValid())
1462    return false;
1463
1464  gfx::Range text_range;
1465  if (!GetTextRange(&text_range) || !text_range.Contains(range))
1466    return false;
1467
1468  *range_text = model_->GetTextFromRange(range);
1469  return true;
1470}
1471
1472void Textfield::OnInputMethodChanged() {}
1473
1474bool Textfield::ChangeTextDirectionAndLayoutAlignment(
1475    base::i18n::TextDirection direction) {
1476  // Restore text directionality mode when the indicated direction matches the
1477  // current forced mode; otherwise, force the mode indicated. This helps users
1478  // manage BiDi text layout without getting stuck in forced LTR or RTL modes.
1479  const gfx::DirectionalityMode mode = direction == base::i18n::RIGHT_TO_LEFT ?
1480      gfx::DIRECTIONALITY_FORCE_RTL : gfx::DIRECTIONALITY_FORCE_LTR;
1481  if (mode == GetRenderText()->directionality_mode())
1482    GetRenderText()->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_TEXT);
1483  else
1484    GetRenderText()->SetDirectionalityMode(mode);
1485  SchedulePaint();
1486  return true;
1487}
1488
1489void Textfield::ExtendSelectionAndDelete(size_t before, size_t after) {
1490  gfx::Range range = GetRenderText()->selection();
1491  DCHECK_GE(range.start(), before);
1492
1493  range.set_start(range.start() - before);
1494  range.set_end(range.end() + after);
1495  gfx::Range text_range;
1496  if (GetTextRange(&text_range) && text_range.Contains(range))
1497    DeleteRange(range);
1498}
1499
1500void Textfield::EnsureCaretInRect(const gfx::Rect& rect) {}
1501
1502void Textfield::OnCandidateWindowShown() {}
1503
1504void Textfield::OnCandidateWindowUpdated() {}
1505
1506void Textfield::OnCandidateWindowHidden() {}
1507
1508bool Textfield::IsEditingCommandEnabled(int command_id) {
1509  return IsCommandIdEnabled(command_id);
1510}
1511
1512void Textfield::ExecuteEditingCommand(int command_id) {
1513  ExecuteCommand(command_id);
1514}
1515
1516////////////////////////////////////////////////////////////////////////////////
1517// Textfield, protected:
1518
1519gfx::RenderText* Textfield::GetRenderText() const {
1520  return model_->render_text();
1521}
1522
1523base::string16 Textfield::GetSelectionClipboardText() const {
1524  base::string16 selection_clipboard_text;
1525  ui::Clipboard::GetForCurrentThread()->ReadText(
1526      ui::CLIPBOARD_TYPE_SELECTION, &selection_clipboard_text);
1527  return selection_clipboard_text;
1528}
1529
1530////////////////////////////////////////////////////////////////////////////////
1531// Textfield, private:
1532
1533void Textfield::AccessibilitySetValue(const base::string16& new_value) {
1534  if (!read_only()) {
1535    SetText(new_value);
1536    ClearSelection();
1537  }
1538}
1539
1540void Textfield::UpdateBackgroundColor() {
1541  const SkColor color = GetBackgroundColor();
1542  set_background(Background::CreateSolidBackground(color));
1543  GetRenderText()->set_background_is_transparent(SkColorGetA(color) != 0xFF);
1544  SchedulePaint();
1545}
1546
1547void Textfield::UpdateAfterChange(bool text_changed, bool cursor_changed) {
1548  if (text_changed) {
1549    if (controller_)
1550      controller_->ContentsChanged(this, text());
1551    NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true);
1552  }
1553  if (cursor_changed) {
1554    cursor_visible_ = true;
1555    RepaintCursor();
1556    if (cursor_repaint_timer_.IsRunning())
1557      cursor_repaint_timer_.Reset();
1558    if (!text_changed) {
1559      // TEXT_CHANGED implies SELECTION_CHANGED, so we only need to fire
1560      // this if only the selection changed.
1561      NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION_CHANGED, true);
1562    }
1563  }
1564  if (text_changed || cursor_changed) {
1565    OnCaretBoundsChanged();
1566    SchedulePaint();
1567  }
1568}
1569
1570void Textfield::UpdateCursor() {
1571  const size_t caret_blink_ms = Textfield::GetCaretBlinkMs();
1572  cursor_visible_ = !cursor_visible_ || (caret_blink_ms == 0);
1573  RepaintCursor();
1574}
1575
1576void Textfield::RepaintCursor() {
1577  gfx::Rect r(GetRenderText()->GetUpdatedCursorBounds());
1578  r.Inset(-1, -1, -1, -1);
1579  SchedulePaintInRect(r);
1580}
1581
1582void Textfield::PaintTextAndCursor(gfx::Canvas* canvas) {
1583  TRACE_EVENT0("views", "Textfield::PaintTextAndCursor");
1584  canvas->Save();
1585
1586  // Draw placeholder text if needed.
1587  gfx::RenderText* render_text = GetRenderText();
1588  if (text().empty() && !GetPlaceholderText().empty()) {
1589    canvas->DrawStringRect(GetPlaceholderText(), GetFontList(),
1590        placeholder_text_color(), render_text->display_rect());
1591  }
1592
1593  // Draw the text, cursor, and selection.
1594  render_text->set_cursor_visible(cursor_visible_ && !drop_cursor_visible_ &&
1595                                  !HasSelection());
1596  render_text->Draw(canvas);
1597
1598  // Draw the detached drop cursor that marks where the text will be dropped.
1599  if (drop_cursor_visible_)
1600    render_text->DrawCursor(canvas, drop_cursor_position_);
1601
1602  canvas->Restore();
1603}
1604
1605void Textfield::MoveCursorTo(const gfx::Point& point, bool select) {
1606  if (model_->MoveCursorTo(point, select))
1607    UpdateAfterChange(false, true);
1608}
1609
1610void Textfield::SelectThroughLastDragLocation() {
1611  OnBeforeUserAction();
1612  model_->MoveCursorTo(last_drag_location_, true);
1613  if (aggregated_clicks_ == 1) {
1614    model_->SelectWord();
1615    // Expand the selection so the initially selected word remains selected.
1616    gfx::Range selection = GetRenderText()->selection();
1617    const size_t min = std::min(selection.GetMin(),
1618                                double_click_word_.GetMin());
1619    const size_t max = std::max(selection.GetMax(),
1620                                double_click_word_.GetMax());
1621    const bool reversed = selection.is_reversed();
1622    selection.set_start(reversed ? max : min);
1623    selection.set_end(reversed ? min : max);
1624    model_->SelectRange(selection);
1625  }
1626  UpdateAfterChange(false, true);
1627  OnAfterUserAction();
1628}
1629
1630void Textfield::OnCaretBoundsChanged() {
1631  if (GetInputMethod())
1632    GetInputMethod()->OnCaretBoundsChanged(this);
1633  if (touch_selection_controller_)
1634    touch_selection_controller_->SelectionChanged();
1635}
1636
1637void Textfield::OnBeforeUserAction() {
1638  DCHECK(!performing_user_action_);
1639  performing_user_action_ = true;
1640  if (controller_)
1641    controller_->OnBeforeUserAction(this);
1642}
1643
1644void Textfield::OnAfterUserAction() {
1645  if (controller_)
1646    controller_->OnAfterUserAction(this);
1647  DCHECK(performing_user_action_);
1648  performing_user_action_ = false;
1649}
1650
1651bool Textfield::Cut() {
1652  if (!read_only() && text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD &&
1653      model_->Cut()) {
1654    if (controller_)
1655      controller_->OnAfterCutOrCopy(ui::CLIPBOARD_TYPE_COPY_PASTE);
1656    return true;
1657  }
1658  return false;
1659}
1660
1661bool Textfield::Copy() {
1662  if (text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD && model_->Copy()) {
1663    if (controller_)
1664      controller_->OnAfterCutOrCopy(ui::CLIPBOARD_TYPE_COPY_PASTE);
1665    return true;
1666  }
1667  return false;
1668}
1669
1670bool Textfield::Paste() {
1671  if (!read_only() && model_->Paste()) {
1672    if (controller_)
1673      controller_->OnAfterPaste();
1674    return true;
1675  }
1676  return false;
1677}
1678
1679void Textfield::UpdateContextMenu() {
1680  if (!context_menu_contents_.get()) {
1681    context_menu_contents_.reset(new ui::SimpleMenuModel(this));
1682    context_menu_contents_->AddItemWithStringId(IDS_APP_UNDO, IDS_APP_UNDO);
1683    context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
1684    context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
1685    context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
1686    context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
1687    context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE);
1688    context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
1689    context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
1690                                                IDS_APP_SELECT_ALL);
1691    if (controller_)
1692      controller_->UpdateContextMenu(context_menu_contents_.get());
1693  }
1694  context_menu_runner_.reset(new MenuRunner(context_menu_contents_.get()));
1695}
1696
1697void Textfield::TrackMouseClicks(const ui::MouseEvent& event) {
1698  if (event.IsOnlyLeftMouseButton()) {
1699    base::TimeDelta time_delta = event.time_stamp() - last_click_time_;
1700    if (time_delta.InMilliseconds() <= GetDoubleClickInterval() &&
1701        !ExceededDragThreshold(event.location() - last_click_location_)) {
1702      // Upon clicking after a triple click, the count should go back to double
1703      // click and alternate between double and triple. This assignment maps
1704      // 0 to 1, 1 to 2, 2 to 1.
1705      aggregated_clicks_ = (aggregated_clicks_ % 2) + 1;
1706    } else {
1707      aggregated_clicks_ = 0;
1708    }
1709    last_click_time_ = event.time_stamp();
1710    last_click_location_ = event.location();
1711  }
1712}
1713
1714bool Textfield::ImeEditingAllowed() const {
1715  // Disallow input method editing of password fields.
1716  ui::TextInputType t = GetTextInputType();
1717  return (t != ui::TEXT_INPUT_TYPE_NONE && t != ui::TEXT_INPUT_TYPE_PASSWORD);
1718}
1719
1720void Textfield::RevealPasswordChar(int index) {
1721  GetRenderText()->SetObscuredRevealIndex(index);
1722  SchedulePaint();
1723
1724  if (index != -1) {
1725    password_reveal_timer_.Start(FROM_HERE, password_reveal_duration_,
1726        base::Bind(&Textfield::RevealPasswordChar,
1727                   weak_ptr_factory_.GetWeakPtr(), -1));
1728  }
1729}
1730
1731void Textfield::CreateTouchSelectionControllerAndNotifyIt() {
1732  if (!touch_selection_controller_) {
1733    touch_selection_controller_.reset(
1734        ui::TouchSelectionController::create(this));
1735  }
1736  if (touch_selection_controller_)
1737    touch_selection_controller_->SelectionChanged();
1738}
1739
1740void Textfield::UpdateSelectionClipboard() const {
1741#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
1742  if (performing_user_action_ && HasSelection()) {
1743    ui::ScopedClipboardWriter(
1744        ui::Clipboard::GetForCurrentThread(),
1745        ui::CLIPBOARD_TYPE_SELECTION).WriteText(GetSelectedText());
1746    if (controller_)
1747      controller_->OnAfterCutOrCopy(ui::CLIPBOARD_TYPE_SELECTION);
1748  }
1749#endif
1750}
1751
1752void Textfield::PasteSelectionClipboard(const ui::MouseEvent& event) {
1753  DCHECK(event.IsOnlyMiddleMouseButton());
1754  DCHECK(!read_only());
1755  base::string16 selection_clipboard_text = GetSelectionClipboardText();
1756  if (!selection_clipboard_text.empty()) {
1757    OnBeforeUserAction();
1758    gfx::Range range = GetSelectionModel().selection();
1759    gfx::LogicalCursorDirection affinity = GetSelectionModel().caret_affinity();
1760    const gfx::SelectionModel mouse =
1761        GetRenderText()->FindCursorPosition(event.location());
1762    model_->MoveCursorTo(mouse);
1763    model_->InsertText(selection_clipboard_text);
1764    // Update the new selection range as needed.
1765    if (range.GetMin() >= mouse.caret_pos()) {
1766      const size_t length = selection_clipboard_text.length();
1767      range = gfx::Range(range.start() + length, range.end() + length);
1768    }
1769    model_->MoveCursorTo(gfx::SelectionModel(range, affinity));
1770    UpdateAfterChange(true, true);
1771    OnAfterUserAction();
1772  }
1773}
1774
1775}  // namespace views
1776