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