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