summaryrefslogtreecommitdiffstats
path: root/views/controls
diff options
context:
space:
mode:
authormsw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-25 05:11:57 +0000
committermsw@chromium.org <msw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-25 05:11:57 +0000
commit689d9d0d463d2b2f622a0cd74d79d1b60f432fc1 (patch)
tree9641f9d6b5fffa1d8a477a0dbfd6caeddd0772d6 /views/controls
parent906625821f97a508d76810fba7b9641335f68b51 (diff)
downloadchromium_src-689d9d0d463d2b2f622a0cd74d79d1b60f432fc1.zip
chromium_src-689d9d0d463d2b2f622a0cd74d79d1b60f432fc1.tar.gz
chromium_src-689d9d0d463d2b2f622a0cd74d79d1b60f432fc1.tar.bz2
Add gfx::RenderText and support code.
RenderText is NativeTextFieldViews' interface to platform-specific text rendering engines. This change doesn't hook in any new Pango or Uniscribe functionality, it will just setup the necessary API. Review URL: http://codereview.chromium.org/7265011 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@93840 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views/controls')
-rw-r--r--views/controls/textfield/native_textfield_gtk.cc10
-rw-r--r--views/controls/textfield/native_textfield_gtk.h6
-rw-r--r--views/controls/textfield/native_textfield_views.cc295
-rw-r--r--views/controls/textfield/native_textfield_views.h32
-rw-r--r--views/controls/textfield/native_textfield_views_unittest.cc10
-rw-r--r--views/controls/textfield/native_textfield_win.cc10
-rw-r--r--views/controls/textfield/native_textfield_win.h6
-rw-r--r--views/controls/textfield/native_textfield_wrapper.h17
-rw-r--r--views/controls/textfield/text_style.cc54
-rw-r--r--views/controls/textfield/text_style.h65
-rw-r--r--views/controls/textfield/textfield.cc14
-rw-r--r--views/controls/textfield/textfield.h31
-rw-r--r--views/controls/textfield/textfield_views_model.cc522
-rw-r--r--views/controls/textfield/textfield_views_model.h122
-rw-r--r--views/controls/textfield/textfield_views_model_unittest.cc922
15 files changed, 581 insertions, 1535 deletions
diff --git a/views/controls/textfield/native_textfield_gtk.cc b/views/controls/textfield/native_textfield_gtk.cc
index 78fb2f9..3d799a8 100644
--- a/views/controls/textfield/native_textfield_gtk.cc
+++ b/views/controls/textfield/native_textfield_gtk.cc
@@ -283,17 +283,11 @@ TextInputClient* NativeTextfieldGtk::GetTextInputClient() {
return NULL;
}
-TextStyle* NativeTextfieldGtk::CreateTextStyle() {
- NOTREACHED();
- return NULL;
-}
-
-void NativeTextfieldGtk::ApplyTextStyle(const TextStyle* style,
- const ui::Range& range) {
+void NativeTextfieldGtk::ApplyStyleRange(const gfx::StyleRange& style) {
NOTREACHED();
}
-void NativeTextfieldGtk::ClearAllTextStyles() {
+void NativeTextfieldGtk::ApplyDefaultStyle() {
NOTREACHED();
}
diff --git a/views/controls/textfield/native_textfield_gtk.h b/views/controls/textfield/native_textfield_gtk.h
index 92b4e36..8420fcb 100644
--- a/views/controls/textfield/native_textfield_gtk.h
+++ b/views/controls/textfield/native_textfield_gtk.h
@@ -57,10 +57,8 @@ class NativeTextfieldGtk : public NativeControlGtk,
virtual void HandleFocus() OVERRIDE;
virtual void HandleBlur() OVERRIDE;
virtual TextInputClient* GetTextInputClient() OVERRIDE;
- virtual TextStyle* CreateTextStyle() OVERRIDE;
- virtual void ApplyTextStyle(const TextStyle* style,
- const ui::Range& range) OVERRIDE;
- virtual void ClearAllTextStyles() OVERRIDE;
+ virtual void ApplyStyleRange(const gfx::StyleRange& style) OVERRIDE;
+ virtual void ApplyDefaultStyle() OVERRIDE;
virtual void ClearEditHistory() OVERRIDE;
// Overridden from NativeControlGtk:
diff --git a/views/controls/textfield/native_textfield_views.cc b/views/controls/textfield/native_textfield_views.cc
index adc6288..b3f005d 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,15 +37,8 @@
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;
+// Text color for read only.
+const SkColor kReadonlyTextColor = SK_ColorDKGRAY;
// Parameters to control cursor blinking.
const int kCursorVisibleTimeMs = 800;
@@ -62,9 +55,8 @@ 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),
+ is_drop_cursor_visible_(false),
skip_input_method_cancel_composition_(false),
initiating_drag_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(cursor_timer_(this)),
@@ -76,6 +68,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);
}
@@ -105,7 +103,7 @@ bool NativeTextfieldViews::OnMousePressed(const MouseEvent& event) {
initiating_drag_ = false;
switch(aggregated_clicks_) {
case 0:
- if (!IsPointInSelection(event.location()))
+ if (!GetRenderText()->IsPointInSelection(event.location()))
MoveCursorTo(event.location(), event.IsShiftDown());
else
initiating_drag_ = true;
@@ -176,14 +174,14 @@ bool NativeTextfieldViews::CanDrop(const OSExchangeData& data) {
int NativeTextfieldViews::OnDragUpdated(const DropTargetEvent& event) {
DCHECK(CanDrop(event.data()));
- bool is_point_in_selection = IsPointInSelection(event.location());
- is_drop_cursor_visible_ = !is_point_in_selection;
+ bool in_selection = GetRenderText()->IsPointInSelection(event.location());
+ is_drop_cursor_visible_ = !in_selection;
// TODO(msw): Pan over text when the user drags to the visible text edge.
- UpdateCursorBoundsAndTextOffset(FindCursorPosition(event.location()), true);
+ OnCaretBoundsChanged();
SchedulePaint();
if (initiating_drag_) {
- if (is_point_in_selection)
+ if (in_selection)
return ui::DragDropTypes::DRAG_NONE;
return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY :
ui::DragDropTypes::DRAG_MOVE;
@@ -193,11 +191,14 @@ int NativeTextfieldViews::OnDragUpdated(const DropTargetEvent& event) {
int NativeTextfieldViews::OnPerformDrop(const DropTargetEvent& event) {
DCHECK(CanDrop(event.data()));
- DCHECK(!initiating_drag_ || !IsPointInSelection(event.location()));
+ DCHECK(!initiating_drag_ ||
+ !GetRenderText()->IsPointInSelection(event.location()));
OnBeforeUserAction();
skip_input_method_cancel_composition_ = true;
- size_t drop_destination = FindCursorPosition(event.location());
+ // TODO(msw): Remove final reference to FindCursorPosition.
+ size_t drop_destination =
+ GetRenderText()->FindCursorPosition(event.location());
string16 text;
event.data().GetString(&text);
@@ -215,7 +216,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;
@@ -246,14 +247,15 @@ void NativeTextfieldViews::OnBlur() {
}
gfx::NativeCursor NativeTextfieldViews::GetCursor(const MouseEvent& event) {
- bool text = !initiating_drag_ && (event.type() == ui::ET_MOUSE_DRAGGED ||
- !IsPointInSelection(event.location()));
+ bool in_selection = GetRenderText()->IsPointInSelection(event.location());
+ bool drag_event = event.type() == ui::ET_MOUSE_DRAGGED;
+ bool text_cursor = !initiating_drag_ && (drag_event || !in_selection);
#if defined(OS_WIN)
static HCURSOR ibeam = LoadCursor(NULL, IDC_IBEAM);
static HCURSOR arrow = LoadCursor(NULL, IDC_ARROW);
- return text ? ibeam : arrow;
+ return text_cursor ? ibeam : arrow;
#else
- return text ? gfx::GetCursor(GDK_XTERM) : NULL;
+ return text_cursor ? gfx::GetCursor(GDK_XTERM) : NULL;
#endif
}
@@ -282,7 +284,7 @@ void NativeTextfieldViews::WriteDragDataForView(views::View* sender,
int NativeTextfieldViews::GetDragOperationsForView(views::View* sender,
const gfx::Point& p) {
- if (!textfield_->IsEnabled() || !IsPointInSelection(p))
+ if (!textfield_->IsEnabled() || !GetRenderText()->IsPointInSelection(p))
return ui::DragDropTypes::DRAG_NONE;
if (sender == this && !textfield_->read_only())
return ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY;
@@ -292,19 +294,19 @@ int NativeTextfieldViews::GetDragOperationsForView(views::View* sender,
bool NativeTextfieldViews::CanStartDragForView(View* sender,
const gfx::Point& press_pt,
const gfx::Point& p) {
- return IsPointInSelection(press_pt);
+ return GetRenderText()->IsPointInSelection(press_pt);
}
/////////////////////////////////////////////////////////////////
// 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 +314,7 @@ void NativeTextfieldViews::AppendText(const string16& text) {
if (text.empty())
return;
model_->Append(text);
- UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_);
+ OnCaretBoundsChanged();
SchedulePaint();
}
@@ -353,17 +355,24 @@ void NativeTextfieldViews::UpdateBackgroundColor() {
}
void NativeTextfieldViews::UpdateReadOnly() {
+ // Update the default text style.
+ gfx::StyleRange default_style(GetRenderText()->default_style());
+ default_style.foreground = textfield_->read_only() ? kReadonlyTextColor :
+ textfield_->text_color();
+ GetRenderText()->set_default_style(default_style);
+ GetRenderText()->ApplyDefaultStyle();
+
SchedulePaint();
OnTextInputTypeChanged();
}
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 +394,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 +402,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 +429,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 +450,7 @@ bool NativeTextfieldViews::HandleKeyReleased(const KeyEvent& e) {
}
void NativeTextfieldViews::HandleFocus() {
+ GetRenderText()->set_focused(true);
is_cursor_visible_ = true;
SchedulePaint();
OnCaretBoundsChanged();
@@ -453,6 +462,7 @@ void NativeTextfieldViews::HandleFocus() {
}
void NativeTextfieldViews::HandleBlur() {
+ GetRenderText()->set_focused(false);
// Stop blinking cursor.
cursor_timer_.RevokeAll();
if (is_cursor_visible_) {
@@ -536,23 +546,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 +614,7 @@ void NativeTextfieldViews::InsertText(const string16& text) {
OnBeforeUserAction();
skip_input_method_cancel_composition_ = true;
- if (insert_)
+ if (GetRenderText()->insert_mode())
model_->InsertText(text);
else
model_->ReplaceText(text);
@@ -619,7 +631,7 @@ void NativeTextfieldViews::InsertChar(char16 ch, int flags) {
OnBeforeUserAction();
skip_input_method_cancel_composition_ = true;
- if (insert_)
+ if (GetRenderText()->insert_mode())
model_->InsertChar(ch);
else
model_->ReplaceChar(ch);
@@ -637,7 +649,9 @@ ui::TextInputType NativeTextfieldViews::GetTextInputType() {
}
gfx::Rect NativeTextfieldViews::GetCaretBounds() {
- return cursor_bounds_;
+ gfx::RenderText* render_text = GetRenderText();
+ return render_text->GetCursorBounds(render_text->GetCursorPosition(),
+ render_text->insert_mode());
}
bool NativeTextfieldViews::HasCompositionText() {
@@ -725,12 +739,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_->render_text();
}
void NativeTextfieldViews::UpdateCursor() {
@@ -743,108 +753,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 +809,21 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
cursor_changed = text_changed = Paste();
break;
case ui::VKEY_RIGHT:
- control ? model_->MoveCursorToNextWord(selection)
- : model_->MoveCursorRight(selection);
+ model_->MoveCursorRight(
+ control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK, selection);
cursor_changed = true;
break;
case ui::VKEY_LEFT:
- control ? model_->MoveCursorToPreviousWord(selection)
- : model_->MoveCursorLeft(selection);
+ model_->MoveCursorLeft(
+ control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK, selection);
cursor_changed = true;
break;
case ui::VKEY_END:
- model_->MoveCursorToEnd(selection);
+ model_->MoveCursorRight(gfx::LINE_BREAK, selection);
cursor_changed = true;
break;
case ui::VKEY_HOME:
- model_->MoveCursorToHome(selection);
+ model_->MoveCursorLeft(gfx::LINE_BREAK, selection);
cursor_changed = true;
break;
case ui::VKEY_BACK:
@@ -916,11 +836,11 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
#if defined(OS_WIN)
break;
#else
- model_->MoveCursorToHome(true);
+ model_->MoveCursorLeft(gfx::LINE_BREAK, true);
#endif
} else if (control) {
// If only control is pressed, then erase the previous word.
- model_->MoveCursorToPreviousWord(true);
+ model_->MoveCursorLeft(gfx::WORD_BREAK, true);
}
}
text_changed = model_->Backspace();
@@ -936,17 +856,17 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
#if defined(OS_WIN)
break;
#else
- model_->MoveCursorToEnd(true);
+ model_->MoveCursorRight(gfx::LINE_BREAK, true);
#endif
} else if (control) {
// If only control is pressed, then erase the next word.
- model_->MoveCursorToNextWord(true);
+ model_->MoveCursorRight(gfx::WORD_BREAK, true);
}
}
cursor_changed = text_changed = model_->Delete();
break;
case ui::VKEY_INSERT:
- insert_ = !insert_;
+ GetRenderText()->toggle_insert_mode();
cursor_changed = true;
break;
default:
@@ -963,52 +883,11 @@ 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);
- return (pos >= range.GetMin() && pos < range.GetMax());
-}
-
bool NativeTextfieldViews::MoveCursorTo(const gfx::Point& point, bool select) {
- size_t pos = FindCursorPosition(point);
- if (model_->MoveCursorTo(pos, select)) {
- UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_);
- return true;
- }
- return false;
+ if (!model_->MoveCursorTo(point, select))
+ return false;
+ OnCaretBoundsChanged();
+ return true;
}
void NativeTextfieldViews::PropagateTextChange() {
@@ -1024,7 +903,7 @@ void NativeTextfieldViews::UpdateAfterChange(bool text_changed,
RepaintCursor();
}
if (text_changed || cursor_changed) {
- UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_);
+ OnCaretBoundsChanged();
SchedulePaint();
}
}
@@ -1078,7 +957,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());
diff --git a/views/controls/textfield/native_textfield_views.h b/views/controls/textfield/native_textfield_views.h
index 4851549..ea6fec8 100644
--- a/views/controls/textfield/native_textfield_views.h
+++ b/views/controls/textfield/native_textfield_views.h
@@ -114,10 +114,8 @@ class NativeTextfieldViews : public View,
virtual void HandleFocus() OVERRIDE;
virtual void HandleBlur() OVERRIDE;
virtual TextInputClient* GetTextInputClient() OVERRIDE;
- virtual TextStyle* CreateTextStyle() OVERRIDE;
- virtual void ApplyTextStyle(const TextStyle* style,
- const ui::Range& range) OVERRIDE;
- virtual void ClearAllTextStyles() OVERRIDE;
+ virtual void ApplyStyleRange(const gfx::StyleRange& style) OVERRIDE;
+ virtual void ApplyDefaultStyle() OVERRIDE;
virtual void ClearEditHistory() OVERRIDE;
// ui::SimpleMenuModel::Delegate overrides
@@ -164,11 +162,8 @@ class NativeTextfieldViews : public View,
// Overridden from TextfieldViewsModel::Delegate:
virtual void OnCompositionTextConfirmedOrCleared() OVERRIDE;
- // Returns the Textfield's font.
- const gfx::Font& GetFont() const;
-
- // Returns the Textfield's text color.
- SkColor GetTextColor() const;
+ // Returns the TextfieldViewsModel's text/cursor/selection rendering model.
+ gfx::RenderText* GetRenderText() const;
// A callback function to periodically update the cursor state.
void UpdateCursor();
@@ -176,9 +171,6 @@ class NativeTextfieldViews : public View,
// Repaint the cursor.
void RepaintCursor();
- // Returns the bounds of character at the current cursor.
- gfx::Rect GetCursorBounds(size_t cursor_pos, bool insert_mode) const;
-
// Update the cursor_bounds and text_offset.
void UpdateCursorBoundsAndTextOffset(size_t cursor_pos, bool insert_mode);
@@ -187,12 +179,6 @@ class NativeTextfieldViews : public View,
// Handle the keyevent.
bool HandleKeyEvent(const KeyEvent& key_event);
- // Find a cusor position for given |point| in this views coordinates.
- size_t FindCursorPosition(const gfx::Point& point) const;
-
- // Returns true if the local point is over the selected range of text.
- bool IsPointInSelection(const gfx::Point& point) const;
-
// Helper function to call MoveCursorTo on the TextfieldViewsModel.
bool MoveCursorTo(const gfx::Point& point, bool select);
@@ -236,16 +222,8 @@ class NativeTextfieldViews : public View,
// The reference to the border class. The object is owned by View::border_.
FocusableBorder* text_border_;
- // The x offset for the text to be drawn, without insets;
- int text_offset_;
-
- // True if the textfield is in insert mode.
- bool insert_;
-
- // The local bounds and visibility of the textfield's text cursor.
- gfx::Rect cursor_bounds_;
+ // The textfield's text and drop cursor visibility.
bool is_cursor_visible_;
-
// The drop cursor is a visual cue for where dragged text will be dropped.
bool is_drop_cursor_visible_;
diff --git a/views/controls/textfield/native_textfield_views_unittest.cc b/views/controls/textfield/native_textfield_views_unittest.cc
index 31a5e51..0c8ec2e 100644
--- a/views/controls/textfield/native_textfield_views_unittest.cc
+++ b/views/controls/textfield/native_textfield_views_unittest.cc
@@ -15,6 +15,7 @@
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/keycodes/keyboard_codes.h"
+#include "ui/gfx/render_text.h"
#include "views/controls/textfield/native_textfield_views.h"
#include "views/controls/textfield/textfield.h"
#include "views/controls/textfield/textfield_controller.h"
@@ -218,9 +219,8 @@ class NativeTextfieldViewsTest : public ViewsTestBase,
}
int GetCursorPositionX(int cursor_pos) {
- const string16 text = textfield_->text().substr(0, cursor_pos);
- return textfield_view_->GetInsets().left() + textfield_view_->text_offset_ +
- textfield_view_->GetFont().GetStringWidth(text);
+ gfx::RenderText* render_text = textfield_view_->GetRenderText();
+ return render_text->GetCursorBounds(cursor_pos, false).x();
}
// We need widget to populate wrapper class.
@@ -254,12 +254,12 @@ TEST_F(NativeTextfieldViewsTest, ModelChangesTest) {
last_contents_.clear();
textfield_->SetText(ASCIIToUTF16("this is"));
- EXPECT_STR_EQ("this is", model_->text());
+ EXPECT_STR_EQ("this is", model_->GetText());
EXPECT_STR_EQ("this is", textfield_->text());
EXPECT_TRUE(last_contents_.empty());
textfield_->AppendText(ASCIIToUTF16(" a test"));
- EXPECT_STR_EQ("this is a test", model_->text());
+ EXPECT_STR_EQ("this is a test", model_->GetText());
EXPECT_STR_EQ("this is a test", textfield_->text());
EXPECT_TRUE(last_contents_.empty());
diff --git a/views/controls/textfield/native_textfield_win.cc b/views/controls/textfield/native_textfield_win.cc
index f53e67b..97e876d6 100644
--- a/views/controls/textfield/native_textfield_win.cc
+++ b/views/controls/textfield/native_textfield_win.cc
@@ -367,17 +367,11 @@ TextInputClient* NativeTextfieldWin::GetTextInputClient() {
return NULL;
}
-TextStyle* NativeTextfieldWin::CreateTextStyle() {
- NOTREACHED();
- return NULL;
-}
-
-void NativeTextfieldWin::ApplyTextStyle(const TextStyle* style,
- const ui::Range& range) {
+void NativeTextfieldWin::ApplyStyleRange(const gfx::StyleRange& style) {
NOTREACHED();
}
-void NativeTextfieldWin::ClearAllTextStyles() {
+void NativeTextfieldWin::ApplyDefaultStyle() {
NOTREACHED();
}
diff --git a/views/controls/textfield/native_textfield_win.h b/views/controls/textfield/native_textfield_win.h
index bb0fc2b..ceabb34 100644
--- a/views/controls/textfield/native_textfield_win.h
+++ b/views/controls/textfield/native_textfield_win.h
@@ -86,10 +86,8 @@ class NativeTextfieldWin
virtual void HandleFocus() OVERRIDE;
virtual void HandleBlur() OVERRIDE;
virtual TextInputClient* GetTextInputClient() OVERRIDE;
- virtual TextStyle* CreateTextStyle() OVERRIDE;
- virtual void ApplyTextStyle(const TextStyle* style,
- const ui::Range& range) OVERRIDE;
- virtual void ClearAllTextStyles() OVERRIDE;
+ virtual void ApplyStyleRange(const gfx::StyleRange& style) OVERRIDE;
+ virtual void ApplyDefaultStyle() OVERRIDE;
virtual void ClearEditHistory() OVERRIDE;
// Overridden from ui::SimpleMenuModel::Delegate:
diff --git a/views/controls/textfield/native_textfield_wrapper.h b/views/controls/textfield/native_textfield_wrapper.h
index 8d694eb..6cef09f 100644
--- a/views/controls/textfield/native_textfield_wrapper.h
+++ b/views/controls/textfield/native_textfield_wrapper.h
@@ -11,6 +11,7 @@
namespace gfx {
class Insets;
+struct StyleRange;
} // namespace gfx
namespace ui {
@@ -22,7 +23,6 @@ namespace views {
class KeyEvent;
class Textfield;
class TextInputClient;
-class TextStyle;
class View;
// An interface implemented by an object that provides a platform-native
@@ -126,17 +126,12 @@ class NativeTextfieldWrapper {
// support text input.
virtual TextInputClient* GetTextInputClient() = 0;
- // Creates a new TextStyle for this textfield.
- // See |Textfield::CreateTextStyle| for detail.
- virtual TextStyle* CreateTextStyle() = 0;
+ // Applies the |style| to the text specified by its range.
+ // See |Textfield::ApplyStyleRange| for detail.
+ virtual void ApplyStyleRange(const gfx::StyleRange& style) = 0;
- // Applies the |style| to the text specified by the |range|.
- // See |Textfield::ApplyTextStyle| for detail.
- virtual void ApplyTextStyle(const TextStyle* style,
- const ui::Range& range) = 0;
-
- // Clears all text styles in this textfield.
- virtual void ClearAllTextStyles() = 0;
+ // Applies the default style to the textfield.
+ virtual void ApplyDefaultStyle() = 0;
// Clears Edit history.
virtual void ClearEditHistory() = 0;
diff --git a/views/controls/textfield/text_style.cc b/views/controls/textfield/text_style.cc
deleted file mode 100644
index 18400c6..0000000
--- a/views/controls/textfield/text_style.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "views/controls/textfield/text_style.h"
-
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/canvas_skia.h"
-#include "ui/gfx/font.h"
-
-namespace {
-// Text color for read only.
-const SkColor kReadonlyTextColor = SK_ColorDKGRAY;
-
-// Strike line width.
-const int kStrikeWidth = 2;
-}
-
-namespace views {
-
-TextStyle::TextStyle()
- : foreground_(SK_ColorBLACK),
- strike_(false),
- underline_(false) {
-}
-
-TextStyle::~TextStyle() {
-}
-
-void TextStyle::DrawString(gfx::Canvas* canvas,
- string16& text,
- gfx::Font& base_font,
- bool readonly,
- int x, int y, int width, int height) const {
- SkColor text_color = readonly ? kReadonlyTextColor : foreground_;
-
- gfx::Font font = underline_ ?
- base_font.DeriveFont(0, base_font.GetStyle() | gfx::Font::UNDERLINED) :
- base_font;
- canvas->DrawStringInt(text, font, text_color, x, y, width, height);
- if (strike_) {
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(text_color);
- paint.setStrokeWidth(kStrikeWidth);
- canvas->AsCanvasSkia()->drawLine(
- SkIntToScalar(x), SkIntToScalar(y + height),
- SkIntToScalar(x + width), SkIntToScalar(y),
- paint);
- }
-}
-
-} // namespace views
diff --git a/views/controls/textfield/text_style.h b/views/controls/textfield/text_style.h
deleted file mode 100644
index e489aee..0000000
--- a/views/controls/textfield/text_style.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef VIEWS_CONTROLS_TEXTFIELD_TEXT_STYLE_H_
-#define VIEWS_CONTROLS_TEXTFIELD_TEXT_STYLE_H_
-#pragma once
-
-#include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
-#include "base/string16.h"
-#include "third_party/skia/include/core/SkColor.h"
-
-namespace gfx {
-class Canvas;
-class Font;
-}
-
-namespace views {
-
-// A class that specifies text style for TextfieldViews.
-// TODO(suzhe|oshima): support underline color and thick style.
-class TextStyle {
- public:
- // Foreground color for the text.
- void set_foreground(SkColor color) { foreground_ = color; }
-
- // Draws diagnoal strike acrosss the text.
- void set_strike(bool strike) { strike_ = strike; }
-
- // Adds underline to the text.
- void set_underline(bool underline) { underline_ = underline; }
-
- private:
- friend class NativeTextfieldViews;
- friend class TextfieldViewsModel;
-
- FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, TextStyleTest);
- FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_CompositionText);
- FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, CompositionTextTest);
-
- TextStyle();
- virtual ~TextStyle();
-
- SkColor foreground() const { return foreground_; }
- bool underline() const { return underline_; }
-
- // Draw string to the canvas within the region given
- // by |x|,|y|,|width|,|height|.
- void DrawString(gfx::Canvas* canvas,
- string16& text,
- gfx::Font& base_font,
- bool read_only,
- int x, int y, int width, int height) const;
-
- SkColor foreground_;
- bool strike_;
- bool underline_;
-
- DISALLOW_COPY_AND_ASSIGN(TextStyle);
-};
-
-} // namespace views
-
-#endif // VIEWS_CONTROLS_TEXTFIELD_TEXT_STYLE_H_
diff --git a/views/controls/textfield/textfield.cc b/views/controls/textfield/textfield.cc
index 9cd6185..a51beda 100644
--- a/views/controls/textfield/textfield.cc
+++ b/views/controls/textfield/textfield.cc
@@ -261,20 +261,14 @@ size_t Textfield::GetCursorPosition() const {
return native_wrapper_->GetCursorPosition();
}
-TextStyle* Textfield::CreateTextStyle() {
+void Textfield::ApplyStyleRange(const gfx::StyleRange& style) {
DCHECK(native_wrapper_);
- return native_wrapper_->CreateTextStyle();
+ return native_wrapper_->ApplyStyleRange(style);
}
-void Textfield::ApplyTextStyle(const TextStyle* style,
- const ui::Range& range) {
+void Textfield::ApplyDefaultStyle() {
DCHECK(native_wrapper_);
- return native_wrapper_->ApplyTextStyle(style, range);
-}
-
-void Textfield::ClearAllTextStyles() {
- DCHECK(native_wrapper_);
- native_wrapper_->ClearAllTextStyles();
+ native_wrapper_->ApplyDefaultStyle();
}
void Textfield::ClearEditHistory() {
diff --git a/views/controls/textfield/textfield.h b/views/controls/textfield/textfield.h
index 3965050..66675d5 100644
--- a/views/controls/textfield/textfield.h
+++ b/views/controls/textfield/textfield.h
@@ -30,6 +30,10 @@
#include "views/controls/textfield/native_textfield_wrapper.h"
#endif
+namespace gfx {
+struct StyleRange;
+} // namespace gfx
+
namespace ui {
class Range;
} // namespace ui
@@ -39,7 +43,6 @@ namespace views {
class KeyEvent;
class NativeTextfieldWrapper;
class TextfieldController;
-class TextStyle;
// This class implements a View that wraps a native text (edit) field.
class Textfield : public View {
@@ -186,24 +189,14 @@ class Textfield : public View {
// only and has to be called after the wrapper is created.
size_t GetCursorPosition() const;
- // Creates a new TextStyle for this textfield. The object is owned
- // by the textfield and gets deleted when the textfield is deleted.
- // This is views-implementation only and has to be called after the
- // wrapper is created.
- TextStyle* CreateTextStyle();
-
- // Applies the |style| to the text specified by the |range|. If
- // there is already a style applied in the |range|, the style of the
- // overlapping part will be replaced by this sytle. The style will
- // be ignored if range is empty or invalid. This is
- // views-implementation only and has to be called after the wrapper
- // is created.
- void ApplyTextStyle(const TextStyle* style, const ui::Range& range);
-
- // Clears All TextStyles.
- // This is views-implementation only and has to be called after the
- // wrapper is created.
- void ClearAllTextStyles();
+ // Applies |style| to the text specified by its range. The style will be
+ // ignored if range is empty or invalid. This is views-implementation only and
+ // has to be called after the wrapper is created.
+ void ApplyStyleRange(const gfx::StyleRange& style);
+
+ // Applies the default style to the textfield. This is views-implementation
+ // only and has to be called after the wrapper is created.
+ void ApplyDefaultStyle();
// Clears Edit history.
void ClearEditHistory();
diff --git a/views/controls/textfield/textfield_views_model.cc b/views/controls/textfield/textfield_views_model.cc
index 1605546..548e014 100644
--- a/views/controls/textfield/textfield_views_model.cc
+++ b/views/controls/textfield/textfield_views_model.cc
@@ -13,8 +13,9 @@
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/range/range.h"
+#include "ui/gfx/canvas.h"
#include "ui/gfx/font.h"
-#include "views/controls/textfield/text_style.h"
+#include "ui/gfx/render_text.h"
#include "views/controls/textfield/textfield.h"
#include "views/views_delegate.h"
@@ -256,116 +257,8 @@ class DeleteEdit : public Edit {
}
};
-struct TextStyleRange {
- TextStyleRange(const TextStyle* s, size_t start, size_t end)
- : style(s),
- range(start, end) {
- }
- TextStyleRange(const TextStyle* s, const ui::Range& r)
- : style(s),
- range(r) {
- }
- const TextStyle *style;
- ui::Range range;
-};
-
} // namespace internal
-namespace {
-
-using views::internal::TextStyleRange;
-
-static bool TextStyleRangeComparator(const TextStyleRange* i,
- const TextStyleRange* j) {
- return i->range.start() < j->range.start();
-}
-
-#ifndef NDEBUG
-// A test function to check TextStyleRanges' invariant condition:
-// "no overlapping range".
-bool CheckInvariant(const TextStyleRanges* style_ranges) {
- TextStyleRanges copy = *style_ranges;
- std::sort(copy.begin(), copy.end(), TextStyleRangeComparator);
-
- for (TextStyleRanges::size_type i = 0; i < copy.size() - 1; i++) {
- ui::Range& former = copy[i]->range;
- ui::Range& latter = copy[i + 1]->range;
- if (former.is_empty()) {
- LOG(WARNING) << "Empty range at " << i << " :" << former;
- return false;
- }
- if (!former.IsValid()) {
- LOG(WARNING) << "Invalid range at " << i << " :" << former;
- return false;
- }
- if (former.GetMax() > latter.GetMin()) {
- LOG(WARNING) <<
- "Sorting error. former:" << former << " latter:" << latter;
- return false;
- }
- if (former.Intersects(latter)) {
- LOG(ERROR) << "overlapping style range found: former=" << former
- << ", latter=" << latter;
- return false;
- }
- }
- if ((*copy.rbegin())->range.is_empty()) {
- LOG(WARNING) << "Empty range at end";
- return false;
- }
- if (!(*copy.rbegin())->range.IsValid()) {
- LOG(WARNING) << "Invalid range at end";
- return false;
- }
- return true;
-}
-#endif
-
-void InsertStyle(TextStyleRanges* style_ranges,
- TextStyleRange* text_style_range) {
- const ui::Range& range = text_style_range->range;
- if (range.is_empty() || !range.IsValid()) {
- delete text_style_range;
- return;
- }
- CHECK(!range.is_reversed());
-
- // Invariant condition: all items in the range has no overlaps.
- TextStyleRanges::size_type index = 0;
- while (index < style_ranges->size()) {
- TextStyleRange* current = (*style_ranges)[index];
- if (range.Contains(current->range)) {
- style_ranges->erase(style_ranges->begin() + index);
- delete current;
- continue;
- } else if (current->range.Contains(range) &&
- range.start() != current->range.start() &&
- range.end() != current->range.end()) {
- // Split current style into two styles.
- style_ranges->push_back(
- new TextStyleRange(current->style,
- range.GetMax(), current->range.GetMax()));
- current->range.set_end(range.GetMin());
- } else if (range.Intersects(current->range)) {
- if (current->range.GetMax() <= range.GetMax()) {
- current->range.set_end(range.GetMin());
- } else {
- current->range.set_start(range.GetMax());
- }
- } else {
- // No change needed. Pass it through.
- }
- index ++;
- }
- // Add the new range at the end.
- style_ranges->push_back(text_style_range);
-#ifndef NDEBUG
- DCHECK(CheckInvariant(style_ranges));
-#endif
-}
-
-} // namespace
-
using internal::Edit;
using internal::DeleteEdit;
using internal::InsertEdit;
@@ -383,70 +276,18 @@ TextfieldViewsModel::Delegate::~Delegate() {
TextfieldViewsModel::TextfieldViewsModel(Delegate* delegate)
: delegate_(delegate),
- cursor_pos_(0),
- selection_start_(0),
- composition_start_(0),
- composition_end_(0),
+ render_text_(gfx::RenderText::CreateRenderText()),
is_password_(false),
- current_edit_(edit_history_.end()),
- sort_style_ranges_(false) {
+ current_edit_(edit_history_.end()) {
}
TextfieldViewsModel::~TextfieldViewsModel() {
ClearEditHistory();
ClearComposition();
- ClearAllTextStyles();
- TextStyles::iterator begin = text_styles_.begin();
- TextStyles::iterator end = text_styles_.end();
- while (begin != end) {
- TextStyles::iterator temp = begin;
- ++begin;
- delete *temp;
- }
}
-void TextfieldViewsModel::GetFragments(TextFragments* fragments) {
- static const TextStyle* kNormalStyle = new TextStyle();
-
- if (sort_style_ranges_) {
- sort_style_ranges_ = false;
- std::sort(style_ranges_.begin(), style_ranges_.end(),
- TextStyleRangeComparator);
- }
-
- // If a user is compositing text, use composition's style.
- // TODO(oshima): ask suzhe for expected behavior.
- const TextStyleRanges& ranges = composition_style_ranges_.size() > 0 ?
- composition_style_ranges_ : style_ranges_;
- TextStyleRanges::const_iterator next_ = ranges.begin();
-
- DCHECK(fragments);
- fragments->clear();
- size_t current = 0;
- size_t end = text_.length();
- while(next_ != ranges.end()) {
- const TextStyleRange* text_style_range = *next_++;
- const ui::Range& range = text_style_range->range;
- const TextStyle* style = text_style_range->style;
-
- DCHECK(!range.is_empty());
- DCHECK(range.IsValid());
- if (range.is_empty() || !range.IsValid())
- continue;
-
- size_t start = std::min(range.start(), end);
-
- if (start == end) // Exit loop if it reached the end.
- break;
- else if (current < start) // Fill the gap to next style with normal text.
- fragments->push_back(TextFragment(current, start, kNormalStyle));
-
- current = std::min(range.end(), end);
- fragments->push_back(TextFragment(start, current, style));
- }
- // If there is any text left add it as normal text.
- if (current != end)
- fragments->push_back(TextFragment(current, end, kNormalStyle));
+const string16& TextfieldViewsModel::GetText() const {
+ return render_text_->text();
}
bool TextfieldViewsModel::SetText(const string16& text) {
@@ -455,10 +296,10 @@ bool TextfieldViewsModel::SetText(const string16& text) {
ConfirmCompositionText();
changed = true;
}
- if (text_ != text) {
+ if (GetText() != text) {
if (changed) // No need to remember composition.
Undo();
- size_t old_cursor = cursor_pos_;
+ size_t old_cursor = GetCursorPosition();
size_t new_cursor = old_cursor > text.length() ? text.length() : old_cursor;
SelectAll();
// If there is a composition text, don't merge with previous edit.
@@ -469,7 +310,7 @@ bool TextfieldViewsModel::SetText(const string16& text) {
new_cursor,
text,
0U);
- cursor_pos_ = new_cursor;
+ render_text_->SetCursorPosition(new_cursor);
}
ClearSelection();
return changed;
@@ -478,10 +319,10 @@ bool TextfieldViewsModel::SetText(const string16& text) {
void TextfieldViewsModel::Append(const string16& text) {
if (HasCompositionText())
ConfirmCompositionText();
- size_t save = cursor_pos_;
- MoveCursorToEnd(false);
+ size_t save = GetCursorPosition();
+ MoveCursorRight(gfx::LINE_BREAK, false);
InsertText(text);
- cursor_pos_ = save;
+ render_text_->SetCursorPosition(save);
ClearSelection();
}
@@ -495,8 +336,9 @@ bool TextfieldViewsModel::Delete() {
DeleteSelection();
return true;
}
- if (text_.length() > cursor_pos_) {
- ExecuteAndRecordDelete(cursor_pos_, cursor_pos_ + 1, true);
+ if (GetText().length() > GetCursorPosition()) {
+ size_t cursor_position = GetCursorPosition();
+ ExecuteAndRecordDelete(cursor_position, cursor_position + 1, true);
return true;
}
return false;
@@ -512,194 +354,79 @@ bool TextfieldViewsModel::Backspace() {
DeleteSelection();
return true;
}
- if (cursor_pos_ > 0) {
- ExecuteAndRecordDelete(cursor_pos_, cursor_pos_ - 1, true);
+ if (GetCursorPosition() > 0) {
+ size_t cursor_position = GetCursorPosition();
+ ExecuteAndRecordDelete(cursor_position, cursor_position - 1, true);
return true;
}
return false;
}
-void TextfieldViewsModel::MoveCursorLeft(bool select) {
- if (HasCompositionText())
- ConfirmCompositionText();
- // TODO(oshima): support BIDI
- if (select) {
- if (cursor_pos_ > 0)
- cursor_pos_--;
- } else {
- if (HasSelection())
- cursor_pos_ = std::min(cursor_pos_, selection_start_);
- else if (cursor_pos_ > 0)
- cursor_pos_--;
- ClearSelection();
- }
+size_t TextfieldViewsModel::GetCursorPosition() const {
+ return render_text_->GetCursorPosition();
}
-void TextfieldViewsModel::MoveCursorRight(bool select) {
+void TextfieldViewsModel::MoveCursorLeft(gfx::BreakType break_type,
+ bool select) {
if (HasCompositionText())
ConfirmCompositionText();
- // TODO(oshima): support BIDI
- if (select) {
- cursor_pos_ = std::min(text_.length(), cursor_pos_ + 1);
- } else {
- if (HasSelection())
- cursor_pos_ = std::max(cursor_pos_, selection_start_);
- else
- cursor_pos_ = std::min(text_.length(), cursor_pos_ + 1);
- ClearSelection();
- }
+ render_text_->MoveCursorLeft(break_type, select);
}
-void TextfieldViewsModel::MoveCursorToPreviousWord(bool select) {
+void TextfieldViewsModel::MoveCursorRight(gfx::BreakType break_type,
+ bool select) {
if (HasCompositionText())
ConfirmCompositionText();
- // Notes: We always iterate words from the begining.
- // This is probably fast enough for our usage, but we may
- // want to modify WordIterator so that it can start from the
- // middle of string and advance backwards.
- base::i18n::BreakIterator iter(text_, base::i18n::BreakIterator::BREAK_WORD);
- bool success = iter.Init();
- DCHECK(success);
- if (!success)
- return;
- int last = 0;
- while (iter.Advance()) {
- if (iter.IsWord()) {
- size_t begin = iter.pos() - iter.GetString().length();
- if (begin == cursor_pos_) {
- // The cursor is at the beginning of a word.
- // Move to previous word.
- break;
- } else if(iter.pos() >= cursor_pos_) {
- // The cursor is in the middle or at the end of a word.
- // Move to the top of current word.
- last = begin;
- break;
- } else {
- last = iter.pos() - iter.GetString().length();
- }
- }
- }
-
- cursor_pos_ = last;
- if (!select)
- ClearSelection();
+ render_text_->MoveCursorRight(break_type, select);
}
-void TextfieldViewsModel::MoveCursorToNextWord(bool select) {
+bool TextfieldViewsModel::MoveCursorTo(size_t pos, bool select) {
if (HasCompositionText())
ConfirmCompositionText();
- base::i18n::BreakIterator iter(text_, base::i18n::BreakIterator::BREAK_WORD);
- bool success = iter.Init();
- DCHECK(success);
- if (!success)
- return;
- size_t pos = 0;
- while (iter.Advance()) {
- pos = iter.pos();
- if (iter.IsWord() && pos > cursor_pos_) {
- break;
- }
- }
- cursor_pos_ = pos;
- if (!select)
- ClearSelection();
-}
-
-void TextfieldViewsModel::MoveCursorToHome(bool select) {
- MoveCursorTo(0, select);
-}
-
-void TextfieldViewsModel::MoveCursorToEnd(bool select) {
- MoveCursorTo(text_.length(), select);
+ return render_text_->MoveCursorTo(pos, select);
}
-bool TextfieldViewsModel::MoveCursorTo(size_t pos, bool select) {
+bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) {
if (HasCompositionText())
ConfirmCompositionText();
- bool changed = cursor_pos_ != pos || select != HasSelection();
- cursor_pos_ = pos;
- if (!select)
- ClearSelection();
- return changed;
+ return render_text_->MoveCursorTo(point, select);
}
-gfx::Rect TextfieldViewsModel::GetSelectionBounds(const gfx::Font& font) const {
- if (!HasSelection())
- return gfx::Rect();
- size_t start = std::min(selection_start_, cursor_pos_);
- size_t end = std::max(selection_start_, cursor_pos_);
- int start_x = font.GetStringWidth(text_.substr(0, start));
- int end_x = font.GetStringWidth(text_.substr(0, end));
- return gfx::Rect(start_x, 0, end_x - start_x, font.GetHeight());
+std::vector<gfx::Rect> TextfieldViewsModel::GetSelectionBounds() const {
+ return render_text_->GetSubstringBounds(render_text_->GetSelection());
}
string16 TextfieldViewsModel::GetSelectedText() const {
- return text_.substr(
- std::min(cursor_pos_, selection_start_),
- std::abs(static_cast<long>(cursor_pos_ - selection_start_)));
+ ui::Range selection = render_text_->GetSelection();
+ return GetText().substr(selection.GetMin(), selection.length());
}
void TextfieldViewsModel::GetSelectedRange(ui::Range* range) const {
- *range = ui::Range(selection_start_, cursor_pos_);
+ *range = render_text_->GetSelection();
}
void TextfieldViewsModel::SelectRange(const ui::Range& range) {
if (HasCompositionText())
ConfirmCompositionText();
- selection_start_ = GetSafePosition(range.start());
- cursor_pos_ = GetSafePosition(range.end());
+ render_text_->SetSelection(range);
}
void TextfieldViewsModel::SelectAll() {
if (HasCompositionText())
ConfirmCompositionText();
- // SelectAll selects towards the end.
- cursor_pos_ = text_.length();
- selection_start_ = 0;
+ render_text_->SelectAll();
}
void TextfieldViewsModel::SelectWord() {
if (HasCompositionText())
ConfirmCompositionText();
- // First we setup selection_start_ and cursor_pos_. There are so many cases
- // because we try to emulate what select-word looks like in a gtk textfield.
- // See associated testcase for different cases.
- if (cursor_pos_ > 0 && cursor_pos_ < text_.length()) {
- if (isalnum(text_[cursor_pos_])) {
- selection_start_ = cursor_pos_;
- cursor_pos_++;
- } else
- selection_start_ = cursor_pos_ - 1;
- } else if (cursor_pos_ == 0) {
- selection_start_ = cursor_pos_;
- if (text_.length() > 0)
- cursor_pos_++;
- } else {
- selection_start_ = cursor_pos_ - 1;
- }
-
- // Now we move selection_start_ to beginning of selection. Selection boundary
- // is defined as the position where we have alpha-num character on one side
- // and non-alpha-num char on the other side.
- for (; selection_start_ > 0; selection_start_--) {
- if (IsPositionAtWordSelectionBoundary(selection_start_))
- break;
- }
-
- // Now we move cursor_pos_ to end of selection. Selection boundary
- // is defined as the position where we have alpha-num character on one side
- // and non-alpha-num char on the other side.
- for (; cursor_pos_ < text_.length(); cursor_pos_++) {
- if (IsPositionAtWordSelectionBoundary(cursor_pos_))
- break;
- }
+ render_text_->SelectWord();
}
void TextfieldViewsModel::ClearSelection() {
if (HasCompositionText())
ConfirmCompositionText();
- selection_start_ = cursor_pos_;
+ render_text_->ClearSelection();
}
bool TextfieldViewsModel::CanUndo() {
@@ -723,8 +450,8 @@ bool TextfieldViewsModel::Undo() {
if (HasCompositionText()) // safe guard for release build.
CancelCompositionText();
- string16 old = text_;
- size_t old_cursor = cursor_pos_;
+ string16 old = GetText();
+ size_t old_cursor = GetCursorPosition();
(*current_edit_)->Commit();
(*current_edit_)->Undo(this);
@@ -732,7 +459,7 @@ bool TextfieldViewsModel::Undo() {
current_edit_ = edit_history_.end();
else
current_edit_--;
- return old != text_ || old_cursor != cursor_pos_;
+ return old != GetText() || old_cursor != GetCursorPosition();
}
bool TextfieldViewsModel::Redo() {
@@ -746,10 +473,14 @@ bool TextfieldViewsModel::Redo() {
current_edit_ = edit_history_.begin();
else
current_edit_ ++;
- string16 old = text_;
- size_t old_cursor = cursor_pos_;
+ string16 old = GetText();
+ size_t old_cursor = GetCursorPosition();
(*current_edit_)->Redo(this);
- return old != text_ || old_cursor != cursor_pos_;
+ return old != GetText() || old_cursor != GetCursorPosition();
+}
+
+string16 TextfieldViewsModel::GetVisibleText() const {
+ return GetVisibleText(0U, GetText().length());
}
bool TextfieldViewsModel::Cut() {
@@ -761,7 +492,8 @@ bool TextfieldViewsModel::Cut() {
// than beginning, unlike Delete/Backspace.
// TODO(oshima): Change Delete/Backspace to use DeleteSelection,
// update DeleteEdit and remove this trick.
- std::swap(cursor_pos_, selection_start_);
+ ui::Range selection = render_text_->GetSelection();
+ render_text_->SetSelection(ui::Range(selection.end(), selection.start()));
DeleteSelection();
return true;
}
@@ -787,13 +519,14 @@ bool TextfieldViewsModel::Paste() {
}
bool TextfieldViewsModel::HasSelection() const {
- return selection_start_ != cursor_pos_;
+ return !render_text_->GetSelection().is_empty();
}
void TextfieldViewsModel::DeleteSelection() {
DCHECK(!HasCompositionText());
DCHECK(HasSelection());
- ExecuteAndRecordDelete(selection_start_, cursor_pos_, false);
+ ui::Range selection = render_text_->GetSelection();
+ ExecuteAndRecordDelete(selection.start(), selection.end(), false);
}
void TextfieldViewsModel::DeleteSelectionAndInsertTextAt(
@@ -801,26 +534,24 @@ void TextfieldViewsModel::DeleteSelectionAndInsertTextAt(
if (HasCompositionText())
CancelCompositionText();
ExecuteAndRecordReplace(DO_NOT_MERGE,
- cursor_pos_,
+ GetCursorPosition(),
position + text.length(),
text,
position);
}
string16 TextfieldViewsModel::GetTextFromRange(const ui::Range& range) const {
- if (range.IsValid() && range.GetMin() < text_.length())
- return text_.substr(range.GetMin(), range.length());
+ if (range.IsValid() && range.GetMin() < GetText().length())
+ return GetText().substr(range.GetMin(), range.length());
return string16();
}
void TextfieldViewsModel::GetTextRange(ui::Range* range) const {
- *range = ui::Range(0, text_.length());
+ *range = ui::Range(0, GetText().length());
}
void TextfieldViewsModel::SetCompositionText(
const ui::CompositionText& composition) {
- static const TextStyle* composition_style = CreateUnderlineStyle();
-
if (HasCompositionText())
CancelCompositionText();
else if (HasSelection())
@@ -829,95 +560,55 @@ void TextfieldViewsModel::SetCompositionText(
if (composition.text.empty())
return;
- size_t length = composition.text.length();
- text_.insert(cursor_pos_, composition.text);
- composition_start_ = cursor_pos_;
- composition_end_ = composition_start_ + length;
- for (ui::CompositionUnderlines::const_iterator iter =
- composition.underlines.begin();
- iter != composition.underlines.end();
- iter++) {
- size_t start = composition_start_ + iter->start_offset;
- size_t end = composition_start_ + iter->end_offset;
- InsertStyle(&composition_style_ranges_,
- new TextStyleRange(composition_style, start, end));
- }
- std::sort(composition_style_ranges_.begin(),
- composition_style_ranges_.end(), TextStyleRangeComparator);
-
- if (composition.selection.IsValid()) {
- selection_start_ =
- std::min(composition_start_ + composition.selection.start(),
- composition_end_);
- cursor_pos_ =
- std::min(composition_start_ + composition.selection.end(),
- composition_end_);
- } else {
- cursor_pos_ = composition_end_;
- ClearSelection();
- }
+ size_t cursor = GetCursorPosition();
+ string16 new_text = GetText();
+ render_text_->SetText(new_text.insert(cursor, composition.text));
+ ui::Range range(cursor, cursor + composition.text.length());
+ render_text_->SetCompositionRange(range);
+ // TODO(msw): Support multiple composition underline ranges.
+
+ if (composition.selection.IsValid())
+ render_text_->SetSelection(ui::Range(
+ std::min(range.start() + composition.selection.start(), range.end()),
+ std::min(range.start() + composition.selection.end(), range.end())));
+ else
+ render_text_->SetCursorPosition(range.end());
}
void TextfieldViewsModel::ConfirmCompositionText() {
DCHECK(HasCompositionText());
- string16 new_text =
- text_.substr(composition_start_, composition_end_ - composition_start_);
+ ui::Range range = render_text_->GetCompositionRange();
+ string16 text = GetText().substr(range.start(), range.length());
// TODO(oshima): current behavior on ChromeOS is a bit weird and not
// sure exactly how this should work. Find out and fix if necessary.
- AddOrMergeEditHistory(new InsertEdit(false, new_text, composition_start_));
- cursor_pos_ = composition_end_;
+ AddOrMergeEditHistory(new InsertEdit(false, text, range.start()));
+ render_text_->SetCursorPosition(range.end());
ClearComposition();
- ClearSelection();
if (delegate_)
delegate_->OnCompositionTextConfirmedOrCleared();
}
void TextfieldViewsModel::CancelCompositionText() {
DCHECK(HasCompositionText());
- text_.erase(composition_start_, composition_end_ - composition_start_);
- cursor_pos_ = composition_start_;
+ ui::Range range = render_text_->GetCompositionRange();
+ string16 new_text = GetText();
+ render_text_->SetText(new_text.erase(range.start(), range.length()));
+ render_text_->SetCursorPosition(range.start());
ClearComposition();
- ClearSelection();
if (delegate_)
delegate_->OnCompositionTextConfirmedOrCleared();
}
void TextfieldViewsModel::ClearComposition() {
- composition_start_ = composition_end_ = string16::npos;
- STLDeleteContainerPointers(composition_style_ranges_.begin(),
- composition_style_ranges_.end());
- composition_style_ranges_.clear();
-}
-
-void TextfieldViewsModel::ApplyTextStyle(const TextStyle* style,
- const ui::Range& range) {
- TextStyleRange* new_text_style_range = range.is_reversed() ?
- new TextStyleRange(style, ui::Range(range.end(), range.start())) :
- new TextStyleRange(style, range);
- InsertStyle(&style_ranges_, new_text_style_range);
- sort_style_ranges_ = true;
+ render_text_->SetCompositionRange(ui::Range::InvalidRange());
}
void TextfieldViewsModel::GetCompositionTextRange(ui::Range* range) const {
- if (HasCompositionText())
- *range = ui::Range(composition_start_, composition_end_);
- else
- *range = ui::Range::InvalidRange();
+ *range = ui::Range(render_text_->GetCompositionRange());
}
bool TextfieldViewsModel::HasCompositionText() const {
- return composition_start_ != composition_end_;
-}
-
-TextStyle* TextfieldViewsModel::CreateTextStyle() {
- TextStyle* style = new TextStyle();
- text_styles_.push_back(style);
- return style;
-}
-
-void TextfieldViewsModel::ClearAllTextStyles() {
- STLDeleteContainerPointers(style_ranges_.begin(), style_ranges_.end());
- style_ranges_.clear();
+ return !render_text_->GetCompositionRange().is_empty();
}
/////////////////////////////////////////////////////////////////
@@ -927,19 +618,7 @@ string16 TextfieldViewsModel::GetVisibleText(size_t begin, size_t end) const {
DCHECK(end >= begin);
if (is_password_)
return string16(end - begin, '*');
- return text_.substr(begin, end - begin);
-}
-
-bool TextfieldViewsModel::IsPositionAtWordSelectionBoundary(size_t pos) {
- return (isalnum(text_[pos - 1]) && !isalnum(text_[pos])) ||
- (!isalnum(text_[pos - 1]) && isalnum(text_[pos]));
-}
-
-size_t TextfieldViewsModel::GetSafePosition(size_t position) const {
- if (position > text_.length()) {
- return text_.length();
- }
- return position;
+ return GetText().substr(begin, end - begin);
}
void TextfieldViewsModel::InsertTextInternal(const string16& text,
@@ -957,10 +636,12 @@ void TextfieldViewsModel::InsertTextInternal(const string16& text,
void TextfieldViewsModel::ReplaceTextInternal(const string16& text,
bool mergeable) {
- if (HasCompositionText())
+ if (HasCompositionText()) {
CancelCompositionText();
- else if (!HasSelection())
- SelectRange(ui::Range(cursor_pos_ + text.length(), cursor_pos_));
+ } else if (!HasSelection()) {
+ size_t cursor = GetCursorPosition();
+ render_text_->SetSelection(ui::Range(cursor + text.length(), cursor));
+ }
// Edit history is recorded in InsertText.
InsertTextInternal(text, mergeable);
}
@@ -989,7 +670,7 @@ void TextfieldViewsModel::ExecuteAndRecordDelete(size_t from,
size_t to,
bool mergeable) {
size_t old_text_start = std::min(from, to);
- const string16 text = text_.substr(old_text_start,
+ const string16 text = GetText().substr(old_text_start,
std::abs(static_cast<long>(from - to)));
bool backward = from > to;
Edit* edit = new DeleteEdit(mergeable, text, old_text_start, backward);
@@ -1001,10 +682,10 @@ void TextfieldViewsModel::ExecuteAndRecordDelete(size_t from,
void TextfieldViewsModel::ExecuteAndRecordReplaceSelection(
MergeType merge_type, const string16& new_text) {
- size_t new_text_start = std::min(cursor_pos_, selection_start_);
+ size_t new_text_start = render_text_->GetSelection().GetMin();
size_t new_cursor_pos = new_text_start + new_text.length();
ExecuteAndRecordReplace(merge_type,
- cursor_pos_,
+ GetCursorPosition(),
new_cursor_pos,
new_text,
new_text_start);
@@ -1015,8 +696,8 @@ void TextfieldViewsModel::ExecuteAndRecordReplace(MergeType merge_type,
size_t new_cursor_pos,
const string16& new_text,
size_t new_text_start) {
- size_t old_text_start = std::min(cursor_pos_, selection_start_);
- bool backward = selection_start_ > cursor_pos_;
+ size_t old_text_start = render_text_->GetSelection().GetMin();
+ bool backward = render_text_->GetSelection().is_reversed();
Edit* edit = new ReplaceEdit(merge_type,
GetSelectedText(),
old_cursor_pos,
@@ -1033,7 +714,7 @@ void TextfieldViewsModel::ExecuteAndRecordReplace(MergeType merge_type,
void TextfieldViewsModel::ExecuteAndRecordInsert(const string16& text,
bool mergeable) {
- Edit* edit = new InsertEdit(mergeable, text, cursor_pos_);
+ Edit* edit = new InsertEdit(mergeable, text, GetCursorPosition());
bool delete_edit = AddOrMergeEditHistory(edit);
edit->Redo(this);
if (delete_edit)
@@ -1067,21 +748,14 @@ void TextfieldViewsModel::ModifyText(size_t delete_from,
size_t new_text_insert_at,
size_t new_cursor_pos) {
DCHECK_LE(delete_from, delete_to);
+ string16 text = GetText();
if (delete_from != delete_to)
- text_.erase(delete_from, delete_to - delete_from);
+ render_text_->SetText(text.erase(delete_from, delete_to - delete_from));
if (!new_text.empty())
- text_.insert(new_text_insert_at, new_text);
- cursor_pos_ = new_cursor_pos;
- ClearSelection();
+ render_text_->SetText(text.insert(new_text_insert_at, new_text));
+ render_text_->SetCursorPosition(new_cursor_pos);
// TODO(oshima): mac selects the text that is just undone (but gtk doesn't).
// This looks fine feature and we may want to do the same.
}
-// static
-TextStyle* TextfieldViewsModel::CreateUnderlineStyle() {
- TextStyle* style = new TextStyle();
- style->set_underline(true);
- return style;
-}
-
} // namespace views
diff --git a/views/controls/textfield/textfield_views_model.h b/views/controls/textfield/textfield_views_model.h
index 297c8ae..3f63fe4 100644
--- a/views/controls/textfield/textfield_views_model.h
+++ b/views/controls/textfield/textfield_views_model.h
@@ -10,13 +10,18 @@
#include <vector>
#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
#include "base/string16.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/ime/composition_text.h"
#include "ui/gfx/rect.h"
+#include "ui/gfx/render_text.h"
namespace gfx {
+class Canvas;
class Font;
+class RenderText;
+struct StyleRange;
} // namespace gfx
namespace ui {
@@ -25,15 +30,10 @@ class Range;
namespace views {
-class TextStyle;
-typedef std::vector<TextStyle*> TextStyles;
-
namespace internal {
// Internal Edit class that keeps track of edits for undo/redo.
class Edit;
-struct TextStyleRange;
-
// C++ doesn't allow forward decl enum, so let's define here.
enum MergeType {
// The edit should not be merged with next edit. It still may
@@ -49,8 +49,6 @@ enum MergeType {
} // namespace internal
-typedef std::vector<internal::TextStyleRange*> TextStyleRanges;
-
// A model that represents a text content for TextfieldViews.
// It supports editing, selection and cursor manipulation.
class TextfieldViewsModel {
@@ -70,31 +68,14 @@ class TextfieldViewsModel {
explicit TextfieldViewsModel(Delegate* delegate);
virtual ~TextfieldViewsModel();
- // Text fragment info. Used to draw selected text.
- // We may replace this with TextAttribute class
- // in the future to support multi-color text
- // for omnibox.
- struct TextFragment {
- TextFragment(size_t start, size_t end, const views::TextStyle* s)
- : range(start, end), style(s) {
- }
- // The start and end position of text fragment.
- ui::Range range;
- const TextStyle* style;
- };
- typedef std::vector<TextFragment> TextFragments;
-
- // Gets the text element info.
- void GetFragments(TextFragments* elements);
-
void set_is_password(bool is_password) {
is_password_ = is_password;
}
- const string16& text() const { return text_; }
// Edit related methods.
- // Sest the text. Returns true if the text has been modified. The
+ const string16& GetText() const;
+ // Sets the text. Returns true if the text has been modified. The
// current composition text will be confirmed first. Setting
// the same text will not add edit history because it's not user
// visible change nor user-initiated change. This allow a client
@@ -102,6 +83,8 @@ class TextfieldViewsModel {
// messing edit history.
bool SetText(const string16& text);
+ gfx::RenderText* render_text() { return render_text_.get(); }
+
// Inserts given |text| at the current cursor position.
// The current composition text will be cleared.
void InsertText(const string16& text) {
@@ -143,46 +126,23 @@ class TextfieldViewsModel {
// Cursor related methods.
// Returns the current cursor position.
- size_t cursor_pos() const { return cursor_pos_; }
-
- // Moves the cursor left by one position (as if, the user has pressed the left
- // arrow key). If |select| is true, it updates the selection accordingly.
- // The current composition text will be confirmed.
- void MoveCursorLeft(bool select);
+ size_t GetCursorPosition() const;
- // Moves the cursor right by one position (as if, the user has pressed the
- // right arrow key). If |select| is true, it updates the selection
- // accordingly.
- // The current composition text will be confirmed.
- void MoveCursorRight(bool select);
-
- // Moves the cursor left by one word (word boundry is defined by space).
- // If |select| is true, it updates the selection accordingly.
- // The current composition text will be confirmed.
- void MoveCursorToPreviousWord(bool select);
-
- // Moves the cursor right by one word (word boundry is defined by space).
- // If |select| is true, it updates the selection accordingly.
- // The current composition text will be confirmed.
- void MoveCursorToNextWord(bool select);
-
- // Moves the cursor to start of the textfield contents.
- // If |select| is true, it updates the selection accordingly.
+ // Moves the cursor, see RenderText for additional details.
// The current composition text will be confirmed.
- void MoveCursorToHome(bool select);
-
- // Moves the cursor to end of the textfield contents.
- // If |select| is true, it updates the selection accordingly.
- // The current composition text will be confirmed.
- void MoveCursorToEnd(bool select);
+ void MoveCursorLeft(gfx::BreakType break_type, bool select);
+ void MoveCursorRight(gfx::BreakType break_type, bool select);
// Moves the cursor to the specified |position|.
// If |select| is true, it updates the selection accordingly.
// The current composition text will be confirmed.
bool MoveCursorTo(size_t position, bool select);
+ // Helper function to call MoveCursorTo on the TextfieldViewsModel.
+ bool MoveCursorTo(const gfx::Point& point, bool select);
+
// Returns the bounds of selected text.
- gfx::Rect GetSelectionBounds(const gfx::Font& font) const;
+ std::vector<gfx::Rect> GetSelectionBounds() const;
// Selection related method
@@ -223,9 +183,7 @@ class TextfieldViewsModel {
// Returns visible text. If the field is password, it returns the
// sequence of "*".
- string16 GetVisibleText() const {
- return GetVisibleText(0U, text_.length());
- }
+ string16 GetVisibleText() const;
// Cuts the currently selected text and puts it to clipboard. Returns true
// if text has changed after cutting.
@@ -277,15 +235,10 @@ class TextfieldViewsModel {
// Returns true if there is composition text.
bool HasCompositionText() const;
- TextStyle* CreateTextStyle();
-
- void ClearAllTextStyles();
-
private:
friend class NativeTextfieldViews;
friend class NativeTextfieldViewsTest;
friend class TextfieldViewsModelTest;
- friend class TextStyle;
friend class UndoRedo_BasicTest;
friend class UndoRedo_CutCopyPasteTest;
friend class UndoRedo_ReplaceTest;
@@ -294,18 +247,10 @@ class TextfieldViewsModel {
FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_BasicTest);
FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest);
FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, UndoRedo_ReplaceTest);
- FRIEND_TEST_ALL_PREFIXES(TextfieldViewsModelTest, TextStyleTest);
// Returns the visible text given |start| and |end|.
string16 GetVisibleText(size_t start, size_t end) const;
- // Utility for SelectWord(). Checks whether position pos is at word boundary.
- bool IsPositionAtWordSelectionBoundary(size_t pos);
-
- // Returns the normalized cursor position that does not exceed the
- // text length.
- size_t GetSafePosition(size_t position) const;
-
// Insert the given |text|. |mergeable| indicates if this insert
// operation can be merged to previous edit in the edit history.
void InsertTextInternal(const string16& text, bool mergeable);
@@ -349,26 +294,12 @@ class TextfieldViewsModel {
void ClearComposition();
- void ApplyTextStyle(const TextStyle* style, const ui::Range& range);
-
- static TextStyle* CreateUnderlineStyle();
-
// Pointer to a TextfieldViewsModel::Delegate instance, should be provided by
// the View object.
Delegate* delegate_;
- // The text in utf16 format.
- string16 text_;
-
- // Current cursor position.
- size_t cursor_pos_;
-
- // Selection range.
- size_t selection_start_;
-
- // Composition text range.
- size_t composition_start_;
- size_t composition_end_;
+ // The stylized text, cursor, selection, and the visual layout model.
+ scoped_ptr<gfx::RenderText> render_text_;
// True if the text is the password.
bool is_password_;
@@ -389,19 +320,6 @@ class TextfieldViewsModel {
// 3) redone all undone edits.
EditHistory::iterator current_edit_;
- // This manages all styles objects.
- TextStyles text_styles_;
-
- // List of style ranges. Elements in the list never overlap each other.
- // Elements are not sorted at the time of insertion, and gets sorted
- // when it's painted (if necessary).
- TextStyleRanges style_ranges_;
- // True if the style_ranges_ needs to be sorted.
- bool sort_style_ranges_;
-
- // List of style ranges for composition text.
- TextStyleRanges composition_style_ranges_;
-
DISALLOW_COPY_AND_ASSIGN(TextfieldViewsModel);
};
diff --git a/views/controls/textfield/textfield_views_model_unittest.cc b/views/controls/textfield/textfield_views_model_unittest.cc
index 7e2f7e6..907e353 100644
--- a/views/controls/textfield/textfield_views_model_unittest.cc
+++ b/views/controls/textfield/textfield_views_model_unittest.cc
@@ -10,7 +10,7 @@
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/range/range.h"
-#include "views/controls/textfield/text_style.h"
+#include "ui/gfx/render_text.h"
#include "views/controls/textfield/textfield.h"
#include "views/controls/textfield/textfield_views_model.h"
#include "views/test/test_views_delegate.h"
@@ -19,8 +19,6 @@
namespace views {
-#include "views/test/views_test_base.h"
-
class TextfieldViewsModelTest : public ViewsTestBase,
public TextfieldViewsModel::Delegate {
public:
@@ -47,57 +45,56 @@ class TextfieldViewsModelTest : public ViewsTestBase,
#define EXPECT_STR_EQ(ascii, utf16) \
EXPECT_EQ(ASCIIToWide(ascii), UTF16ToWide(utf16))
-
TEST_F(TextfieldViewsModelTest, EditString) {
TextfieldViewsModel model(NULL);
// append two strings
model.Append(ASCIIToUTF16("HILL"));
- EXPECT_STR_EQ("HILL", model.text());
+ EXPECT_STR_EQ("HILL", model.GetText());
model.Append(ASCIIToUTF16("WORLD"));
- EXPECT_STR_EQ("HILLWORLD", model.text());
+ EXPECT_STR_EQ("HILLWORLD", model.GetText());
// Insert "E" to make hello
- model.MoveCursorRight(false);
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, false);
model.InsertChar('E');
- EXPECT_STR_EQ("HEILLWORLD", model.text());
+ EXPECT_STR_EQ("HEILLWORLD", model.GetText());
// Replace "I" with "L"
model.ReplaceChar('L');
- EXPECT_STR_EQ("HELLLWORLD", model.text());
+ EXPECT_STR_EQ("HELLLWORLD", model.GetText());
model.ReplaceChar('L');
model.ReplaceChar('O');
- EXPECT_STR_EQ("HELLOWORLD", model.text());
+ EXPECT_STR_EQ("HELLOWORLD", model.GetText());
// Delete 6th char "W", then delete 5th char O"
- EXPECT_EQ(5U, model.cursor_pos());
+ EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("HELLOORLD", model.text());
+ EXPECT_STR_EQ("HELLOORLD", model.GetText());
EXPECT_TRUE(model.Backspace());
- EXPECT_EQ(4U, model.cursor_pos());
- EXPECT_STR_EQ("HELLORLD", model.text());
+ EXPECT_EQ(4U, model.GetCursorPosition());
+ EXPECT_STR_EQ("HELLORLD", model.GetText());
// Move the cursor to start. backspace should fail.
- model.MoveCursorToHome(false);
+ model.MoveCursorLeft(gfx::LINE_BREAK, false);
EXPECT_FALSE(model.Backspace());
- EXPECT_STR_EQ("HELLORLD", model.text());
+ EXPECT_STR_EQ("HELLORLD", model.GetText());
// Move the cursor to the end. delete should fail.
- model.MoveCursorToEnd(false);
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
EXPECT_FALSE(model.Delete());
- EXPECT_STR_EQ("HELLORLD", model.text());
+ EXPECT_STR_EQ("HELLORLD", model.GetText());
// but backspace should work.
EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("HELLORL", model.text());
+ EXPECT_STR_EQ("HELLORL", model.GetText());
}
TEST_F(TextfieldViewsModelTest, EmptyString) {
TextfieldViewsModel model(NULL);
- EXPECT_EQ(string16(), model.text());
+ EXPECT_EQ(string16(), model.GetText());
EXPECT_EQ(string16(), model.GetSelectedText());
EXPECT_EQ(string16(), model.GetVisibleText());
- model.MoveCursorLeft(true);
- EXPECT_EQ(0U, model.cursor_pos());
- model.MoveCursorRight(true);
- EXPECT_EQ(0U, model.cursor_pos());
+ model.MoveCursorLeft(gfx::CHARACTER_BREAK, true);
+ EXPECT_EQ(0U, model.GetCursorPosition());
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, true);
+ EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_EQ(string16(), model.GetSelectedText());
@@ -108,15 +105,15 @@ TEST_F(TextfieldViewsModelTest, EmptyString) {
TEST_F(TextfieldViewsModelTest, Selection) {
TextfieldViewsModel model(NULL);
model.Append(ASCIIToUTF16("HELLO"));
- model.MoveCursorRight(false);
- model.MoveCursorRight(true);
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, false);
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, true);
EXPECT_STR_EQ("E", model.GetSelectedText());
- model.MoveCursorRight(true);
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, true);
EXPECT_STR_EQ("EL", model.GetSelectedText());
- model.MoveCursorToHome(true);
+ model.MoveCursorLeft(gfx::LINE_BREAK, true);
EXPECT_STR_EQ("H", model.GetSelectedText());
- model.MoveCursorToEnd(true);
+ model.MoveCursorRight(gfx::LINE_BREAK, true);
EXPECT_STR_EQ("ELLO", model.GetSelectedText());
model.ClearSelection();
EXPECT_EQ(string16(), model.GetSelectedText());
@@ -132,49 +129,49 @@ TEST_F(TextfieldViewsModelTest, Selection) {
model.MoveCursorTo(1U, false);
model.MoveCursorTo(3U, true);
EXPECT_STR_EQ("EL", model.GetSelectedText());
- model.MoveCursorLeft(false);
- EXPECT_EQ(1U, model.cursor_pos());
+ model.MoveCursorLeft(gfx::CHARACTER_BREAK, false);
+ EXPECT_EQ(1U, model.GetCursorPosition());
model.MoveCursorTo(1U, false);
model.MoveCursorTo(3U, true);
- model.MoveCursorRight(false);
- EXPECT_EQ(3U, model.cursor_pos());
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, false);
+ EXPECT_EQ(3U, model.GetCursorPosition());
// Select all and move cursor
model.SelectAll();
- model.MoveCursorLeft(false);
- EXPECT_EQ(0U, model.cursor_pos());
+ model.MoveCursorLeft(gfx::CHARACTER_BREAK, false);
+ EXPECT_EQ(0U, model.GetCursorPosition());
model.SelectAll();
- model.MoveCursorRight(false);
- EXPECT_EQ(5U, model.cursor_pos());
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, false);
+ EXPECT_EQ(5U, model.GetCursorPosition());
}
TEST_F(TextfieldViewsModelTest, SelectionAndEdit) {
TextfieldViewsModel model(NULL);
model.Append(ASCIIToUTF16("HELLO"));
- model.MoveCursorRight(false);
- model.MoveCursorRight(true);
- model.MoveCursorRight(true); // select "EL"
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, false);
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, true);
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, true); // select "EL"
EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("HLO", model.text());
+ EXPECT_STR_EQ("HLO", model.GetText());
model.Append(ASCIIToUTF16("ILL"));
- model.MoveCursorRight(true);
- model.MoveCursorRight(true); // select "LO"
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, true);
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, true); // select "LO"
EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("HILL", model.text());
- EXPECT_EQ(1U, model.cursor_pos());
- model.MoveCursorRight(true); // select "I"
+ EXPECT_STR_EQ("HILL", model.GetText());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, true); // select "I"
model.InsertChar('E');
- EXPECT_STR_EQ("HELL", model.text());
- model.MoveCursorToHome(false);
- model.MoveCursorRight(true); // select "H"
+ EXPECT_STR_EQ("HELL", model.GetText());
+ model.MoveCursorLeft(gfx::LINE_BREAK, false);
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, true); // select "H"
model.ReplaceChar('B');
- EXPECT_STR_EQ("BELL", model.text());
- model.MoveCursorToEnd(false);
- model.MoveCursorLeft(true);
- model.MoveCursorLeft(true); // select ">LL"
+ EXPECT_STR_EQ("BELL", model.GetText());
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
+ model.MoveCursorLeft(gfx::CHARACTER_BREAK, true);
+ model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); // select "ELL"
model.ReplaceChar('E');
- EXPECT_STR_EQ("BEE", model.text());
+ EXPECT_STR_EQ("BEE", model.GetText());
}
TEST_F(TextfieldViewsModelTest, Password) {
@@ -182,110 +179,88 @@ TEST_F(TextfieldViewsModelTest, Password) {
model.set_is_password(true);
model.Append(ASCIIToUTF16("HELLO"));
EXPECT_STR_EQ("*****", model.GetVisibleText());
- EXPECT_STR_EQ("HELLO", model.text());
+ EXPECT_STR_EQ("HELLO", model.GetText());
EXPECT_TRUE(model.Delete());
EXPECT_STR_EQ("****", model.GetVisibleText());
- EXPECT_STR_EQ("ELLO", model.text());
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("ELLO", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition());
model.SelectAll();
EXPECT_STR_EQ("ELLO", model.GetSelectedText());
- EXPECT_EQ(4U, model.cursor_pos());
+ EXPECT_EQ(4U, model.GetCursorPosition());
model.InsertChar('X');
EXPECT_STR_EQ("*", model.GetVisibleText());
- EXPECT_STR_EQ("X", model.text());
+ EXPECT_STR_EQ("X", model.GetText());
}
TEST_F(TextfieldViewsModelTest, Word) {
TextfieldViewsModel model(NULL);
model.Append(
ASCIIToUTF16("The answer to Life, the Universe, and Everything"));
- model.MoveCursorToNextWord(false);
- EXPECT_EQ(3U, model.cursor_pos());
- model.MoveCursorToNextWord(false);
- EXPECT_EQ(10U, model.cursor_pos());
- model.MoveCursorToNextWord(false);
- model.MoveCursorToNextWord(false);
- EXPECT_EQ(18U, model.cursor_pos());
+ model.MoveCursorRight(gfx::WORD_BREAK, false);
+ EXPECT_EQ(3U, model.GetCursorPosition());
+ model.MoveCursorRight(gfx::WORD_BREAK, false);
+ EXPECT_EQ(10U, model.GetCursorPosition());
+ model.MoveCursorRight(gfx::WORD_BREAK, false);
+ model.MoveCursorRight(gfx::WORD_BREAK, false);
+ EXPECT_EQ(18U, model.GetCursorPosition());
// Should passes the non word char ','
- model.MoveCursorToNextWord(true);
- EXPECT_EQ(23U, model.cursor_pos());
+ model.MoveCursorRight(gfx::WORD_BREAK, true);
+ EXPECT_EQ(23U, model.GetCursorPosition());
EXPECT_STR_EQ(", the", model.GetSelectedText());
// Move to the end.
- model.MoveCursorToNextWord(true);
- model.MoveCursorToNextWord(true);
- model.MoveCursorToNextWord(true);
+ model.MoveCursorRight(gfx::WORD_BREAK, true);
+ model.MoveCursorRight(gfx::WORD_BREAK, true);
+ model.MoveCursorRight(gfx::WORD_BREAK, true);
EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText());
// Should be safe to go next word at the end.
- model.MoveCursorToNextWord(true);
+ model.MoveCursorRight(gfx::WORD_BREAK, true);
EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText());
model.InsertChar('2');
- EXPECT_EQ(19U, model.cursor_pos());
+ EXPECT_EQ(19U, model.GetCursorPosition());
// Now backwards.
- model.MoveCursorLeft(false); // leave 2.
- model.MoveCursorToPreviousWord(true);
- EXPECT_EQ(14U, model.cursor_pos());
+ model.MoveCursorLeft(gfx::CHARACTER_BREAK, false); // leave 2.
+ model.MoveCursorLeft(gfx::WORD_BREAK, true);
+ EXPECT_EQ(14U, model.GetCursorPosition());
EXPECT_STR_EQ("Life", model.GetSelectedText());
- model.MoveCursorToPreviousWord(true);
+ model.MoveCursorLeft(gfx::WORD_BREAK, true);
EXPECT_STR_EQ("to Life", model.GetSelectedText());
- model.MoveCursorToPreviousWord(true);
- model.MoveCursorToPreviousWord(true);
- model.MoveCursorToPreviousWord(true); // Select to the begining.
+ model.MoveCursorLeft(gfx::WORD_BREAK, true);
+ model.MoveCursorLeft(gfx::WORD_BREAK, true);
+ model.MoveCursorLeft(gfx::WORD_BREAK, true); // Select to the begining.
EXPECT_STR_EQ("The answer to Life", model.GetSelectedText());
// Should be safe to go pervious word at the begining.
- model.MoveCursorToPreviousWord(true);
+ model.MoveCursorLeft(gfx::WORD_BREAK, true);
EXPECT_STR_EQ("The answer to Life", model.GetSelectedText());
model.ReplaceChar('4');
EXPECT_EQ(string16(), model.GetSelectedText());
EXPECT_STR_EQ("42", model.GetVisibleText());
}
-TEST_F(TextfieldViewsModelTest, TextFragment) {
- TextfieldViewsModel model(NULL);
- TextfieldViewsModel::TextFragments fragments;
- // Empty string has no fragment.
- model.GetFragments(&fragments);
- EXPECT_EQ(0U, fragments.size());
-
- // Some string
- model.Append(ASCIIToUTF16("Hello world"));
- model.GetFragments(&fragments);
- EXPECT_EQ(1U, fragments.size());
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(11U, fragments[0].range.end());
-
- // Selection won't change fragment.
- model.MoveCursorToNextWord(true);
- model.GetFragments(&fragments);
- EXPECT_EQ(1U, fragments.size());
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(11U, fragments[0].range.end());
-}
-
TEST_F(TextfieldViewsModelTest, SetText) {
TextfieldViewsModel model(NULL);
model.Append(ASCIIToUTF16("HELLO"));
- model.MoveCursorToEnd(false);
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
model.SetText(ASCIIToUTF16("GOODBYE"));
- EXPECT_STR_EQ("GOODBYE", model.text());
+ EXPECT_STR_EQ("GOODBYE", model.GetText());
// SetText won't reset the cursor posistion.
- EXPECT_EQ(5U, model.cursor_pos());
+ EXPECT_EQ(5U, model.GetCursorPosition());
model.SelectAll();
EXPECT_STR_EQ("GOODBYE", model.GetSelectedText());
- model.MoveCursorToEnd(false);
- EXPECT_EQ(7U, model.cursor_pos());
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
+ EXPECT_EQ(7U, model.GetCursorPosition());
model.SetText(ASCIIToUTF16("BYE"));
// Setting shorter string moves the cursor to the end of the new string.
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_EQ(string16(), model.GetSelectedText());
model.SetText(ASCIIToUTF16(""));
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_EQ(0U, model.GetCursorPosition());
}
TEST_F(TextfieldViewsModelTest, Clipboard) {
@@ -296,29 +271,29 @@ TEST_F(TextfieldViewsModelTest, Clipboard) {
string16 clipboard_text;
TextfieldViewsModel model(NULL);
model.Append(ASCIIToUTF16("HELLO WORLD"));
- model.MoveCursorToEnd(false);
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
// Test for cut: Empty selection.
EXPECT_FALSE(model.Cut());
clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &clipboard_text);
EXPECT_STR_EQ(UTF16ToUTF8(initial_clipboard_text), clipboard_text);
- EXPECT_STR_EQ("HELLO WORLD", model.text());
- EXPECT_EQ(11U, model.cursor_pos());
+ EXPECT_STR_EQ("HELLO WORLD", model.GetText());
+ EXPECT_EQ(11U, model.GetCursorPosition());
// Test for cut: Non-empty selection.
- model.MoveCursorToPreviousWord(true);
+ model.MoveCursorLeft(gfx::WORD_BREAK, true);
EXPECT_TRUE(model.Cut());
clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &clipboard_text);
EXPECT_STR_EQ("WORLD", clipboard_text);
- EXPECT_STR_EQ("HELLO ", model.text());
- EXPECT_EQ(6U, model.cursor_pos());
+ EXPECT_STR_EQ("HELLO ", model.GetText());
+ EXPECT_EQ(6U, model.GetCursorPosition());
// Test for copy: Empty selection.
model.Copy();
clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &clipboard_text);
EXPECT_STR_EQ("WORLD", clipboard_text);
- EXPECT_STR_EQ("HELLO ", model.text());
- EXPECT_EQ(6U, model.cursor_pos());
+ EXPECT_STR_EQ("HELLO ", model.GetText());
+ EXPECT_EQ(6U, model.GetCursorPosition());
// Test for copy: Non-empty selection.
model.Append(ASCIIToUTF16("HELLO WORLD"));
@@ -326,24 +301,24 @@ TEST_F(TextfieldViewsModelTest, Clipboard) {
model.Copy();
clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &clipboard_text);
EXPECT_STR_EQ("HELLO HELLO WORLD", clipboard_text);
- EXPECT_STR_EQ("HELLO HELLO WORLD", model.text());
- EXPECT_EQ(17U, model.cursor_pos());
+ EXPECT_STR_EQ("HELLO HELLO WORLD", model.GetText());
+ EXPECT_EQ(17U, model.GetCursorPosition());
// Test for paste.
model.ClearSelection();
- model.MoveCursorToEnd(false);
- model.MoveCursorToPreviousWord(true);
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
+ model.MoveCursorLeft(gfx::WORD_BREAK, true);
EXPECT_TRUE(model.Paste());
clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &clipboard_text);
EXPECT_STR_EQ("HELLO HELLO WORLD", clipboard_text);
- EXPECT_STR_EQ("HELLO HELLO HELLO HELLO WORLD", model.text());
- EXPECT_EQ(29U, model.cursor_pos());
+ EXPECT_STR_EQ("HELLO HELLO HELLO HELLO WORLD", model.GetText());
+ EXPECT_EQ(29U, model.GetCursorPosition());
}
void SelectWordTestVerifier(TextfieldViewsModel &model,
const std::string &expected_selected_string, size_t expected_cursor_pos) {
EXPECT_STR_EQ(expected_selected_string, model.GetSelectedText());
- EXPECT_EQ(expected_cursor_pos, model.cursor_pos());
+ EXPECT_EQ(expected_cursor_pos, model.GetCursorPosition());
}
TEST_F(TextfieldViewsModelTest, SelectWordTest) {
@@ -351,7 +326,7 @@ TEST_F(TextfieldViewsModelTest, SelectWordTest) {
model.Append(ASCIIToUTF16(" HELLO !! WO RLD "));
// Test when cursor is at the beginning.
- model.MoveCursorToHome(false);
+ model.MoveCursorLeft(gfx::LINE_BREAK, false);
model.SelectWord();
SelectWordTestVerifier(model, " ", 2U);
@@ -378,7 +353,7 @@ TEST_F(TextfieldViewsModelTest, SelectWordTest) {
SelectWordTestVerifier(model, " ", 20U);
// Test when cursor is at the end.
- model.MoveCursorToEnd(false);
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
model.SelectWord();
SelectWordTestVerifier(model, " ", 24U);
}
@@ -386,61 +361,61 @@ TEST_F(TextfieldViewsModelTest, SelectWordTest) {
TEST_F(TextfieldViewsModelTest, RangeTest) {
TextfieldViewsModel model(NULL);
model.Append(ASCIIToUTF16("HELLO WORLD"));
- model.MoveCursorToHome(false);
+ model.MoveCursorLeft(gfx::LINE_BREAK, false);
ui::Range range;
model.GetSelectedRange(&range);
EXPECT_TRUE(range.is_empty());
EXPECT_EQ(0U, range.start());
EXPECT_EQ(0U, range.end());
- model.MoveCursorToNextWord(true);
+ model.MoveCursorRight(gfx::WORD_BREAK, true);
model.GetSelectedRange(&range);
EXPECT_FALSE(range.is_empty());
EXPECT_FALSE(range.is_reversed());
EXPECT_EQ(0U, range.start());
EXPECT_EQ(5U, range.end());
- model.MoveCursorLeft(true);
+ model.MoveCursorLeft(gfx::CHARACTER_BREAK, true);
model.GetSelectedRange(&range);
EXPECT_FALSE(range.is_empty());
EXPECT_EQ(0U, range.start());
EXPECT_EQ(4U, range.end());
- model.MoveCursorToPreviousWord(true);
+ model.MoveCursorLeft(gfx::WORD_BREAK, true);
model.GetSelectedRange(&range);
EXPECT_TRUE(range.is_empty());
EXPECT_EQ(0U, range.start());
EXPECT_EQ(0U, range.end());
// now from the end.
- model.MoveCursorToEnd(false);
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
model.GetSelectedRange(&range);
EXPECT_TRUE(range.is_empty());
EXPECT_EQ(11U, range.start());
EXPECT_EQ(11U, range.end());
- model.MoveCursorToPreviousWord(true);
+ model.MoveCursorLeft(gfx::WORD_BREAK, true);
model.GetSelectedRange(&range);
EXPECT_FALSE(range.is_empty());
EXPECT_TRUE(range.is_reversed());
EXPECT_EQ(11U, range.start());
EXPECT_EQ(6U, range.end());
- model.MoveCursorRight(true);
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, true);
model.GetSelectedRange(&range);
EXPECT_FALSE(range.is_empty());
EXPECT_TRUE(range.is_reversed());
EXPECT_EQ(11U, range.start());
EXPECT_EQ(7U, range.end());
- model.MoveCursorToNextWord(true);
+ model.MoveCursorRight(gfx::WORD_BREAK, true);
model.GetSelectedRange(&range);
EXPECT_TRUE(range.is_empty());
EXPECT_EQ(11U, range.start());
EXPECT_EQ(11U, range.end());
// Select All
- model.MoveCursorToHome(true);
+ model.MoveCursorLeft(gfx::LINE_BREAK, true);
model.GetSelectedRange(&range);
EXPECT_FALSE(range.is_empty());
EXPECT_TRUE(range.is_reversed());
@@ -497,7 +472,7 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) {
model.Append(ASCIIToUTF16("1234590"));
model.SelectRange(ui::Range(5, 5));
EXPECT_FALSE(model.HasSelection());
- EXPECT_EQ(5U, model.cursor_pos());
+ EXPECT_EQ(5U, model.GetCursorPosition());
ui::Range range;
model.GetTextRange(&range);
@@ -514,7 +489,7 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) {
model.GetTextRange(&range);
EXPECT_EQ(10U, range.end());
- EXPECT_STR_EQ("1234567890", model.text());
+ EXPECT_STR_EQ("1234567890", model.GetText());
model.GetCompositionTextRange(&range);
EXPECT_EQ(5U, range.start());
@@ -527,55 +502,40 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) {
EXPECT_EQ(8U, range.end());
EXPECT_STR_EQ("8", model.GetSelectedText());
- TextfieldViewsModel::TextFragments fragments;
- model.GetFragments(&fragments);
- EXPECT_EQ(3U, fragments.size());
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(5U, fragments[0].range.end());
- EXPECT_FALSE(fragments[0].style->underline());
-
- EXPECT_EQ(5U, fragments[1].range.start());
- EXPECT_EQ(8U, fragments[1].range.end());
- EXPECT_TRUE(fragments[1].style->underline());
-
- EXPECT_EQ(8U, fragments[2].range.start());
- EXPECT_EQ(10U, fragments[2].range.end());
- EXPECT_FALSE(fragments[2].style->underline());
-
EXPECT_FALSE(composition_text_confirmed_or_cleared_);
model.CancelCompositionText();
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
EXPECT_FALSE(model.HasCompositionText());
EXPECT_FALSE(model.HasSelection());
- EXPECT_EQ(5U, model.cursor_pos());
+ EXPECT_EQ(5U, model.GetCursorPosition());
model.SetCompositionText(composition);
- EXPECT_STR_EQ("1234567890", model.text());
+ EXPECT_STR_EQ("1234567890", model.GetText());
EXPECT_TRUE(model.SetText(ASCIIToUTF16("1234567890")));
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- model.MoveCursorToEnd(false);
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
model.SetCompositionText(composition);
- EXPECT_STR_EQ("1234567890678", model.text());
+ EXPECT_STR_EQ("1234567890678", model.GetText());
model.InsertText(UTF8ToUTF16("-"));
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-", model.text());
+ EXPECT_STR_EQ("1234567890-", model.GetText());
EXPECT_FALSE(model.HasCompositionText());
EXPECT_FALSE(model.HasSelection());
- model.MoveCursorLeft(true);
+ model.MoveCursorLeft(gfx::CHARACTER_BREAK, true);
EXPECT_STR_EQ("-", model.GetSelectedText());
model.SetCompositionText(composition);
- EXPECT_STR_EQ("1234567890678", model.text());
+ EXPECT_STR_EQ("1234567890678", model.GetText());
model.ReplaceText(UTF8ToUTF16("-"));
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-", model.text());
+ EXPECT_STR_EQ("1234567890-", model.GetText());
EXPECT_FALSE(model.HasCompositionText());
EXPECT_FALSE(model.HasSelection());
@@ -583,82 +543,82 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) {
model.Append(UTF8ToUTF16("-"));
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-678-", model.text());
+ EXPECT_STR_EQ("1234567890-678-", model.GetText());
model.SetCompositionText(composition);
model.Delete();
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-678-", model.text());
+ EXPECT_STR_EQ("1234567890-678-", model.GetText());
model.SetCompositionText(composition);
model.Backspace();
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("1234567890-678-", model.text());
+ EXPECT_STR_EQ("1234567890-678-", model.GetText());
model.SetText(string16());
model.SetCompositionText(composition);
- model.MoveCursorLeft(false);
+ model.MoveCursorLeft(gfx::CHARACTER_BREAK, false);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.text());
- EXPECT_EQ(2U, model.cursor_pos());
+ EXPECT_STR_EQ("678", model.GetText());
+ EXPECT_EQ(2U, model.GetCursorPosition());
model.SetCompositionText(composition);
- model.MoveCursorRight(false);
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, false);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("676788", model.text());
- EXPECT_EQ(6U, model.cursor_pos());
+ EXPECT_STR_EQ("676788", model.GetText());
+ EXPECT_EQ(6U, model.GetCursorPosition());
model.SetCompositionText(composition);
- model.MoveCursorToPreviousWord(false);
+ model.MoveCursorLeft(gfx::WORD_BREAK, false);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("676788678", model.text());
+ EXPECT_STR_EQ("676788678", model.GetText());
model.SetText(string16());
model.SetCompositionText(composition);
- model.MoveCursorToNextWord(false);
+ model.MoveCursorRight(gfx::WORD_BREAK, false);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
model.SetCompositionText(composition);
- model.MoveCursorToHome(true);
+ model.MoveCursorLeft(gfx::LINE_BREAK, true);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678678", model.text());
+ EXPECT_STR_EQ("678678", model.GetText());
model.SetCompositionText(composition);
- model.MoveCursorToEnd(false);
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.text());
+ EXPECT_STR_EQ("678", model.GetText());
model.SetCompositionText(composition);
model.MoveCursorTo(0, true);
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678678", model.text());
+ EXPECT_STR_EQ("678678", model.GetText());
model.SetCompositionText(composition);
model.SelectRange(ui::Range(0, 3));
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.text());
+ EXPECT_STR_EQ("678", model.GetText());
model.SetCompositionText(composition);
model.SelectAll();
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.text());
+ EXPECT_STR_EQ("678", model.GetText());
model.SetCompositionText(composition);
model.SelectWord();
EXPECT_TRUE(composition_text_confirmed_or_cleared_);
composition_text_confirmed_or_cleared_ = false;
- EXPECT_STR_EQ("678", model.text());
+ EXPECT_STR_EQ("678", model.GetText());
model.SetCompositionText(composition);
model.ClearSelection();
@@ -675,157 +635,157 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_BasicTest) {
model.InsertChar('a');
EXPECT_FALSE(model.Redo()); // nothing to redo
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.text());
+ EXPECT_STR_EQ("", model.GetText());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("a", model.text());
+ EXPECT_STR_EQ("a", model.GetText());
// Continuous inserts are treated as one edit.
model.InsertChar('b');
model.InsertChar('c');
- EXPECT_STR_EQ("abc", model.text());
+ EXPECT_STR_EQ("abc", model.GetText());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("a", model.text());
- EXPECT_EQ(1U, model.cursor_pos());
+ EXPECT_STR_EQ("a", model.GetText());
+ EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.text());
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition());
// Undoing further shouldn't change the text.
EXPECT_FALSE(model.Undo());
- EXPECT_STR_EQ("", model.text());
+ EXPECT_STR_EQ("", model.GetText());
EXPECT_FALSE(model.Undo());
- EXPECT_STR_EQ("", model.text());
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition());
// Redoing to the latest text.
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("a", model.text());
- EXPECT_EQ(1U, model.cursor_pos());
+ EXPECT_STR_EQ("a", model.GetText());
+ EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("abc", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("abc", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
// Backspace ===============================
EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("ab", model.text());
+ EXPECT_STR_EQ("ab", model.GetText());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("abc", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("abc", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ab", model.text());
- EXPECT_EQ(2U, model.cursor_pos());
+ EXPECT_STR_EQ("ab", model.GetText());
+ EXPECT_EQ(2U, model.GetCursorPosition());
// Continous backspaces are treated as one edit.
EXPECT_TRUE(model.Backspace());
EXPECT_TRUE(model.Backspace());
- EXPECT_STR_EQ("", model.text());
+ EXPECT_STR_EQ("", model.GetText());
// Extra backspace shouldn't affect the history.
EXPECT_FALSE(model.Backspace());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ab", model.text());
- EXPECT_EQ(2U, model.cursor_pos());
+ EXPECT_STR_EQ("ab", model.GetText());
+ EXPECT_EQ(2U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("abc", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("abc", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("a", model.text());
- EXPECT_EQ(1U, model.cursor_pos());
+ EXPECT_STR_EQ("a", model.GetText());
+ EXPECT_EQ(1U, model.GetCursorPosition());
// Clear history
model.ClearEditHistory();
EXPECT_FALSE(model.Undo());
EXPECT_FALSE(model.Redo());
- EXPECT_STR_EQ("a", model.text());
- EXPECT_EQ(1U, model.cursor_pos());
+ EXPECT_STR_EQ("a", model.GetText());
+ EXPECT_EQ(1U, model.GetCursorPosition());
// Delete ===============================
model.SetText(ASCIIToUTF16("ABCDE"));
model.ClearEditHistory();
model.MoveCursorTo(2, false);
EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("ABDE", model.text());
- model.MoveCursorToHome(false);
+ EXPECT_STR_EQ("ABDE", model.GetText());
+ model.MoveCursorLeft(gfx::LINE_BREAK, false);
EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("BDE", model.text());
+ EXPECT_STR_EQ("BDE", model.GetText());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABDE", model.text());
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("ABDE", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.text());
- EXPECT_EQ(2U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_EQ(2U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABDE", model.text());
- EXPECT_EQ(2U, model.cursor_pos());
+ EXPECT_STR_EQ("ABDE", model.GetText());
+ EXPECT_EQ(2U, model.GetCursorPosition());
// Continous deletes are treated as one edit.
EXPECT_TRUE(model.Delete());
EXPECT_TRUE(model.Delete());
- EXPECT_STR_EQ("AB", model.text());
+ EXPECT_STR_EQ("AB", model.GetText());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABDE", model.text());
- EXPECT_EQ(2U, model.cursor_pos());
+ EXPECT_STR_EQ("ABDE", model.GetText());
+ EXPECT_EQ(2U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("AB", model.text());
- EXPECT_EQ(2U, model.cursor_pos());
+ EXPECT_STR_EQ("AB", model.GetText());
+ EXPECT_EQ(2U, model.GetCursorPosition());
}
TEST_F(TextfieldViewsModelTest, UndoRedo_SetText) {
// This is to test the undo/redo behavior of omnibox.
TextfieldViewsModel model(NULL);
model.InsertChar('w');
- EXPECT_STR_EQ("w", model.text());
- EXPECT_EQ(1U, model.cursor_pos());
+ EXPECT_STR_EQ("w", model.GetText());
+ EXPECT_EQ(1U, model.GetCursorPosition());
model.SetText(ASCIIToUTF16("www.google.com"));
- EXPECT_EQ(1U, model.cursor_pos());
- EXPECT_STR_EQ("www.google.com", model.text());
+ EXPECT_EQ(1U, model.GetCursorPosition());
+ EXPECT_STR_EQ("www.google.com", model.GetText());
model.SelectRange(ui::Range(14, 1));
model.InsertChar('w');
- EXPECT_STR_EQ("ww", model.text());
+ EXPECT_STR_EQ("ww", model.GetText());
model.SetText(ASCIIToUTF16("www.google.com"));
model.SelectRange(ui::Range(14, 2));
model.InsertChar('w');
- EXPECT_STR_EQ("www", model.text());
+ EXPECT_STR_EQ("www", model.GetText());
model.SetText(ASCIIToUTF16("www.google.com"));
model.SelectRange(ui::Range(14, 3));
model.InsertChar('.');
- EXPECT_STR_EQ("www.", model.text());
+ EXPECT_STR_EQ("www.", model.GetText());
model.SetText(ASCIIToUTF16("www.google.com"));
model.SelectRange(ui::Range(14, 4));
model.InsertChar('y');
- EXPECT_STR_EQ("www.y", model.text());
+ EXPECT_STR_EQ("www.y", model.GetText());
model.SetText(ASCIIToUTF16("www.youtube.com"));
- EXPECT_STR_EQ("www.youtube.com", model.text());
- EXPECT_EQ(5U, model.cursor_pos());
+ EXPECT_STR_EQ("www.youtube.com", model.GetText());
+ EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.text());
- EXPECT_EQ(4U, model.cursor_pos());
+ EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_EQ(4U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.text());
- EXPECT_EQ(2U, model.cursor_pos());
+ EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_EQ(2U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("www.google.com", model.text());
- EXPECT_EQ(1U, model.cursor_pos());
+ EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.text());
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_FALSE(model.Undo());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.google.com", model.text());
- EXPECT_EQ(1U, model.cursor_pos());
+ EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.google.com", model.text());
- EXPECT_EQ(2U, model.cursor_pos());
+ EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_EQ(2U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.google.com", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.google.com", model.text());
- EXPECT_EQ(4U, model.cursor_pos());
+ EXPECT_STR_EQ("www.google.com", model.GetText());
+ EXPECT_EQ(4U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("www.youtube.com", model.text());
- EXPECT_EQ(5U, model.cursor_pos());
+ EXPECT_STR_EQ("www.youtube.com", model.GetText());
+ EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_FALSE(model.Redo());
}
@@ -837,153 +797,153 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest) {
model.MoveCursorTo(1, false);
model.MoveCursorTo(3, true);
model.Cut();
- EXPECT_STR_EQ("ADE", model.text());
- EXPECT_EQ(1U, model.cursor_pos());
+ EXPECT_STR_EQ("ADE", model.GetText());
+ EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.text());
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_FALSE(model.Undo()); // no more undo
- EXPECT_STR_EQ("", model.text());
+ EXPECT_STR_EQ("", model.GetText());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDE", model.text());
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ADE", model.text());
- EXPECT_EQ(1U, model.cursor_pos());
+ EXPECT_STR_EQ("ADE", model.GetText());
+ EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_FALSE(model.Redo()); // no more redo
- EXPECT_STR_EQ("ADE", model.text());
+ EXPECT_STR_EQ("ADE", model.GetText());
model.Paste();
model.Paste();
model.Paste();
- EXPECT_STR_EQ("ABCBCBCDE", model.text());
- EXPECT_EQ(7U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCBCBCDE", model.GetText());
+ EXPECT_EQ(7U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCBCDE", model.text());
- EXPECT_EQ(5U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCBCDE", model.GetText());
+ EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ADE", model.text());
- EXPECT_EQ(1U, model.cursor_pos());
+ EXPECT_STR_EQ("ADE", model.GetText());
+ EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.text());
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_FALSE(model.Undo());
- EXPECT_STR_EQ("", model.text());
+ EXPECT_STR_EQ("", model.GetText());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDE", model.text()); // Redoing SetText
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCDE", model.GetText()); // Redoing SetText
+ EXPECT_EQ(0U, model.GetCursorPosition());
// Redo
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ADE", model.text());
- EXPECT_EQ(1U, model.cursor_pos());
+ EXPECT_STR_EQ("ADE", model.GetText());
+ EXPECT_EQ(1U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDE", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCDE", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCBCDE", model.text());
- EXPECT_EQ(5U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCBCDE", model.GetText());
+ EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCBCBCDE", model.text());
- EXPECT_EQ(7U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCBCBCDE", model.GetText());
+ EXPECT_EQ(7U, model.GetCursorPosition());
EXPECT_FALSE(model.Redo());
// with SelectRange
model.SelectRange(ui::Range(1, 3));
EXPECT_TRUE(model.Cut());
- EXPECT_STR_EQ("ABCBCDE", model.text());
- EXPECT_EQ(1U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCBCDE", model.GetText());
+ EXPECT_EQ(1U, model.GetCursorPosition());
model.SelectRange(ui::Range(1, 1));
EXPECT_FALSE(model.Cut());
- model.MoveCursorToEnd(false);
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
EXPECT_TRUE(model.Paste());
- EXPECT_STR_EQ("ABCBCDEBC", model.text());
- EXPECT_EQ(9U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCBCDEBC", model.GetText());
+ EXPECT_EQ(9U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCBCDE", model.text());
- EXPECT_EQ(7U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCBCDE", model.GetText());
+ EXPECT_EQ(7U, model.GetCursorPosition());
// empty cut shouldn't create an edit.
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCBCBCDE", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("ABCBCBCDE", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
// Copy
ResetModel(&model);
model.SetText(ASCIIToUTF16("12345"));
- EXPECT_STR_EQ("12345", model.text());
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("12345", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition());
model.MoveCursorTo(1, false);
model.MoveCursorTo(3, true);
model.Copy(); // Copy "23"
- EXPECT_STR_EQ("12345", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("12345", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
model.Paste(); // Paste "23" into "23".
- EXPECT_STR_EQ("12345", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("12345", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
model.Paste();
- EXPECT_STR_EQ("1232345", model.text());
- EXPECT_EQ(5U, model.cursor_pos());
+ EXPECT_STR_EQ("1232345", model.GetText());
+ EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("12345", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("12345", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
// TODO(oshima): We need to change the return type from bool to enum.
EXPECT_FALSE(model.Undo()); // No text change.
- EXPECT_STR_EQ("12345", model.text());
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("12345", model.GetText());
+ EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.text());
+ EXPECT_STR_EQ("", model.GetText());
EXPECT_FALSE(model.Undo());
// Redo
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("12345", model.text());
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("12345", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("12345", model.text()); // For 1st paste
- EXPECT_EQ(3U, model.cursor_pos());
+ EXPECT_STR_EQ("12345", model.GetText()); // For 1st paste
+ EXPECT_EQ(3U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("1232345", model.text());
- EXPECT_EQ(5U, model.cursor_pos());
+ EXPECT_STR_EQ("1232345", model.GetText());
+ EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_FALSE(model.Redo());
- EXPECT_STR_EQ("1232345", model.text());
+ EXPECT_STR_EQ("1232345", model.GetText());
- // with SelectRange
+ // Test using SelectRange
model.SelectRange(ui::Range(1, 3));
model.Copy();
- EXPECT_STR_EQ("1232345", model.text());
- model.MoveCursorToEnd(false);
+ EXPECT_STR_EQ("1232345", model.GetText());
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
EXPECT_TRUE(model.Paste());
- EXPECT_STR_EQ("123234523", model.text());
- EXPECT_EQ(9U, model.cursor_pos());
+ EXPECT_STR_EQ("123234523", model.GetText());
+ EXPECT_EQ(9U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("1232345", model.text());
- EXPECT_EQ(7U, model.cursor_pos());
+ EXPECT_STR_EQ("1232345", model.GetText());
+ EXPECT_EQ(7U, model.GetCursorPosition());
}
TEST_F(TextfieldViewsModelTest, UndoRedo_CursorTest) {
TextfieldViewsModel model(NULL);
model.InsertChar('a');
- model.MoveCursorLeft(false);
- model.MoveCursorRight(false);
+ model.MoveCursorLeft(gfx::CHARACTER_BREAK, false);
+ model.MoveCursorRight(gfx::CHARACTER_BREAK, false);
model.InsertChar('b');
- // Moving cursor shoudln't create a new edit.
- EXPECT_STR_EQ("ab", model.text());
+ // Moving the cursor shouldn't create a new edit.
+ EXPECT_STR_EQ("ab", model.GetText());
EXPECT_FALSE(model.Redo());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.text());
+ EXPECT_STR_EQ("", model.GetText());
EXPECT_FALSE(model.Undo());
- EXPECT_STR_EQ("", model.text());
+ EXPECT_STR_EQ("", model.GetText());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ab", model.text());
- EXPECT_EQ(2U, model.cursor_pos());
+ EXPECT_STR_EQ("ab", model.GetText());
+ EXPECT_EQ(2U, model.GetCursorPosition());
EXPECT_FALSE(model.Redo());
}
@@ -995,21 +955,21 @@ void RunInsertReplaceTest(TextfieldViewsModel& model) {
model.InsertChar('1');
model.InsertChar('2');
model.InsertChar('3');
- EXPECT_STR_EQ("a123d", model.text());
- EXPECT_EQ(4U, model.cursor_pos());
+ EXPECT_STR_EQ("a123d", model.GetText());
+ EXPECT_EQ(4U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("abcd", model.text());
- EXPECT_EQ(reverse ? 1U : 3U, model.cursor_pos());
+ EXPECT_STR_EQ("abcd", model.GetText());
+ EXPECT_EQ(reverse ? 1U : 3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.text());
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_FALSE(model.Undo());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("abcd", model.text());
- EXPECT_EQ(0U, model.cursor_pos()); // By SetText
+ EXPECT_STR_EQ("abcd", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition()); // By SetText
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("a123d", model.text());
- EXPECT_EQ(4U, model.cursor_pos());
+ EXPECT_STR_EQ("a123d", model.GetText());
+ EXPECT_EQ(4U, model.GetCursorPosition());
EXPECT_FALSE(model.Redo());
}
@@ -1022,21 +982,21 @@ void RunOverwriteReplaceTest(TextfieldViewsModel& model) {
model.ReplaceChar('2');
model.ReplaceChar('3');
model.ReplaceChar('4');
- EXPECT_STR_EQ("a1234", model.text());
- EXPECT_EQ(5U, model.cursor_pos());
+ EXPECT_STR_EQ("a1234", model.GetText());
+ EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("abcd", model.text());
- EXPECT_EQ(reverse ? 1U : 3U, model.cursor_pos());
+ EXPECT_STR_EQ("abcd", model.GetText());
+ EXPECT_EQ(reverse ? 1U : 3U, model.GetCursorPosition());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.text());
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_FALSE(model.Undo());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("abcd", model.text());
- EXPECT_EQ(0U, model.cursor_pos());
+ EXPECT_STR_EQ("abcd", model.GetText());
+ EXPECT_EQ(0U, model.GetCursorPosition());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("a1234", model.text());
- EXPECT_EQ(5U, model.cursor_pos());
+ EXPECT_STR_EQ("a1234", model.GetText());
+ EXPECT_EQ(5U, model.GetCursorPosition());
EXPECT_FALSE(model.Redo());
}
@@ -1114,282 +1074,72 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CompositionText) {
composition.selection = ui::Range(2, 3);
model.SetText(ASCIIToUTF16("ABCDE"));
- model.MoveCursorToEnd(false);
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
model.InsertChar('x');
- EXPECT_STR_EQ("ABCDEx", model.text());
+ EXPECT_STR_EQ("ABCDEx", model.GetText());
EXPECT_TRUE(model.Undo()); // set composition should forget undone edit.
model.SetCompositionText(composition);
EXPECT_TRUE(model.HasCompositionText());
EXPECT_TRUE(model.HasSelection());
- EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_STR_EQ("ABCDEabc", model.GetText());
// Accepting composition
model.ConfirmCompositionText();
- EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_STR_EQ("ABCDEabc", model.GetText());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_STR_EQ("ABCDE", model.GetText());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("", model.text());
+ EXPECT_STR_EQ("", model.GetText());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_STR_EQ("ABCDE", model.GetText());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_STR_EQ("ABCDEabc", model.GetText());
EXPECT_FALSE(model.Redo());
// Canceling composition
- model.MoveCursorToHome(false);
+ model.MoveCursorLeft(gfx::LINE_BREAK, false);
model.SetCompositionText(composition);
- EXPECT_STR_EQ("abcABCDEabc", model.text());
+ EXPECT_STR_EQ("abcABCDEabc", model.GetText());
model.CancelCompositionText();
- EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_STR_EQ("ABCDEabc", model.GetText());
EXPECT_FALSE(model.Redo());
- EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_STR_EQ("ABCDEabc", model.GetText());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_STR_EQ("ABCDE", model.GetText());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_STR_EQ("ABCDEabc", model.GetText());
EXPECT_FALSE(model.Redo());
// SetText with the same text as the result.
ResetModel(&model);
model.SetText(ASCIIToUTF16("ABCDE"));
- model.MoveCursorToEnd(false);
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
model.SetCompositionText(composition);
- EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_STR_EQ("ABCDEabc", model.GetText());
model.SetText(ASCIIToUTF16("ABCDEabc"));
- EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_STR_EQ("ABCDEabc", model.GetText());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_STR_EQ("ABCDE", model.GetText());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_STR_EQ("ABCDEabc", model.GetText());
EXPECT_FALSE(model.Redo());
// SetText with the different text than the result should not
// remember composition text.
ResetModel(&model);
model.SetText(ASCIIToUTF16("ABCDE"));
- model.MoveCursorToEnd(false);
+ model.MoveCursorRight(gfx::LINE_BREAK, false);
model.SetCompositionText(composition);
- EXPECT_STR_EQ("ABCDEabc", model.text());
+ EXPECT_STR_EQ("ABCDEabc", model.GetText());
model.SetText(ASCIIToUTF16("1234"));
- EXPECT_STR_EQ("1234", model.text());
+ EXPECT_STR_EQ("1234", model.GetText());
EXPECT_TRUE(model.Undo());
- EXPECT_STR_EQ("ABCDE", model.text());
+ EXPECT_STR_EQ("ABCDE", model.GetText());
EXPECT_TRUE(model.Redo());
- EXPECT_STR_EQ("1234", model.text());
+ EXPECT_STR_EQ("1234", model.GetText());
EXPECT_FALSE(model.Redo());
// TODO(oshima): We need MockInputMethod to test the behavior with IME.
}
-TEST_F(TextfieldViewsModelTest, TextStyleTest) {
- const SkColor black = 0xFF000000; // black is default text color.
- const SkColor white = 0xFFFFFFFF;
- TextfieldViewsModel model(NULL);
- TextStyle* color = model.CreateTextStyle();
- color->set_foreground(white);
- TextStyle* underline = model.CreateTextStyle();
- underline->set_underline(true);
- underline->set_foreground(white);
- TextStyle* strike = model.CreateTextStyle();
- strike->set_strike(true);
- strike->set_foreground(white);
-
- // Case 1: No overlaps
- model.ApplyTextStyle(color, ui::Range(1, 3));
- model.ApplyTextStyle(underline, ui::Range(5, 6));
-
- TextfieldViewsModel::TextFragments fragments;
- model.GetFragments(&fragments);
- // Styles with empty string simply returns an empty fragments.
- EXPECT_EQ(0U, fragments.size());
-
- // 1st style only.
- model.SetText(ASCIIToUTF16("01234")); // SetText doesn't change styles.
- model.GetFragments(&fragments);
- EXPECT_EQ(3U, fragments.size());
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(1U, fragments[0].range.end());
- EXPECT_EQ(black, fragments[0].style->foreground());
-
- EXPECT_EQ(1U, fragments[1].range.start());
- EXPECT_EQ(3U, fragments[1].range.end());
- EXPECT_EQ(color, fragments[1].style);
-
- EXPECT_EQ(3U, fragments[2].range.start());
- EXPECT_EQ(5U, fragments[2].range.end());
- EXPECT_EQ(black, fragments[2].style->foreground());
-
- // Clear styles
- model.ClearAllTextStyles();
- model.GetFragments(&fragments);
- EXPECT_EQ(1U, fragments.size());
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(5U, fragments[0].range.end());
- EXPECT_EQ(black, fragments[0].style->foreground());
-
- // Case 2: Overlaps on left and on right
- model.ApplyTextStyle(color, ui::Range(1, 3));
- model.ApplyTextStyle(strike, ui::Range(6, 8));
- model.ApplyTextStyle(underline, ui::Range(2, 7));
-
- // With short string
- model.SetText(ASCIIToUTF16("0"));
- model.GetFragments(&fragments);
- EXPECT_EQ(1U, fragments.size());
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(1U, fragments[0].range.end());
- EXPECT_EQ(black, fragments[0].style->foreground());
-
- // With mid-length string
- model.SetText(ASCIIToUTF16("0123"));
- model.GetFragments(&fragments);
- EXPECT_EQ(3U, fragments.size());
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(1U, fragments[0].range.end());
- EXPECT_EQ(black, fragments[0].style->foreground());
-
- EXPECT_EQ(1U, fragments[1].range.start());
- EXPECT_EQ(2U, fragments[1].range.end());
- EXPECT_EQ(color, fragments[1].style);
-
- EXPECT_EQ(2U, fragments[2].range.start());
- EXPECT_EQ(4U, fragments[2].range.end());
- EXPECT_EQ(underline, fragments[2].style);
-
- // With long (longer than styles) string
- model.SetText(ASCIIToUTF16("0123456789"));
- model.GetFragments(&fragments);
- EXPECT_EQ(5U, fragments.size());
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(1U, fragments[0].range.end());
- EXPECT_EQ(black, fragments[0].style->foreground());
-
- EXPECT_EQ(1U, fragments[1].range.start());
- EXPECT_EQ(2U, fragments[1].range.end());
- EXPECT_EQ(color, fragments[1].style);
-
- EXPECT_EQ(2U, fragments[2].range.start());
- EXPECT_EQ(7U, fragments[2].range.end());
- EXPECT_EQ(underline, fragments[2].style);
-
- EXPECT_EQ(7U, fragments[3].range.start());
- EXPECT_EQ(8U, fragments[3].range.end());
- EXPECT_EQ(strike, fragments[3].style);
-
- EXPECT_EQ(8U, fragments[4].range.start());
- EXPECT_EQ(10U, fragments[4].range.end());
- EXPECT_EQ(black, fragments[4].style->foreground());
-
- model.ClearAllTextStyles();
-
- // Case 3: The underline style splits the color style underneath.
- model.ApplyTextStyle(color, ui::Range(0, 15));
- model.ApplyTextStyle(underline, ui::Range(5, 6));
- model.GetFragments(&fragments);
- EXPECT_EQ(3U, fragments.size());
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(5U, fragments[0].range.end());
- EXPECT_EQ(color, fragments[0].style);
-
- EXPECT_EQ(5U, fragments[1].range.start());
- EXPECT_EQ(6U, fragments[1].range.end());
- EXPECT_EQ(underline, fragments[1].style);
-
- EXPECT_EQ(6U, fragments[2].range.start());
- EXPECT_EQ(10U, fragments[2].range.end());
- EXPECT_EQ(color, fragments[2].style);
-
- model.ClearAllTextStyles();
-
- // Case 4: The underline style moves the color style underneath.
- model.ApplyTextStyle(color, ui::Range(0, 15));
- model.ApplyTextStyle(underline, ui::Range(0, 6));
- model.GetFragments(&fragments);
- EXPECT_EQ(2U, fragments.size());
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(6U, fragments[0].range.end());
- EXPECT_EQ(underline, fragments[0].style);
-
- EXPECT_EQ(6U, fragments[1].range.start());
- EXPECT_EQ(10U, fragments[1].range.end());
- EXPECT_EQ(color, fragments[1].style);
-
- model.ClearAllTextStyles();
-
- model.ApplyTextStyle(color, ui::Range(0, 10));
- model.ApplyTextStyle(underline, ui::Range(6, 10));
- model.GetFragments(&fragments);
- EXPECT_EQ(2U, fragments.size());
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(6U, fragments[0].range.end());
- EXPECT_EQ(color, fragments[0].style);
-
- EXPECT_EQ(6U, fragments[1].range.start());
- EXPECT_EQ(10U, fragments[1].range.end());
- EXPECT_EQ(underline, fragments[1].style);
-
- model.ClearAllTextStyles();
- // Case 5: The strike style hides the unerline style underneath.
- model.ApplyTextStyle(color, ui::Range(0, 15));
- model.ApplyTextStyle(underline, ui::Range(0, 6));
- model.ApplyTextStyle(strike, ui::Range(4, 7));
- model.GetFragments(&fragments);
- EXPECT_EQ(3U, fragments.size());
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(4U, fragments[0].range.end());
- EXPECT_EQ(underline, fragments[0].style);
-
- EXPECT_EQ(4U, fragments[1].range.start());
- EXPECT_EQ(7U, fragments[1].range.end());
- EXPECT_EQ(strike, fragments[1].style);
-
- EXPECT_EQ(7U, fragments[2].range.start());
- EXPECT_EQ(10U, fragments[2].range.end());
- EXPECT_EQ(color, fragments[2].style);
-
- // Case 6: Reversed range.
- model.ClearAllTextStyles();
- model.ApplyTextStyle(color, ui::Range(3, 1));
- model.ApplyTextStyle(underline, ui::Range(6, 4));
- model.ApplyTextStyle(strike, ui::Range(5, 2));
- model.GetFragments(&fragments);
- EXPECT_EQ(5U, fragments.size());
-
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(1U, fragments[0].range.end());
- EXPECT_EQ(black, fragments[0].style->foreground());
-
- EXPECT_EQ(1U, fragments[1].range.start());
- EXPECT_EQ(2U, fragments[1].range.end());
- EXPECT_EQ(color, fragments[1].style);
-
- EXPECT_EQ(2U, fragments[2].range.start());
- EXPECT_EQ(5U, fragments[2].range.end());
- EXPECT_EQ(strike, fragments[2].style);
-
- EXPECT_EQ(5U, fragments[3].range.start());
- EXPECT_EQ(6U, fragments[3].range.end());
- EXPECT_EQ(underline, fragments[3].style);
-
- EXPECT_EQ(6U, fragments[4].range.start());
- EXPECT_EQ(10U, fragments[4].range.end());
- EXPECT_EQ(black, fragments[4].style->foreground());
-
- // Case 7: empty / invald range
- model.ClearAllTextStyles();
- model.ApplyTextStyle(color, ui::Range(0, 0));
- model.ApplyTextStyle(underline, ui::Range(4, 4));
- ui::Range invalid = ui::Range(0, 2).Intersect(ui::Range(3, 4));
- ASSERT_FALSE(invalid.IsValid());
-
- model.ApplyTextStyle(strike, invalid);
- model.GetFragments(&fragments);
- EXPECT_EQ(1U, fragments.size());
-
- EXPECT_EQ(0U, fragments[0].range.start());
- EXPECT_EQ(10U, fragments[0].range.end());
- EXPECT_EQ(black, fragments[0].style->foreground());
-}
-
} // namespace views