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

Unified Diff: views/controls/textfield/native_textfield_views.cc

Issue 7265011: RenderText API Outline. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Almost at parity with the current implementation. Created 9 years, 5 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 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());

Powered by Google App Engine
This is Rietveld 408576698