Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: views/controls/textfield/native_textfield_views.cc

Issue 6675005: Integrate the new input method API for Views into Chromium. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: TouchUI: Always dispatch key events to the input method. Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "views/controls/textfield/native_textfield_views.h" 5 #include "views/controls/textfield/native_textfield_views.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/message_loop.h" 11 #include "base/message_loop.h"
12 #include "base/utf_string_conversions.h" 12 #include "base/utf_string_conversions.h"
13 #include "grit/app_strings.h" 13 #include "grit/app_strings.h"
14 #include "ui/base/clipboard/clipboard.h" 14 #include "ui/base/clipboard/clipboard.h"
15 #include "ui/base/range/range.h" 15 #include "ui/base/range/range.h"
16 #include "ui/gfx/canvas.h" 16 #include "ui/gfx/canvas.h"
17 #include "ui/gfx/canvas_skia.h" 17 #include "ui/gfx/canvas_skia.h"
18 #include "ui/gfx/insets.h" 18 #include "ui/gfx/insets.h"
19 #include "views/background.h" 19 #include "views/background.h"
20 #include "views/border.h" 20 #include "views/border.h"
21 #include "views/controls/menu/menu_2.h" 21 #include "views/controls/menu/menu_2.h"
22 #include "views/controls/textfield/textfield.h" 22 #include "views/controls/textfield/textfield.h"
23 #include "views/controls/textfield/textfield_controller.h" 23 #include "views/controls/textfield/textfield_controller.h"
24 #include "views/controls/textfield/textfield_views_model.h" 24 #include "views/controls/textfield/textfield_views_model.h"
25 #include "views/events/event.h" 25 #include "views/events/event.h"
26 #include "views/ime/input_method.h"
26 #include "views/metrics.h" 27 #include "views/metrics.h"
27 #include "views/views_delegate.h" 28 #include "views/views_delegate.h"
28 29
29 #if defined(OS_LINUX) 30 #if defined(OS_LINUX)
30 #include "ui/gfx/gtk_util.h" 31 #include "ui/gfx/gtk_util.h"
31 #endif 32 #endif
32 33
33 namespace { 34 namespace {
34 35
35 // A global flag to switch the Textfield wrapper to TextfieldViews. 36 // A global flag to switch the Textfield wrapper to TextfieldViews.
(...skipping 18 matching lines...) Expand all
54 const char kEnableViewsBasedTextfieldSwitch[] = "enable-textfield-views"; 55 const char kEnableViewsBasedTextfieldSwitch[] = "enable-textfield-views";
55 } // namespace 56 } // namespace
56 57
57 namespace views { 58 namespace views {
58 59
59 const char NativeTextfieldViews::kViewClassName[] = 60 const char NativeTextfieldViews::kViewClassName[] =
60 "views/NativeTextfieldViews"; 61 "views/NativeTextfieldViews";
61 62
62 NativeTextfieldViews::NativeTextfieldViews(Textfield* parent) 63 NativeTextfieldViews::NativeTextfieldViews(Textfield* parent)
63 : textfield_(parent), 64 : textfield_(parent),
64 model_(new TextfieldViewsModel()), 65 ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TextfieldViewsModel(this))),
65 text_border_(new TextfieldBorder()), 66 text_border_(new TextfieldBorder()),
66 text_offset_(0), 67 text_offset_(0),
67 insert_(true), 68 insert_(true),
68 is_cursor_visible_(false), 69 is_cursor_visible_(false),
70 skip_input_method_cancel_composition_(false),
69 ALLOW_THIS_IN_INITIALIZER_LIST(cursor_timer_(this)), 71 ALLOW_THIS_IN_INITIALIZER_LIST(cursor_timer_(this)),
70 last_mouse_press_time_(base::Time::FromInternalValue(0)), 72 last_mouse_press_time_(base::Time::FromInternalValue(0)),
71 click_state_(NONE) { 73 click_state_(NONE) {
72 set_border(text_border_); 74 set_border(text_border_);
73 75
74 // Multiline is not supported. 76 // Multiline is not supported.
75 DCHECK_NE(parent->style(), Textfield::STYLE_MULTILINE); 77 DCHECK_NE(parent->style(), Textfield::STYLE_MULTILINE);
76 // Lowercase is not supported. 78 // Lowercase is not supported.
77 DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE); 79 DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE);
78 80
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 } 159 }
158 160
159 ///////////////////////////////////////////////////////////////// 161 /////////////////////////////////////////////////////////////////
160 // NativeTextfieldViews, NativeTextifieldWrapper overrides: 162 // NativeTextfieldViews, NativeTextifieldWrapper overrides:
161 163
162 string16 NativeTextfieldViews::GetText() const { 164 string16 NativeTextfieldViews::GetText() const {
163 return model_->text(); 165 return model_->text();
164 } 166 }
165 167
166 void NativeTextfieldViews::UpdateText() { 168 void NativeTextfieldViews::UpdateText() {
167 bool changed = model_->SetText(textfield_->text()); 169 model_->SetText(textfield_->text());
168 UpdateCursorBoundsAndTextOffset(); 170 UpdateCursorBoundsAndTextOffset();
169 SchedulePaint(); 171 SchedulePaint();
170 if (changed) {
171 TextfieldController* controller = textfield_->GetController();
172 if (controller)
173 controller->ContentsChanged(textfield_, GetText());
174 }
175 } 172 }
176 173
177 void NativeTextfieldViews::AppendText(const string16& text) { 174 void NativeTextfieldViews::AppendText(const string16& text) {
178 if (text.empty()) 175 if (text.empty())
179 return; 176 return;
180 model_->Append(text); 177 model_->Append(text);
181 UpdateCursorBoundsAndTextOffset(); 178 UpdateCursorBoundsAndTextOffset();
182 SchedulePaint(); 179 SchedulePaint();
183
184 TextfieldController* controller = textfield_->GetController();
185 if (controller)
186 controller->ContentsChanged(textfield_, GetText());
187 } 180 }
188 181
189 string16 NativeTextfieldViews::GetSelectedText() const { 182 string16 NativeTextfieldViews::GetSelectedText() const {
190 return model_->GetSelectedText(); 183 return model_->GetSelectedText();
191 } 184 }
192 185
193 void NativeTextfieldViews::SelectAll() { 186 void NativeTextfieldViews::SelectAll() {
194 model_->SelectAll(); 187 model_->SelectAll();
195 SchedulePaint(); 188 SchedulePaint();
196 } 189 }
(...skipping 20 matching lines...) Expand all
217 210
218 void NativeTextfieldViews::UpdateBackgroundColor() { 211 void NativeTextfieldViews::UpdateBackgroundColor() {
219 // TODO(oshima): Background has to match the border's shape. 212 // TODO(oshima): Background has to match the border's shape.
220 set_background( 213 set_background(
221 Background::CreateSolidBackground(textfield_->background_color())); 214 Background::CreateSolidBackground(textfield_->background_color()));
222 SchedulePaint(); 215 SchedulePaint();
223 } 216 }
224 217
225 void NativeTextfieldViews::UpdateReadOnly() { 218 void NativeTextfieldViews::UpdateReadOnly() {
226 SchedulePaint(); 219 SchedulePaint();
220 OnTextInputTypeChanged();
227 } 221 }
228 222
229 void NativeTextfieldViews::UpdateFont() { 223 void NativeTextfieldViews::UpdateFont() {
230 UpdateCursorBoundsAndTextOffset(); 224 UpdateCursorBoundsAndTextOffset();
231 } 225 }
232 226
233 void NativeTextfieldViews::UpdateIsPassword() { 227 void NativeTextfieldViews::UpdateIsPassword() {
234 model_->set_is_password(textfield_->IsPassword()); 228 model_->set_is_password(textfield_->IsPassword());
235 UpdateCursorBoundsAndTextOffset(); 229 UpdateCursorBoundsAndTextOffset();
236 SchedulePaint(); 230 SchedulePaint();
231 OnTextInputTypeChanged();
237 } 232 }
238 233
239 void NativeTextfieldViews::UpdateEnabled() { 234 void NativeTextfieldViews::UpdateEnabled() {
240 SetEnabled(textfield_->IsEnabled()); 235 SetEnabled(textfield_->IsEnabled());
241 SchedulePaint(); 236 SchedulePaint();
237 OnTextInputTypeChanged();
242 } 238 }
243 239
244 gfx::Insets NativeTextfieldViews::CalculateInsets() { 240 gfx::Insets NativeTextfieldViews::CalculateInsets() {
245 return GetInsets(); 241 return GetInsets();
246 } 242 }
247 243
248 void NativeTextfieldViews::UpdateHorizontalMargins() { 244 void NativeTextfieldViews::UpdateHorizontalMargins() {
249 int left, right; 245 int left, right;
250 if (!textfield_->GetHorizontalMargins(&left, &right)) 246 if (!textfield_->GetHorizontalMargins(&left, &right))
251 return; 247 return;
(...skipping 20 matching lines...) Expand all
272 View* NativeTextfieldViews::GetView() { 268 View* NativeTextfieldViews::GetView() {
273 return this; 269 return this;
274 } 270 }
275 271
276 gfx::NativeView NativeTextfieldViews::GetTestingHandle() const { 272 gfx::NativeView NativeTextfieldViews::GetTestingHandle() const {
277 NOTREACHED(); 273 NOTREACHED();
278 return NULL; 274 return NULL;
279 } 275 }
280 276
281 bool NativeTextfieldViews::IsIMEComposing() const { 277 bool NativeTextfieldViews::IsIMEComposing() const {
282 return false; 278 return model_->HasCompositionText();
283 } 279 }
284 280
285 void NativeTextfieldViews::GetSelectedRange(ui::Range* range) const { 281 void NativeTextfieldViews::GetSelectedRange(ui::Range* range) const {
286 model_->GetSelectedRange(range); 282 model_->GetSelectedRange(range);
287 } 283 }
288 284
289 void NativeTextfieldViews::SelectRange(const ui::Range& range) { 285 void NativeTextfieldViews::SelectRange(const ui::Range& range) {
290 model_->SelectRange(range); 286 model_->SelectRange(range);
291 UpdateCursorBoundsAndTextOffset(); 287 UpdateCursorBoundsAndTextOffset();
292 SchedulePaint(); 288 SchedulePaint();
(...skipping 11 matching lines...) Expand all
304 return handled || HandleKeyEvent(e); 300 return handled || HandleKeyEvent(e);
305 } 301 }
306 302
307 bool NativeTextfieldViews::HandleKeyReleased(const views::KeyEvent& e) { 303 bool NativeTextfieldViews::HandleKeyReleased(const views::KeyEvent& e) {
308 return true; 304 return true;
309 } 305 }
310 306
311 void NativeTextfieldViews::HandleFocus() { 307 void NativeTextfieldViews::HandleFocus() {
312 is_cursor_visible_ = true; 308 is_cursor_visible_ = true;
313 SchedulePaint(); 309 SchedulePaint();
310 OnCaretBoundsChanged();
314 // Start blinking cursor. 311 // Start blinking cursor.
315 MessageLoop::current()->PostDelayedTask( 312 MessageLoop::current()->PostDelayedTask(
316 FROM_HERE, 313 FROM_HERE,
317 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor), 314 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor),
318 kCursorVisibleTimeMs); 315 kCursorVisibleTimeMs);
319 } 316 }
320 317
321 void NativeTextfieldViews::HandleBlur() { 318 void NativeTextfieldViews::HandleBlur() {
322 // Stop blinking cursor. 319 // Stop blinking cursor.
323 cursor_timer_.RevokeAll(); 320 cursor_timer_.RevokeAll();
324 if (is_cursor_visible_) { 321 if (is_cursor_visible_) {
325 is_cursor_visible_ = false; 322 is_cursor_visible_ = false;
326 RepaintCursor(); 323 RepaintCursor();
327 } 324 }
328 } 325 }
329 326
327 TextInputClient* NativeTextfieldViews::GetTextInputClient() {
328 return textfield_->read_only() ? NULL : this;
329 }
330
330 ///////////////////////////////////////////////////////////////// 331 /////////////////////////////////////////////////////////////////
331 // NativeTextfieldViews, ui::SimpleMenuModel::Delegate overrides: 332 // NativeTextfieldViews, ui::SimpleMenuModel::Delegate overrides:
332 333
333 bool NativeTextfieldViews::IsCommandIdChecked(int command_id) const { 334 bool NativeTextfieldViews::IsCommandIdChecked(int command_id) const {
334 return true; 335 return true;
335 } 336 }
336 337
337 bool NativeTextfieldViews::IsCommandIdEnabled(int command_id) const { 338 bool NativeTextfieldViews::IsCommandIdEnabled(int command_id) const {
338 bool editable = !textfield_->read_only(); 339 bool editable = !textfield_->read_only();
339 string16 result; 340 string16 result;
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 void NativeTextfieldViews::SetEnableTextfieldViews(bool enabled) { 410 void NativeTextfieldViews::SetEnableTextfieldViews(bool enabled) {
410 textfield_view_enabled = enabled; 411 textfield_view_enabled = enabled;
411 } 412 }
412 413
413 void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) { 414 void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) {
414 UpdateCursorBoundsAndTextOffset(); 415 UpdateCursorBoundsAndTextOffset();
415 } 416 }
416 417
417 418
418 /////////////////////////////////////////////////////////////////////////////// 419 ///////////////////////////////////////////////////////////////////////////////
419 // NativeTextfieldViews private: 420 // NativeTextfieldViews, TextInputClient implementation, private:
421
422 void NativeTextfieldViews::SetCompositionText(
423 const ui::CompositionText& composition) {
424 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
425 return;
426
427 OnBeforeUserAction();
428 skip_input_method_cancel_composition_ = true;
429 model_->SetCompositionText(composition);
430 skip_input_method_cancel_composition_ = false;
431 UpdateAfterChange(true, true);
432 OnAfterUserAction();
433 }
434
435 void NativeTextfieldViews::ConfirmCompositionText() {
436 if (!model_->HasCompositionText())
437 return;
438
439 OnBeforeUserAction();
440 skip_input_method_cancel_composition_ = true;
441 model_->ConfirmCompositionText();
442 skip_input_method_cancel_composition_ = false;
443 UpdateAfterChange(true, true);
444 OnAfterUserAction();
445 }
446
447 void NativeTextfieldViews::ClearCompositionText() {
448 if (!model_->HasCompositionText())
449 return;
450
451 OnBeforeUserAction();
452 skip_input_method_cancel_composition_ = true;
453 model_->ClearCompositionText();
454 skip_input_method_cancel_composition_ = false;
455 UpdateAfterChange(true, true);
456 OnAfterUserAction();
457 }
458
459 void NativeTextfieldViews::InsertText(const string16& text) {
460 // TODO(suzhe): Filter invalid characters.
461 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || text.empty())
462 return;
463
464 OnBeforeUserAction();
465 skip_input_method_cancel_composition_ = true;
466 if (insert_)
467 model_->InsertText(text);
468 else
469 model_->ReplaceText(text);
470 skip_input_method_cancel_composition_ = false;
471 UpdateAfterChange(true, true);
472 OnAfterUserAction();
473 }
474
475 void NativeTextfieldViews::InsertChar(char16 ch, int flags) {
476 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE ||
477 !ShouldInsertChar(ch, flags)) {
478 return;
479 }
480
481 OnBeforeUserAction();
482 skip_input_method_cancel_composition_ = true;
483 if (insert_)
484 model_->InsertChar(ch);
485 else
486 model_->ReplaceChar(ch);
487 skip_input_method_cancel_composition_ = false;
488 UpdateAfterChange(true, true);
489 OnAfterUserAction();
490 }
491
492 ui::TextInputType NativeTextfieldViews::GetTextInputType() {
493 if (textfield_->read_only() || !textfield_->IsEnabled())
494 return ui::TEXT_INPUT_TYPE_NONE;
495 else if (textfield_->IsPassword())
496 return ui::TEXT_INPUT_TYPE_PASSWORD;
497 return ui::TEXT_INPUT_TYPE_TEXT;
498 }
499
500 gfx::Rect NativeTextfieldViews::GetCaretBounds() {
501 return cursor_bounds_;
502 }
503
504 bool NativeTextfieldViews::HasCompositionText() {
505 return model_->HasCompositionText();
506 }
507
508 bool NativeTextfieldViews::GetTextRange(ui::Range* range) {
509 // We don't allow the input method to retrieve or delete content from a
510 // password box.
511 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT)
512 return false;
513
514 model_->GetTextRange(range);
515 return true;
516 }
517
518 bool NativeTextfieldViews::GetCompositionTextRange(ui::Range* range) {
519 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT)
520 return false;
521
522 model_->GetCompositionTextRange(range);
523 return true;
524 }
525
526 bool NativeTextfieldViews::GetSelectionRange(ui::Range* range) {
527 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT)
528 return false;
529
530 model_->GetSelectedRange(range);
531 return true;
532 }
533
534 bool NativeTextfieldViews::SetSelectionRange(const ui::Range& range) {
535 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT || !range.IsValid())
536 return false;
537
538 OnBeforeUserAction();
539 SelectRange(range);
540 OnAfterUserAction();
541 return true;
542 }
543
544 bool NativeTextfieldViews::DeleteRange(const ui::Range& range) {
545 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT || range.is_empty())
546 return false;
547
548 OnBeforeUserAction();
549 model_->SelectRange(range);
550 if (model_->HasSelection()) {
551 model_->DeleteSelection();
552 UpdateAfterChange(true, true);
553 }
554 OnAfterUserAction();
555 return true;
556 }
557
558 bool NativeTextfieldViews::GetTextFromRange(
559 const ui::Range& range,
560 const base::Callback<void(const string16&)>& callback) {
561 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT || range.is_empty())
562 return false;
563
564 callback.Run(model_->GetTextFromRange(range));
565 return true;
566 }
567
568 void NativeTextfieldViews::OnInputMethodChanged() {
569 NOTIMPLEMENTED();
570 }
571
572 bool NativeTextfieldViews::ChangeTextDirectionAndLayoutAlignment(
573 base::i18n::TextDirection direction) {
574 NOTIMPLEMENTED();
575 return false;
576 }
577
578 void NativeTextfieldViews::OnCompositionTextConfirmedOrCleared() {
579 if (skip_input_method_cancel_composition_ || !textfield_->HasFocus())
580 return;
581
582 InputMethod* input_method = textfield_->GetInputMethod();
583 if (input_method)
584 input_method->CancelComposition(textfield_);
585 }
420 586
421 const gfx::Font& NativeTextfieldViews::GetFont() const { 587 const gfx::Font& NativeTextfieldViews::GetFont() const {
422 return textfield_->font(); 588 return textfield_->font();
423 } 589 }
424 590
425 SkColor NativeTextfieldViews::GetTextColor() const { 591 SkColor NativeTextfieldViews::GetTextColor() const {
426 return textfield_->text_color(); 592 return textfield_->text_color();
427 } 593 }
428 594
429 void NativeTextfieldViews::UpdateCursor() { 595 void NativeTextfieldViews::UpdateCursor() {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
472 text_offset_ = -cursor_bounds_.x(); 638 text_offset_ = -cursor_bounds_.x();
473 } else if(full_width > width && text_offset_ + full_width < width) { 639 } else if(full_width > width && text_offset_ + full_width < width) {
474 // when the cursor moves within the textfield with the text 640 // when the cursor moves within the textfield with the text
475 // longer than the field. 641 // longer than the field.
476 text_offset_ = width - full_width; 642 text_offset_ = width - full_width;
477 } else { 643 } else {
478 // move cursor freely. 644 // move cursor freely.
479 } 645 }
480 // shift cursor bounds to fit insets. 646 // shift cursor bounds to fit insets.
481 cursor_bounds_.set_x(cursor_bounds_.x() + text_offset_ + insets.left()); 647 cursor_bounds_.set_x(cursor_bounds_.x() + text_offset_ + insets.left());
648
649 OnCaretBoundsChanged();
482 } 650 }
483 651
484 void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) { 652 void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) {
485 gfx::Insets insets = GetInsets(); 653 gfx::Insets insets = GetInsets();
486 654
487 canvas->Save(); 655 canvas->Save();
488 canvas->ClipRectInt(insets.left(), insets.top(), 656 canvas->ClipRectInt(insets.left(), insets.top(),
489 width() - insets.width(), height() - insets.height()); 657 width() - insets.width(), height() - insets.height());
490 658
491 // TODO(oshima): bidi support 659 // TODO(oshima): bidi support
492 // TODO(varunjain): re-implement this so only that dirty text is painted. 660 // TODO(varunjain): re-implement this so only that dirty text is painted.
493 TextfieldViewsModel::TextFragments fragments; 661 TextfieldViewsModel::TextFragments fragments;
494 model_->GetFragments(&fragments); 662 model_->GetFragments(&fragments);
495 int x_offset = text_offset_ + insets.left(); 663 int x_offset = text_offset_ + insets.left();
496 int y = insets.top(); 664 int y = insets.top();
497 int text_height = height() - insets.height(); 665 int text_height = height() - insets.height();
498 SkColor selection_color = 666 SkColor selection_color =
499 textfield_->HasFocus() ? 667 textfield_->HasFocus() ?
500 kFocusedSelectionColor : kUnfocusedSelectionColor; 668 kFocusedSelectionColor : kUnfocusedSelectionColor;
501 SkColor text_color = 669 SkColor text_color =
502 textfield_->read_only() ? kReadonlyTextColor : GetTextColor(); 670 textfield_->read_only() ? kReadonlyTextColor : GetTextColor();
503 671
504 for (TextfieldViewsModel::TextFragments::const_iterator iter = 672 for (TextfieldViewsModel::TextFragments::const_iterator iter =
505 fragments.begin(); 673 fragments.begin();
506 iter != fragments.end(); 674 iter != fragments.end();
507 iter++) { 675 iter++) {
508 string16 text = model_->GetVisibleText((*iter).begin, (*iter).end); 676 string16 text = model_->GetVisibleText(iter->start, iter->end);
677
678 gfx::Font font = GetFont();
679 if (iter->underline)
680 font = font.DeriveFont(0, font.GetStyle() | gfx::Font::UNDERLINED);
681
509 // TODO(oshima): This does not give the accurate position due to 682 // TODO(oshima): This does not give the accurate position due to
510 // kerning. Figure out how webkit does this with skia. 683 // kerning. Figure out how webkit does this with skia.
511 int width = GetFont().GetStringWidth(text); 684 int width = font.GetStringWidth(text);
512 685
513 if ((*iter).selected) { 686 if (iter->selected) {
514 canvas->FillRectInt(selection_color, x_offset, y, width, text_height); 687 canvas->FillRectInt(selection_color, x_offset, y, width, text_height);
515 canvas->DrawStringInt(text, GetFont(), kSelectedTextColor, 688 canvas->DrawStringInt(text, font, kSelectedTextColor,
516 x_offset, y, width, text_height); 689 x_offset, y, width, text_height);
517 } else { 690 } else {
518 canvas->DrawStringInt(text, GetFont(), text_color, 691 canvas->DrawStringInt(text, font, text_color,
519 x_offset, y, width, text_height); 692 x_offset, y, width, text_height);
520 } 693 }
521 x_offset += width; 694 x_offset += width;
522 } 695 }
523 canvas->Restore(); 696 canvas->Restore();
524 697
525 if (textfield_->IsEnabled() && is_cursor_visible_ && 698 if (textfield_->IsEnabled() && is_cursor_visible_ &&
526 !model_->HasSelection()) { 699 !model_->HasSelection()) {
527 // Paint Cursor. Replace cursor is drawn as rectangle for now. 700 // Paint Cursor. Replace cursor is drawn as rectangle for now.
528 canvas->DrawRectInt(kCursorColor, 701 canvas->DrawRectInt(kCursorColor,
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 case ui::VKEY_LEFT: 747 case ui::VKEY_LEFT:
575 control ? model_->MoveCursorToPreviousWord(selection) 748 control ? model_->MoveCursorToPreviousWord(selection)
576 : model_->MoveCursorLeft(selection); 749 : model_->MoveCursorLeft(selection);
577 cursor_changed = true; 750 cursor_changed = true;
578 break; 751 break;
579 case ui::VKEY_END: 752 case ui::VKEY_END:
580 model_->MoveCursorToEnd(selection); 753 model_->MoveCursorToEnd(selection);
581 cursor_changed = true; 754 cursor_changed = true;
582 break; 755 break;
583 case ui::VKEY_HOME: 756 case ui::VKEY_HOME:
584 model_->MoveCursorToStart(selection); 757 model_->MoveCursorToHome(selection);
585 cursor_changed = true; 758 cursor_changed = true;
586 break; 759 break;
587 case ui::VKEY_BACK: 760 case ui::VKEY_BACK:
588 if (!editable) 761 if (!editable)
589 break; 762 break;
590 if (!model_->HasSelection()) { 763 if (!model_->HasSelection()) {
591 if (selection && control) { 764 if (selection && control) {
592 // If both shift and control are pressed, then erase upto the 765 // If both shift and control are pressed, then erase upto the
593 // beginning of the buffer in ChromeOS. In windows, do nothing. 766 // beginning of the buffer in ChromeOS. In windows, do nothing.
594 #if defined(OS_WIN) 767 #if defined(OS_WIN)
595 break; 768 break;
596 #else 769 #else
597 model_->MoveCursorToStart(true); 770 model_->MoveCursorToHome(true);
598 #endif 771 #endif
599 } else if (control) { 772 } else if (control) {
600 // If only control is pressed, then erase the previous word. 773 // If only control is pressed, then erase the previous word.
601 model_->MoveCursorToPreviousWord(true); 774 model_->MoveCursorToPreviousWord(true);
602 } 775 }
603 } 776 }
604 text_changed = model_->Backspace(); 777 text_changed = model_->Backspace();
605 cursor_changed = true; 778 cursor_changed = true;
606 break; 779 break;
607 case ui::VKEY_DELETE: 780 case ui::VKEY_DELETE:
(...skipping 15 matching lines...) Expand all
623 } 796 }
624 cursor_changed = text_changed = model_->Delete(); 797 cursor_changed = text_changed = model_->Delete();
625 break; 798 break;
626 case ui::VKEY_INSERT: 799 case ui::VKEY_INSERT:
627 insert_ = !insert_; 800 insert_ = !insert_;
628 cursor_changed = true; 801 cursor_changed = true;
629 break; 802 break;
630 default: 803 default:
631 break; 804 break;
632 } 805 }
633 char16 ch = key_event.GetCharacter(); 806
634 if (editable && ShouldInsertChar(ch, key_event.flags())) { 807 // Only handle text input by ourselves if there is no input method.
635 if (insert_) 808 if (!textfield_->GetInputMethod()) {
636 model_->Insert(ch); 809 char16 ch = key_event.GetCharacter();
637 else 810 if (editable && ShouldInsertChar(ch, key_event.flags())) {
638 model_->Replace(ch); 811 if (insert_)
639 text_changed = true; 812 model_->InsertChar(ch);
813 else
814 model_->ReplaceChar(ch);
815 text_changed = true;
816 }
640 } 817 }
641 818
642 UpdateAfterChange(text_changed, cursor_changed); 819 UpdateAfterChange(text_changed, cursor_changed);
643 OnAfterUserAction(); 820 OnAfterUserAction();
644 return (text_changed || cursor_changed); 821 return (text_changed || cursor_changed);
645 } 822 }
646 return false; 823 return false;
647 } 824 }
648 825
649 size_t NativeTextfieldViews::FindCursorPosition(const gfx::Point& point) const { 826 size_t NativeTextfieldViews::FindCursorPosition(const gfx::Point& point) const {
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
714 891
715 void NativeTextfieldViews::SetCursorForMouseClick(const views::MouseEvent& e) { 892 void NativeTextfieldViews::SetCursorForMouseClick(const views::MouseEvent& e) {
716 size_t pos = FindCursorPosition(e.location()); 893 size_t pos = FindCursorPosition(e.location());
717 if (model_->MoveCursorTo(pos, false)) { 894 if (model_->MoveCursorTo(pos, false)) {
718 UpdateCursorBoundsAndTextOffset(); 895 UpdateCursorBoundsAndTextOffset();
719 } 896 }
720 } 897 }
721 898
722 void NativeTextfieldViews::PropagateTextChange() { 899 void NativeTextfieldViews::PropagateTextChange() {
723 textfield_->SyncText(); 900 textfield_->SyncText();
724 TextfieldController* controller = textfield_->GetController();
725 if (controller)
726 controller->ContentsChanged(textfield_, GetText());
727 } 901 }
728 902
729 void NativeTextfieldViews::UpdateAfterChange(bool text_changed, 903 void NativeTextfieldViews::UpdateAfterChange(bool text_changed,
730 bool cursor_changed) { 904 bool cursor_changed) {
731 if (text_changed) 905 if (text_changed)
732 PropagateTextChange(); 906 PropagateTextChange();
733 if (cursor_changed) { 907 if (cursor_changed) {
734 is_cursor_visible_ = true; 908 is_cursor_visible_ = true;
735 RepaintCursor(); 909 RepaintCursor();
736 } 910 }
(...skipping 10 matching lines...) Expand all
747 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT); 921 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
748 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY); 922 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
749 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE); 923 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
750 context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE); 924 context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE);
751 context_menu_contents_->AddSeparator(); 925 context_menu_contents_->AddSeparator();
752 context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL, 926 context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
753 IDS_APP_SELECT_ALL); 927 IDS_APP_SELECT_ALL);
754 context_menu_menu_.reset(new Menu2(context_menu_contents_.get())); 928 context_menu_menu_.reset(new Menu2(context_menu_contents_.get()));
755 } 929 }
756 930
931 void NativeTextfieldViews::OnTextInputTypeChanged() {
932 if (!textfield_->HasFocus())
933 return;
oshima 2011/03/29 19:07:55 can we check this in input_method? is it bad idea?
James Su 2011/03/29 19:21:51 InputMethod implementations also do this check. Th
oshima 2011/03/30 21:06:34 The code that has no effect or speculative code ma
Peng 2011/03/30 21:28:27 We have several input_method implementations (Ibus
James Su 2011/03/30 21:30:32 Existing InputMethod implementations simply return
James Su 2011/03/30 21:30:32 Yes. I updated comments of these methods to clarif
oshima 2011/03/30 21:51:25 Thanks. Just for clarification, I was fine with ei
934
935 InputMethod* input_method = textfield_->GetInputMethod();
oshima 2011/03/29 19:07:55 when input_method can be NULL?
James Su 2011/03/29 19:21:51 Right now, it's only possible in test code, where
oshima 2011/03/30 21:06:34 If it shouldn't be null for regular case, I'd pref
James Su 2011/03/30 21:30:32 I'd prefer to keep this check, otherwise we need s
oshima 2011/03/30 21:51:25 Altering the code for unittest to pass sounds wron
James Su 2011/03/30 22:46:38 Sounds reasonable. I'll remove the check.
936 if (input_method)
937 input_method->OnTextInputTypeChanged(textfield_);
938 }
939
940 void NativeTextfieldViews::OnCaretBoundsChanged() {
941 if (!textfield_->HasFocus())
942 return;
943
944 InputMethod* input_method = textfield_->GetInputMethod();
945 if (input_method)
946 input_method->OnCaretBoundsChanged(textfield_);
947 }
948
757 void NativeTextfieldViews::OnBeforeUserAction() { 949 void NativeTextfieldViews::OnBeforeUserAction() {
758 TextfieldController* controller = textfield_->GetController(); 950 TextfieldController* controller = textfield_->GetController();
759 if (controller) 951 if (controller)
760 controller->OnBeforeUserAction(textfield_); 952 controller->OnBeforeUserAction(textfield_);
761 } 953 }
762 954
763 void NativeTextfieldViews::OnAfterUserAction() { 955 void NativeTextfieldViews::OnAfterUserAction() {
764 TextfieldController* controller = textfield_->GetController(); 956 TextfieldController* controller = textfield_->GetController();
765 if (controller) 957 if (controller)
766 controller->OnAfterUserAction(textfield_); 958 controller->OnAfterUserAction(textfield_);
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
825 } 1017 }
826 1018
827 void NativeTextfieldViews::TextfieldBorder::SetInsets(int top, 1019 void NativeTextfieldViews::TextfieldBorder::SetInsets(int top,
828 int left, 1020 int left,
829 int bottom, 1021 int bottom,
830 int right) { 1022 int right) {
831 insets_.Set(top, left, bottom, right); 1023 insets_.Set(top, left, bottom, right);
832 } 1024 }
833 1025
834 } // namespace views 1026 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698