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/command_line.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "ui/base/accessibility/accessible_view_state.h"
13 #include "ui/base/ime/text_input_type.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/base/ui_base_switches.h"
16 #include "ui/events/event.h"
17 #include "ui/events/keycodes/keyboard_codes.h"
18 #include "ui/gfx/insets.h"
19 #include "ui/gfx/range/range.h"
20 #include "ui/gfx/selection_model.h"
21 #include "ui/native_theme/native_theme.h"
22 #include "ui/views/controls/native/native_view_host.h"
23 #include "ui/views/controls/textfield/native_textfield_views.h"
24 #include "ui/views/controls/textfield/native_textfield_wrapper.h"
25 #include "ui/views/controls/textfield/textfield_controller.h"
26 #include "ui/views/painter.h"
27 #include "ui/views/views_delegate.h"
28 #include "ui/views/widget/widget.h"
29
30 namespace {
31
32 // Default placeholder text color.
33 const SkColor kDefaultPlaceholderTextColor = SK_ColorLTGRAY;
34
GetDefaultFontList()35 gfx::FontList GetDefaultFontList() {
36 return ResourceBundle::GetSharedInstance().GetFontList(
37 ResourceBundle::BaseFont);
38 }
39
40 } // namespace
41
42 namespace views {
43
44 // static
45 const char Textfield::kViewClassName[] = "Textfield";
46
47 // static
GetCaretBlinkMs()48 size_t Textfield::GetCaretBlinkMs() {
49 static const size_t default_value = 500;
50 #if defined(OS_WIN)
51 static const size_t system_value = ::GetCaretBlinkTime();
52 if (system_value != 0)
53 return (system_value == INFINITE) ? 0 : system_value;
54 #endif
55 return default_value;
56 }
57
Textfield()58 Textfield::Textfield()
59 : native_wrapper_(NULL),
60 controller_(NULL),
61 style_(STYLE_DEFAULT),
62 font_list_(GetDefaultFontList()),
63 read_only_(false),
64 default_width_in_chars_(0),
65 draw_border_(true),
66 text_color_(SK_ColorBLACK),
67 use_default_text_color_(true),
68 background_color_(SK_ColorWHITE),
69 use_default_background_color_(true),
70 horizontal_margins_were_set_(false),
71 vertical_margins_were_set_(false),
72 placeholder_text_color_(kDefaultPlaceholderTextColor),
73 text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
74 weak_ptr_factory_(this) {
75 SetFocusable(true);
76
77 if (ViewsDelegate::views_delegate) {
78 obscured_reveal_duration_ = ViewsDelegate::views_delegate->
79 GetDefaultTextfieldObscuredRevealDuration();
80 }
81
82 if (NativeViewHost::kRenderNativeControlFocus)
83 focus_painter_ = Painter::CreateDashedFocusPainter();
84 }
85
Textfield(StyleFlags style)86 Textfield::Textfield(StyleFlags style)
87 : native_wrapper_(NULL),
88 controller_(NULL),
89 style_(style),
90 font_list_(GetDefaultFontList()),
91 read_only_(false),
92 default_width_in_chars_(0),
93 draw_border_(true),
94 text_color_(SK_ColorBLACK),
95 use_default_text_color_(true),
96 background_color_(SK_ColorWHITE),
97 use_default_background_color_(true),
98 horizontal_margins_were_set_(false),
99 vertical_margins_were_set_(false),
100 placeholder_text_color_(kDefaultPlaceholderTextColor),
101 text_input_type_(ui::TEXT_INPUT_TYPE_TEXT),
102 weak_ptr_factory_(this) {
103 SetFocusable(true);
104 if (IsObscured())
105 SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
106
107 if (ViewsDelegate::views_delegate) {
108 obscured_reveal_duration_ = ViewsDelegate::views_delegate->
109 GetDefaultTextfieldObscuredRevealDuration();
110 }
111
112 if (NativeViewHost::kRenderNativeControlFocus)
113 focus_painter_ = Painter::CreateDashedFocusPainter();
114 }
115
~Textfield()116 Textfield::~Textfield() {
117 }
118
SetController(TextfieldController * controller)119 void Textfield::SetController(TextfieldController* controller) {
120 controller_ = controller;
121 }
122
GetController() const123 TextfieldController* Textfield::GetController() const {
124 return controller_;
125 }
126
SetReadOnly(bool read_only)127 void Textfield::SetReadOnly(bool read_only) {
128 // Update read-only without changing the focusable state (or active, etc.).
129 read_only_ = read_only;
130 if (native_wrapper_) {
131 native_wrapper_->UpdateReadOnly();
132 native_wrapper_->UpdateTextColor();
133 native_wrapper_->UpdateBackgroundColor();
134 }
135 }
136
IsObscured() const137 bool Textfield::IsObscured() const {
138 return style_ & STYLE_OBSCURED;
139 }
140
SetObscured(bool obscured)141 void Textfield::SetObscured(bool obscured) {
142 if (obscured) {
143 style_ = static_cast<StyleFlags>(style_ | STYLE_OBSCURED);
144 SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
145 } else {
146 style_ = static_cast<StyleFlags>(style_ & ~STYLE_OBSCURED);
147 SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT);
148 }
149 if (native_wrapper_)
150 native_wrapper_->UpdateIsObscured();
151 }
152
GetTextInputType() const153 ui::TextInputType Textfield::GetTextInputType() const {
154 if (read_only() || !enabled())
155 return ui::TEXT_INPUT_TYPE_NONE;
156 return text_input_type_;
157 }
158
SetTextInputType(ui::TextInputType type)159 void Textfield::SetTextInputType(ui::TextInputType type) {
160 text_input_type_ = type;
161 bool should_be_obscured = type == ui::TEXT_INPUT_TYPE_PASSWORD;
162 if (IsObscured() != should_be_obscured)
163 SetObscured(should_be_obscured);
164 }
165
SetText(const string16 & text)166 void Textfield::SetText(const string16& text) {
167 text_ = text;
168 if (native_wrapper_)
169 native_wrapper_->UpdateText();
170 }
171
AppendText(const string16 & text)172 void Textfield::AppendText(const string16& text) {
173 text_ += text;
174 if (native_wrapper_)
175 native_wrapper_->AppendText(text);
176 }
177
InsertOrReplaceText(const string16 & text)178 void Textfield::InsertOrReplaceText(const string16& text) {
179 if (native_wrapper_) {
180 native_wrapper_->InsertOrReplaceText(text);
181 text_ = native_wrapper_->GetText();
182 }
183 }
184
GetTextDirection() const185 base::i18n::TextDirection Textfield::GetTextDirection() const {
186 return native_wrapper_ ?
187 native_wrapper_->GetTextDirection() : base::i18n::UNKNOWN_DIRECTION;
188 }
189
SelectAll(bool reversed)190 void Textfield::SelectAll(bool reversed) {
191 if (native_wrapper_)
192 native_wrapper_->SelectAll(reversed);
193 }
194
GetSelectedText() const195 string16 Textfield::GetSelectedText() const {
196 return native_wrapper_ ? native_wrapper_->GetSelectedText() : string16();
197 }
198
ClearSelection() const199 void Textfield::ClearSelection() const {
200 if (native_wrapper_)
201 native_wrapper_->ClearSelection();
202 }
203
HasSelection() const204 bool Textfield::HasSelection() const {
205 return native_wrapper_ && !native_wrapper_->GetSelectedRange().is_empty();
206 }
207
GetTextColor() const208 SkColor Textfield::GetTextColor() const {
209 if (!use_default_text_color_)
210 return text_color_;
211
212 return GetNativeTheme()->GetSystemColor(read_only() ?
213 ui::NativeTheme::kColorId_TextfieldReadOnlyColor :
214 ui::NativeTheme::kColorId_TextfieldDefaultColor);
215 }
216
SetTextColor(SkColor color)217 void Textfield::SetTextColor(SkColor color) {
218 text_color_ = color;
219 use_default_text_color_ = false;
220 if (native_wrapper_)
221 native_wrapper_->UpdateTextColor();
222 }
223
UseDefaultTextColor()224 void Textfield::UseDefaultTextColor() {
225 use_default_text_color_ = true;
226 if (native_wrapper_)
227 native_wrapper_->UpdateTextColor();
228 }
229
GetBackgroundColor() const230 SkColor Textfield::GetBackgroundColor() const {
231 if (!use_default_background_color_)
232 return background_color_;
233
234 return GetNativeTheme()->GetSystemColor(read_only() ?
235 ui::NativeTheme::kColorId_TextfieldReadOnlyBackground :
236 ui::NativeTheme::kColorId_TextfieldDefaultBackground);
237 }
238
SetBackgroundColor(SkColor color)239 void Textfield::SetBackgroundColor(SkColor color) {
240 background_color_ = color;
241 use_default_background_color_ = false;
242 if (native_wrapper_)
243 native_wrapper_->UpdateBackgroundColor();
244 }
245
UseDefaultBackgroundColor()246 void Textfield::UseDefaultBackgroundColor() {
247 use_default_background_color_ = true;
248 if (native_wrapper_)
249 native_wrapper_->UpdateBackgroundColor();
250 }
251
GetCursorEnabled() const252 bool Textfield::GetCursorEnabled() const {
253 return native_wrapper_ && native_wrapper_->GetCursorEnabled();
254 }
255
SetCursorEnabled(bool enabled)256 void Textfield::SetCursorEnabled(bool enabled) {
257 if (native_wrapper_)
258 native_wrapper_->SetCursorEnabled(enabled);
259 }
260
SetFontList(const gfx::FontList & font_list)261 void Textfield::SetFontList(const gfx::FontList& font_list) {
262 font_list_ = font_list;
263 if (native_wrapper_)
264 native_wrapper_->UpdateFont();
265 PreferredSizeChanged();
266 }
267
GetPrimaryFont() const268 const gfx::Font& Textfield::GetPrimaryFont() const {
269 return font_list_.GetPrimaryFont();
270 }
271
SetFont(const gfx::Font & font)272 void Textfield::SetFont(const gfx::Font& font) {
273 SetFontList(gfx::FontList(font));
274 }
275
SetHorizontalMargins(int left,int right)276 void Textfield::SetHorizontalMargins(int left, int right) {
277 if (horizontal_margins_were_set_ &&
278 left == margins_.left() && right == margins_.right()) {
279 return;
280 }
281 margins_.Set(margins_.top(), left, margins_.bottom(), right);
282 horizontal_margins_were_set_ = true;
283 if (native_wrapper_)
284 native_wrapper_->UpdateHorizontalMargins();
285 PreferredSizeChanged();
286 }
287
SetVerticalMargins(int top,int bottom)288 void Textfield::SetVerticalMargins(int top, int bottom) {
289 if (vertical_margins_were_set_ &&
290 top == margins_.top() && bottom == margins_.bottom()) {
291 return;
292 }
293 margins_.Set(top, margins_.left(), bottom, margins_.right());
294 vertical_margins_were_set_ = true;
295 if (native_wrapper_)
296 native_wrapper_->UpdateVerticalMargins();
297 PreferredSizeChanged();
298 }
299
RemoveBorder()300 void Textfield::RemoveBorder() {
301 if (!draw_border_)
302 return;
303
304 draw_border_ = false;
305 if (native_wrapper_)
306 native_wrapper_->UpdateBorder();
307 }
308
GetPlaceholderText() const309 base::string16 Textfield::GetPlaceholderText() const {
310 return placeholder_text_;
311 }
312
GetHorizontalMargins(int * left,int * right)313 bool Textfield::GetHorizontalMargins(int* left, int* right) {
314 if (!horizontal_margins_were_set_)
315 return false;
316
317 *left = margins_.left();
318 *right = margins_.right();
319 return true;
320 }
321
GetVerticalMargins(int * top,int * bottom)322 bool Textfield::GetVerticalMargins(int* top, int* bottom) {
323 if (!vertical_margins_were_set_)
324 return false;
325
326 *top = margins_.top();
327 *bottom = margins_.bottom();
328 return true;
329 }
330
UpdateAllProperties()331 void Textfield::UpdateAllProperties() {
332 if (native_wrapper_) {
333 native_wrapper_->UpdateText();
334 native_wrapper_->UpdateTextColor();
335 native_wrapper_->UpdateBackgroundColor();
336 native_wrapper_->UpdateReadOnly();
337 native_wrapper_->UpdateFont();
338 native_wrapper_->UpdateEnabled();
339 native_wrapper_->UpdateBorder();
340 native_wrapper_->UpdateIsObscured();
341 native_wrapper_->UpdateHorizontalMargins();
342 native_wrapper_->UpdateVerticalMargins();
343 }
344 }
345
SyncText()346 void Textfield::SyncText() {
347 if (native_wrapper_) {
348 string16 new_text = native_wrapper_->GetText();
349 if (new_text != text_) {
350 text_ = new_text;
351 if (controller_)
352 controller_->ContentsChanged(this, text_);
353 }
354 }
355 }
356
IsIMEComposing() const357 bool Textfield::IsIMEComposing() const {
358 return native_wrapper_ && native_wrapper_->IsIMEComposing();
359 }
360
GetSelectedRange() const361 gfx::Range Textfield::GetSelectedRange() const {
362 return native_wrapper_->GetSelectedRange();
363 }
364
SelectRange(const gfx::Range & range)365 void Textfield::SelectRange(const gfx::Range& range) {
366 native_wrapper_->SelectRange(range);
367 }
368
GetSelectionModel() const369 gfx::SelectionModel Textfield::GetSelectionModel() const {
370 return native_wrapper_->GetSelectionModel();
371 }
372
SelectSelectionModel(const gfx::SelectionModel & sel)373 void Textfield::SelectSelectionModel(const gfx::SelectionModel& sel) {
374 native_wrapper_->SelectSelectionModel(sel);
375 }
376
GetCursorPosition() const377 size_t Textfield::GetCursorPosition() const {
378 return native_wrapper_->GetCursorPosition();
379 }
380
SetColor(SkColor value)381 void Textfield::SetColor(SkColor value) {
382 return native_wrapper_->SetColor(value);
383 }
384
ApplyColor(SkColor value,const gfx::Range & range)385 void Textfield::ApplyColor(SkColor value, const gfx::Range& range) {
386 return native_wrapper_->ApplyColor(value, range);
387 }
388
SetStyle(gfx::TextStyle style,bool value)389 void Textfield::SetStyle(gfx::TextStyle style, bool value) {
390 return native_wrapper_->SetStyle(style, value);
391 }
392
ApplyStyle(gfx::TextStyle style,bool value,const gfx::Range & range)393 void Textfield::ApplyStyle(gfx::TextStyle style,
394 bool value,
395 const gfx::Range& range) {
396 return native_wrapper_->ApplyStyle(style, value, range);
397 }
398
ClearEditHistory()399 void Textfield::ClearEditHistory() {
400 native_wrapper_->ClearEditHistory();
401 }
402
SetAccessibleName(const string16 & name)403 void Textfield::SetAccessibleName(const string16& name) {
404 accessible_name_ = name;
405 }
406
ExecuteCommand(int command_id)407 void Textfield::ExecuteCommand(int command_id) {
408 native_wrapper_->ExecuteTextCommand(command_id);
409 }
410
SetFocusPainter(scoped_ptr<Painter> focus_painter)411 void Textfield::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
412 focus_painter_ = focus_painter.Pass();
413 }
414
HasTextBeingDragged()415 bool Textfield::HasTextBeingDragged() {
416 return native_wrapper_->HasTextBeingDragged();
417 }
418
419 ////////////////////////////////////////////////////////////////////////////////
420 // Textfield, View overrides:
421
Layout()422 void Textfield::Layout() {
423 if (native_wrapper_) {
424 native_wrapper_->GetView()->SetBoundsRect(GetContentsBounds());
425 native_wrapper_->GetView()->Layout();
426 }
427 }
428
GetBaseline() const429 int Textfield::GetBaseline() const {
430 gfx::Insets insets = GetTextInsets();
431 const int baseline = native_wrapper_ ?
432 native_wrapper_->GetTextfieldBaseline() : font_list_.GetBaseline();
433 return insets.top() + baseline;
434 }
435
GetPreferredSize()436 gfx::Size Textfield::GetPreferredSize() {
437 gfx::Insets insets = GetTextInsets();
438
439 const int font_height = native_wrapper_ ? native_wrapper_->GetFontHeight() :
440 font_list_.GetHeight();
441 return gfx::Size(
442 GetPrimaryFont().GetExpectedTextWidth(default_width_in_chars_)
443 + insets.width(),
444 font_height + insets.height());
445 }
446
AboutToRequestFocusFromTabTraversal(bool reverse)447 void Textfield::AboutToRequestFocusFromTabTraversal(bool reverse) {
448 SelectAll(false);
449 }
450
SkipDefaultKeyEventProcessing(const ui::KeyEvent & e)451 bool Textfield::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) {
452 // Skip any accelerator handling of backspace; textfields handle this key.
453 // Also skip processing of [Alt]+<num-pad digit> Unicode alt key codes.
454 return e.key_code() == ui::VKEY_BACK || e.IsUnicodeKeyCode();
455 }
456
OnPaint(gfx::Canvas * canvas)457 void Textfield::OnPaint(gfx::Canvas* canvas) {
458 View::OnPaint(canvas);
459 if (NativeViewHost::kRenderNativeControlFocus)
460 Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
461 }
462
OnKeyPressed(const ui::KeyEvent & e)463 bool Textfield::OnKeyPressed(const ui::KeyEvent& e) {
464 return native_wrapper_ && native_wrapper_->HandleKeyPressed(e);
465 }
466
OnKeyReleased(const ui::KeyEvent & e)467 bool Textfield::OnKeyReleased(const ui::KeyEvent& e) {
468 return native_wrapper_ && native_wrapper_->HandleKeyReleased(e);
469 }
470
OnMouseDragged(const ui::MouseEvent & e)471 bool Textfield::OnMouseDragged(const ui::MouseEvent& e) {
472 if (!e.IsOnlyRightMouseButton())
473 return View::OnMouseDragged(e);
474 return true;
475 }
476
OnFocus()477 void Textfield::OnFocus() {
478 if (native_wrapper_)
479 native_wrapper_->HandleFocus();
480
481 // Forward the focus to the wrapper if it exists.
482 if (!native_wrapper_ || !native_wrapper_->SetFocus()) {
483 // If there is no wrapper or the wrapper didn't take focus, call
484 // View::Focus to clear the native focus so that we still get
485 // keyboard messages.
486 View::OnFocus();
487 }
488
489 // Border typically draws focus indicator.
490 SchedulePaint();
491 }
492
OnBlur()493 void Textfield::OnBlur() {
494 if (native_wrapper_)
495 native_wrapper_->HandleBlur();
496
497 // Border typically draws focus indicator.
498 SchedulePaint();
499 }
500
GetAccessibleState(ui::AccessibleViewState * state)501 void Textfield::GetAccessibleState(ui::AccessibleViewState* state) {
502 state->role = ui::AccessibilityTypes::ROLE_TEXT;
503 state->name = accessible_name_;
504 if (read_only())
505 state->state |= ui::AccessibilityTypes::STATE_READONLY;
506 if (IsObscured())
507 state->state |= ui::AccessibilityTypes::STATE_PROTECTED;
508 state->value = text_;
509
510 const gfx::Range range = native_wrapper_->GetSelectedRange();
511 state->selection_start = range.start();
512 state->selection_end = range.end();
513
514 if (!read_only()) {
515 state->set_value_callback =
516 base::Bind(&Textfield::AccessibilitySetValue,
517 weak_ptr_factory_.GetWeakPtr());
518 }
519 }
520
GetTextInputClient()521 ui::TextInputClient* Textfield::GetTextInputClient() {
522 return native_wrapper_ ? native_wrapper_->GetTextInputClient() : NULL;
523 }
524
GetKeyboardContextMenuLocation()525 gfx::Point Textfield::GetKeyboardContextMenuLocation() {
526 return native_wrapper_ ? native_wrapper_->GetContextMenuLocation() :
527 View::GetKeyboardContextMenuLocation();
528 }
529
OnEnabledChanged()530 void Textfield::OnEnabledChanged() {
531 View::OnEnabledChanged();
532 if (native_wrapper_)
533 native_wrapper_->UpdateEnabled();
534 }
535
ViewHierarchyChanged(const ViewHierarchyChangedDetails & details)536 void Textfield::ViewHierarchyChanged(
537 const ViewHierarchyChangedDetails& details) {
538 if (details.is_add && !native_wrapper_ && GetWidget()) {
539 // The native wrapper's lifetime will be managed by the view hierarchy after
540 // we call AddChildView.
541 native_wrapper_ = NativeTextfieldWrapper::CreateWrapper(this);
542 AddChildViewAt(native_wrapper_->GetView(), 0);
543 Layout();
544 UpdateAllProperties();
545 }
546 }
547
GetClassName() const548 const char* Textfield::GetClassName() const {
549 return kViewClassName;
550 }
551
552 ////////////////////////////////////////////////////////////////////////////////
553 // Textfield, private:
554
GetTextInsets() const555 gfx::Insets Textfield::GetTextInsets() const {
556 gfx::Insets insets = GetInsets();
557 if (draw_border_ && native_wrapper_)
558 insets += native_wrapper_->CalculateInsets();
559 return insets;
560 }
561
AccessibilitySetValue(const string16 & new_value)562 void Textfield::AccessibilitySetValue(const string16& new_value) {
563 if (!read_only()) {
564 SetText(new_value);
565 ClearSelection();
566 }
567 }
568
569 ////////////////////////////////////////////////////////////////////////////////
570 // NativeTextfieldWrapper, public:
571
572 // static
CreateWrapper(Textfield * field)573 NativeTextfieldWrapper* NativeTextfieldWrapper::CreateWrapper(
574 Textfield* field) {
575 return new NativeTextfieldViews(field);
576 }
577
578 } // namespace views
579