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