1// Copyright (c) 2013 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/native_textfield_views.h"
6
7#include <algorithm>
8#include <set>
9
10#include "base/bind.h"
11#include "base/debug/trace_event.h"
12#include "base/i18n/case_conversion.h"
13#include "base/logging.h"
14#include "base/message_loop/message_loop.h"
15#include "base/strings/utf_string_conversions.h"
16#include "grit/ui_strings.h"
17#include "third_party/icu/source/common/unicode/uchar.h"
18#include "third_party/skia/include/core/SkColor.h"
19#include "ui/base/clipboard/clipboard.h"
20#include "ui/base/dragdrop/drag_drop_types.h"
21#include "ui/base/dragdrop/drag_utils.h"
22#include "ui/base/events/event.h"
23#include "ui/base/l10n/l10n_util.h"
24#include "ui/base/range/range.h"
25#include "ui/base/ui_base_switches_util.h"
26#include "ui/compositor/layer.h"
27#include "ui/gfx/canvas.h"
28#include "ui/gfx/insets.h"
29#include "ui/gfx/render_text.h"
30#include "ui/gfx/text_constants.h"
31#include "ui/native_theme/native_theme.h"
32#include "ui/views/background.h"
33#include "ui/views/border.h"
34#include "ui/views/controls/focusable_border.h"
35#include "ui/views/controls/menu/menu_item_view.h"
36#include "ui/views/controls/menu/menu_model_adapter.h"
37#include "ui/views/controls/menu/menu_runner.h"
38#include "ui/views/controls/textfield/textfield.h"
39#include "ui/views/controls/textfield/textfield_controller.h"
40#include "ui/views/controls/textfield/textfield_views_model.h"
41#include "ui/views/drag_utils.h"
42#include "ui/views/ime/input_method.h"
43#include "ui/views/metrics.h"
44#include "ui/views/widget/widget.h"
45
46#if defined(USE_AURA)
47#include "ui/base/cursor/cursor.h"
48#endif
49
50#if defined(OS_WIN) && defined(USE_AURA)
51#include "base/win/win_util.h"
52#endif
53
54namespace {
55
56void ConvertRectToScreen(const views::View* src, gfx::Rect* r) {
57  DCHECK(src);
58
59  gfx::Point new_origin = r->origin();
60  views::View::ConvertPointToScreen(src, &new_origin);
61  r->set_origin(new_origin);
62}
63
64}  // namespace
65
66namespace views {
67
68const char NativeTextfieldViews::kViewClassName[] =
69    "views/NativeTextfieldViews";
70
71const int NativeTextfieldViews::kCursorBlinkCycleMs = 1000;
72
73NativeTextfieldViews::NativeTextfieldViews(Textfield* parent)
74    : textfield_(parent),
75      model_(new TextfieldViewsModel(this)),
76      text_border_(new FocusableBorder()),
77      is_cursor_visible_(false),
78      is_drop_cursor_visible_(false),
79      skip_input_method_cancel_composition_(false),
80      initiating_drag_(false),
81      cursor_timer_(this),
82      aggregated_clicks_(0) {
83  set_border(text_border_);
84  GetRenderText()->SetFontList(textfield_->font_list());
85  UpdateColorsFromTheme(GetNativeTheme());
86  set_context_menu_controller(this);
87  parent->set_context_menu_controller(this);
88  set_drag_controller(this);
89}
90
91NativeTextfieldViews::~NativeTextfieldViews() {
92}
93
94////////////////////////////////////////////////////////////////////////////////
95// NativeTextfieldViews, View overrides:
96
97bool NativeTextfieldViews::OnMousePressed(const ui::MouseEvent& event) {
98  OnBeforeUserAction();
99  TrackMouseClicks(event);
100
101  TextfieldController* controller = textfield_->GetController();
102  if (!(controller && controller->HandleMouseEvent(textfield_, event)) &&
103      !textfield_->OnMousePressed(event)) {
104    HandleMousePressEvent(event);
105  }
106
107  OnAfterUserAction();
108  touch_selection_controller_.reset();
109  return true;
110}
111
112bool NativeTextfieldViews::ExceededDragThresholdFromLastClickLocation(
113    const ui::MouseEvent& event) {
114  return ExceededDragThreshold(event.location() - last_click_location_);
115}
116
117bool NativeTextfieldViews::OnMouseDragged(const ui::MouseEvent& event) {
118  // Don't adjust the cursor on a potential drag and drop, or if the mouse
119  // movement from the last mouse click does not exceed the drag threshold.
120  if (initiating_drag_ || !ExceededDragThresholdFromLastClickLocation(event) ||
121      !event.IsOnlyLeftMouseButton()) {
122    return true;
123  }
124
125  OnBeforeUserAction();
126  // TODO: Remove once NativeTextfield implementations are consolidated to
127  // Textfield.
128  if (!textfield_->OnMouseDragged(event)) {
129    MoveCursorTo(event.location(), true);
130    if (aggregated_clicks_ == 1) {
131      model_->SelectWord();
132      // Expand the selection so the initially selected word remains selected.
133      ui::Range selection = GetRenderText()->selection();
134      const size_t min = std::min(selection.GetMin(),
135                                  double_click_word_.GetMin());
136      const size_t max = std::max(selection.GetMax(),
137                                  double_click_word_.GetMax());
138      const bool reversed = selection.is_reversed();
139      selection.set_start(reversed ? max : min);
140      selection.set_end(reversed ? min : max);
141      model_->SelectRange(selection);
142    }
143    SchedulePaint();
144  }
145  OnAfterUserAction();
146  return true;
147}
148
149void NativeTextfieldViews::OnMouseReleased(const ui::MouseEvent& event) {
150  OnBeforeUserAction();
151  // TODO: Remove once NativeTextfield implementations are consolidated to
152  // Textfield.
153  textfield_->OnMouseReleased(event);
154  // Cancel suspected drag initiations, the user was clicking in the selection.
155  if (initiating_drag_ && MoveCursorTo(event.location(), false))
156    SchedulePaint();
157  initiating_drag_ = false;
158  OnAfterUserAction();
159}
160
161void NativeTextfieldViews::OnGestureEvent(ui::GestureEvent* event) {
162  textfield_->OnGestureEvent(event);
163  if (event->handled())
164    return;
165
166  switch (event->type()) {
167    case ui::ET_GESTURE_TAP_DOWN:
168      OnBeforeUserAction();
169      textfield_->RequestFocus();
170      // We don't deselect if the point is in the selection
171      // because TAP_DOWN may turn into a LONG_PRESS.
172      if (!GetRenderText()->IsPointInSelection(event->location()) &&
173          MoveCursorTo(event->location(), false))
174        SchedulePaint();
175      OnAfterUserAction();
176      event->SetHandled();
177      break;
178    case ui::ET_GESTURE_SCROLL_UPDATE:
179      OnBeforeUserAction();
180      if (MoveCursorTo(event->location(), true))
181        SchedulePaint();
182      OnAfterUserAction();
183      event->SetHandled();
184      break;
185    case ui::ET_GESTURE_TAP:
186      if (event->details().tap_count() == 1) {
187        CreateTouchSelectionControllerAndNotifyIt();
188      } else {
189        OnBeforeUserAction();
190        SelectAll(false);
191        OnAfterUserAction();
192        event->SetHandled();
193      }
194      break;
195    case ui::ET_GESTURE_LONG_PRESS:
196      // If long press happens outside selection, select word and show context
197      // menu (If touch selection is enabled, context menu is shown by the
198      // |touch_selection_controller_|, hence we mark the event handled.
199      // Otherwise, the regular context menu will be shown by views).
200      // If long press happens in selected text and touch drag drop is enabled,
201      // we will turn off touch selection (if one exists) and let views do drag
202      // drop.
203      if (!GetRenderText()->IsPointInSelection(event->location())) {
204        OnBeforeUserAction();
205        model_->SelectWord();
206        touch_selection_controller_.reset(
207            ui::TouchSelectionController::create(this));
208        OnCaretBoundsChanged();
209        SchedulePaint();
210        OnAfterUserAction();
211        if (touch_selection_controller_.get())
212          event->SetHandled();
213      } else if (switches::IsTouchDragDropEnabled()) {
214        initiating_drag_ = true;
215        touch_selection_controller_.reset();
216      } else {
217        if (!touch_selection_controller_.get())
218          CreateTouchSelectionControllerAndNotifyIt();
219        if (touch_selection_controller_.get())
220          event->SetHandled();
221      }
222      return;
223    case ui::ET_GESTURE_LONG_TAP:
224      if (!touch_selection_controller_.get())
225        CreateTouchSelectionControllerAndNotifyIt();
226
227      // If touch selection is enabled, the context menu on long tap will be
228      // shown by the |touch_selection_controller_|, hence we mark the event
229      // handled so views does not try to show context menu on it.
230      if (touch_selection_controller_.get())
231        event->SetHandled();
232      break;
233    default:
234      View::OnGestureEvent(event);
235      return;
236  }
237  PlatformGestureEventHandling(event);
238}
239
240bool NativeTextfieldViews::OnKeyPressed(const ui::KeyEvent& event) {
241  // OnKeyPressed/OnKeyReleased/OnFocus/OnBlur will never be invoked on
242  // NativeTextfieldViews as it will never gain focus.
243  NOTREACHED();
244  return false;
245}
246
247bool NativeTextfieldViews::OnKeyReleased(const ui::KeyEvent& event) {
248  NOTREACHED();
249  return false;
250}
251
252bool NativeTextfieldViews::GetDropFormats(
253    int* formats,
254    std::set<OSExchangeData::CustomFormat>* custom_formats) {
255  if (!textfield_->enabled() || textfield_->read_only())
256    return false;
257  // TODO(msw): Can we support URL, FILENAME, etc.?
258  *formats = ui::OSExchangeData::STRING;
259  TextfieldController* controller = textfield_->GetController();
260  if (controller)
261    controller->AppendDropFormats(formats, custom_formats);
262  return true;
263}
264
265bool NativeTextfieldViews::CanDrop(const OSExchangeData& data) {
266  int formats;
267  std::set<OSExchangeData::CustomFormat> custom_formats;
268  GetDropFormats(&formats, &custom_formats);
269  return textfield_->enabled() && !textfield_->read_only() &&
270      data.HasAnyFormat(formats, custom_formats);
271}
272
273int NativeTextfieldViews::OnDragUpdated(const ui::DropTargetEvent& event) {
274  DCHECK(CanDrop(event.data()));
275
276  const ui::Range& selection = GetRenderText()->selection();
277  drop_cursor_position_ = GetRenderText()->FindCursorPosition(event.location());
278  bool in_selection = !selection.is_empty() &&
279      selection.Contains(ui::Range(drop_cursor_position_.caret_pos()));
280  is_drop_cursor_visible_ = !in_selection;
281  // TODO(msw): Pan over text when the user drags to the visible text edge.
282  OnCaretBoundsChanged();
283  SchedulePaint();
284
285  if (initiating_drag_) {
286    if (in_selection)
287      return ui::DragDropTypes::DRAG_NONE;
288    return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY :
289                                   ui::DragDropTypes::DRAG_MOVE;
290  }
291  return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
292}
293
294void NativeTextfieldViews::OnDragExited() {
295  is_drop_cursor_visible_ = false;
296  SchedulePaint();
297}
298
299int NativeTextfieldViews::OnPerformDrop(const ui::DropTargetEvent& event) {
300  DCHECK(CanDrop(event.data()));
301
302  is_drop_cursor_visible_ = false;
303
304  TextfieldController* controller = textfield_->GetController();
305  if (controller) {
306      int drag_operation = controller->OnDrop(event.data());
307      if (drag_operation != ui::DragDropTypes::DRAG_NONE)
308        return drag_operation;
309  }
310
311  DCHECK(!initiating_drag_ ||
312         !GetRenderText()->IsPointInSelection(event.location()));
313  OnBeforeUserAction();
314  skip_input_method_cancel_composition_ = true;
315
316  gfx::SelectionModel drop_destination_model =
317      GetRenderText()->FindCursorPosition(event.location());
318  string16 text;
319  event.data().GetString(&text);
320  text = GetTextForDisplay(text);
321
322  // Delete the current selection for a drag and drop within this view.
323  const bool move = initiating_drag_ && !event.IsControlDown() &&
324                    event.source_operations() & ui::DragDropTypes::DRAG_MOVE;
325  if (move) {
326    // Adjust the drop destination if it is on or after the current selection.
327    size_t drop = drop_destination_model.caret_pos();
328    drop -= GetSelectedRange().Intersect(ui::Range(0, drop)).length();
329    model_->DeleteSelectionAndInsertTextAt(text, drop);
330  } else {
331    model_->MoveCursorTo(drop_destination_model);
332    // Drop always inserts text even if the textfield is not in insert mode.
333    model_->InsertText(text);
334  }
335  skip_input_method_cancel_composition_ = false;
336  UpdateAfterChange(true, true);
337  OnAfterUserAction();
338  return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY;
339}
340
341void NativeTextfieldViews::OnDragDone() {
342  initiating_drag_ = false;
343  is_drop_cursor_visible_ = false;
344}
345
346void NativeTextfieldViews::OnPaint(gfx::Canvas* canvas) {
347  text_border_->set_has_focus(textfield_->HasFocus());
348  OnPaintBackground(canvas);
349  PaintTextAndCursor(canvas);
350  if (textfield_->draw_border())
351    OnPaintBorder(canvas);
352}
353
354void NativeTextfieldViews::OnFocus() {
355  NOTREACHED();
356}
357
358void NativeTextfieldViews::OnBlur() {
359  NOTREACHED();
360}
361
362void NativeTextfieldViews::OnNativeThemeChanged(const ui::NativeTheme* theme) {
363  UpdateColorsFromTheme(theme);
364}
365
366void NativeTextfieldViews::SelectRect(const gfx::Point& start,
367                                      const gfx::Point& end) {
368  if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
369    return;
370
371  gfx::SelectionModel start_caret = GetRenderText()->FindCursorPosition(start);
372  gfx::SelectionModel end_caret = GetRenderText()->FindCursorPosition(end);
373  gfx::SelectionModel selection(
374      ui::Range(start_caret.caret_pos(), end_caret.caret_pos()),
375      end_caret.caret_affinity());
376
377  OnBeforeUserAction();
378  model_->SelectSelectionModel(selection);
379  OnCaretBoundsChanged();
380  SchedulePaint();
381  OnAfterUserAction();
382}
383
384void NativeTextfieldViews::MoveCaretTo(const gfx::Point& point) {
385  SelectRect(point, point);
386}
387
388void NativeTextfieldViews::GetSelectionEndPoints(gfx::Rect* p1,
389                                                 gfx::Rect* p2) {
390  gfx::RenderText* render_text = GetRenderText();
391  const gfx::SelectionModel& sel = render_text->selection_model();
392  gfx::SelectionModel start_sel =
393      render_text->GetSelectionModelForSelectionStart();
394  *p1 = render_text->GetCursorBounds(start_sel, true);
395  *p2 = render_text->GetCursorBounds(sel, true);
396}
397
398gfx::Rect NativeTextfieldViews::GetBounds() {
399  return bounds();
400}
401
402gfx::NativeView NativeTextfieldViews::GetNativeView() {
403  return GetWidget()->GetNativeView();
404}
405
406void NativeTextfieldViews::ConvertPointToScreen(gfx::Point* point) {
407  View::ConvertPointToScreen(this, point);
408}
409
410void NativeTextfieldViews::ConvertPointFromScreen(gfx::Point* point) {
411  View::ConvertPointFromScreen(this, point);
412}
413
414bool NativeTextfieldViews::DrawsHandles() {
415  return false;
416}
417
418void NativeTextfieldViews::OpenContextMenu(const gfx::Point& anchor) {
419  touch_selection_controller_.reset();
420  ShowContextMenu(anchor, ui::MENU_SOURCE_TOUCH_EDIT_MENU);
421}
422
423gfx::NativeCursor NativeTextfieldViews::GetCursor(const ui::MouseEvent& event) {
424  bool in_selection = GetRenderText()->IsPointInSelection(event.location());
425  bool drag_event = event.type() == ui::ET_MOUSE_DRAGGED;
426  bool text_cursor = !initiating_drag_ && (drag_event || !in_selection);
427#if defined(USE_AURA)
428  return text_cursor ? ui::kCursorIBeam : ui::kCursorNull;
429#elif defined(OS_WIN)
430  static HCURSOR ibeam = LoadCursor(NULL, IDC_IBEAM);
431  static HCURSOR arrow = LoadCursor(NULL, IDC_ARROW);
432  return text_cursor ? ibeam : arrow;
433#endif
434}
435
436/////////////////////////////////////////////////////////////////
437// NativeTextfieldViews, ContextMenuController overrides:
438void NativeTextfieldViews::ShowContextMenuForView(
439    View* source,
440    const gfx::Point& point,
441    ui::MenuSourceType source_type) {
442  UpdateContextMenu();
443  if (context_menu_runner_->RunMenuAt(GetWidget(), NULL,
444          gfx::Rect(point, gfx::Size()), views::MenuItemView::TOPLEFT,
445          source_type,
446          MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU) ==
447      MenuRunner::MENU_DELETED)
448    return;
449}
450
451/////////////////////////////////////////////////////////////////
452// NativeTextfieldViews, views::DragController overrides:
453void NativeTextfieldViews::WriteDragDataForView(views::View* sender,
454                                                const gfx::Point& press_pt,
455                                                OSExchangeData* data) {
456  DCHECK_NE(ui::DragDropTypes::DRAG_NONE,
457            GetDragOperationsForView(sender, press_pt));
458  data->SetString(GetSelectedText());
459  scoped_ptr<gfx::Canvas> canvas(
460      views::GetCanvasForDragImage(textfield_->GetWidget(), size()));
461  GetRenderText()->DrawSelectedTextForDrag(canvas.get());
462  drag_utils::SetDragImageOnDataObject(*canvas, size(),
463                                       press_pt.OffsetFromOrigin(),
464                                       data);
465  TextfieldController* controller = textfield_->GetController();
466  if (controller)
467    controller->OnWriteDragData(data);
468}
469
470int NativeTextfieldViews::GetDragOperationsForView(views::View* sender,
471                                                   const gfx::Point& p) {
472  int drag_operations = ui::DragDropTypes::DRAG_COPY;
473  if (!textfield_->enabled() || textfield_->IsObscured() ||
474      !GetRenderText()->IsPointInSelection(p))
475    drag_operations = ui::DragDropTypes::DRAG_NONE;
476  else if (sender == this && !textfield_->read_only())
477    drag_operations =
478        ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY;
479  TextfieldController* controller = textfield_->GetController();
480  if (controller)
481    controller->OnGetDragOperationsForTextfield(&drag_operations);
482  return drag_operations;
483}
484
485bool NativeTextfieldViews::CanStartDragForView(View* sender,
486                                               const gfx::Point& press_pt,
487                                               const gfx::Point& p) {
488  return initiating_drag_ && GetRenderText()->IsPointInSelection(press_pt);
489}
490
491/////////////////////////////////////////////////////////////////
492// NativeTextfieldViews, NativeTextifieldWrapper overrides:
493
494string16 NativeTextfieldViews::GetText() const {
495  return model_->GetText();
496}
497
498void NativeTextfieldViews::UpdateText() {
499  model_->SetText(GetTextForDisplay(textfield_->text()));
500  OnCaretBoundsChanged();
501  SchedulePaint();
502  textfield_->NotifyAccessibilityEvent(
503      ui::AccessibilityTypes::EVENT_TEXT_CHANGED, true);
504}
505
506void NativeTextfieldViews::AppendText(const string16& text) {
507  if (text.empty())
508    return;
509  model_->Append(GetTextForDisplay(text));
510  OnCaretBoundsChanged();
511  SchedulePaint();
512}
513
514void NativeTextfieldViews::InsertOrReplaceText(const string16& text) {
515  if (text.empty())
516    return;
517  model_->InsertText(text);
518  OnCaretBoundsChanged();
519  SchedulePaint();
520}
521
522base::i18n::TextDirection NativeTextfieldViews::GetTextDirection() const {
523  return GetRenderText()->GetTextDirection();
524}
525
526string16 NativeTextfieldViews::GetSelectedText() const {
527  return model_->GetSelectedText();
528}
529
530void NativeTextfieldViews::SelectAll(bool reversed) {
531  model_->SelectAll(reversed);
532  OnCaretBoundsChanged();
533  SchedulePaint();
534}
535
536void NativeTextfieldViews::ClearSelection() {
537  model_->ClearSelection();
538  OnCaretBoundsChanged();
539  SchedulePaint();
540}
541
542void NativeTextfieldViews::UpdateBorder() {
543  // By default, if a caller calls Textfield::RemoveBorder() and does not set
544  // any explicit margins, they should get zero margins.  But also call
545  // UpdateXXXMargins() so we respect any explicitly-set margins.
546  //
547  // NOTE: If someday Textfield supports toggling |draw_border_| back on, we'll
548  // need to update this conditional to set the insets to their default values.
549  if (!textfield_->draw_border())
550    text_border_->SetInsets(0, 0, 0, 0);
551  UpdateHorizontalMargins();
552  UpdateVerticalMargins();
553}
554
555void NativeTextfieldViews::UpdateTextColor() {
556  SetColor(textfield_->GetTextColor());
557}
558
559void NativeTextfieldViews::UpdateBackgroundColor() {
560  const SkColor color = textfield_->GetBackgroundColor();
561  set_background(Background::CreateSolidBackground(color));
562  GetRenderText()->set_background_is_transparent(SkColorGetA(color) != 0xFF);
563  SchedulePaint();
564}
565
566void NativeTextfieldViews::UpdateReadOnly() {
567  OnTextInputTypeChanged();
568}
569
570void NativeTextfieldViews::UpdateFont() {
571  GetRenderText()->SetFontList(textfield_->font_list());
572  OnCaretBoundsChanged();
573}
574
575void NativeTextfieldViews::UpdateIsObscured() {
576  GetRenderText()->SetObscured(textfield_->IsObscured());
577  OnCaretBoundsChanged();
578  SchedulePaint();
579  OnTextInputTypeChanged();
580}
581
582void NativeTextfieldViews::UpdateEnabled() {
583  SetEnabled(textfield_->enabled());
584  SchedulePaint();
585  OnTextInputTypeChanged();
586}
587
588gfx::Insets NativeTextfieldViews::CalculateInsets() {
589  return GetInsets();
590}
591
592void NativeTextfieldViews::UpdateHorizontalMargins() {
593  int left, right;
594  if (!textfield_->GetHorizontalMargins(&left, &right))
595    return;
596  gfx::Insets inset = GetInsets();
597  text_border_->SetInsets(inset.top(), left, inset.bottom(), right);
598  OnBoundsChanged(GetBounds());
599}
600
601void NativeTextfieldViews::UpdateVerticalMargins() {
602  int top, bottom;
603  if (!textfield_->GetVerticalMargins(&top, &bottom))
604    return;
605  gfx::Insets inset = GetInsets();
606  text_border_->SetInsets(top, inset.left(), bottom, inset.right());
607  OnBoundsChanged(GetBounds());
608}
609
610void NativeTextfieldViews::UpdateVerticalAlignment() {
611  GetRenderText()->SetVerticalAlignment(textfield_->vertical_alignment());
612  SchedulePaint();
613}
614
615bool NativeTextfieldViews::SetFocus() {
616  return false;
617}
618
619View* NativeTextfieldViews::GetView() {
620  return this;
621}
622
623gfx::NativeView NativeTextfieldViews::GetTestingHandle() const {
624  NOTREACHED();
625  return NULL;
626}
627
628bool NativeTextfieldViews::IsIMEComposing() const {
629  return model_->HasCompositionText();
630}
631
632ui::Range NativeTextfieldViews::GetSelectedRange() const {
633  return GetRenderText()->selection();
634}
635
636void NativeTextfieldViews::SelectRange(const ui::Range& range) {
637  model_->SelectRange(range);
638  OnCaretBoundsChanged();
639  SchedulePaint();
640  textfield_->NotifyAccessibilityEvent(
641      ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true);
642}
643
644gfx::SelectionModel NativeTextfieldViews::GetSelectionModel() const {
645  return GetRenderText()->selection_model();
646}
647
648void NativeTextfieldViews::SelectSelectionModel(
649    const gfx::SelectionModel& sel) {
650  model_->SelectSelectionModel(sel);
651  OnCaretBoundsChanged();
652  SchedulePaint();
653}
654
655size_t NativeTextfieldViews::GetCursorPosition() const {
656  return model_->GetCursorPosition();
657}
658
659bool NativeTextfieldViews::GetCursorEnabled() const {
660  return GetRenderText()->cursor_enabled();
661}
662
663void NativeTextfieldViews::SetCursorEnabled(bool enabled) {
664  GetRenderText()->SetCursorEnabled(enabled);
665}
666
667bool NativeTextfieldViews::HandleKeyPressed(const ui::KeyEvent& e) {
668  TextfieldController* controller = textfield_->GetController();
669  bool handled = false;
670  if (controller)
671    handled = controller->HandleKeyEvent(textfield_, e);
672  touch_selection_controller_.reset();
673  return handled || HandleKeyEvent(e);
674}
675
676bool NativeTextfieldViews::HandleKeyReleased(const ui::KeyEvent& e) {
677  return false;  // crbug.com/127520
678}
679
680void NativeTextfieldViews::HandleFocus() {
681  GetRenderText()->set_focused(true);
682  is_cursor_visible_ = true;
683  SchedulePaint();
684  GetInputMethod()->OnFocus();
685  OnCaretBoundsChanged();
686  // Start blinking cursor.
687  base::MessageLoop::current()->PostDelayedTask(
688      FROM_HERE,
689      base::Bind(&NativeTextfieldViews::UpdateCursor,
690                 cursor_timer_.GetWeakPtr()),
691      base::TimeDelta::FromMilliseconds(kCursorBlinkCycleMs / 2));
692}
693
694void NativeTextfieldViews::HandleBlur() {
695  GetRenderText()->set_focused(false);
696  GetInputMethod()->OnBlur();
697  // Stop blinking cursor.
698  cursor_timer_.InvalidateWeakPtrs();
699  if (is_cursor_visible_) {
700    is_cursor_visible_ = false;
701    RepaintCursor();
702  }
703
704  touch_selection_controller_.reset();
705
706  ClearSelection();
707}
708
709ui::TextInputClient* NativeTextfieldViews::GetTextInputClient() {
710  return textfield_->read_only() ? NULL : this;
711}
712
713void NativeTextfieldViews::ClearEditHistory() {
714  model_->ClearEditHistory();
715}
716
717int NativeTextfieldViews::GetFontHeight() {
718  return GetRenderText()->font_list().GetHeight();
719}
720
721int NativeTextfieldViews::GetTextfieldBaseline() const {
722  return GetRenderText()->font_list().GetBaseline();
723}
724
725int NativeTextfieldViews::GetWidthNeededForText() const {
726  return GetRenderText()->GetContentWidth() + GetInsets().width();
727}
728
729void NativeTextfieldViews::ExecuteTextCommand(int command_id) {
730  ExecuteCommand(command_id, 0);
731}
732
733bool NativeTextfieldViews::HasTextBeingDragged() {
734  return initiating_drag_;
735}
736
737/////////////////////////////////////////////////////////////////
738// NativeTextfieldViews, ui::SimpleMenuModel::Delegate overrides:
739
740bool NativeTextfieldViews::IsCommandIdChecked(int command_id) const {
741  return true;
742}
743
744bool NativeTextfieldViews::IsCommandIdEnabled(int command_id) const {
745  bool editable = !textfield_->read_only();
746  string16 result;
747  switch (command_id) {
748    case IDS_APP_CUT:
749      return editable && model_->HasSelection() && !textfield_->IsObscured();
750    case IDS_APP_COPY:
751      return model_->HasSelection() && !textfield_->IsObscured();
752    case IDS_APP_PASTE:
753      ui::Clipboard::GetForCurrentThread()->ReadText(
754          ui::Clipboard::BUFFER_STANDARD, &result);
755      return editable && !result.empty();
756    case IDS_APP_DELETE:
757      return editable && model_->HasSelection();
758    case IDS_APP_SELECT_ALL:
759      return !model_->GetText().empty();
760    default:
761      return textfield_->GetController()->IsCommandIdEnabled(command_id);
762  }
763}
764
765bool NativeTextfieldViews::GetAcceleratorForCommandId(int command_id,
766    ui::Accelerator* accelerator) {
767  return false;
768}
769
770bool NativeTextfieldViews::IsItemForCommandIdDynamic(int command_id) const {
771  const TextfieldController* controller = textfield_->GetController();
772  return controller && controller->IsItemForCommandIdDynamic(command_id);
773}
774
775string16 NativeTextfieldViews::GetLabelForCommandId(int command_id) const {
776  const TextfieldController* controller = textfield_->GetController();
777  return controller ? controller->GetLabelForCommandId(command_id) : string16();
778}
779
780void NativeTextfieldViews::ExecuteCommand(int command_id, int event_flags) {
781  touch_selection_controller_.reset();
782  if (!IsCommandIdEnabled(command_id))
783    return;
784
785  TextfieldController* controller = textfield_->GetController();
786  if (controller && controller->HandlesCommand(command_id)) {
787    controller->ExecuteCommand(command_id, 0);
788  } else {
789    bool text_changed = false;
790    switch (command_id) {
791      case IDS_APP_CUT:
792        OnBeforeUserAction();
793        text_changed = Cut();
794        UpdateAfterChange(text_changed, text_changed);
795        OnAfterUserAction();
796        break;
797      case IDS_APP_COPY:
798        OnBeforeUserAction();
799        Copy();
800        OnAfterUserAction();
801        break;
802      case IDS_APP_PASTE:
803        OnBeforeUserAction();
804        text_changed = Paste();
805        UpdateAfterChange(text_changed, text_changed);
806        OnAfterUserAction();
807        break;
808      case IDS_APP_DELETE:
809        OnBeforeUserAction();
810        text_changed = model_->Delete();
811        UpdateAfterChange(text_changed, text_changed);
812        OnAfterUserAction();
813        break;
814      case IDS_APP_SELECT_ALL:
815        OnBeforeUserAction();
816        SelectAll(false);
817        UpdateAfterChange(false, true);
818        OnAfterUserAction();
819        break;
820      default:
821        controller->ExecuteCommand(command_id, 0);
822        break;
823    }
824  }
825}
826
827void NativeTextfieldViews::SetColor(SkColor value) {
828  GetRenderText()->SetColor(value);
829  SchedulePaint();
830}
831
832void NativeTextfieldViews::ApplyColor(SkColor value, const ui::Range& range) {
833  GetRenderText()->ApplyColor(value, range);
834  SchedulePaint();
835}
836
837void NativeTextfieldViews::SetStyle(gfx::TextStyle style, bool value) {
838  GetRenderText()->SetStyle(style, value);
839  SchedulePaint();
840}
841
842void NativeTextfieldViews::ApplyStyle(gfx::TextStyle style,
843                                      bool value,
844                                      const ui::Range& range) {
845  GetRenderText()->ApplyStyle(style, value, range);
846  SchedulePaint();
847}
848
849void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) {
850  // Set the RenderText display area.
851  gfx::Insets insets = GetInsets();
852  gfx::Rect display_rect(insets.left(),
853                         insets.top(),
854                         width() - insets.width(),
855                         height() - insets.height());
856  GetRenderText()->SetDisplayRect(display_rect);
857  OnCaretBoundsChanged();
858}
859
860///////////////////////////////////////////////////////////////////////////////
861// NativeTextfieldViews, ui::TextInputClient implementation, private:
862
863void NativeTextfieldViews::SetCompositionText(
864    const ui::CompositionText& composition) {
865  if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
866    return;
867
868  OnBeforeUserAction();
869  skip_input_method_cancel_composition_ = true;
870  model_->SetCompositionText(composition);
871  skip_input_method_cancel_composition_ = false;
872  UpdateAfterChange(true, true);
873  OnAfterUserAction();
874}
875
876void NativeTextfieldViews::ConfirmCompositionText() {
877  if (!model_->HasCompositionText())
878    return;
879
880  OnBeforeUserAction();
881  skip_input_method_cancel_composition_ = true;
882  model_->ConfirmCompositionText();
883  skip_input_method_cancel_composition_ = false;
884  UpdateAfterChange(true, true);
885  OnAfterUserAction();
886}
887
888void NativeTextfieldViews::ClearCompositionText() {
889  if (!model_->HasCompositionText())
890    return;
891
892  OnBeforeUserAction();
893  skip_input_method_cancel_composition_ = true;
894  model_->CancelCompositionText();
895  skip_input_method_cancel_composition_ = false;
896  UpdateAfterChange(true, true);
897  OnAfterUserAction();
898}
899
900void NativeTextfieldViews::InsertText(const string16& text) {
901  // TODO(suzhe): Filter invalid characters.
902  if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || text.empty())
903    return;
904
905  OnBeforeUserAction();
906  skip_input_method_cancel_composition_ = true;
907  if (GetRenderText()->insert_mode())
908    model_->InsertText(GetTextForDisplay(text));
909  else
910    model_->ReplaceText(GetTextForDisplay(text));
911  skip_input_method_cancel_composition_ = false;
912  UpdateAfterChange(true, true);
913  OnAfterUserAction();
914}
915
916void NativeTextfieldViews::InsertChar(char16 ch, int flags) {
917  if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE ||
918      !ShouldInsertChar(ch, flags)) {
919    return;
920  }
921
922  OnBeforeUserAction();
923  skip_input_method_cancel_composition_ = true;
924  if (GetRenderText()->insert_mode())
925    model_->InsertChar(ch);
926  else
927    model_->ReplaceChar(ch);
928  skip_input_method_cancel_composition_ = false;
929
930  model_->SetText(GetTextForDisplay(GetText()));
931
932  UpdateAfterChange(true, true);
933  OnAfterUserAction();
934
935  if (textfield_->IsObscured()) {
936    const base::TimeDelta& reveal_duration =
937        textfield_->obscured_reveal_duration();
938    if (reveal_duration != base::TimeDelta()) {
939      const size_t change_offset = model_->GetCursorPosition();
940      DCHECK_GT(change_offset, 0u);
941      RevealObscuredChar(change_offset - 1, reveal_duration);
942    }
943  }
944}
945
946gfx::NativeWindow NativeTextfieldViews::GetAttachedWindow() const {
947  // Imagine the following hierarchy.
948  //   [NativeWidget A] - FocusManager
949  //     [View]
950  //     [NativeWidget B]
951  //       [View]
952  //         [View X]
953  // An important thing is that [NativeWidget A] owns Win32 input focus even
954  // when [View X] is logically focused by FocusManager. As a result, an Win32
955  // IME may want to interact with the native view of [NativeWidget A] rather
956  // than that of [NativeWidget B]. This is why we need to call
957  // GetTopLevelWidget() here.
958  return GetWidget()->GetTopLevelWidget()->GetNativeView();
959}
960
961ui::TextInputType NativeTextfieldViews::GetTextInputType() const {
962  return textfield_->GetTextInputType();
963}
964
965ui::TextInputMode NativeTextfieldViews::GetTextInputMode() const {
966  return ui::TEXT_INPUT_MODE_DEFAULT;
967}
968
969bool NativeTextfieldViews::CanComposeInline() const {
970  return true;
971}
972
973gfx::Rect NativeTextfieldViews::GetCaretBounds() {
974  // TextInputClient::GetCaretBounds is expected to return a value in screen
975  // coordinates.
976  gfx::Rect rect = GetRenderText()->GetUpdatedCursorBounds();
977  ConvertRectToScreen(this, &rect);
978  return rect;
979}
980
981bool NativeTextfieldViews::GetCompositionCharacterBounds(uint32 index,
982                                                         gfx::Rect* rect) {
983  DCHECK(rect);
984  if (!HasCompositionText())
985    return false;
986  const ui::Range& composition_range = GetRenderText()->GetCompositionRange();
987  const uint32 left_cursor_pos = composition_range.start() + index;
988  const uint32 right_cursor_pos = composition_range.start() + index + 1;
989  DCHECK(!composition_range.is_empty());
990  if (composition_range.end() < right_cursor_pos)
991    return false;
992  const gfx::SelectionModel start_position(left_cursor_pos,
993                                           gfx::CURSOR_BACKWARD);
994  const gfx::SelectionModel end_position(right_cursor_pos,
995                                         gfx::CURSOR_BACKWARD);
996  gfx::Rect start_cursor = GetRenderText()->GetCursorBounds(start_position,
997                                                            false);
998  gfx::Rect end_cursor = GetRenderText()->GetCursorBounds(end_position, false);
999
1000  // TextInputClient::GetCompositionCharacterBounds is expected to fill |rect|
1001  // in screen coordinates and GetCaretBounds returns screen coordinates.
1002  *rect = gfx::Rect(start_cursor.x(),
1003                    start_cursor.y(),
1004                    end_cursor.x() - start_cursor.x(),
1005                    start_cursor.height());
1006  ConvertRectToScreen(this, rect);
1007
1008  return true;
1009}
1010
1011bool NativeTextfieldViews::HasCompositionText() {
1012  return model_->HasCompositionText();
1013}
1014
1015bool NativeTextfieldViews::GetTextRange(ui::Range* range) {
1016  if (!ImeEditingAllowed())
1017    return false;
1018
1019  model_->GetTextRange(range);
1020  return true;
1021}
1022
1023bool NativeTextfieldViews::GetCompositionTextRange(ui::Range* range) {
1024  if (!ImeEditingAllowed())
1025    return false;
1026
1027  model_->GetCompositionTextRange(range);
1028  return true;
1029}
1030
1031bool NativeTextfieldViews::GetSelectionRange(ui::Range* range) {
1032  if (!ImeEditingAllowed())
1033    return false;
1034  *range = GetSelectedRange();
1035  return true;
1036}
1037
1038bool NativeTextfieldViews::SetSelectionRange(const ui::Range& range) {
1039  if (!ImeEditingAllowed() || !range.IsValid())
1040    return false;
1041
1042  OnBeforeUserAction();
1043  SelectRange(range);
1044  OnAfterUserAction();
1045  return true;
1046}
1047
1048bool NativeTextfieldViews::DeleteRange(const ui::Range& range) {
1049  if (!ImeEditingAllowed() || range.is_empty())
1050    return false;
1051
1052  OnBeforeUserAction();
1053  model_->SelectRange(range);
1054  if (model_->HasSelection()) {
1055    model_->DeleteSelection();
1056    UpdateAfterChange(true, true);
1057  }
1058  OnAfterUserAction();
1059  return true;
1060}
1061
1062bool NativeTextfieldViews::GetTextFromRange(
1063    const ui::Range& range,
1064    string16* text) {
1065  if (!ImeEditingAllowed() || !range.IsValid())
1066    return false;
1067
1068  ui::Range text_range;
1069  if (!GetTextRange(&text_range) || !text_range.Contains(range))
1070    return false;
1071
1072  *text = model_->GetTextFromRange(range);
1073  return true;
1074}
1075
1076void NativeTextfieldViews::OnInputMethodChanged() {
1077  // TODO(msw): NOTIMPLEMENTED(); see http://crbug.com/140402
1078}
1079
1080bool NativeTextfieldViews::ChangeTextDirectionAndLayoutAlignment(
1081    base::i18n::TextDirection direction) {
1082  NOTIMPLEMENTED();
1083  return false;
1084}
1085
1086void NativeTextfieldViews::ExtendSelectionAndDelete(
1087    size_t before,
1088    size_t after) {
1089  ui::Range range = GetSelectedRange();
1090  DCHECK_GE(range.start(), before);
1091
1092  range.set_start(range.start() - before);
1093  range.set_end(range.end() + after);
1094  ui::Range text_range;
1095  if (GetTextRange(&text_range) && text_range.Contains(range))
1096    DeleteRange(range);
1097}
1098
1099void NativeTextfieldViews::EnsureCaretInRect(const gfx::Rect& rect) {
1100}
1101
1102void NativeTextfieldViews::OnCompositionTextConfirmedOrCleared() {
1103  if (skip_input_method_cancel_composition_)
1104    return;
1105  DCHECK(textfield_->GetInputMethod());
1106  textfield_->GetInputMethod()->CancelComposition(textfield_);
1107}
1108
1109gfx::RenderText* NativeTextfieldViews::GetRenderText() const {
1110  return model_->render_text();
1111}
1112
1113string16 NativeTextfieldViews::GetTextForDisplay(const string16& text) {
1114  return textfield_->style() & Textfield::STYLE_LOWERCASE ?
1115      base::i18n::ToLower(text) : text;
1116}
1117
1118void NativeTextfieldViews::UpdateColorsFromTheme(const ui::NativeTheme* theme) {
1119  UpdateTextColor();
1120  UpdateBackgroundColor();
1121  gfx::RenderText* render_text = GetRenderText();
1122  render_text->set_cursor_color(textfield_->GetTextColor());
1123  render_text->set_selection_color(theme->GetSystemColor(
1124      ui::NativeTheme::kColorId_TextfieldSelectionColor));
1125  render_text->set_selection_background_focused_color(theme->GetSystemColor(
1126      ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused));
1127}
1128
1129void NativeTextfieldViews::UpdateCursor() {
1130  is_cursor_visible_ = !is_cursor_visible_;
1131  RepaintCursor();
1132  base::MessageLoop::current()->PostDelayedTask(
1133      FROM_HERE,
1134      base::Bind(&NativeTextfieldViews::UpdateCursor,
1135                 cursor_timer_.GetWeakPtr()),
1136      base::TimeDelta::FromMilliseconds(kCursorBlinkCycleMs / 2));
1137}
1138
1139void NativeTextfieldViews::RepaintCursor() {
1140  gfx::Rect r(GetRenderText()->GetUpdatedCursorBounds());
1141  r.Inset(-1, -1, -1, -1);
1142  SchedulePaintInRect(r);
1143}
1144
1145void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) {
1146  TRACE_EVENT0("views", "NativeTextfieldViews::PaintTextAndCursor");
1147  canvas->Save();
1148  GetRenderText()->set_cursor_visible(!is_drop_cursor_visible_ &&
1149      is_cursor_visible_ && !model_->HasSelection());
1150  // Draw the text, cursor, and selection.
1151  GetRenderText()->Draw(canvas);
1152
1153  // Draw the detached drop cursor that marks where the text will be dropped.
1154  if (is_drop_cursor_visible_)
1155    GetRenderText()->DrawCursor(canvas, drop_cursor_position_);
1156
1157  // Draw placeholder text if needed.
1158  if (model_->GetText().empty() &&
1159      !textfield_->placeholder_text().empty()) {
1160    canvas->DrawStringInt(
1161        textfield_->placeholder_text(),
1162        GetRenderText()->GetPrimaryFont(),
1163        textfield_->placeholder_text_color(),
1164        GetRenderText()->display_rect());
1165  }
1166  canvas->Restore();
1167}
1168
1169bool NativeTextfieldViews::HandleKeyEvent(const ui::KeyEvent& key_event) {
1170  // TODO(oshima): Refactor and consolidate with ExecuteCommand.
1171  if (key_event.type() == ui::ET_KEY_PRESSED) {
1172    ui::KeyboardCode key_code = key_event.key_code();
1173    if (key_code == ui::VKEY_TAB || key_event.IsUnicodeKeyCode())
1174      return false;
1175
1176    OnBeforeUserAction();
1177    const bool editable = !textfield_->read_only();
1178    const bool readable = !textfield_->IsObscured();
1179    const bool shift = key_event.IsShiftDown();
1180    const bool control = key_event.IsControlDown();
1181    const bool alt = key_event.IsAltDown();
1182    bool text_changed = false;
1183    bool cursor_changed = false;
1184    switch (key_code) {
1185      case ui::VKEY_Z:
1186        if (control && !shift && !alt && editable)
1187          cursor_changed = text_changed = model_->Undo();
1188        else if (control && shift && !alt && editable)
1189          cursor_changed = text_changed = model_->Redo();
1190        break;
1191      case ui::VKEY_Y:
1192        if (control && !alt && editable)
1193          cursor_changed = text_changed = model_->Redo();
1194        break;
1195      case ui::VKEY_A:
1196        if (control && !alt) {
1197          model_->SelectAll(false);
1198          cursor_changed = true;
1199        }
1200        break;
1201      case ui::VKEY_X:
1202        if (control && !alt && editable && readable)
1203          cursor_changed = text_changed = Cut();
1204        break;
1205      case ui::VKEY_C:
1206        if (control && !alt && readable)
1207          Copy();
1208        break;
1209      case ui::VKEY_V:
1210        if (control && !alt && editable)
1211          cursor_changed = text_changed = Paste();
1212        break;
1213      case ui::VKEY_RIGHT:
1214      case ui::VKEY_LEFT: {
1215        // We should ignore the alt-left/right keys because alt key doesn't make
1216        // any special effects for them and they can be shortcut keys such like
1217        // forward/back of the browser history.
1218        if (alt)
1219          break;
1220        const ui::Range selection_range = GetSelectedRange();
1221        model_->MoveCursor(
1222            control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK,
1223            (key_code == ui::VKEY_RIGHT) ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT,
1224            shift);
1225        cursor_changed = GetSelectedRange() != selection_range;
1226        break;
1227      }
1228      case ui::VKEY_END:
1229      case ui::VKEY_HOME:
1230        if ((key_code == ui::VKEY_HOME) ==
1231            (GetRenderText()->GetTextDirection() == base::i18n::RIGHT_TO_LEFT))
1232          model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, shift);
1233        else
1234          model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, shift);
1235        cursor_changed = true;
1236        break;
1237      case ui::VKEY_BACK:
1238      case ui::VKEY_DELETE:
1239        if (!editable)
1240          break;
1241        if (!model_->HasSelection()) {
1242          gfx::VisualCursorDirection direction = (key_code == ui::VKEY_DELETE) ?
1243              gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT;
1244          if (shift && control) {
1245            // If both shift and control are pressed, then erase up to the
1246            // beginning/end of the buffer in ChromeOS. In windows, do nothing.
1247#if defined(OS_WIN)
1248            break;
1249#else
1250            model_->MoveCursor(gfx::LINE_BREAK, direction, true);
1251#endif
1252          } else if (control) {
1253            // If only control is pressed, then erase the previous/next word.
1254            model_->MoveCursor(gfx::WORD_BREAK, direction, true);
1255          }
1256        }
1257        if (key_code == ui::VKEY_BACK)
1258          model_->Backspace();
1259        else if (shift && model_->HasSelection() && readable)
1260          Cut();
1261        else
1262          model_->Delete();
1263
1264        // Consume backspace and delete keys even if the edit did nothing. This
1265        // prevents potential unintended side-effects of further event handling.
1266        text_changed = true;
1267        break;
1268      case ui::VKEY_INSERT:
1269        if (control && !shift && readable)
1270          Copy();
1271        else if (shift && !control && editable)
1272          cursor_changed = text_changed = Paste();
1273        break;
1274      default:
1275        break;
1276    }
1277
1278    // We must have input method in order to support text input.
1279    DCHECK(textfield_->GetInputMethod());
1280
1281    UpdateAfterChange(text_changed, cursor_changed);
1282    OnAfterUserAction();
1283    return (text_changed || cursor_changed);
1284  }
1285  return false;
1286}
1287
1288bool NativeTextfieldViews::MoveCursorTo(const gfx::Point& point, bool select) {
1289  if (!model_->MoveCursorTo(point, select))
1290    return false;
1291  OnCaretBoundsChanged();
1292  return true;
1293}
1294
1295void NativeTextfieldViews::PropagateTextChange() {
1296  textfield_->SyncText();
1297}
1298
1299void NativeTextfieldViews::UpdateAfterChange(bool text_changed,
1300                                             bool cursor_changed) {
1301  if (text_changed) {
1302    PropagateTextChange();
1303    textfield_->NotifyAccessibilityEvent(
1304        ui::AccessibilityTypes::EVENT_TEXT_CHANGED, true);
1305  }
1306  if (cursor_changed) {
1307    is_cursor_visible_ = true;
1308    RepaintCursor();
1309    if (!text_changed) {
1310      // TEXT_CHANGED implies SELECTION_CHANGED, so we only need to fire
1311      // this if only the selection changed.
1312      textfield_->NotifyAccessibilityEvent(
1313          ui::AccessibilityTypes::EVENT_SELECTION_CHANGED, true);
1314    }
1315  }
1316  if (text_changed || cursor_changed) {
1317    OnCaretBoundsChanged();
1318    SchedulePaint();
1319  }
1320}
1321
1322void NativeTextfieldViews::UpdateContextMenu() {
1323  if (!context_menu_contents_.get()) {
1324    context_menu_contents_.reset(new ui::SimpleMenuModel(this));
1325    context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
1326    context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
1327    context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
1328    context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE);
1329    context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
1330    context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
1331                                                IDS_APP_SELECT_ALL);
1332    TextfieldController* controller = textfield_->GetController();
1333    if (controller)
1334      controller->UpdateContextMenu(context_menu_contents_.get());
1335
1336    context_menu_delegate_.reset(
1337        new views::MenuModelAdapter(context_menu_contents_.get()));
1338    context_menu_runner_.reset(
1339        new MenuRunner(new views::MenuItemView(context_menu_delegate_.get())));
1340  }
1341
1342  context_menu_delegate_->BuildMenu(context_menu_runner_->GetMenu());
1343}
1344
1345void NativeTextfieldViews::OnTextInputTypeChanged() {
1346  // TODO(suzhe): changed from DCHECK. See http://crbug.com/81320.
1347  if (textfield_->GetInputMethod())
1348    textfield_->GetInputMethod()->OnTextInputTypeChanged(textfield_);
1349}
1350
1351void NativeTextfieldViews::OnCaretBoundsChanged() {
1352  // TODO(suzhe): changed from DCHECK. See http://crbug.com/81320.
1353  if (textfield_->GetInputMethod())
1354    textfield_->GetInputMethod()->OnCaretBoundsChanged(textfield_);
1355
1356  // Notify selection controller
1357  if (touch_selection_controller_.get())
1358    touch_selection_controller_->SelectionChanged();
1359}
1360
1361void NativeTextfieldViews::OnBeforeUserAction() {
1362  TextfieldController* controller = textfield_->GetController();
1363  if (controller)
1364    controller->OnBeforeUserAction(textfield_);
1365}
1366
1367void NativeTextfieldViews::OnAfterUserAction() {
1368  TextfieldController* controller = textfield_->GetController();
1369  if (controller)
1370    controller->OnAfterUserAction(textfield_);
1371}
1372
1373bool NativeTextfieldViews::Cut() {
1374  if (!textfield_->read_only() && !textfield_->IsObscured() && model_->Cut()) {
1375    TextfieldController* controller = textfield_->GetController();
1376    if (controller)
1377      controller->OnAfterCutOrCopy();
1378    return true;
1379  }
1380  return false;
1381}
1382
1383bool NativeTextfieldViews::Copy() {
1384  if (!textfield_->IsObscured() && model_->Copy()) {
1385    TextfieldController* controller = textfield_->GetController();
1386    if (controller)
1387      controller->OnAfterCutOrCopy();
1388    return true;
1389  }
1390  return false;
1391}
1392
1393bool NativeTextfieldViews::Paste() {
1394  if (textfield_->read_only())
1395    return false;
1396
1397  const string16 original_text = GetText();
1398  const bool success = model_->Paste();
1399
1400  if (success) {
1401    // As Paste is handled in model_->Paste(), the RenderText may contain
1402    // upper case characters. This is not consistent with other places
1403    // which keeps RenderText only containing lower case characters.
1404    string16 new_text = GetTextForDisplay(GetText());
1405    model_->SetText(new_text);
1406
1407    TextfieldController* controller = textfield_->GetController();
1408    if (controller)
1409      controller->OnAfterPaste();
1410  }
1411  return success;
1412}
1413
1414void NativeTextfieldViews::TrackMouseClicks(const ui::MouseEvent& event) {
1415  if (event.IsOnlyLeftMouseButton()) {
1416    base::TimeDelta time_delta = event.time_stamp() - last_click_time_;
1417    if (time_delta.InMilliseconds() <= GetDoubleClickInterval() &&
1418        !ExceededDragThresholdFromLastClickLocation(event)) {
1419      // Upon clicking after a triple click, the count should go back to double
1420      // click and alternate between double and triple. This assignment maps
1421      // 0 to 1, 1 to 2, 2 to 1.
1422      aggregated_clicks_ = (aggregated_clicks_ % 2) + 1;
1423    } else {
1424      aggregated_clicks_ = 0;
1425    }
1426    last_click_time_ = event.time_stamp();
1427    last_click_location_ = event.location();
1428  }
1429}
1430
1431void NativeTextfieldViews::HandleMousePressEvent(const ui::MouseEvent& event) {
1432  if (event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton())
1433    textfield_->RequestFocus();
1434
1435  if (!event.IsOnlyLeftMouseButton())
1436    return;
1437
1438  initiating_drag_ = false;
1439  bool can_drag = true;
1440
1441  switch (aggregated_clicks_) {
1442    case 0:
1443      if (can_drag && GetRenderText()->IsPointInSelection(event.location()))
1444        initiating_drag_ = true;
1445      else
1446        MoveCursorTo(event.location(), event.IsShiftDown());
1447      break;
1448    case 1:
1449      MoveCursorTo(event.location(), false);
1450      model_->SelectWord();
1451      double_click_word_ = GetRenderText()->selection();
1452      OnCaretBoundsChanged();
1453      break;
1454    case 2:
1455      model_->SelectAll(false);
1456      OnCaretBoundsChanged();
1457      break;
1458    default:
1459      NOTREACHED();
1460  }
1461  SchedulePaint();
1462}
1463
1464bool NativeTextfieldViews::ImeEditingAllowed() const {
1465  // We don't allow the input method to retrieve or delete content from a
1466  // password field.
1467  ui::TextInputType t = GetTextInputType();
1468  return (t != ui::TEXT_INPUT_TYPE_NONE && t != ui::TEXT_INPUT_TYPE_PASSWORD);
1469}
1470
1471// static
1472bool NativeTextfieldViews::ShouldInsertChar(char16 ch, int flags) {
1473  // Filter out all control characters, including tab and new line characters,
1474  // and all characters with Alt modifier. But we need to allow characters with
1475  // AltGr modifier.
1476  // On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a different
1477  // flag that we don't care about.
1478  return ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) &&
1479      (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN;
1480}
1481
1482void NativeTextfieldViews::CreateTouchSelectionControllerAndNotifyIt() {
1483  if (!touch_selection_controller_) {
1484    touch_selection_controller_.reset(
1485        ui::TouchSelectionController::create(this));
1486  }
1487  if (touch_selection_controller_)
1488    touch_selection_controller_->SelectionChanged();
1489}
1490
1491void NativeTextfieldViews::PlatformGestureEventHandling(
1492    const ui::GestureEvent* event) {
1493#if defined(OS_WIN) && defined(USE_AURA)
1494  if (event->type() == ui::ET_GESTURE_TAP && !textfield_->read_only())
1495    base::win::DisplayVirtualKeyboard();
1496#endif
1497}
1498
1499void NativeTextfieldViews::RevealObscuredChar(int index,
1500                                              const base::TimeDelta& duration) {
1501  GetRenderText()->SetObscuredRevealIndex(index);
1502  SchedulePaint();
1503
1504  if (index != -1) {
1505    obscured_reveal_timer_.Start(
1506        FROM_HERE,
1507        duration,
1508        base::Bind(&NativeTextfieldViews::RevealObscuredChar,
1509                   base::Unretained(this), -1, base::TimeDelta()));
1510  }
1511}
1512
1513}  // namespace views
1514