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 2a6a4c6666ec62b437c611f807c80d183bf1a388..91dd47d615f97e71ca02d218b01aac4e0db079fe 100644 |
--- a/views/controls/textfield/native_textfield_views.cc |
+++ b/views/controls/textfield/native_textfield_views.cc |
@@ -16,12 +16,12 @@ |
#include "ui/base/range/range.h" |
#include "ui/gfx/canvas.h" |
#include "ui/gfx/insets.h" |
+#include "ui/gfx/render_text.h" |
#include "views/background.h" |
#include "views/border.h" |
#include "views/controls/focusable_border.h" |
#include "views/controls/menu/menu_item_view.h" |
#include "views/controls/menu/menu_model_adapter.h" |
-#include "views/controls/textfield/text_style.h" |
#include "views/controls/textfield/textfield.h" |
#include "views/controls/textfield/textfield_controller.h" |
#include "views/controls/textfield/textfield_views_model.h" |
@@ -37,16 +37,6 @@ |
namespace { |
-// Color settings for text, backgrounds and cursor. |
-// These are tentative, and should be derived from theme, system |
-// settings and current settings. |
-// TODO(oshima): Change this to match the standard chrome |
-// before dogfooding textfield views. |
-const SkColor kSelectedTextColor = SK_ColorWHITE; |
-const SkColor kFocusedSelectionColor = SK_ColorCYAN; |
-const SkColor kUnfocusedSelectionColor = SK_ColorLTGRAY; |
-const SkColor kCursorColor = SK_ColorBLACK; |
- |
// Parameters to control cursor blinking. |
const int kCursorVisibleTimeMs = 800; |
const int kCursorInvisibleTimeMs = 500; |
@@ -62,8 +52,6 @@ NativeTextfieldViews::NativeTextfieldViews(Textfield* parent) |
: textfield_(parent), |
ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TextfieldViewsModel(this))), |
text_border_(new FocusableBorder()), |
- text_offset_(0), |
- insert_(true), |
is_cursor_visible_(false), |
skip_input_method_cancel_composition_(false), |
initiating_drag_(false), |
@@ -76,6 +64,12 @@ NativeTextfieldViews::NativeTextfieldViews(Textfield* parent) |
// Lowercase is not supported. |
DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE); |
+ // Set the default text style. |
+ gfx::StyleRange default_style; |
+ default_style.font = textfield_->font(); |
+ default_style.foreground = textfield_->text_color(); |
+ GetRenderText()->set_default_style(default_style); |
+ |
set_context_menu_controller(this); |
set_drag_controller(this); |
} |
@@ -179,7 +173,8 @@ int NativeTextfieldViews::OnDragUpdated(const DropTargetEvent& event) { |
bool is_point_in_selection = IsPointInSelection(event.location()); |
is_drop_cursor_visible_ = !is_point_in_selection; |
// TODO(msw): Pan over text when the user drags to the visible text edge. |
- UpdateCursorBoundsAndTextOffset(FindCursorPosition(event.location()), true); |
+ size_t cursor_pos = GetRenderText()->FindCursorPosition(event.location()); |
+ OnCaretBoundsChanged(); |
SchedulePaint(); |
if (initiating_drag_) { |
@@ -197,7 +192,8 @@ int NativeTextfieldViews::OnPerformDrop(const DropTargetEvent& event) { |
OnBeforeUserAction(); |
skip_input_method_cancel_composition_ = true; |
- size_t drop_destination = FindCursorPosition(event.location()); |
+ size_t drop_destination = |
+ GetRenderText()->FindCursorPosition(event.location()); |
string16 text; |
event.data().GetString(&text); |
@@ -215,7 +211,7 @@ int NativeTextfieldViews::OnPerformDrop(const DropTargetEvent& event) { |
model_->DeleteSelectionAndInsertTextAt(text, drop_destination); |
} else { |
model_->MoveCursorTo(drop_destination, false); |
- // Drop always inserts a text even if insert_ == false. |
+ // Drop always inserts text even if the textfield is not in insert mode. |
model_->InsertText(text); |
} |
skip_input_method_cancel_composition_ = false; |
@@ -299,12 +295,12 @@ bool NativeTextfieldViews::CanStartDragForView(View* sender, |
// NativeTextfieldViews, NativeTextifieldWrapper overrides: |
string16 NativeTextfieldViews::GetText() const { |
- return model_->text(); |
+ return model_->GetText(); |
} |
void NativeTextfieldViews::UpdateText() { |
model_->SetText(textfield_->text()); |
- UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); |
+ OnCaretBoundsChanged(); |
SchedulePaint(); |
} |
@@ -312,7 +308,7 @@ void NativeTextfieldViews::AppendText(const string16& text) { |
if (text.empty()) |
return; |
model_->Append(text); |
- UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); |
+ OnCaretBoundsChanged(); |
SchedulePaint(); |
} |
@@ -358,12 +354,12 @@ void NativeTextfieldViews::UpdateReadOnly() { |
} |
void NativeTextfieldViews::UpdateFont() { |
- UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); |
+ OnCaretBoundsChanged(); |
} |
void NativeTextfieldViews::UpdateIsPassword() { |
model_->set_is_password(textfield_->IsPassword()); |
- UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); |
+ OnCaretBoundsChanged(); |
SchedulePaint(); |
OnTextInputTypeChanged(); |
} |
@@ -385,7 +381,7 @@ void NativeTextfieldViews::UpdateHorizontalMargins() { |
gfx::Insets inset = GetInsets(); |
text_border_->SetInsets(inset.top(), left, inset.bottom(), right); |
- UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); |
+ OnCaretBoundsChanged(); |
} |
void NativeTextfieldViews::UpdateVerticalMargins() { |
@@ -393,9 +389,8 @@ void NativeTextfieldViews::UpdateVerticalMargins() { |
if (!textfield_->GetVerticalMargins(&top, &bottom)) |
return; |
gfx::Insets inset = GetInsets(); |
- |
text_border_->SetInsets(top, inset.left(), bottom, inset.right()); |
- UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); |
+ OnCaretBoundsChanged(); |
} |
bool NativeTextfieldViews::SetFocus() { |
@@ -421,12 +416,12 @@ void NativeTextfieldViews::GetSelectedRange(ui::Range* range) const { |
void NativeTextfieldViews::SelectRange(const ui::Range& range) { |
model_->SelectRange(range); |
- UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); |
+ OnCaretBoundsChanged(); |
SchedulePaint(); |
} |
size_t NativeTextfieldViews::GetCursorPosition() const { |
- return model_->cursor_pos(); |
+ return model_->GetCursorPosition(); |
} |
bool NativeTextfieldViews::HandleKeyPressed(const KeyEvent& e) { |
@@ -442,6 +437,7 @@ bool NativeTextfieldViews::HandleKeyReleased(const KeyEvent& e) { |
} |
void NativeTextfieldViews::HandleFocus() { |
+ GetRenderText()->set_focused(true); |
is_cursor_visible_ = true; |
SchedulePaint(); |
OnCaretBoundsChanged(); |
@@ -453,6 +449,7 @@ void NativeTextfieldViews::HandleFocus() { |
} |
void NativeTextfieldViews::HandleBlur() { |
+ GetRenderText()->set_focused(false); |
// Stop blinking cursor. |
cursor_timer_.RevokeAll(); |
if (is_cursor_visible_) { |
@@ -536,23 +533,25 @@ void NativeTextfieldViews::ExecuteCommand(int command_id) { |
OnAfterUserAction(); |
} |
-TextStyle* NativeTextfieldViews::CreateTextStyle() { |
- return model_->CreateTextStyle(); |
-} |
- |
-void NativeTextfieldViews::ApplyTextStyle(const TextStyle* style, |
- const ui::Range& range) { |
- model_->ApplyTextStyle(style, range); |
+void NativeTextfieldViews::ApplyStyleRange(const gfx::StyleRange& style) { |
+ GetRenderText()->ApplyStyleRange(style); |
SchedulePaint(); |
} |
-void NativeTextfieldViews::ClearAllTextStyles() { |
- model_->ClearAllTextStyles(); |
+void NativeTextfieldViews::ApplyDefaultStyle() { |
+ GetRenderText()->ApplyDefaultStyle(); |
SchedulePaint(); |
} |
void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) { |
- UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); |
+ // Set the RenderText display area. |
+ gfx::Insets insets = GetInsets(); |
+ gfx::Rect display_rect(insets.left(), |
+ insets.top(), |
+ width() - insets.width(), |
+ height() - insets.height()); |
+ GetRenderText()->set_display_rect(display_rect); |
+ OnCaretBoundsChanged(); |
} |
/////////////////////////////////////////////////////////////////////////////// |
@@ -602,7 +601,7 @@ void NativeTextfieldViews::InsertText(const string16& text) { |
OnBeforeUserAction(); |
skip_input_method_cancel_composition_ = true; |
- if (insert_) |
+ if (GetRenderText()->get_insert_mode()) |
model_->InsertText(text); |
else |
model_->ReplaceText(text); |
@@ -619,7 +618,7 @@ void NativeTextfieldViews::InsertChar(char16 ch, int flags) { |
OnBeforeUserAction(); |
skip_input_method_cancel_composition_ = true; |
- if (insert_) |
+ if (GetRenderText()->get_insert_mode()) |
model_->InsertChar(ch); |
else |
model_->ReplaceChar(ch); |
@@ -637,7 +636,9 @@ ui::TextInputType NativeTextfieldViews::GetTextInputType() { |
} |
gfx::Rect NativeTextfieldViews::GetCaretBounds() { |
- return cursor_bounds_; |
+ gfx::RenderText* render_text = GetRenderText(); |
+ return render_text->GetCursorBounds(render_text->GetCursor(), |
+ render_text->get_insert_mode()); |
} |
bool NativeTextfieldViews::HasCompositionText() { |
@@ -725,12 +726,8 @@ void NativeTextfieldViews::OnCompositionTextConfirmedOrCleared() { |
textfield_->GetInputMethod()->CancelComposition(textfield_); |
} |
-const gfx::Font& NativeTextfieldViews::GetFont() const { |
- return textfield_->font(); |
-} |
- |
-SkColor NativeTextfieldViews::GetTextColor() const { |
- return textfield_->text_color(); |
+gfx::RenderText* NativeTextfieldViews::GetRenderText() const { |
+ return model_->get_render_text(); |
} |
void NativeTextfieldViews::UpdateCursor() { |
@@ -743,108 +740,18 @@ void NativeTextfieldViews::UpdateCursor() { |
} |
void NativeTextfieldViews::RepaintCursor() { |
- gfx::Rect r = cursor_bounds_; |
+ gfx::Rect r(GetCaretBounds()); |
r.Inset(-1, -1, -1, -1); |
SchedulePaintInRect(r); |
} |
-gfx::Rect NativeTextfieldViews::GetCursorBounds(size_t cursor_pos, |
- bool insert_mode) const { |
- string16 text = model_->GetVisibleText(); |
- const gfx::Font& font = GetFont(); |
- int x = font.GetStringWidth(text.substr(0U, cursor_pos)); |
- DCHECK_GE(x, 0); |
- int h = std::min(height() - GetInsets().height(), font.GetHeight()); |
- gfx::Rect bounds(x, (height() - h) / 2, 0, h); |
- if (!insert_mode && text.length() != cursor_pos) |
- bounds.set_width(font.GetStringWidth(text.substr(0, cursor_pos + 1)) - x); |
- return bounds; |
-} |
- |
- |
-void NativeTextfieldViews::UpdateCursorBoundsAndTextOffset(size_t cursor_pos, |
- bool insert_mode) { |
- if (bounds().IsEmpty()) |
- return; |
- |
- // TODO(oshima): bidi |
- int width = bounds().width() - GetInsets().width(); |
- int full_width = GetFont().GetStringWidth(model_->GetVisibleText()); |
- cursor_bounds_ = GetCursorBounds(cursor_pos, insert_mode); |
- |
- if (full_width < width) { |
- // Show all text whenever the text fits to the size. |
- text_offset_ = 0; |
- } else if ((text_offset_ + cursor_bounds_.right()) > width) { |
- // when the cursor overflows to the right |
- text_offset_ = width - cursor_bounds_.right(); |
- } else if ((text_offset_ + cursor_bounds_.x()) < 0) { |
- // when the cursor overflows to the left |
- text_offset_ = -cursor_bounds_.x(); |
- } else if (full_width > width && text_offset_ + full_width < width) { |
- // when the cursor moves within the textfield with the text |
- // longer than the field. |
- text_offset_ = width - full_width; |
- } else { |
- // move cursor freely. |
- } |
- // shift cursor bounds to fit insets. |
- cursor_bounds_.set_x(cursor_bounds_.x() + text_offset_ + GetInsets().left()); |
- |
- OnCaretBoundsChanged(); |
-} |
- |
void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) { |
- gfx::Insets insets = GetInsets(); |
- |
canvas->Save(); |
- canvas->ClipRectInt(insets.left(), insets.top(), |
- width() - insets.width(), height() - insets.height()); |
- |
- // TODO(oshima): bidi support |
- // TODO(varunjain): re-implement this so only that dirty text is painted. |
- TextfieldViewsModel::TextFragments fragments; |
- model_->GetFragments(&fragments); |
- int x_offset = text_offset_ + insets.left(); |
- int y = insets.top(); |
- int text_height = height() - insets.height(); |
- SkColor selection_color = |
- textfield_->HasFocus() ? |
- kFocusedSelectionColor : kUnfocusedSelectionColor; |
- gfx::Font font = GetFont(); |
- gfx::Rect selection_bounds = model_->GetSelectionBounds(font); |
- |
- if (!selection_bounds.IsEmpty()) { |
- canvas->FillRectInt(selection_color, |
- x_offset + selection_bounds.x(), |
- (height() - selection_bounds.height()) / 2, |
- selection_bounds.width(), |
- selection_bounds.height()); |
- } |
- |
- for (TextfieldViewsModel::TextFragments::const_iterator iter = |
- fragments.begin(); |
- iter != fragments.end(); |
- iter++) { |
- string16 text = model_->GetVisibleText(iter->range.start(), |
- iter->range.end()); |
- // TODO(oshima): This does not give the accurate position due to |
- // kerning. Figure out how to do. |
- int width = font.GetStringWidth(text); |
- iter->style->DrawString(canvas, text, font, textfield_->read_only(), |
- x_offset, y, width, text_height); |
- x_offset += width; |
- } |
+ GetRenderText()->set_cursor_visible(is_drop_cursor_visible_ || |
+ (is_cursor_visible_ && !model_->HasSelection())); |
+ // Draw the text, cursor, and selection. |
+ GetRenderText()->Draw(canvas); |
canvas->Restore(); |
- |
- // Paint cursor. Replace cursor is drawn as rectangle for now. |
- if (textfield_->IsEnabled() && (is_drop_cursor_visible_ || |
- (is_cursor_visible_ && !model_->HasSelection()))) |
- canvas->DrawRectInt(kCursorColor, |
- cursor_bounds_.x(), |
- cursor_bounds_.y(), |
- cursor_bounds_.width(), |
- cursor_bounds_.height()); |
} |
bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { |
@@ -889,21 +796,21 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { |
cursor_changed = text_changed = Paste(); |
break; |
case ui::VKEY_RIGHT: |
- control ? model_->MoveCursorToNextWord(selection) |
+ control ? model_->MoveCursorRightByWord(selection) |
: model_->MoveCursorRight(selection); |
cursor_changed = true; |
break; |
case ui::VKEY_LEFT: |
- control ? model_->MoveCursorToPreviousWord(selection) |
+ control ? model_->MoveCursorLeftByWord(selection) |
: model_->MoveCursorLeft(selection); |
cursor_changed = true; |
break; |
case ui::VKEY_END: |
- model_->MoveCursorToEnd(selection); |
+ model_->MoveCursorToRightEnd(selection); |
cursor_changed = true; |
break; |
case ui::VKEY_HOME: |
- model_->MoveCursorToHome(selection); |
+ model_->MoveCursorToLeftEnd(selection); |
cursor_changed = true; |
break; |
case ui::VKEY_BACK: |
@@ -916,11 +823,11 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { |
#if defined(OS_WIN) |
break; |
#else |
- model_->MoveCursorToHome(true); |
+ model_->MoveCursorToLeftEnd(true); |
#endif |
} else if (control) { |
// If only control is pressed, then erase the previous word. |
- model_->MoveCursorToPreviousWord(true); |
+ model_->MoveCursorLeftByWord(true); |
} |
} |
text_changed = model_->Backspace(); |
@@ -936,17 +843,17 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { |
#if defined(OS_WIN) |
break; |
#else |
- model_->MoveCursorToEnd(true); |
+ model_->MoveCursorToRightEnd(true); |
#endif |
} else if (control) { |
// If only control is pressed, then erase the next word. |
- model_->MoveCursorToNextWord(true); |
+ model_->MoveCursorRightByWord(true); |
} |
} |
cursor_changed = text_changed = model_->Delete(); |
break; |
case ui::VKEY_INSERT: |
- insert_ = !insert_; |
+ GetRenderText()->set_insert_mode(!GetRenderText()->get_insert_mode()); |
oshima
2011/07/15 21:21:36
may be flip_insert_mode() is simpler.
msw
2011/07/19 07:11:22
Done.
|
cursor_changed = true; |
break; |
default: |
@@ -963,49 +870,17 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { |
return false; |
} |
-size_t NativeTextfieldViews::FindCursorPosition(const gfx::Point& point) const { |
- // TODO(oshima): BIDI/i18n support. |
- gfx::Font font = GetFont(); |
- gfx::Insets insets = GetInsets(); |
- string16 text = model_->GetVisibleText(); |
- int left = 0; |
- int left_pos = 0; |
- int right = font.GetStringWidth(text); |
- int right_pos = text.length(); |
- |
- int x = point.x() - insets.left() - text_offset_; |
- if (x <= left) return left_pos; |
- if (x >= right) return right_pos; |
- // binary searching the cursor position. |
- // TODO(oshima): use the center of character instead of edge. |
- // Binary search may not work for language like arabic. |
- while (std::abs(static_cast<long>(right_pos - left_pos) > 1)) { |
- int pivot_pos = left_pos + (right_pos - left_pos) / 2; |
- int pivot = font.GetStringWidth(text.substr(0, pivot_pos)); |
- if (pivot < x) { |
- left = pivot; |
- left_pos = pivot_pos; |
- } else if (pivot == x) { |
- return pivot_pos; |
- } else { |
- right = pivot; |
- right_pos = pivot_pos; |
- } |
- } |
- return left_pos; |
-} |
- |
bool NativeTextfieldViews::IsPointInSelection(const gfx::Point& point) const { |
ui::Range range; |
GetSelectedRange(&range); |
- size_t pos = FindCursorPosition(point); |
+ size_t pos = GetRenderText()->FindCursorPosition(point); |
return (pos >= range.GetMin() && pos < range.GetMax()); |
} |
bool NativeTextfieldViews::MoveCursorTo(const gfx::Point& point, bool select) { |
- size_t pos = FindCursorPosition(point); |
+ size_t pos = GetRenderText()->FindCursorPosition(point); |
if (model_->MoveCursorTo(pos, select)) { |
- UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); |
+ OnCaretBoundsChanged(); |
return true; |
} |
return false; |
@@ -1024,7 +899,7 @@ void NativeTextfieldViews::UpdateAfterChange(bool text_changed, |
RepaintCursor(); |
} |
if (text_changed || cursor_changed) { |
- UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); |
+ OnCaretBoundsChanged(); |
SchedulePaint(); |
} |
} |
@@ -1078,7 +953,7 @@ bool NativeTextfieldViews::Paste() { |
// Calls TextfieldController::ContentsChanged() explicitly if the paste action |
// did not change the content at all. See http://crbug.com/79002 |
- if (success && model_->text() == textfield_->text()) { |
+ if (success && GetText() == textfield_->text()) { |
TextfieldController* controller = textfield_->GetController(); |
if (controller) |
controller->ContentsChanged(textfield_, textfield_->text()); |