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

Unified 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: Fix Windows build. Created 9 years, 9 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 side-by-side diff with in-line comments
Download patch
Index: views/controls/textfield/native_textfield_views.cc
diff --git a/views/controls/textfield/native_textfield_views.cc b/views/controls/textfield/native_textfield_views.cc
index e1b8ccc248122b6ec708036253a0d458e5c3185c..73b95f3710e7f7bd57159a5b5851b5ca237571c7 100644
--- a/views/controls/textfield/native_textfield_views.cc
+++ b/views/controls/textfield/native_textfield_views.cc
@@ -23,6 +23,7 @@
#include "views/controls/textfield/textfield_controller.h"
#include "views/controls/textfield/textfield_views_model.h"
#include "views/events/event.h"
+#include "views/ime/input_method.h"
#include "views/metrics.h"
#include "views/views_delegate.h"
@@ -61,11 +62,12 @@ const char NativeTextfieldViews::kViewClassName[] =
NativeTextfieldViews::NativeTextfieldViews(Textfield* parent)
: textfield_(parent),
- model_(new TextfieldViewsModel()),
+ ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TextfieldViewsModel(this))),
text_border_(new TextfieldBorder()),
text_offset_(0),
insert_(true),
is_cursor_visible_(false),
+ skip_input_method_cancel_composition_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(cursor_timer_(this)),
last_mouse_press_time_(base::Time::FromInternalValue(0)),
click_state_(NONE) {
@@ -160,14 +162,9 @@ string16 NativeTextfieldViews::GetText() const {
}
void NativeTextfieldViews::UpdateText() {
- bool changed = model_->SetText(textfield_->text());
+ model_->SetText(textfield_->text());
UpdateCursorBoundsAndTextOffset();
SchedulePaint();
- if (changed) {
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->ContentsChanged(textfield_, GetText());
- }
}
void NativeTextfieldViews::AppendText(const string16& text) {
@@ -176,10 +173,6 @@ void NativeTextfieldViews::AppendText(const string16& text) {
model_->Append(text);
UpdateCursorBoundsAndTextOffset();
SchedulePaint();
-
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->ContentsChanged(textfield_, GetText());
}
string16 NativeTextfieldViews::GetSelectedText() const {
@@ -220,6 +213,7 @@ void NativeTextfieldViews::UpdateBackgroundColor() {
void NativeTextfieldViews::UpdateReadOnly() {
SchedulePaint();
+ OnTextInputTypeChanged();
}
void NativeTextfieldViews::UpdateFont() {
@@ -230,11 +224,13 @@ void NativeTextfieldViews::UpdateIsPassword() {
model_->set_is_password(textfield_->IsPassword());
UpdateCursorBoundsAndTextOffset();
SchedulePaint();
+ OnTextInputTypeChanged();
}
void NativeTextfieldViews::UpdateEnabled() {
SetEnabled(textfield_->IsEnabled());
SchedulePaint();
+ OnTextInputTypeChanged();
}
gfx::Insets NativeTextfieldViews::CalculateInsets() {
@@ -275,7 +271,7 @@ gfx::NativeView NativeTextfieldViews::GetTestingHandle() const {
}
bool NativeTextfieldViews::IsIMEComposing() const {
- return false;
+ return model_->HasCompositionText();
}
void NativeTextfieldViews::GetSelectedRange(ui::Range* range) const {
@@ -307,6 +303,7 @@ bool NativeTextfieldViews::HandleKeyReleased(const views::KeyEvent& e) {
void NativeTextfieldViews::HandleFocus() {
is_cursor_visible_ = true;
SchedulePaint();
+ OnCaretBoundsChanged();
// Start blinking cursor.
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
@@ -323,6 +320,10 @@ void NativeTextfieldViews::HandleBlur() {
}
}
+TextInputClient* NativeTextfieldViews::GetTextInputClient() {
+ return textfield_->read_only() ? NULL : this;
+}
+
/////////////////////////////////////////////////////////////////
// NativeTextfieldViews, ui::SimpleMenuModel::Delegate overrides:
@@ -412,7 +413,174 @@ void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) {
///////////////////////////////////////////////////////////////////////////////
-// NativeTextfieldViews private:
+// NativeTextfieldViews, TextInputClient implementation, private:
+
+void NativeTextfieldViews::SetCompositionText(
+ const ui::CompositionText& composition) {
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ model_->SetCompositionText(composition);
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+}
+
+void NativeTextfieldViews::ConfirmCompositionText() {
+ if (!model_->HasCompositionText())
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ model_->ConfirmCompositionText();
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+}
+
+void NativeTextfieldViews::ClearCompositionText() {
+ if (!model_->HasCompositionText())
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ model_->ClearCompositionText();
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+}
+
+void NativeTextfieldViews::InsertText(const string16& text) {
+ // TODO(suzhe): Filter invalid characters.
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || text.empty())
+ return;
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ if (insert_)
+ model_->InsertText(text);
+ else
+ model_->ReplaceText(text);
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+}
+
+void NativeTextfieldViews::InsertChar(char16 ch, int flags) {
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE ||
+ !ShouldInsertChar(ch, flags)) {
+ return;
+ }
+
+ OnBeforeUserAction();
+ skip_input_method_cancel_composition_ = true;
+ if (insert_)
+ model_->InsertChar(ch);
+ else
+ model_->ReplaceChar(ch);
+ skip_input_method_cancel_composition_ = false;
+ UpdateAfterChange(true, true);
+ OnAfterUserAction();
+}
+
+ui::TextInputType NativeTextfieldViews::GetTextInputType() {
+ if (textfield_->read_only() || !textfield_->IsEnabled())
+ return ui::TEXT_INPUT_TYPE_NONE;
+ else if (textfield_->IsPassword())
+ return ui::TEXT_INPUT_TYPE_PASSWORD;
+ return ui::TEXT_INPUT_TYPE_TEXT;
+}
+
+gfx::Rect NativeTextfieldViews::GetCaretBounds() {
+ return cursor_bounds_;
+}
+
+bool NativeTextfieldViews::HasCompositionText() {
+ return model_->HasCompositionText();
+}
+
+bool NativeTextfieldViews::GetTextRange(ui::Range* range) {
+ // We don't allow the input method to retrieve or delete content from a
+ // password box.
+ if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT)
+ return false;
+
+ model_->GetTextRange(range);
+ return true;
+}
+
+bool NativeTextfieldViews::GetCompositionTextRange(ui::Range* range) {
+ if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT)
+ return false;
+
+ model_->GetCompositionTextRange(range);
+ return true;
+}
+
+bool NativeTextfieldViews::GetSelectionRange(ui::Range* range) {
+ if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT)
+ return false;
+
+ model_->GetSelectedRange(range);
+ return true;
+}
+
+bool NativeTextfieldViews::SetSelectionRange(const ui::Range& range) {
+ if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT || !range.IsValid())
+ return false;
+
+ OnBeforeUserAction();
+ SelectRange(range);
+ OnAfterUserAction();
+ return true;
+}
+
+bool NativeTextfieldViews::DeleteRange(const ui::Range& range) {
+ if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT || range.is_empty())
+ return false;
+
+ OnBeforeUserAction();
+ model_->SelectRange(range);
+ if (model_->HasSelection()) {
+ model_->DeleteSelection();
+ UpdateAfterChange(true, true);
+ }
+ OnAfterUserAction();
+ return true;
+}
+
+bool NativeTextfieldViews::GetTextFromRange(
+ const ui::Range& range,
+ const base::Callback<void(const string16&)>& callback) {
+ if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT || range.is_empty())
+ return false;
+
+ callback.Run(model_->GetTextFromRange(range));
+ return true;
+}
+
+void NativeTextfieldViews::OnInputMethodChanged() {
+ NOTIMPLEMENTED();
+}
+
+bool NativeTextfieldViews::ChangeTextDirectionAndLayoutAlignment(
+ base::i18n::TextDirection direction) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+View* NativeTextfieldViews::GetOwnerViewOfTextInputClient() {
+ return textfield_;
+}
+
+void NativeTextfieldViews::OnCompositionTextConfirmedOrCleared() {
+ if (skip_input_method_cancel_composition_)
+ return;
+ DCHECK(textfield_->GetInputMethod());
+ textfield_->GetInputMethod()->CancelComposition(textfield_);
+}
const gfx::Font& NativeTextfieldViews::GetFont() const {
return textfield_->font();
@@ -475,6 +643,8 @@ void NativeTextfieldViews::UpdateCursorBoundsAndTextOffset() {
}
// shift cursor bounds to fit insets.
cursor_bounds_.set_x(cursor_bounds_.x() + text_offset_ + insets.left());
+
+ OnCaretBoundsChanged();
}
void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) {
@@ -501,17 +671,22 @@ void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) {
fragments.begin();
iter != fragments.end();
iter++) {
- string16 text = model_->GetVisibleText((*iter).begin, (*iter).end);
+ string16 text = model_->GetVisibleText(iter->start, iter->end);
+
+ gfx::Font font = GetFont();
+ if (iter->underline)
+ font = font.DeriveFont(0, font.GetStyle() | gfx::Font::UNDERLINED);
+
// TODO(oshima): This does not give the accurate position due to
// kerning. Figure out how webkit does this with skia.
- int width = GetFont().GetStringWidth(text);
+ int width = font.GetStringWidth(text);
- if ((*iter).selected) {
+ if (iter->selected) {
canvas->FillRectInt(selection_color, x_offset, y, width, text_height);
- canvas->DrawStringInt(text, GetFont(), kSelectedTextColor,
+ canvas->DrawStringInt(text, font, kSelectedTextColor,
x_offset, y, width, text_height);
} else {
- canvas->DrawStringInt(text, GetFont(), text_color,
+ canvas->DrawStringInt(text, font, text_color,
x_offset, y, width, text_height);
}
x_offset += width;
@@ -577,7 +752,7 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
cursor_changed = true;
break;
case ui::VKEY_HOME:
- model_->MoveCursorToStart(selection);
+ model_->MoveCursorToHome(selection);
cursor_changed = true;
break;
case ui::VKEY_BACK:
@@ -590,7 +765,7 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
#if defined(OS_WIN)
break;
#else
- model_->MoveCursorToStart(true);
+ model_->MoveCursorToHome(true);
#endif
} else if (control) {
// If only control is pressed, then erase the previous word.
@@ -626,14 +801,9 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
default:
break;
}
- char16 ch = key_event.GetCharacter();
- if (editable && ShouldInsertChar(ch, key_event.flags())) {
- if (insert_)
- model_->Insert(ch);
- else
- model_->Replace(ch);
- text_changed = true;
- }
+
+ // We must have input method in order to support text input.
+ DCHECK(textfield_->GetInputMethod());
UpdateAfterChange(text_changed, cursor_changed);
OnAfterUserAction();
@@ -717,9 +887,6 @@ void NativeTextfieldViews::SetCursorForMouseClick(const views::MouseEvent& e) {
void NativeTextfieldViews::PropagateTextChange() {
textfield_->SyncText();
- TextfieldController* controller = textfield_->GetController();
- if (controller)
- controller->ContentsChanged(textfield_, GetText());
}
void NativeTextfieldViews::UpdateAfterChange(bool text_changed,
@@ -750,6 +917,16 @@ void NativeTextfieldViews::InitContextMenuIfRequired() {
context_menu_menu_.reset(new Menu2(context_menu_contents_.get()));
}
+void NativeTextfieldViews::OnTextInputTypeChanged() {
+ DCHECK(textfield_->GetInputMethod());
+ textfield_->GetInputMethod()->OnTextInputTypeChanged(textfield_);
+}
+
+void NativeTextfieldViews::OnCaretBoundsChanged() {
+ DCHECK(textfield_->GetInputMethod());
+ textfield_->GetInputMethod()->OnCaretBoundsChanged(textfield_);
+}
+
void NativeTextfieldViews::OnBeforeUserAction() {
TextfieldController* controller = textfield_->GetController();
if (controller)
« no previous file with comments | « views/controls/textfield/native_textfield_views.h ('k') | views/controls/textfield/native_textfield_views_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698