diff options
author | benrg@chromium.org <benrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-21 01:27:28 +0000 |
---|---|---|
committer | benrg@chromium.org <benrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-21 01:27:28 +0000 |
commit | d66009e4f25eab259ce05315ff8b506cb52c24f6 (patch) | |
tree | dc854e251b329b0aa8cf95ae2378cd3561af33df | |
parent | d4ab68006f402ef6e5ccf0fc3b075ab65b638f3e (diff) | |
download | chromium_src-d66009e4f25eab259ce05315ff8b506cb52c24f6.zip chromium_src-d66009e4f25eab259ce05315ff8b506cb52c24f6.tar.gz chromium_src-d66009e4f25eab259ce05315ff8b506cb52c24f6.tar.bz2 |
Merge left and right cursor movement code in RenderText, and misc fixes
* Combine method pairs for left/right cursor motion in RenderText{,Linux,Win}, eliminating a lot of duplicate logic. The merged functions use new enums VisualTextDirection {VISUAL_LEFT, VISUAL_RIGHT} and LogicalTextDirection {LOGICAL_PREVIOUS, LOGICAL_NEXT}.
* Make CalculateSubstringBounds and GetSelectionBounds return the result instead of taking it as an out pointer argument.
* Remove Utf16IndexOfAdjacentGrapheme for clarity (it took a UTF-8 index as its argument)
* Delete some unused obsolete methods in RenderText, remove some logging code, and fix some comments.
The logic should be unchanged except that in the Backspace handler in NativeTextfieldViews, cursor_changed is now set to true only if the text changed (like Delete). Formerly it was always set to true, which appears to be a bug.
BUG=none
TEST=existing unit tests
Review URL: http://codereview.chromium.org/8958024
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@118580 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ui/gfx/render_text.cc | 184 | ||||
-rw-r--r-- | ui/gfx/render_text.h | 100 | ||||
-rw-r--r-- | ui/gfx/render_text_linux.cc | 439 | ||||
-rw-r--r-- | ui/gfx/render_text_linux.h | 66 | ||||
-rw-r--r-- | ui/gfx/render_text_unittest.cc | 124 | ||||
-rw-r--r-- | ui/gfx/render_text_win.cc | 247 | ||||
-rw-r--r-- | ui/gfx/render_text_win.h | 28 | ||||
-rw-r--r-- | ui/views/controls/textfield/native_textfield_views.cc | 48 | ||||
-rw-r--r-- | ui/views/controls/textfield/textfield_views_model.cc | 30 | ||||
-rw-r--r-- | ui/views/controls/textfield/textfield_views_model.h | 7 | ||||
-rw-r--r-- | ui/views/controls/textfield/textfield_views_model_unittest.cc | 222 |
11 files changed, 616 insertions, 879 deletions
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc index ec744ca..bc62a66 100644 --- a/ui/gfx/render_text.cc +++ b/ui/gfx/render_text.cc @@ -18,6 +18,16 @@ 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 = SkColorSetRGB(30, 144, 255); +const SkColor kUnfocusedSelectionColor = SK_ColorLTGRAY; +const SkColor kCursorColor = SK_ColorBLACK; + #ifndef NDEBUG // Check StyleRanges invariant conditions: sorted and non-overlapping ranges. void CheckStyleRanges(const gfx::StyleRanges& style_ranges, size_t length) { @@ -340,42 +350,26 @@ void RenderText::SetCursorPosition(size_t position) { MoveCursorTo(position, false); } -void RenderText::MoveCursorLeft(BreakType break_type, bool select) { - SelectionModel position(selection_model()); - position.set_selection_start(GetCursorPosition()); - // Cancelling a selection moves to the edge of the selection. - if (break_type != LINE_BREAK && !EmptySelection() && !select) { - // Use the selection start if it is left of the selection end. - SelectionModel selection_start = GetSelectionModelForSelectionStart(); - if (GetCursorBounds(selection_start, true).x() < - GetCursorBounds(position, true).x()) - position = selection_start; - // For word breaks, use the nearest word boundary left of the selection. - if (break_type == WORD_BREAK) - position = GetLeftSelectionModel(position, break_type); - } else { - position = GetLeftSelectionModel(position, break_type); - } - if (select) - position.set_selection_start(GetSelectionStart()); - MoveCursorTo(position); -} - -void RenderText::MoveCursorRight(BreakType break_type, bool select) { +void RenderText::MoveCursor(BreakType break_type, + VisualCursorDirection direction, + bool select) { SelectionModel position(selection_model()); position.set_selection_start(GetCursorPosition()); // Cancelling a selection moves to the edge of the selection. if (break_type != LINE_BREAK && !EmptySelection() && !select) { - // Use the selection start if it is right of the selection end. SelectionModel selection_start = GetSelectionModelForSelectionStart(); - if (GetCursorBounds(selection_start, true).x() > - GetCursorBounds(position, true).x()) + int start_x = GetCursorBounds(selection_start, true).x(); + int cursor_x = GetCursorBounds(position, true).x(); + // Use the selection start if it is left (when |direction| is CURSOR_LEFT) + // or right (when |direction| is CURSOR_RIGHT) of the selection end. + if (direction == CURSOR_RIGHT ? start_x > cursor_x : start_x < cursor_x) position = selection_start; - // For word breaks, use the nearest word boundary right of the selection. + // For word breaks, use the nearest word boundary in the appropriate + // |direction|. if (break_type == WORD_BREAK) - position = GetRightSelectionModel(position, break_type); + position = GetAdjacentSelectionModel(position, break_type, direction); } else { - position = GetRightSelectionModel(position, break_type); + position = GetAdjacentSelectionModel(position, break_type, direction); } if (select) position.set_selection_start(GetSelectionStart()); @@ -395,10 +389,10 @@ bool RenderText::MoveCursorTo(const SelectionModel& model) { sel.set_caret_pos(0); sel.set_caret_placement(SelectionModel::LEADING); } else if (sel.caret_pos() >= text_length) { - SelectionModel end = GetTextDirection() == base::i18n::RIGHT_TO_LEFT ? - LeftEndSelectionModel() : RightEndSelectionModel(); - sel.set_caret_pos(end.caret_pos()); - sel.set_caret_placement(end.caret_placement()); + SelectionModel end_selection = + EdgeSelectionModel(GetVisualDirectionOfLogicalEnd()); + sel.set_caret_pos(end_selection.caret_pos()); + sel.set_caret_placement(end_selection.caret_placement()); } if (!IsCursorablePosition(sel.selection_start()) || @@ -429,14 +423,14 @@ bool RenderText::SelectRange(const ui::Range& range) { size_t pos = end; SelectionModel::CaretPlacement placement = SelectionModel::LEADING; if (start < end) { - pos = GetIndexOfPreviousGrapheme(end); + pos = IndexOfAdjacentGrapheme(end, CURSOR_BACKWARD); DCHECK_LT(pos, end); placement = SelectionModel::TRAILING; } else if (end == text_length) { - SelectionModel boundary = GetTextDirection() == base::i18n::RIGHT_TO_LEFT ? - LeftEndSelectionModel() : RightEndSelectionModel(); - pos = boundary.caret_pos(); - placement = boundary.caret_placement(); + SelectionModel end_selection = + EdgeSelectionModel(GetVisualDirectionOfLogicalEnd()); + pos = end_selection.caret_pos(); + placement = end_selection.caret_placement(); } SetSelectionModel(SelectionModel(start, end, pos, placement)); return true; @@ -459,8 +453,8 @@ void RenderText::ClearSelection() { } void RenderText::SelectAll() { - SelectionModel sel(RightEndSelectionModel()); - sel.set_selection_start(LeftEndSelectionModel().selection_start()); + SelectionModel sel = EdgeSelectionModel(CURSOR_RIGHT); + sel.set_selection_start(EdgeSelectionModel(CURSOR_LEFT).selection_start()); SetSelectionModel(sel); } @@ -529,10 +523,9 @@ void RenderText::ApplyDefaultStyle() { UpdateLayout(); } -base::i18n::TextDirection RenderText::GetTextDirection() { - if (base::i18n::IsRTL()) - return base::i18n::RIGHT_TO_LEFT; - return base::i18n::LEFT_TO_RIGHT; +VisualCursorDirection RenderText::GetVisualDirectionOfLogicalEnd() { + return GetTextDirection() == base::i18n::LEFT_TO_RIGHT ? + CURSOR_RIGHT : CURSOR_LEFT; } void RenderText::Draw(Canvas* canvas) { @@ -562,10 +555,6 @@ const Rect& RenderText::GetUpdatedCursorBounds() { return cursor_bounds_; } -size_t RenderText::GetIndexOfNextGrapheme(size_t position) { - return IndexOfAdjacentGrapheme(position, true); -} - SelectionModel RenderText::GetSelectionModelForSelectionStart() { size_t selection_start = GetSelectionStart(); size_t selection_end = GetCursorPosition(); @@ -574,9 +563,10 @@ SelectionModel RenderText::GetSelectionModelForSelectionStart() { selection_start, SelectionModel::LEADING); else if (selection_start > selection_end) - return SelectionModel(selection_start, - GetIndexOfPreviousGrapheme(selection_start), - SelectionModel::TRAILING); + return SelectionModel( + selection_start, + IndexOfAdjacentGrapheme(selection_start, CURSOR_BACKWARD), + SelectionModel::TRAILING); return selection_model_; } @@ -595,77 +585,18 @@ const Point& RenderText::GetUpdatedDisplayOffset() { return display_offset_; } -SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current, - BreakType break_type) { - if (break_type == LINE_BREAK) - return LeftEndSelectionModel(); - size_t pos = std::max<int>(current.selection_end() - 1, 0); - if (break_type == CHARACTER_BREAK) - return SelectionModel(pos, pos, SelectionModel::LEADING); +SelectionModel RenderText::GetAdjacentSelectionModel( + const SelectionModel& current, + BreakType break_type, + VisualCursorDirection direction) { + EnsureLayout(); - // Notes: We always iterate words from the beginning. - // 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 current; - while (iter.Advance()) { - if (iter.IsWord()) { - size_t begin = iter.pos() - iter.GetString().length(); - if (begin == current.selection_end()) { - // The cursor is at the beginning of a word. - // Move to previous word. - break; - } else if (iter.pos() >= current.selection_end()) { - // The cursor is in the middle or at the end of a word. - // Move to the top of current word. - pos = begin; - break; - } else { - pos = iter.pos() - iter.GetString().length(); - } - } - } - - return SelectionModel(pos, pos, SelectionModel::LEADING); -} - -SelectionModel RenderText::GetRightSelectionModel(const SelectionModel& current, - BreakType break_type) { - if (text_.empty()) - return SelectionModel(0, 0, SelectionModel::LEADING); - if (break_type == LINE_BREAK) - return RightEndSelectionModel(); - size_t pos = std::min(current.selection_end() + 1, text().length()); + if (break_type == LINE_BREAK || text().empty()) + return EdgeSelectionModel(direction); if (break_type == CHARACTER_BREAK) - return SelectionModel(pos, pos, SelectionModel::LEADING); - - base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); - bool success = iter.Init(); - DCHECK(success); - if (!success) - return current; - while (iter.Advance()) { - pos = iter.pos(); - if (iter.IsWord() && pos > current.selection_end()) - break; - } - return SelectionModel(pos, pos, SelectionModel::LEADING); -} - -SelectionModel RenderText::LeftEndSelectionModel() { - return SelectionModel(0, 0, SelectionModel::LEADING); -} - -SelectionModel RenderText::RightEndSelectionModel() { - size_t cursor = text().length(); - size_t caret_pos = GetIndexOfPreviousGrapheme(cursor); - SelectionModel::CaretPlacement placement = (caret_pos == cursor) ? - SelectionModel::LEADING : SelectionModel::TRAILING; - return SelectionModel(cursor, caret_pos, placement); + return AdjacentCharSelectionModel(current, direction); + DCHECK(break_type == WORD_BREAK); + return AdjacentWordSelectionModel(current, direction); } void RenderText::SetSelectionModel(const SelectionModel& model) { @@ -680,10 +611,6 @@ void RenderText::SetSelectionModel(const SelectionModel& model) { cached_bounds_and_offset_valid_ = false; } -size_t RenderText::GetIndexOfPreviousGrapheme(size_t position) { - return IndexOfAdjacentGrapheme(position, false); -} - void RenderText::ApplyCompositionAndSelectionStyles( StyleRanges* style_ranges) { // TODO(msw): This pattern ought to be reconsidered; what about composition @@ -717,7 +644,8 @@ void RenderText::ApplyCompositionAndSelectionStyles( replacement_mode_style.foreground = kSelectedTextColor; size_t cursor = GetCursorPosition(); replacement_mode_style.range.set_start(cursor); - replacement_mode_style.range.set_end(GetIndexOfNextGrapheme(cursor)); + replacement_mode_style.range.set_end( + IndexOfAdjacentGrapheme(cursor, CURSOR_FORWARD)); ApplyStyleRangeImpl(style_ranges, replacement_mode_style); } } @@ -807,7 +735,7 @@ int RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) { void RenderText::MoveCursorTo(size_t position, bool select) { size_t cursor = std::min(position, text().length()); - size_t caret_pos = GetIndexOfPreviousGrapheme(cursor); + size_t caret_pos = IndexOfAdjacentGrapheme(cursor, CURSOR_BACKWARD); SelectionModel::CaretPlacement placement = (caret_pos == cursor) ? SelectionModel::LEADING : SelectionModel::TRAILING; size_t selection_start = select ? GetSelectionStart() : cursor; @@ -857,16 +785,14 @@ void RenderText::UpdateCachedBoundsAndOffset() { } void RenderText::DrawSelection(Canvas* canvas) { - TRACE_EVENT0("gfx", "RenderText::DrawSelection"); - std::vector<Rect> sel; - GetSubstringBounds(GetSelectionStart(), GetCursorPosition(), &sel); + std::vector<Rect> sel = GetSubstringBounds( + GetSelectionStart(), GetCursorPosition()); SkColor color = focused() ? kFocusedSelectionColor : kUnfocusedSelectionColor; for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i) canvas->FillRect(color, *i); } void RenderText::DrawCursor(Canvas* canvas) { - TRACE_EVENT0("gfx", "RenderText::DrawCursor"); // Paint cursor. Replace cursor is drawn as rectangle for now. // TODO(msw): Draw a better cursor with a better indication of association. if (cursor_visible() && focused()) { diff --git a/ui/gfx/render_text.h b/ui/gfx/render_text.h index 65057ab..e784f1d 100644 --- a/ui/gfx/render_text.h +++ b/ui/gfx/render_text.h @@ -57,16 +57,6 @@ class SkiaTextRenderer { } // namespace internal -// 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 = SkColorSetRGB(30, 144, 255); -const SkColor kUnfocusedSelectionColor = SK_ColorLTGRAY; -const SkColor kCursorColor = SK_ColorBLACK; - // A visual style applicable to a range of text. struct UI_EXPORT StyleRange { StyleRange(); @@ -91,7 +81,22 @@ enum BreakType { LINE_BREAK, }; -// TODO(msw): Implement RenderText[Win|Linux] for Uniscribe/Pango BiDi... +// VisualCursorDirection and LogicalCursorDirection represent directions of +// motion of the cursor in BiDi text. The combinations that make sense are: +// +// base::i18n::TextDirection VisualCursorDirection LogicalCursorDirection +// LEFT_TO_RIGHT CURSOR_LEFT CURSOR_BACKWARD +// LEFT_TO_RIGHT CURSOR_RIGHT CURSOR_FORWARD +// RIGHT_TO_LEFT CURSOR_RIGHT CURSOR_BACKWARD +// RIGHT_TO_LEFT CURSOR_LEFT CURSOR_FORWARD +enum VisualCursorDirection { + CURSOR_LEFT, + CURSOR_RIGHT +}; +enum LogicalCursorDirection { + CURSOR_BACKWARD, + CURSOR_FORWARD +}; // RenderText represents an abstract model of styled text and its corresponding // visual layout. Support is built in for a cursor, a selection, simple styling, @@ -144,8 +149,9 @@ class UI_EXPORT RenderText { // Moves the cursor left or right. Cursor movement is visual, meaning that // left and right are relative to screen, not the directionality of the text. // If |select| is false, the selection start is moved to the same position. - void MoveCursorLeft(BreakType break_type, bool select); - void MoveCursorRight(BreakType break_type, bool select); + void MoveCursor(BreakType break_type, + VisualCursorDirection direction, + bool select); // Set the selection_model_ to the value of |selection|. // The selection model components are modified if invalid. @@ -197,7 +203,13 @@ class UI_EXPORT RenderText { // Apply |default_style_| over the entire text range. void ApplyDefaultStyle(); - virtual base::i18n::TextDirection GetTextDirection(); + // Returns the dominant direction of the current text. + virtual base::i18n::TextDirection GetTextDirection() = 0; + + // Returns the visual movement direction corresponding to the logical end + // of the text, considering only the dominant direction returned by + // |GetTextDirection()|, not the direction of a particular run. + VisualCursorDirection GetVisualDirectionOfLogicalEnd(); // Get the width of the entire string. virtual int GetStringWidth() = 0; @@ -220,8 +232,14 @@ class UI_EXPORT RenderText { // Subsequent text, cursor, or bounds changes may invalidate returned values. const Rect& GetUpdatedCursorBounds(); - // Get the logical index of the grapheme following the argument |position|. - size_t GetIndexOfNextGrapheme(size_t position); + // Given an |index| in text(), return the next or previous grapheme boundary + // in logical order (that is, the nearest index for which + // |IsCursorablePosition(index)| returns true). The return value is in the + // range 0 to text().length() inclusive (the input is clamped if it is out of + // that range). Always moves by at least one character index unless the + // supplied index is already at the boundary of the string. + virtual size_t IndexOfAdjacentGrapheme(size_t index, + LogicalCursorDirection direction) = 0; // Return a SelectionModel with the cursor at the current selection's start. // The returned value represents a cursor/caret position without a selection. @@ -240,28 +258,37 @@ class UI_EXPORT RenderText { // Get the selection model that visually neighbors |position| by |break_type|. // The returned value represents a cursor/caret position without a selection. - virtual SelectionModel GetLeftSelectionModel(const SelectionModel& current, - BreakType break_type); - virtual SelectionModel GetRightSelectionModel(const SelectionModel& current, - BreakType break_type); + SelectionModel GetAdjacentSelectionModel(const SelectionModel& current, + BreakType break_type, + VisualCursorDirection direction); + + // Get the selection model visually left/right of |selection| by one grapheme. + // The returned value represents a cursor/caret position without a selection. + virtual SelectionModel AdjacentCharSelectionModel( + const SelectionModel& selection, + VisualCursorDirection direction) = 0; + + // Get the selection model visually left/right of |selection| by one word. + // The returned value represents a cursor/caret position without a selection. + virtual SelectionModel AdjacentWordSelectionModel( + const SelectionModel& selection, + VisualCursorDirection direction) = 0; // Get the SelectionModels corresponding to visual text ends. // The returned value represents a cursor/caret position without a selection. - virtual SelectionModel LeftEndSelectionModel(); - virtual SelectionModel RightEndSelectionModel(); + virtual SelectionModel EdgeSelectionModel( + VisualCursorDirection direction) = 0; // Sets the selection model, the argument is assumed to be valid. virtual void SetSelectionModel(const SelectionModel& model); // Get the visual bounds containing the logical substring within |from| to - // |to| into |bounds|. If |from| equals to |to|, |bounds| is set as empty. - // These bounds could be visually discontinuous if the substring is split by a - // LTR/RTL level change. These bounds are in local coordinates, but may be - // outside the visible region if the text is longer than the textfield. - // Subsequent text, cursor, or bounds changes may invalidate returned values. - virtual void GetSubstringBounds(size_t from, - size_t to, - std::vector<Rect>* bounds) = 0; + // |to|. If |from| equals |to|, the result is empty. These bounds could be + // visually discontinuous if the substring is split by a LTR/RTL level change. + // These bounds are in local coordinates, but may be outside the visible + // region if the text is longer than the textfield. Subsequent text, cursor, + // or bounds changes may invalidate returned values. + virtual std::vector<Rect> GetSubstringBounds(size_t from, size_t to) = 0; // Return true if cursor can appear in front of the character at |position|, // which means it is a grapheme boundary or the first character in the text. @@ -277,12 +304,6 @@ class UI_EXPORT RenderText { // Draw the text. virtual void DrawVisualText(Canvas* canvas) = 0; - // Get the logical index of the grapheme preceding the argument |position|. - // If |IsCursorablePosition(position)| is true, the result will be the start - // of the previous grapheme, if any. Otherwise, the result will be the start - // of the grapheme containing |position|. - size_t GetIndexOfPreviousGrapheme(size_t position); - // Apply composition style (underline) to composition range and selection // style (foreground) to selection range. void ApplyCompositionAndSelectionStyles(StyleRanges* style_ranges); @@ -314,13 +335,6 @@ class UI_EXPORT RenderText { FRIEND_TEST_ALL_PREFIXES(RenderTextTest, SelectionModels); FRIEND_TEST_ALL_PREFIXES(RenderTextTest, OriginForSkiaDrawing); - // Return an index belonging to the |next| or previous logical grapheme. - // If |next| is false and |IsCursorablePosition(index)| is true, the result - // will be the start of the previous grapheme, if any. Otherwise, the result - // will be the start of the grapheme containing |index|. - // The return value is bounded by 0 and the text length, inclusive. - virtual size_t IndexOfAdjacentGrapheme(size_t index, bool next) = 0; - // Set the cursor to |position|, with the caret trailing the previous // grapheme, or if there is no previous grapheme, leading the cursor position. // If |select| is false, the selection start is moved to the same position. diff --git a/ui/gfx/render_text_linux.cc b/ui/gfx/render_text_linux.cc index fe3287c..1043d88 100644 --- a/ui/gfx/render_text_linux.cc +++ b/ui/gfx/render_text_linux.cc @@ -9,7 +9,6 @@ #include <string> #include <vector> -#include "base/debug/trace_event.h" #include "base/i18n/break_iterator.h" #include "base/logging.h" #include "third_party/skia/include/core/SkTypeface.h" @@ -19,11 +18,25 @@ #include "unicode/uchar.h" #include "unicode/ustring.h" +namespace gfx { + namespace { -// Returns whether the given Pango item is Left to Right. -bool IsRunLTR(const PangoItem* item) { - return (item->analysis.level & 1) == 0; +// Returns the preceding element in a GSList (O(n)). +GSList* GSListPrevious(GSList* head, GSList* item) { + GSList* prev = NULL; + for (GSList* cur = head; cur != item; cur = cur->next) { + DCHECK(cur); + prev = cur; + } + return prev; +} + +// Returns true if the given visual cursor |direction| is logically forward +// motion in the given Pango |item|. +bool IsForwardMotion(VisualCursorDirection direction, const PangoItem* item) { + bool rtl = item->analysis.level & 1; + return rtl == (direction == CURSOR_LEFT); } // Checks whether |range| contains |index|. This is not the same as calling @@ -39,8 +52,6 @@ bool IndexInRange(const ui::Range& range, size_t index) { // Since caret_pos is used internally, we could save utf8 index for caret_pos // to avoid conversion. -namespace gfx { - RenderTextLinux::RenderTextLinux() : layout_(NULL), current_line_(NULL), @@ -84,9 +95,9 @@ SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) { // When the point is outside of text, return HOME/END position. if (p.x() < 0) - return LeftEndSelectionModel(); + return EdgeSelectionModel(CURSOR_LEFT); else if (p.x() > GetStringWidth()) - return RightEndSelectionModel(); + return EdgeSelectionModel(CURSOR_RIGHT); int caret_pos, trailing; pango_layout_xy_to_index(layout_, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE, @@ -133,61 +144,110 @@ Rect RenderTextLinux::GetCursorBounds(const SelectionModel& selection, return bounds; } -SelectionModel RenderTextLinux::GetLeftSelectionModel( - const SelectionModel& current, - BreakType break_type) { - EnsureLayout(); +// Assume caret_pos in |current| is n, 'l' represents leading in +// caret_placement and 't' represents trailing in caret_placement. Following +// is the calculation from (caret_pos, caret_placement) in |current| to +// (selection_end, caret_pos, caret_placement) when moving cursor left/right by +// one grapheme (for simplicity, assume each grapheme is one character). +// If n is in LTR (if moving left) or RTL (if moving right) run, +// (n, t) --> (n, n, l). +// (n, l) --> (n-1, n-1, l) if n is inside run (not at boundary). +// (n, l) --> goto across run case if n is at run boundary. +// Otherwise, +// (n, l) --> (n+1, n, t). +// (n, t) --> (n+2, n+1, t) if n is inside run. +// (n, t) --> goto across run case if n is at run boundary. +// If n is at run boundary, get its visually left/right run, +// If left/right run is LTR/RTL run, +// (n, t) --> (left/right run's end, left/right run's end, l). +// Otherwise, +// (n, t) --> (left/right run's begin + 1, left/right run's begin, t). +SelectionModel RenderTextLinux::AdjacentCharSelectionModel( + const SelectionModel& selection, + VisualCursorDirection direction) { + size_t caret = selection.caret_pos(); + SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); + GSList* run = GetRunContainingPosition(caret); + DCHECK(run); - if (break_type == LINE_BREAK || text().empty()) - return LeftEndSelectionModel(); - if (break_type == CHARACTER_BREAK) - return LeftSelectionModel(current); - DCHECK(break_type == WORD_BREAK); - return LeftSelectionModelByWord(current); -} + PangoLayoutRun* layout_run = reinterpret_cast<PangoLayoutRun*>(run->data); + PangoItem* item = layout_run->item; + size_t run_start = Utf8IndexToUtf16Index(item->offset); + size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); -SelectionModel RenderTextLinux::GetRightSelectionModel( - const SelectionModel& current, - BreakType break_type) { - EnsureLayout(); + if (!IsForwardMotion(direction, item)) { + if (caret_placement == SelectionModel::TRAILING) + return SelectionModel(caret, caret, SelectionModel::LEADING); + else if (caret > run_start) { + caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); + return SelectionModel(caret, caret, SelectionModel::LEADING); + } + } else { + if (caret_placement == SelectionModel::LEADING) { + size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); + return SelectionModel(cursor, caret, SelectionModel::TRAILING); + } else if (selection.selection_end() < run_end) { + caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); + size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); + return SelectionModel(cursor, caret, SelectionModel::TRAILING); + } + } + + // The character is at the edge of its run; advance to the adjacent visual + // run. + // TODO(xji): Keep a vector of runs to avoid using a singly-linked list. + GSList* adjacent_run = (direction == CURSOR_RIGHT) ? + run->next : GSListPrevious(current_line_->runs, run); + if (!adjacent_run) + return EdgeSelectionModel(direction); - if (break_type == LINE_BREAK || text().empty()) - return RightEndSelectionModel(); - if (break_type == CHARACTER_BREAK) - return RightSelectionModel(current); - DCHECK(break_type == WORD_BREAK); - return RightSelectionModelByWord(current); + item = reinterpret_cast<PangoLayoutRun*>(adjacent_run->data)->item; + return IsForwardMotion(direction, item) ? + FirstSelectionModelInsideRun(item) : LastSelectionModelInsideRun(item); } -SelectionModel RenderTextLinux::LeftEndSelectionModel() { - if (GetTextDirection() == base::i18n::RIGHT_TO_LEFT) { - if (current_line_->runs) { - PangoLayoutRun* first_visual_run = - reinterpret_cast<PangoLayoutRun*>(current_line_->runs->data); - PangoItem* item = first_visual_run->item; - if (IsRunLTR(item)) { - size_t caret = Utf8IndexToUtf16Index(item->offset); - return SelectionModel(text().length(), caret, SelectionModel::LEADING); - } else { // RTL. - size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length, - false); - return SelectionModel(text().length(), caret, SelectionModel::TRAILING); - } - } +SelectionModel RenderTextLinux::AdjacentWordSelectionModel( + const SelectionModel& selection, + VisualCursorDirection direction) { + base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); + bool success = iter.Init(); + DCHECK(success); + if (!success) + return selection; + + SelectionModel end = EdgeSelectionModel(direction); + SelectionModel cur(selection); + while (!cur.Equals(end)) { + cur = AdjacentCharSelectionModel(cur, direction); + size_t caret = cur.caret_pos(); + GSList* run = GetRunContainingPosition(caret); + DCHECK(run); + PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; + size_t cursor = cur.selection_end(); + if (IsForwardMotion(direction, item) ? + iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor)) + return cur; } - return SelectionModel(0, 0, SelectionModel::LEADING); -} -SelectionModel RenderTextLinux::RightEndSelectionModel() { - if (GetTextDirection() == base::i18n::LEFT_TO_RIGHT) { - PangoLayoutRun* last_visual_run = GetLastRun(); - if (last_visual_run) { - PangoItem* item = last_visual_run->item; - if (IsRunLTR(item)) { - size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length, - false); + return end; +} + +SelectionModel RenderTextLinux::EdgeSelectionModel( + VisualCursorDirection direction) { + if (direction == GetVisualDirectionOfLogicalEnd()) { + // Advance to the logical end of the text. + GSList* run = current_line_->runs; + if (direction == CURSOR_RIGHT) + run = g_slist_last(run); + if (run) { + PangoLayoutRun* end_run = reinterpret_cast<PangoLayoutRun*>(run->data); + PangoItem* item = end_run->item; + if (IsForwardMotion(direction, item)) { + size_t caret = Utf8IndexToUtf16Index( + Utf8IndexOfAdjacentGrapheme(item->offset + item->length, + CURSOR_BACKWARD)); return SelectionModel(text().length(), caret, SelectionModel::TRAILING); - } else { // RTL. + } else { size_t caret = Utf8IndexToUtf16Index(item->offset); return SelectionModel(text().length(), caret, SelectionModel::LEADING); } @@ -205,22 +265,19 @@ void RenderTextLinux::SetSelectionModel(const SelectionModel& model) { RenderText::SetSelectionModel(model); } -void RenderTextLinux::GetSubstringBounds(size_t from, - size_t to, - std::vector<Rect>* bounds) { +std::vector<Rect> RenderTextLinux::GetSubstringBounds(size_t from, size_t to) { DCHECK(from <= text().length()); DCHECK(to <= text().length()); - bounds->clear(); if (from == to) - return; + return std::vector<Rect>(); EnsureLayout(); if (from == GetSelectionStart() && to == GetCursorPosition()) - GetSelectionBounds(bounds); + return GetSelectionBounds(); else - CalculateSubstringBounds(from, to, bounds); + return CalculateSubstringBounds(from, to); } bool RenderTextLinux::IsCursorablePosition(size_t position) { @@ -300,7 +357,6 @@ void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) { } void RenderTextLinux::DrawVisualText(Canvas* canvas) { - TRACE_EVENT0("gfx", "RenderTextLinux::DrawVisualText"); DCHECK(layout_); Point offset(GetOriginForSkiaDrawing()); @@ -336,7 +392,7 @@ void RenderTextLinux::DrawVisualText(Canvas* canvas) { size_t run_start = run->item->offset; size_t first_glyph_byte_index = run_start + run->glyphs->log_clusters[0]; - size_t style_increment = IsRunLTR(run->item) ? 1 : -1; + size_t style_increment = IsForwardMotion(CURSOR_RIGHT, run->item) ? 1 : -1; // Find the initial style for this run. // TODO(asvitkine): Can we avoid looping here, e.g. by caching this per run? @@ -351,14 +407,13 @@ void RenderTextLinux::DrawVisualText(Canvas* canvas) { PangoFontDescription* native_font = pango_font_describe(run->item->analysis.font); - { - TRACE_EVENT0("gfx", "RenderTextLinux::DrawVisualText SetFont"); - const char* family_name = pango_font_description_get_family(native_font); - SkAutoTUnref<SkTypeface> typeface( - SkTypeface::CreateFromName(family_name, SkTypeface::kNormal)); - renderer.SetTypeface(typeface.get()); - renderer.SetTextSize(GetPangoFontSizeInPixels(native_font)); - } + + const char* family_name = pango_font_description_get_family(native_font); + SkAutoTUnref<SkTypeface> typeface( + SkTypeface::CreateFromName(family_name, SkTypeface::kNormal)); + renderer.SetTypeface(typeface.get()); + renderer.SetTextSize(GetPangoFontSizeInPixels(native_font)); + pango_font_description_free(native_font); SkScalar glyph_x = x; @@ -418,11 +473,14 @@ void RenderTextLinux::DrawVisualText(Canvas* canvas) { } } -size_t RenderTextLinux::IndexOfAdjacentGrapheme(size_t index, bool next) { +size_t RenderTextLinux::IndexOfAdjacentGrapheme( + size_t index, + LogicalCursorDirection direction) { if (index > text().length()) return text().length(); EnsureLayout(); - return Utf16IndexOfAdjacentGrapheme(Utf16IndexToUtf8Index(index), next); + return Utf8IndexToUtf16Index( + Utf8IndexOfAdjacentGrapheme(Utf16IndexToUtf8Index(index), direction)); } GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const { @@ -441,18 +499,18 @@ GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const { size_t RenderTextLinux::Utf8IndexOfAdjacentGrapheme( size_t utf8_index_of_current_grapheme, - bool next) const { + LogicalCursorDirection direction) const { const char* ch = layout_text_ + utf8_index_of_current_grapheme; int char_offset = static_cast<int>(g_utf8_pointer_to_offset(layout_text_, ch)); int start_char_offset = char_offset; - if (!next) { + if (direction == CURSOR_BACKWARD) { if (char_offset > 0) { do { --char_offset; } while (char_offset > 0 && !log_attrs_[char_offset].is_cursor_position); } - } else { + } else { // direction == CURSOR_FORWARD if (char_offset < num_log_attrs_ - 1) { do { ++char_offset; @@ -465,202 +523,21 @@ size_t RenderTextLinux::Utf8IndexOfAdjacentGrapheme( return static_cast<size_t>(ch - layout_text_); } -size_t RenderTextLinux::Utf16IndexOfAdjacentGrapheme( - size_t utf8_index_of_current_grapheme, - bool next) const { - size_t utf8_index = Utf8IndexOfAdjacentGrapheme( - utf8_index_of_current_grapheme, next); - return Utf8IndexToUtf16Index(utf8_index); -} - SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( const PangoItem* item) const { size_t caret = Utf8IndexToUtf16Index(item->offset); - size_t cursor = Utf16IndexOfAdjacentGrapheme(item->offset, true); + size_t cursor = Utf8IndexToUtf16Index( + Utf8IndexOfAdjacentGrapheme(item->offset, CURSOR_FORWARD)); return SelectionModel(cursor, caret, SelectionModel::TRAILING); } SelectionModel RenderTextLinux::LastSelectionModelInsideRun( const PangoItem* item) const { - size_t caret = Utf16IndexOfAdjacentGrapheme(item->offset + item->length, - false); + size_t caret = Utf8IndexToUtf16Index(Utf8IndexOfAdjacentGrapheme( + item->offset + item->length, CURSOR_BACKWARD)); return SelectionModel(caret, caret, SelectionModel::LEADING); } -// Assume caret_pos in |current| is n, 'l' represents leading in -// caret_placement and 't' represents trailing in caret_placement. Following -// is the calculation from (caret_pos, caret_placement) in |current| to -// (selection_end, caret_pos, caret_placement) when moving cursor left by -// one grapheme (for simplicity, assume each grapheme is one character). -// If n is in LTR run, -// (n, t) ---> (n, n, l). -// (n, l) ---> (n-1, n-1, l) if n is inside run (not at boundary). -// (n, l) ---> goto across run case if n is at run boundary. -// If n is in RTL run, -// (n, l) --> (n+1, n, t). -// (n, t) --> (n+2, n+1, t) if n is inside run. -// (n, t) --> goto across run case if n is at run boundary. -// If n is at run boundary, get its visually left run, -// If left run is LTR run, -// (n, t) --> (left run's end, left run's end, l). -// If left run is RTL run, -// (n, t) --> (left run's begin + 1, left run's begin, t). -SelectionModel RenderTextLinux::LeftSelectionModel( - const SelectionModel& selection) { - size_t caret = selection.caret_pos(); - SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); - GSList* run = GetRunContainingPosition(caret); - DCHECK(run); - - PangoLayoutRun* layout_run = reinterpret_cast<PangoLayoutRun*>(run->data); - PangoItem* item = layout_run->item; - size_t run_start = Utf8IndexToUtf16Index(item->offset); - size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); - - if (IsRunLTR(item)) { - if (caret_placement == SelectionModel::TRAILING) - return SelectionModel(caret, caret, SelectionModel::LEADING); - else if (caret > run_start) { - caret = GetIndexOfPreviousGrapheme(caret); - return SelectionModel(caret, caret, SelectionModel::LEADING); - } - } else { // RTL run. - if (caret_placement == SelectionModel::LEADING) { - size_t cursor = GetIndexOfNextGrapheme(caret); - return SelectionModel(cursor, caret, SelectionModel::TRAILING); - } else if (selection.selection_end() < run_end) { - caret = GetIndexOfNextGrapheme(caret); - size_t cursor = GetIndexOfNextGrapheme(caret); - return SelectionModel(cursor, caret, SelectionModel::TRAILING); - } - } - - // The character is at the begin of its run; advance to the previous visual - // run. - PangoLayoutRun* prev_run = GetPreviousRun(layout_run); - if (!prev_run) - return LeftEndSelectionModel(); - - item = prev_run->item; - return IsRunLTR(item) ? LastSelectionModelInsideRun(item) : - FirstSelectionModelInsideRun(item); -} - -// Assume caret_pos in |current| is n, 'l' represents leading in -// caret_placement and 't' represents trailing in caret_placement. Following -// is the calculation from (caret_pos, caret_placement) in |current| to -// (selection_end, caret_pos, caret_placement) when moving cursor right by -// one grapheme (for simplicity, assume each grapheme is one character). -// If n is in LTR run, -// (n, l) ---> (n+1, n, t). -// (n, t) ---> (n+2, n+1, t) if n is inside run (not at boundary). -// (n, t) ---> goto across run case if n is at run boundary. -// If n is in RTL run, -// (n, t) --> (n, n, l). -// (n, l) --> (n-1, n-1, l) if n is inside run. -// (n, l) --> goto across run case if n is at run boundary. -// If n is at run boundary, get its visually right run, -// If right run is LTR run, -// (n, t) --> (right run's begin + 1, right run's begin, t). -// If right run is RTL run, -// (n, t) --> (right run's end, right run's end, l). -SelectionModel RenderTextLinux::RightSelectionModel( - const SelectionModel& selection) { - size_t caret = selection.caret_pos(); - SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); - GSList* run = GetRunContainingPosition(caret); - DCHECK(run); - - PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; - size_t run_start = Utf8IndexToUtf16Index(item->offset); - size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); - - if (IsRunLTR(item)) { - if (caret_placement == SelectionModel::LEADING) { - size_t cursor = GetIndexOfNextGrapheme(caret); - return SelectionModel(cursor, caret, SelectionModel::TRAILING); - } else if (selection.selection_end() < run_end) { - caret = GetIndexOfNextGrapheme(caret); - size_t cursor = GetIndexOfNextGrapheme(caret); - return SelectionModel(cursor, caret, SelectionModel::TRAILING); - } - } else { // RTL run. - if (caret_placement == SelectionModel::TRAILING) - return SelectionModel(caret, caret, SelectionModel::LEADING); - else if (caret > run_start) { - caret = GetIndexOfPreviousGrapheme(caret); - return SelectionModel(caret, caret, SelectionModel::LEADING); - } - } - - // The character is at the end of its run; advance to the next visual run. - GSList* next_run = run->next; - if (!next_run) - return RightEndSelectionModel(); - - item = reinterpret_cast<PangoLayoutRun*>(next_run->data)->item; - return IsRunLTR(item) ? FirstSelectionModelInsideRun(item) : - LastSelectionModelInsideRun(item); -} - -SelectionModel RenderTextLinux::LeftSelectionModelByWord( - const SelectionModel& selection) { - base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); - bool success = iter.Init(); - DCHECK(success); - if (!success) - return selection; - - SelectionModel left_end = LeftEndSelectionModel(); - SelectionModel left(selection); - while (!left.Equals(left_end)) { - left = LeftSelectionModel(left); - size_t caret = left.caret_pos(); - GSList* run = GetRunContainingPosition(caret); - DCHECK(run); - PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; - size_t cursor = left.selection_end(); - if (IsRunLTR(item)) { - if (iter.IsStartOfWord(cursor)) - return left; - } else { // RTL run. - if (iter.IsEndOfWord(cursor)) - return left; - } - } - - return left_end; -} - -SelectionModel RenderTextLinux::RightSelectionModelByWord( - const SelectionModel& selection) { - base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); - bool success = iter.Init(); - DCHECK(success); - if (!success) - return selection; - - SelectionModel right_end = RightEndSelectionModel(); - SelectionModel right(selection); - while (!right.Equals(right_end)) { - right = RightSelectionModel(right); - size_t caret = right.caret_pos(); - GSList* run = GetRunContainingPosition(caret); - DCHECK(run); - PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; - size_t cursor = right.selection_end(); - if (IsRunLTR(item)) { - if (iter.IsEndOfWord(cursor)) - return right; - } else { // RTL run. - if (iter.IsStartOfWord(cursor)) - return right; - } - } - - return right_end; -} - void RenderTextLinux::ResetLayout() { // set_cached_bounds_and_offset_valid(false) is done in RenderText for every // operation that triggers ResetLayout(). @@ -683,27 +560,6 @@ void RenderTextLinux::ResetLayout() { layout_text_len_ = 0; } -// TODO(xji): Keep a vector of runs to avoid using a singly-linked list. -PangoLayoutRun* RenderTextLinux::GetPreviousRun(PangoLayoutRun* run) const { - GSList* current = current_line_->runs; - GSList* prev = NULL; - while (current) { - if (reinterpret_cast<PangoLayoutRun*>(current->data) == run) - return prev ? reinterpret_cast<PangoLayoutRun*>(prev->data) : NULL; - prev = current; - current = current->next; - } - return NULL; -} - -PangoLayoutRun* RenderTextLinux::GetLastRun() const { - GSList* current = current_line_->runs; - while (current && current->next) { - current = current->next; - } - return current ? reinterpret_cast<PangoLayoutRun*>(current->data) : NULL; -} - size_t RenderTextLinux::Utf16IndexToUtf8Index(size_t index) const { int32_t utf8_index = 0; UErrorCode ec = U_ZERO_ERROR; @@ -729,9 +585,8 @@ size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const { return utf16_index; } -void RenderTextLinux::CalculateSubstringBounds(size_t from, - size_t to, - std::vector<Rect>* bounds) { +std::vector<Rect> RenderTextLinux::CalculateSubstringBounds(size_t from, + size_t to) { int* ranges; int n_ranges; size_t from_in_utf8 = Utf16IndexToUtf8Index(from); @@ -748,21 +603,23 @@ void RenderTextLinux::CalculateSubstringBounds(size_t from, int y = (display_rect().height() - height) / 2; + std::vector<Rect> bounds; for (int i = 0; i < n_ranges; ++i) { int x = PANGO_PIXELS(ranges[2 * i]); int width = PANGO_PIXELS(ranges[2 * i + 1]) - x; Rect rect(x, y, width, height); rect.set_origin(ToViewPoint(rect.origin())); - bounds->push_back(rect); + bounds.push_back(rect); } g_free(ranges); + return bounds; } -void RenderTextLinux::GetSelectionBounds(std::vector<Rect>* bounds) { +std::vector<Rect> RenderTextLinux::GetSelectionBounds() { if (selection_visual_bounds_.empty()) - CalculateSubstringBounds(GetSelectionStart(), GetCursorPosition(), - &selection_visual_bounds_); - *bounds = selection_visual_bounds_; + selection_visual_bounds_ = + CalculateSubstringBounds(GetSelectionStart(), GetCursorPosition()); + return selection_visual_bounds_; } } // namespace gfx diff --git a/ui/gfx/render_text_linux.h b/ui/gfx/render_text_linux.h index 8b81a9a..79c87b0 100644 --- a/ui/gfx/render_text_linux.h +++ b/ui/gfx/render_text_linux.h @@ -28,15 +28,15 @@ class RenderTextLinux : public RenderText { protected: // Overridden from RenderText: - virtual SelectionModel GetLeftSelectionModel(const SelectionModel& current, - BreakType break_type) OVERRIDE; - virtual SelectionModel GetRightSelectionModel(const SelectionModel& current, - BreakType break_type) OVERRIDE; - virtual SelectionModel LeftEndSelectionModel() OVERRIDE; - virtual SelectionModel RightEndSelectionModel() OVERRIDE; - virtual void GetSubstringBounds(size_t from, - size_t to, - std::vector<Rect>* bounds) OVERRIDE; + virtual SelectionModel AdjacentCharSelectionModel( + const SelectionModel& selection, + VisualCursorDirection direction) OVERRIDE; + virtual SelectionModel AdjacentWordSelectionModel( + const SelectionModel& selection, + VisualCursorDirection direction) OVERRIDE; + virtual SelectionModel EdgeSelectionModel( + VisualCursorDirection direction) OVERRIDE; + virtual std::vector<Rect> GetSubstringBounds(size_t from, size_t to) OVERRIDE; virtual void SetSelectionModel(const SelectionModel& model) OVERRIDE; virtual bool IsCursorablePosition(size_t position) OVERRIDE; virtual void UpdateLayout() OVERRIDE; @@ -44,19 +44,18 @@ class RenderTextLinux : public RenderText { virtual void DrawVisualText(Canvas* canvas) OVERRIDE; private: - virtual size_t IndexOfAdjacentGrapheme(size_t index, bool next) OVERRIDE; + virtual size_t IndexOfAdjacentGrapheme( + size_t index, + LogicalCursorDirection direction) OVERRIDE; // Returns the run that contains |position|. Return NULL if not found. GSList* GetRunContainingPosition(size_t position) const; - // Given |utf8_index_of_current_grapheme|, returns the UTF8 or UTF16 index of - // next grapheme in the text if |next| is true, otherwise, returns the index - // of previous grapheme. Returns 0 if there is no previous grapheme, and - // returns the |text_| length if there is no next grapheme. + // Given |utf8_index_of_current_grapheme|, returns the UTF-8 index of the + // |next| or previous grapheme in logical order. Returns 0 if there is no + // previous grapheme, or the |text_| length if there is no next grapheme. size_t Utf8IndexOfAdjacentGrapheme(size_t utf8_index_of_current_grapheme, - bool next) const; - size_t Utf16IndexOfAdjacentGrapheme(size_t utf8_index_of_current_grapheme, - bool next) const; + LogicalCursorDirection direction) const; // Given a |run|, returns the SelectionModel that contains the logical first // or last caret position inside (not at a boundary of) the run. @@ -64,42 +63,27 @@ class RenderTextLinux : public RenderText { SelectionModel FirstSelectionModelInsideRun(const PangoItem* run) const; SelectionModel LastSelectionModelInsideRun(const PangoItem* run) const; - // Get the selection model visually left or right of |current| by one - // grapheme. - // The returned value represents a cursor/caret position without a selection. - SelectionModel LeftSelectionModel(const SelectionModel& current); - SelectionModel RightSelectionModel(const SelectionModel& current); - - // Get the selection model visually left or right of |current| by one word. - // The returned value represents a cursor/caret position without a selection. - SelectionModel LeftSelectionModelByWord(const SelectionModel& current); - SelectionModel RightSelectionModelByWord(const SelectionModel& current); - // Unref |layout_| and |pango_line_|. Set them to NULL. void ResetLayout(); // Setup pango attribute: foreground, background, font, strike. void SetupPangoAttributes(PangoLayout* layout); - // Returns |run|'s visually previous run. - // The complexity is O(n) since it is a single-linked list. - PangoLayoutRun* GetPreviousRun(PangoLayoutRun* run) const; - - // Returns the last run in |current_line_|. - // The complexity is O(n) since it is a single-linked list. - PangoLayoutRun* GetLastRun() const; + // Append one pango attribute |pango_attr| into pango attribute list |attrs|. + void AppendPangoAttribute(size_t start, + size_t end, + PangoAttribute* pango_attr, + PangoAttrList* attrs); size_t Utf16IndexToUtf8Index(size_t index) const; size_t Utf8IndexToUtf16Index(size_t index) const; // Calculate the visual bounds containing the logical substring within |from| - // to |to| into |bounds|. - void CalculateSubstringBounds(size_t from, - size_t to, - std::vector<Rect>* bounds); + // to |to|. + std::vector<Rect> CalculateSubstringBounds(size_t from, size_t to); - // Save the visual bounds of logical selection into |bounds|. - void GetSelectionBounds(std::vector<Rect>* bounds); + // Get the visual bounds of the logical selection. + std::vector<Rect> GetSelectionBounds(); // Pango Layout. PangoLayout* layout_; diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc index 63afca1..7b7bea44 100644 --- a/ui/gfx/render_text_unittest.cc +++ b/ui/gfx/render_text_unittest.cc @@ -288,16 +288,16 @@ void RunMoveCursorLeftRightTest(RenderText* render_text, SelectionModel sel = expected[i]; EXPECT_TRUE(render_text->selection_model().Equals(sel)); if (move_right) - render_text->MoveCursorRight(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false); else - render_text->MoveCursorLeft(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false); } SelectionModel sel = expected[expected.size() - 1]; if (move_right) - render_text->MoveCursorRight(LINE_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false); else - render_text->MoveCursorLeft(LINE_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false); EXPECT_TRUE(render_text->selection_model().Equals(sel)); } @@ -380,7 +380,7 @@ TEST_F(RenderTextTest, MoveCursorLeftRightInRtl) { scoped_ptr<RenderText> render_text(RenderText::CreateRenderText()); // Pure RTL. render_text->SetText(WideToUTF16(L"\x05d0\x05d1\x05d2")); - render_text->MoveCursorRight(LINE_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false); std::vector<SelectionModel> expected; #if defined(OS_LINUX) @@ -424,7 +424,7 @@ TEST_F(RenderTextTest, MoveCursorLeftRightInRtlLtr) { scoped_ptr<RenderText> render_text(RenderText::CreateRenderText()); // RTL-LTR render_text->SetText(WideToUTF16(L"\x05d0\x05d1\x05d2"L"abc")); - render_text->MoveCursorRight(LINE_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false); std::vector<SelectionModel> expected; #if defined(OS_LINUX) expected.push_back(SelectionModel(0, 0, SelectionModel::LEADING)); @@ -479,7 +479,7 @@ TEST_F(RenderTextTest, MoveCursorLeftRightInRtlLtrRtl) { scoped_ptr<RenderText> render_text(RenderText::CreateRenderText()); // RTL-LTR-RTL. render_text->SetText(WideToUTF16(L"\x05d0"L"a"L"\x05d1")); - render_text->MoveCursorRight(LINE_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false); std::vector<SelectionModel> expected; #if defined(OS_LINUX) expected.push_back(SelectionModel(0, 0, SelectionModel::LEADING)); @@ -526,22 +526,22 @@ TEST_F(RenderTextTest, MoveCursorLeftRight_ComplexScript) { render_text->SetText(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915")); EXPECT_EQ(0U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(2U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(4U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(5U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(5U, render_text->GetCursorPosition()); - render_text->MoveCursorLeft(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false); EXPECT_EQ(4U, render_text->GetCursorPosition()); - render_text->MoveCursorLeft(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false); EXPECT_EQ(2U, render_text->GetCursorPosition()); - render_text->MoveCursorLeft(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false); EXPECT_EQ(0U, render_text->GetCursorPosition()); - render_text->MoveCursorLeft(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false); EXPECT_EQ(0U, render_text->GetCursorPosition()); } #endif @@ -594,11 +594,13 @@ TEST_F(RenderTextTest, GraphemePositions) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { render_text->SetText(cases[i].text); - size_t next = render_text->GetIndexOfNextGrapheme(cases[i].index); + size_t next = render_text->IndexOfAdjacentGrapheme(cases[i].index, + CURSOR_FORWARD); EXPECT_EQ(cases[i].expected_next, next); EXPECT_TRUE(render_text->IsCursorablePosition(next)); - size_t previous = render_text->GetIndexOfPreviousGrapheme(cases[i].index); + size_t previous = render_text->IndexOfAdjacentGrapheme(cases[i].index, + CURSOR_BACKWARD); EXPECT_EQ(cases[i].expected_previous, previous); EXPECT_TRUE(render_text->IsCursorablePosition(previous)); } @@ -647,12 +649,12 @@ TEST_F(RenderTextTest, SelectionModels) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { render_text->SetText(cases[i].text); - SelectionModel model = render_text->LeftEndSelectionModel(); + SelectionModel model = render_text->EdgeSelectionModel(CURSOR_LEFT); EXPECT_EQ(cases[i].expected_left_end_caret, model.caret_pos()); EXPECT_TRUE(render_text->IsCursorablePosition(model.caret_pos())); EXPECT_EQ(cases[i].expected_left_end_placement, model.caret_placement()); - model = render_text->RightEndSelectionModel(); + model = render_text->EdgeSelectionModel(CURSOR_RIGHT); EXPECT_EQ(cases[i].expected_right_end_caret, model.caret_pos()); EXPECT_TRUE(render_text->IsCursorablePosition(model.caret_pos())); EXPECT_EQ(cases[i].expected_right_end_placement, model.caret_placement()); @@ -663,43 +665,43 @@ TEST_F(RenderTextTest, MoveCursorLeftRightWithSelection) { scoped_ptr<RenderText> render_text(RenderText::CreateRenderText()); render_text->SetText(WideToUTF16(L"abc\x05d0\x05d1\x05d2")); // Left arrow on select ranging (6, 4). - render_text->MoveCursorRight(LINE_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(6U, render_text->GetCursorPosition()); - render_text->MoveCursorLeft(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false); EXPECT_EQ(4U, render_text->GetCursorPosition()); - render_text->MoveCursorLeft(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false); EXPECT_EQ(5U, render_text->GetCursorPosition()); - render_text->MoveCursorLeft(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false); EXPECT_EQ(6U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(CHARACTER_BREAK, true); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, true); EXPECT_EQ(6U, render_text->GetSelectionStart()); EXPECT_EQ(5U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(CHARACTER_BREAK, true); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, true); EXPECT_EQ(6U, render_text->GetSelectionStart()); EXPECT_EQ(4U, render_text->GetCursorPosition()); - render_text->MoveCursorLeft(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false); EXPECT_EQ(6U, render_text->GetCursorPosition()); // Right arrow on select ranging (4, 6). - render_text->MoveCursorLeft(LINE_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false); EXPECT_EQ(0U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(1U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(2U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(3U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(5U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(4U, render_text->GetCursorPosition()); - render_text->MoveCursorLeft(CHARACTER_BREAK, true); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, true); EXPECT_EQ(4U, render_text->GetSelectionStart()); EXPECT_EQ(5U, render_text->GetCursorPosition()); - render_text->MoveCursorLeft(CHARACTER_BREAK, true); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, true); EXPECT_EQ(4U, render_text->GetSelectionStart()); EXPECT_EQ(6U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(4U, render_text->GetCursorPosition()); } @@ -710,13 +712,13 @@ void MoveLeftRightByWordVerifier(RenderText* render_text, render_text->SetText(WideToUTF16(str)); // Test moving by word from left ro right. - render_text->MoveCursorLeft(LINE_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false); bool first_word = true; while (true) { // First, test moving by word from a word break position, such as from // "|abc def" to "abc| def". SelectionModel start = render_text->selection_model(); - render_text->MoveCursorRight(WORD_BREAK, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false); SelectionModel end = render_text->selection_model(); if (end.Equals(start)) // reach the end. break; @@ -726,7 +728,7 @@ void MoveLeftRightByWordVerifier(RenderText* render_text, first_word = false; render_text->MoveCursorTo(start); for (int j = 0; j < num_of_character_moves; ++j) - render_text->MoveCursorRight(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false); EXPECT_TRUE(render_text->selection_model().Equals(end)); // Then, test moving by word from positions inside the word, such as from @@ -734,18 +736,18 @@ void MoveLeftRightByWordVerifier(RenderText* render_text, for (int j = 1; j < num_of_character_moves; ++j) { render_text->MoveCursorTo(start); for (int k = 0; k < j; ++k) - render_text->MoveCursorRight(CHARACTER_BREAK, false); - render_text->MoveCursorRight(WORD_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false); EXPECT_TRUE(render_text->selection_model().Equals(end)); } } // Test moving by word from right to left. - render_text->MoveCursorRight(LINE_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false); first_word = true; while (true) { SelectionModel start = render_text->selection_model(); - render_text->MoveCursorLeft(WORD_BREAK, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false); SelectionModel end = render_text->selection_model(); if (end.Equals(start)) // reach the end. break; @@ -754,14 +756,14 @@ void MoveLeftRightByWordVerifier(RenderText* render_text, first_word = false; render_text->MoveCursorTo(start); for (int j = 0; j < num_of_character_moves; ++j) - render_text->MoveCursorLeft(CHARACTER_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false); EXPECT_TRUE(render_text->selection_model().Equals(end)); for (int j = 1; j < num_of_character_moves; ++j) { render_text->MoveCursorTo(start); for (int k = 0; k < j; ++k) - render_text->MoveCursorLeft(CHARACTER_BREAK, false); - render_text->MoveCursorLeft(WORD_BREAK, false); + render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false); EXPECT_TRUE(render_text->selection_model().Equals(end)); } } @@ -810,21 +812,21 @@ TEST_F(RenderTextTest, MoveLeftRightByWordInBidiText_TestEndOfText) { // But since end of text is always treated as a word break, it returns // position "ab|C". // TODO(xji): Need to make it work as expected. - render_text->MoveCursorRight(LINE_BREAK, false); - render_text->MoveCursorLeft(WORD_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false); // EXPECT_TRUE(render_text->selection_model().Equals(SelectionModel(0))); // Moving the cursor by word from "|abC" to the right returns "abC|". - render_text->MoveCursorLeft(LINE_BREAK, false); - render_text->MoveCursorRight(WORD_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false); EXPECT_TRUE(render_text->selection_model().Equals( SelectionModel(3, 2, SelectionModel::LEADING))); render_text->SetText(WideToUTF16(L"\x05E1\x05E2"L"a")); // For logical text "BCa", moving the cursor by word from "aCB|" to the left // returns "|aCB". - render_text->MoveCursorRight(LINE_BREAK, false); - render_text->MoveCursorLeft(WORD_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false); EXPECT_TRUE(render_text->selection_model().Equals( SelectionModel(3, 2, SelectionModel::LEADING))); @@ -832,8 +834,8 @@ TEST_F(RenderTextTest, MoveLeftRightByWordInBidiText_TestEndOfText) { // But since end of text is always treated as a word break, it returns // position "a|CB". // TODO(xji): Need to make it work as expected. - render_text->MoveCursorLeft(LINE_BREAK, false); - render_text->MoveCursorRight(WORD_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false); // EXPECT_TRUE(render_text->selection_model().Equals(SelectionModel(0))); } @@ -841,28 +843,28 @@ TEST_F(RenderTextTest, MoveLeftRightByWordInTextWithMultiSpaces) { scoped_ptr<RenderText> render_text(RenderText::CreateRenderText()); render_text->SetText(WideToUTF16(L"abc def")); render_text->MoveCursorTo(SelectionModel(5)); - render_text->MoveCursorRight(WORD_BREAK, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(11U, render_text->GetCursorPosition()); render_text->MoveCursorTo(SelectionModel(5)); - render_text->MoveCursorLeft(WORD_BREAK, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false); EXPECT_EQ(0U, render_text->GetCursorPosition()); } TEST_F(RenderTextTest, MoveLeftRightByWordInChineseText) { scoped_ptr<RenderText> render_text(RenderText::CreateRenderText()); render_text->SetText(WideToUTF16(L"\x6211\x4EEC\x53BB\x516C\x56ED\x73A9")); - render_text->MoveCursorLeft(LINE_BREAK, false); + render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false); EXPECT_EQ(0U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(WORD_BREAK, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(2U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(WORD_BREAK, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(3U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(WORD_BREAK, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(5U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(WORD_BREAK, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(6U, render_text->GetCursorPosition()); - render_text->MoveCursorRight(WORD_BREAK, false); + render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false); EXPECT_EQ(6U, render_text->GetCursorPosition()); } diff --git a/ui/gfx/render_text_win.cc b/ui/gfx/render_text_win.cc index 459a29d..9896fb2 100644 --- a/ui/gfx/render_text_win.cc +++ b/ui/gfx/render_text_win.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "base/i18n/break_iterator.h" #include "base/logging.h" #include "base/stl_util.h" #include "base/string_util.h" @@ -129,13 +130,21 @@ RenderTextWin::RenderTextWin() DCHECK(SUCCEEDED(hr)); script_control_.fMergeNeutralItems = true; - MoveCursorTo(LeftEndSelectionModel()); + MoveCursorTo(EdgeSelectionModel(CURSOR_LEFT)); } RenderTextWin::~RenderTextWin() { STLDeleteContainerPointers(runs_.begin(), runs_.end()); } +base::i18n::TextDirection RenderTextWin::GetTextDirection() { + // TODO(benrg): Code moved from RenderText::GetTextDirection. Needs to be + // replaced by a correct Windows implementation. + if (base::i18n::IsRTL()) + return base::i18n::RIGHT_TO_LEFT; + return base::i18n::LEFT_TO_RIGHT; +} + int RenderTextWin::GetStringWidth() { EnsureLayout(); return string_width_; @@ -150,7 +159,7 @@ SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { Point p(ToTextPoint(point)); size_t run_index = GetRunContainingPoint(p); if (run_index == runs_.size()) - return (p.x() < 0) ? LeftEndSelectionModel() : RightEndSelectionModel(); + return EdgeSelectionModel((p.x() < 0) ? CURSOR_LEFT : CURSOR_RIGHT); internal::TextRun* run = runs_[run_index]; int position = 0, trailing = 0; @@ -226,82 +235,123 @@ Rect RenderTextWin::GetCursorBounds(const SelectionModel& selection, return rect; } -SelectionModel RenderTextWin::GetLeftSelectionModel( - const SelectionModel& selection, - BreakType break_type) { - EnsureLayout(); - - if (break_type == LINE_BREAK || text().empty()) - return LeftEndSelectionModel(); - if (break_type == CHARACTER_BREAK) - return LeftSelectionModel(selection); - // TODO(msw): Implement word breaking. - return RenderText::GetLeftSelectionModel(selection, break_type); -} +SelectionModel RenderTextWin::AdjacentCharSelectionModel( + const SelectionModel& selection, VisualCursorDirection direction) { + DCHECK(!needs_layout_); + size_t caret = selection.caret_pos(); + SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); + size_t run_index = GetRunContainingPosition(caret); + DCHECK(run_index < runs_.size()); + internal::TextRun* run = runs_[run_index]; -SelectionModel RenderTextWin::GetRightSelectionModel( - const SelectionModel& selection, - BreakType break_type) { - EnsureLayout(); + bool forward_motion = run->script_analysis.fRTL == (direction == CURSOR_LEFT); + if (forward_motion) { + if (caret_placement == SelectionModel::LEADING) { + size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); + return SelectionModel(cursor, caret, SelectionModel::TRAILING); + } else if (selection.selection_end() < run->range.end()) { + caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); + size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); + return SelectionModel(cursor, caret, SelectionModel::TRAILING); + } + } else { + if (caret_placement == SelectionModel::TRAILING) + return SelectionModel(caret, caret, SelectionModel::LEADING); + else if (caret > run->range.start()) { + caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD); + return SelectionModel(caret, caret, SelectionModel::LEADING); + } + } - if (break_type == LINE_BREAK || text().empty()) - return RightEndSelectionModel(); - if (break_type == CHARACTER_BREAK) - return RightSelectionModel(selection); - // TODO(msw): Implement word breaking. - return RenderText::GetRightSelectionModel(selection, break_type); + // The character is at the beginning/end of its run; go to the previous/next + // visual run. + size_t visual_index = logical_to_visual_[run_index]; + if (visual_index == (direction == CURSOR_LEFT ? 0 : runs_.size() - 1)) + return EdgeSelectionModel(direction); + internal::TextRun* adjacent = runs_[visual_to_logical_[ + direction == CURSOR_LEFT ? visual_index - 1 : visual_index + 1]]; + forward_motion = adjacent->script_analysis.fRTL == (direction == CURSOR_LEFT); + return forward_motion ? FirstSelectionModelInsideRun(adjacent) : + LastSelectionModelInsideRun(adjacent); } -SelectionModel RenderTextWin::LeftEndSelectionModel() { - if (text().empty()) - return SelectionModel(0, 0, SelectionModel::LEADING); - - EnsureLayout(); - size_t cursor = base::i18n::IsRTL() ? text().length() : 0; - internal::TextRun* run = runs_[visual_to_logical_[0]]; - size_t caret; - SelectionModel::CaretPlacement placement; - if (run->script_analysis.fRTL) { - caret = IndexOfAdjacentGrapheme(run->range.end(), false); - placement = SelectionModel::TRAILING; - } else { - caret = run->range.start(); - placement = SelectionModel::LEADING; +// TODO(msw): Implement word breaking for Windows. +SelectionModel RenderTextWin::AdjacentWordSelectionModel( + const SelectionModel& selection, + VisualCursorDirection direction) { + base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); + bool success = iter.Init(); + DCHECK(success); + if (!success) + return selection; + + size_t pos; + if (direction == CURSOR_RIGHT) { + pos = std::min(selection.selection_end() + 1, text().length()); + while (iter.Advance()) { + pos = iter.pos(); + if (iter.IsWord() && pos > selection.selection_end()) + break; + } + } else { // direction == CURSOR_LEFT + // Notes: We always iterate words from the beginning. + // 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. + pos = std::max<int>(selection.selection_end() - 1, 0); + while (iter.Advance()) { + if (iter.IsWord()) { + size_t begin = iter.pos() - iter.GetString().length(); + if (begin == selection.selection_end()) { + // The cursor is at the beginning of a word. + // Move to previous word. + break; + } else if (iter.pos() >= selection.selection_end()) { + // The cursor is in the middle or at the end of a word. + // Move to the top of current word. + pos = begin; + break; + } else { + pos = iter.pos() - iter.GetString().length(); + } + } + } } - return SelectionModel(cursor, caret, placement); + return SelectionModel(pos, pos, SelectionModel::LEADING); } -SelectionModel RenderTextWin::RightEndSelectionModel() { +SelectionModel RenderTextWin::EdgeSelectionModel( + VisualCursorDirection direction) { if (text().empty()) return SelectionModel(0, 0, SelectionModel::LEADING); EnsureLayout(); - size_t cursor = base::i18n::IsRTL() ? 0 : text().length(); - internal::TextRun* run = runs_[visual_to_logical_[runs_.size() - 1]]; + size_t cursor = (direction == GetVisualDirectionOfLogicalEnd()) ? + text().length() : 0; + internal::TextRun* run = runs_[ + visual_to_logical_[direction == CURSOR_RIGHT ? runs_.size() - 1 : 0]]; size_t caret; SelectionModel::CaretPlacement placement; - if (run->script_analysis.fRTL) { + if (run->script_analysis.fRTL == (direction == CURSOR_RIGHT)) { caret = run->range.start(); placement = SelectionModel::LEADING; } else { - caret = IndexOfAdjacentGrapheme(run->range.end(), false); + caret = IndexOfAdjacentGrapheme(run->range.end(), CURSOR_BACKWARD); placement = SelectionModel::TRAILING; } return SelectionModel(cursor, caret, placement); } -void RenderTextWin::GetSubstringBounds(size_t from, - size_t to, - std::vector<Rect>* bounds) { +std::vector<Rect> RenderTextWin::GetSubstringBounds(size_t from, size_t to) { DCHECK(!needs_layout_); ui::Range range(from, to); DCHECK(ui::Range(0, text().length()).Contains(range)); Point display_offset(GetUpdatedDisplayOffset()); HRESULT hr = 0; - bounds->clear(); + std::vector<Rect> bounds; if (from == to) - return; + return bounds; // Add a Rect for each run/selection intersection. // TODO(msw): The bounds should probably not always be leading the range ends. @@ -340,13 +390,14 @@ void RenderTextWin::GetSubstringBounds(size_t from, rect.Offset(0, (display_rect().height() - rect.height()) / 2); rect.set_origin(ToViewPoint(rect.origin())); // Union this with the last rect if they're adjacent. - if (!bounds->empty() && rect.SharesEdgeWith(bounds->back())) { - rect = rect.Union(bounds->back()); - bounds->pop_back(); + if (!bounds.empty() && rect.SharesEdgeWith(bounds.back())) { + rect = rect.Union(bounds.back()); + bounds.pop_back(); } - bounds->push_back(rect); + bounds.push_back(rect); } } + return bounds; } void RenderTextWin::SetSelectionModel(const SelectionModel& model) { @@ -428,14 +479,16 @@ void RenderTextWin::DrawVisualText(Canvas* canvas) { } } -size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) { +size_t RenderTextWin::IndexOfAdjacentGrapheme( + size_t index, + LogicalCursorDirection direction) { EnsureLayout(); if (text().empty()) return 0; if (index >= text().length()) { - if (next || index > text().length()) { + if (direction == CURSOR_FORWARD || index > text().length()) { return text().length(); } else { // The requested |index| is at the end of the text. Use the index of the @@ -452,7 +505,7 @@ size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) { size_t start = run->range.start(); size_t ch = index - start; - if (!next) { + if (direction == CURSOR_BACKWARD) { // If |ch| is the start of the run, use the preceding run, if any. if (ch == 0) { if (run_index == 0) @@ -467,7 +520,7 @@ size_t RenderTextWin::IndexOfAdjacentGrapheme(size_t index, bool next) { do { ch--; } while (ch > 0 && run->logical_clusters[ch - 1] == cluster); - } else { + } else { // direction == CURSOR_FORWARD WORD cluster = run->logical_clusters[ch]; while (ch < run->range.length() && run->logical_clusters[ch] == cluster) ch++; @@ -668,90 +721,16 @@ size_t RenderTextWin::GetRunContainingPoint(const Point& point) const { SelectionModel RenderTextWin::FirstSelectionModelInsideRun( internal::TextRun* run) { size_t caret = run->range.start(); - size_t cursor = IndexOfAdjacentGrapheme(caret, true); + size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); return SelectionModel(cursor, caret, SelectionModel::TRAILING); } SelectionModel RenderTextWin::LastSelectionModelInsideRun( internal::TextRun* run) { - size_t caret = IndexOfAdjacentGrapheme(run->range.end(), false); + size_t caret = IndexOfAdjacentGrapheme(run->range.end(), CURSOR_BACKWARD); return SelectionModel(caret, caret, SelectionModel::LEADING); } -SelectionModel RenderTextWin::LeftSelectionModel( - const SelectionModel& selection) { - DCHECK(!needs_layout_); - size_t caret = selection.caret_pos(); - SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); - size_t run_index = GetRunContainingPosition(caret); - DCHECK(run_index < runs_.size()); - internal::TextRun* run = runs_[run_index]; - - // If the caret's associated character is in a LTR run. - if (!run->script_analysis.fRTL) { - if (caret_placement == SelectionModel::TRAILING) - return SelectionModel(caret, caret, SelectionModel::LEADING); - else if (caret > run->range.start()) { - caret = IndexOfAdjacentGrapheme(caret, false); - return SelectionModel(caret, caret, SelectionModel::LEADING); - } - } else { // The caret's associated character is in a RTL run. - if (caret_placement == SelectionModel::LEADING) { - size_t cursor = IndexOfAdjacentGrapheme(caret, true); - return SelectionModel(cursor, caret, SelectionModel::TRAILING); - } else if (selection.selection_end() < run->range.end()) { - caret = IndexOfAdjacentGrapheme(caret, true); - size_t cursor = IndexOfAdjacentGrapheme(caret, true); - return SelectionModel(cursor, caret, SelectionModel::TRAILING); - } - } - - // The character is at the begin of its run; go to the previous visual run. - size_t visual_index = logical_to_visual_[run_index]; - if (visual_index == 0) - return LeftEndSelectionModel(); - internal::TextRun* prev = runs_[visual_to_logical_[visual_index - 1]]; - return prev->script_analysis.fRTL ? FirstSelectionModelInsideRun(prev) : - LastSelectionModelInsideRun(prev); -} - -SelectionModel RenderTextWin::RightSelectionModel( - const SelectionModel& selection) { - DCHECK(!needs_layout_); - size_t caret = selection.caret_pos(); - SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); - size_t run_index = GetRunContainingPosition(caret); - DCHECK(run_index < runs_.size()); - internal::TextRun* run = runs_[run_index]; - - // If the caret's associated character is in a LTR run. - if (!run->script_analysis.fRTL) { - if (caret_placement == SelectionModel::LEADING) { - size_t cursor = IndexOfAdjacentGrapheme(caret, true); - return SelectionModel(cursor, caret, SelectionModel::TRAILING); - } else if (selection.selection_end() < run->range.end()) { - caret = IndexOfAdjacentGrapheme(caret, true); - size_t cursor = IndexOfAdjacentGrapheme(caret, true); - return SelectionModel(cursor, caret, SelectionModel::TRAILING); - } - } else { // The caret's associated character is in a RTL run. - if (caret_placement == SelectionModel::TRAILING) - return SelectionModel(caret, caret, SelectionModel::LEADING); - else if (caret > run->range.start()) { - caret = IndexOfAdjacentGrapheme(caret, false); - return SelectionModel(caret, caret, SelectionModel::LEADING); - } - } - - // The character is at the end of its run; go to the next visual run. - size_t visual_index = logical_to_visual_[run_index]; - if (visual_index == runs_.size() - 1) - return RightEndSelectionModel(); - internal::TextRun* next = runs_[visual_to_logical_[visual_index + 1]]; - return next->script_analysis.fRTL ? LastSelectionModelInsideRun(next) : - FirstSelectionModelInsideRun(next); -} - RenderText* RenderText::CreateRenderText() { return new RenderTextWin; } diff --git a/ui/gfx/render_text_win.h b/ui/gfx/render_text_win.h index 4cbcb35..f3962d7 100644 --- a/ui/gfx/render_text_win.h +++ b/ui/gfx/render_text_win.h @@ -61,6 +61,7 @@ class RenderTextWin : public RenderText { virtual ~RenderTextWin(); // Overridden from RenderText: + virtual base::i18n::TextDirection GetTextDirection() OVERRIDE; virtual int GetStringWidth() OVERRIDE; virtual SelectionModel FindCursorPosition(const Point& point) OVERRIDE; virtual Rect GetCursorBounds(const SelectionModel& selection, @@ -68,15 +69,15 @@ class RenderTextWin : public RenderText { protected: // Overridden from RenderText: - virtual SelectionModel GetLeftSelectionModel(const SelectionModel& current, - BreakType break_type) OVERRIDE; - virtual SelectionModel GetRightSelectionModel(const SelectionModel& current, - BreakType break_type) OVERRIDE; - virtual SelectionModel LeftEndSelectionModel() OVERRIDE; - virtual SelectionModel RightEndSelectionModel() OVERRIDE; - virtual void GetSubstringBounds(size_t from, - size_t to, - std::vector<Rect>* bounds) OVERRIDE; + virtual SelectionModel AdjacentCharSelectionModel( + const SelectionModel& selection, + VisualCursorDirection direction) OVERRIDE; + virtual SelectionModel AdjacentWordSelectionModel( + const SelectionModel& selection, + VisualCursorDirection direction) OVERRIDE; + virtual SelectionModel EdgeSelectionModel( + VisualCursorDirection direction) OVERRIDE; + virtual std::vector<Rect> GetSubstringBounds(size_t from, size_t to) OVERRIDE; virtual void SetSelectionModel(const SelectionModel& model) OVERRIDE; virtual bool IsCursorablePosition(size_t position) OVERRIDE; virtual void UpdateLayout() OVERRIDE; @@ -84,7 +85,9 @@ class RenderTextWin : public RenderText { virtual void DrawVisualText(Canvas* canvas) OVERRIDE; private: - virtual size_t IndexOfAdjacentGrapheme(size_t index, bool next) OVERRIDE; + virtual size_t IndexOfAdjacentGrapheme( + size_t index, + LogicalCursorDirection direction) OVERRIDE; void ItemizeLogicalText(); void LayoutVisualText(); @@ -100,11 +103,6 @@ class RenderTextWin : public RenderText { SelectionModel FirstSelectionModelInsideRun(internal::TextRun* run); SelectionModel LastSelectionModelInsideRun(internal::TextRun* run); - // Get the selection model visually left/right of |selection| by one grapheme. - // The returned value represents a cursor/caret position without a selection. - SelectionModel LeftSelectionModel(const SelectionModel& selection); - SelectionModel RightSelectionModel(const SelectionModel& selection); - // National Language Support native digit and digit substitution settings. SCRIPT_DIGITSUBSTITUTE digit_substitute_; diff --git a/ui/views/controls/textfield/native_textfield_views.cc b/ui/views/controls/textfield/native_textfield_views.cc index a3beceb..5f2ac4f 100644 --- a/ui/views/controls/textfield/native_textfield_views.cc +++ b/ui/views/controls/textfield/native_textfield_views.cc @@ -870,62 +870,44 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { cursor_changed = text_changed = Paste(); break; case ui::VKEY_RIGHT: - model_->MoveCursorRight( - control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK, selection); - cursor_changed = true; - break; case ui::VKEY_LEFT: - model_->MoveCursorLeft( - control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK, selection); + model_->MoveCursor( + control ? gfx::WORD_BREAK : gfx::CHARACTER_BREAK, + (key_code == ui::VKEY_RIGHT) ? gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT, + selection); cursor_changed = true; break; case ui::VKEY_END: case ui::VKEY_HOME: if ((key_code == ui::VKEY_HOME) == (GetRenderText()->GetTextDirection() == base::i18n::RIGHT_TO_LEFT)) - model_->MoveCursorRight(gfx::LINE_BREAK, selection); + model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, selection); else - model_->MoveCursorLeft(gfx::LINE_BREAK, selection); + model_->MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, selection); cursor_changed = true; break; case ui::VKEY_BACK: - if (!editable) - break; - if (!model_->HasSelection()) { - if (selection && control) { - // If both shift and control are pressed, then erase upto the - // beginning of the buffer in ChromeOS. In windows, do nothing. -#if defined(OS_WIN) - break; -#else - model_->MoveCursorLeft(gfx::LINE_BREAK, true); -#endif - } else if (control) { - // If only control is pressed, then erase the previous word. - model_->MoveCursorLeft(gfx::WORD_BREAK, true); - } - } - text_changed = model_->Backspace(); - cursor_changed = true; - break; case ui::VKEY_DELETE: if (!editable) break; if (!model_->HasSelection()) { + gfx::VisualCursorDirection direction = (key_code == ui::VKEY_DELETE) ? + gfx::CURSOR_RIGHT : gfx::CURSOR_LEFT; if (selection && control) { - // If both shift and control are pressed, then erase upto the - // end of the buffer in ChromeOS. In windows, do nothing. + // If both shift and control are pressed, then erase up to the + // beginning/end of the buffer in ChromeOS. In windows, do nothing. #if defined(OS_WIN) break; #else - model_->MoveCursorRight(gfx::LINE_BREAK, true); + model_->MoveCursor(gfx::LINE_BREAK, direction, true); #endif } else if (control) { - // If only control is pressed, then erase the next word. - model_->MoveCursorRight(gfx::WORD_BREAK, true); + // If only control is pressed, then erase the previous/next word. + model_->MoveCursor(gfx::WORD_BREAK, direction, true); } } - cursor_changed = text_changed = model_->Delete(); + cursor_changed = text_changed = (key_code == ui::VKEY_BACK) ? + model_->Backspace() : model_->Delete(); break; case ui::VKEY_INSERT: GetRenderText()->ToggleInsertMode(); diff --git a/ui/views/controls/textfield/textfield_views_model.cc b/ui/views/controls/textfield/textfield_views_model.cc index 7df402d..ab5a94b 100644 --- a/ui/views/controls/textfield/textfield_views_model.cc +++ b/ui/views/controls/textfield/textfield_views_model.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -324,10 +324,9 @@ void TextfieldViewsModel::Append(const string16& text) { if (HasCompositionText()) ConfirmCompositionText(); size_t save = GetCursorPosition(); - if (render_text_->GetTextDirection() == base::i18n::LEFT_TO_RIGHT) - MoveCursorRight(gfx::LINE_BREAK, false); - else - MoveCursorLeft(gfx::LINE_BREAK, false); + MoveCursor(gfx::LINE_BREAK, + render_text_->GetVisualDirectionOfLogicalEnd(), + false); InsertText(text); render_text_->SetCursorPosition(save); ClearSelection(); @@ -345,8 +344,8 @@ bool TextfieldViewsModel::Delete() { } if (GetText().length() > GetCursorPosition()) { size_t cursor_position = GetCursorPosition(); - size_t next_grapheme_index = - render_text_->GetIndexOfNextGrapheme(cursor_position); + size_t next_grapheme_index = render_text_->IndexOfAdjacentGrapheme( + cursor_position, gfx::CURSOR_FORWARD); ExecuteAndRecordDelete(cursor_position, next_grapheme_index, true); return true; } @@ -375,18 +374,12 @@ size_t TextfieldViewsModel::GetCursorPosition() const { return render_text_->GetCursorPosition(); } -void TextfieldViewsModel::MoveCursorLeft(gfx::BreakType break_type, - bool select) { - if (HasCompositionText()) - ConfirmCompositionText(); - render_text_->MoveCursorLeft(break_type, select); -} - -void TextfieldViewsModel::MoveCursorRight(gfx::BreakType break_type, - bool select) { +void TextfieldViewsModel::MoveCursor(gfx::BreakType break_type, + gfx::VisualCursorDirection direction, + bool select) { if (HasCompositionText()) ConfirmCompositionText(); - render_text_->MoveCursorRight(break_type, select); + render_text_->MoveCursor(break_type, direction, select); } bool TextfieldViewsModel::MoveCursorTo(const gfx::SelectionModel& selection) { @@ -674,7 +667,8 @@ void TextfieldViewsModel::ReplaceTextInternal(const string16& text, const gfx::SelectionModel& model = render_text_->selection_model(); // When there is no selection, the default is to replace the next grapheme // with |text|. So, need to find the index of next grapheme first. - size_t next = render_text_->GetIndexOfNextGrapheme(cursor); + size_t next = + render_text_->IndexOfAdjacentGrapheme(cursor, gfx::CURSOR_FORWARD); if (next == model.selection_end()) render_text_->MoveCursorTo(model); else diff --git a/ui/views/controls/textfield/textfield_views_model.h b/ui/views/controls/textfield/textfield_views_model.h index e3fd7e8..51a4ea4 100644 --- a/ui/views/controls/textfield/textfield_views_model.h +++ b/ui/views/controls/textfield/textfield_views_model.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -127,8 +127,9 @@ class VIEWS_EXPORT TextfieldViewsModel { // Moves the cursor, see RenderText for additional details. // The current composition text will be confirmed. - void MoveCursorLeft(gfx::BreakType break_type, bool select); - void MoveCursorRight(gfx::BreakType break_type, bool select); + void MoveCursor(gfx::BreakType break_type, + gfx::VisualCursorDirection direction, + bool select); // Moves the selection to the specified selection in |selection|. // If there is composition text, it will be confirmed, which will update the diff --git a/ui/views/controls/textfield/textfield_views_model_unittest.cc b/ui/views/controls/textfield/textfield_views_model_unittest.cc index 579056d..39a1375b 100644 --- a/ui/views/controls/textfield/textfield_views_model_unittest.cc +++ b/ui/views/controls/textfield/textfield_views_model_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -75,7 +75,7 @@ TEST_F(TextfieldViewsModelTest, EditString) { EXPECT_STR_EQ("HILLWORLD", model.GetText()); // Insert "E" to make hello - model.MoveCursorRight(gfx::CHARACTER_BREAK, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); model.InsertChar('E'); EXPECT_STR_EQ("HEILLWORLD", model.GetText()); // Replace "I" with "L" @@ -94,11 +94,11 @@ TEST_F(TextfieldViewsModelTest, EditString) { EXPECT_STR_EQ("HELLORLD", model.GetText()); // Move the cursor to start. backspace should fail. - model.MoveCursorLeft(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); EXPECT_FALSE(model.Backspace()); EXPECT_STR_EQ("HELLORLD", model.GetText()); // Move the cursor to the end. delete should fail. - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_FALSE(model.Delete()); EXPECT_STR_EQ("HELLORLD", model.GetText()); // but backspace should work. @@ -236,9 +236,9 @@ TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) { // The first 2 characters are not strong directionality characters. model.SetText(WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9\x05BC")); #if defined(OS_WIN) - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); #else - model.MoveCursorLeft(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); #endif EXPECT_TRUE(model.Backspace()); EXPECT_EQ(WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9"), @@ -251,9 +251,9 @@ TEST_F(TextfieldViewsModelTest, EmptyString) { EXPECT_EQ(string16(), model.GetSelectedText()); EXPECT_EQ(string16(), model.GetVisibleText()); - model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); EXPECT_EQ(0U, model.GetCursorPosition()); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_EQ(0U, model.GetCursorPosition()); EXPECT_EQ(string16(), model.GetSelectedText()); @@ -265,15 +265,15 @@ TEST_F(TextfieldViewsModelTest, EmptyString) { TEST_F(TextfieldViewsModelTest, Selection) { TextfieldViewsModel model(NULL); model.Append(ASCIIToUTF16("HELLO")); - model.MoveCursorRight(gfx::CHARACTER_BREAK, false); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_STR_EQ("E", model.GetSelectedText()); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_STR_EQ("EL", model.GetSelectedText()); - model.MoveCursorLeft(gfx::LINE_BREAK, true); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true); EXPECT_STR_EQ("H", model.GetSelectedText()); - model.MoveCursorRight(gfx::LINE_BREAK, true); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_STR_EQ("ELLO", model.GetSelectedText()); model.ClearSelection(); EXPECT_EQ(string16(), model.GetSelectedText()); @@ -288,18 +288,18 @@ TEST_F(TextfieldViewsModelTest, Selection) { // Select and move cursor model.SelectRange(ui::Range(1U, 3U)); EXPECT_STR_EQ("EL", model.GetSelectedText()); - model.MoveCursorLeft(gfx::CHARACTER_BREAK, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); EXPECT_EQ(1U, model.GetCursorPosition()); model.SelectRange(ui::Range(1U, 3U)); - model.MoveCursorRight(gfx::CHARACTER_BREAK, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_EQ(3U, model.GetCursorPosition()); // Select all and move cursor model.SelectAll(); - model.MoveCursorLeft(gfx::CHARACTER_BREAK, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); EXPECT_EQ(0U, model.GetCursorPosition()); model.SelectAll(); - model.MoveCursorRight(gfx::CHARACTER_BREAK, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_EQ(5U, model.GetCursorPosition()); } @@ -316,26 +316,26 @@ TEST_F(TextfieldViewsModelTest, Selection_BidiWithNonSpacingMarks) { #if defined(OS_LINUX) model.Append(WideToUTF16( L"abc\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8"L"def")); - model.MoveCursorRight(gfx::CHARACTER_BREAK, false); - model.MoveCursorRight(gfx::CHARACTER_BREAK, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_EQ(2U, model.render_text()->GetSelectionStart()); EXPECT_EQ(3U, model.GetCursorPosition()); EXPECT_EQ(WideToUTF16(L"c"), model.GetSelectedText()); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_EQ(2U, model.render_text()->GetSelectionStart()); EXPECT_EQ(7U, model.GetCursorPosition()); EXPECT_EQ(WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8"), model.GetSelectedText()); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_EQ(2U, model.render_text()->GetSelectionStart()); EXPECT_EQ(3U, model.GetCursorPosition()); EXPECT_EQ(WideToUTF16(L"c"), model.GetSelectedText()); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_EQ(2U, model.render_text()->GetSelectionStart()); EXPECT_EQ(10U, model.GetCursorPosition()); EXPECT_EQ(WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8"L"d"), @@ -352,36 +352,36 @@ TEST_F(TextfieldViewsModelTest, Selection_BidiWithNonSpacingMarks) { // an RTL character. model.SetText(WideToUTF16(L"a\x05E9"L"b")); model.MoveCursorTo(gfx::SelectionModel(0)); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_EQ(WideToUTF16(L"a"), model.GetSelectedText()); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_EQ(WideToUTF16(L"a"), model.GetSelectedText()); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_EQ(WideToUTF16(L"a\x05E9"L"b"), model.GetSelectedText()); - model.MoveCursorRight(gfx::CHARACTER_BREAK, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_EQ(3U, model.GetCursorPosition()); - model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); EXPECT_EQ(WideToUTF16(L"b"), model.GetSelectedText()); - model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); EXPECT_EQ(WideToUTF16(L"b"), model.GetSelectedText()); - model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); EXPECT_EQ(WideToUTF16(L"a\x05E9"L"b"), model.GetSelectedText()); - model.MoveCursorLeft(gfx::LINE_BREAK, false); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); - model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); EXPECT_EQ(WideToUTF16(L"a\x05E9"), model.GetSelectedText()); - model.MoveCursorRight(gfx::LINE_BREAK, false); - model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); - model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_EQ(WideToUTF16(L"\x05E9"L"b"), model.GetSelectedText()); model.ClearSelection(); @@ -393,28 +393,28 @@ TEST_F(TextfieldViewsModelTest, Selection_BidiWithNonSpacingMarks) { TEST_F(TextfieldViewsModelTest, SelectionAndEdit) { TextfieldViewsModel model(NULL); model.Append(ASCIIToUTF16("HELLO")); - model.MoveCursorRight(gfx::CHARACTER_BREAK, false); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); // select "EL" + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "EL" EXPECT_TRUE(model.Backspace()); EXPECT_STR_EQ("HLO", model.GetText()); model.Append(ASCIIToUTF16("ILL")); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); // select "LO" + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "LO" EXPECT_TRUE(model.Delete()); EXPECT_STR_EQ("HILL", model.GetText()); EXPECT_EQ(1U, model.GetCursorPosition()); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); // select "I" + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "I" model.InsertChar('E'); EXPECT_STR_EQ("HELL", model.GetText()); - model.MoveCursorLeft(gfx::LINE_BREAK, false); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); // select "H" + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "H" model.ReplaceChar('B'); 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.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); // "ELL" model.ReplaceChar('E'); EXPECT_STR_EQ("BEE", model.GetText()); } @@ -444,43 +444,43 @@ TEST_F(TextfieldViewsModelTest, Word) { TextfieldViewsModel model(NULL); model.Append( ASCIIToUTF16("The answer to Life, the Universe, and Everything")); - model.MoveCursorRight(gfx::WORD_BREAK, false); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_EQ(3U, model.GetCursorPosition()); - model.MoveCursorRight(gfx::WORD_BREAK, false); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_EQ(10U, model.GetCursorPosition()); - model.MoveCursorRight(gfx::WORD_BREAK, false); - model.MoveCursorRight(gfx::WORD_BREAK, false); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_EQ(18U, model.GetCursorPosition()); // Should passes the non word char ',' - model.MoveCursorRight(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_EQ(23U, model.GetCursorPosition()); EXPECT_STR_EQ(", the", model.GetSelectedText()); // Move to the end. - model.MoveCursorRight(gfx::WORD_BREAK, true); - model.MoveCursorRight(gfx::WORD_BREAK, true); - model.MoveCursorRight(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText()); // Should be safe to go next word at the end. - model.MoveCursorRight(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText()); model.InsertChar('2'); EXPECT_EQ(19U, model.GetCursorPosition()); // Now backwards. - model.MoveCursorLeft(gfx::CHARACTER_BREAK, false); // leave 2. - model.MoveCursorLeft(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); // leave 2. + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); EXPECT_EQ(14U, model.GetCursorPosition()); EXPECT_STR_EQ("Life", model.GetSelectedText()); - model.MoveCursorLeft(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); EXPECT_STR_EQ("to Life", model.GetSelectedText()); - model.MoveCursorLeft(gfx::WORD_BREAK, true); - model.MoveCursorLeft(gfx::WORD_BREAK, true); - model.MoveCursorLeft(gfx::WORD_BREAK, true); // Select to the begining. + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); // Now at start. EXPECT_STR_EQ("The answer to Life", model.GetSelectedText()); // Should be safe to go pervious word at the begining. - model.MoveCursorLeft(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); EXPECT_STR_EQ("The answer to Life", model.GetSelectedText()); model.ReplaceChar('4'); EXPECT_EQ(string16(), model.GetSelectedText()); @@ -490,14 +490,14 @@ TEST_F(TextfieldViewsModelTest, Word) { TEST_F(TextfieldViewsModelTest, SetText) { TextfieldViewsModel model(NULL); model.Append(ASCIIToUTF16("HELLO")); - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.SetText(ASCIIToUTF16("GOODBYE")); EXPECT_STR_EQ("GOODBYE", model.GetText()); // SetText won't reset the cursor posistion. EXPECT_EQ(5U, model.GetCursorPosition()); model.SelectAll(); EXPECT_STR_EQ("GOODBYE", model.GetSelectedText()); - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_EQ(7U, model.GetCursorPosition()); model.SetText(ASCIIToUTF16("BYE")); @@ -522,7 +522,7 @@ TEST_F(TextfieldViewsModelTest, MAYBE_Clipboard) { string16 clipboard_text; TextfieldViewsModel model(NULL); model.Append(ASCIIToUTF16("HELLO WORLD")); - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); // Test for cut: Empty selection. EXPECT_FALSE(model.Cut()); @@ -532,7 +532,7 @@ TEST_F(TextfieldViewsModelTest, MAYBE_Clipboard) { EXPECT_EQ(11U, model.GetCursorPosition()); // Test for cut: Non-empty selection. - model.MoveCursorLeft(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); EXPECT_TRUE(model.Cut()); clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &clipboard_text); EXPECT_STR_EQ("WORLD", clipboard_text); @@ -557,8 +557,8 @@ TEST_F(TextfieldViewsModelTest, MAYBE_Clipboard) { // Test for paste. model.ClearSelection(); - model.MoveCursorRight(gfx::LINE_BREAK, false); - model.MoveCursorLeft(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); EXPECT_TRUE(model.Paste()); clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &clipboard_text); EXPECT_STR_EQ("HELLO HELLO WORLD", clipboard_text); @@ -577,7 +577,7 @@ TEST_F(TextfieldViewsModelTest, SelectWordTest) { model.Append(ASCIIToUTF16(" HELLO !! WO RLD ")); // Test when cursor is at the beginning. - model.MoveCursorLeft(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); model.SelectWord(); SelectWordTestVerifier(model, ASCIIToUTF16(" "), 2U); @@ -608,7 +608,7 @@ TEST_F(TextfieldViewsModelTest, SelectWordTest) { SelectWordTestVerifier(model, ASCIIToUTF16(" "), 20U); // Test when cursor is at the end. - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.SelectWord(); SelectWordTestVerifier(model, ASCIIToUTF16(" "), 24U); } @@ -638,9 +638,9 @@ TEST_F(TextfieldViewsModelTest, SelectWordTest_MixScripts) { model.SetText(WideToUTF16(L"a\x05d0 \x05d1\x05d2 \x0915\x094d\x0915 " L"\x4E2D\x56FD\x82B1\x5929")); for (size_t i = 0; i < word_and_cursor.size(); ++i) { - model.MoveCursorLeft(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); for (size_t j = 0; j < i; ++j) - model.MoveCursorRight(gfx::CHARACTER_BREAK, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); model.SelectWord(); SelectWordTestVerifier(model, WideToUTF16(word_and_cursor[i].word), word_and_cursor[i].cursor); @@ -651,61 +651,61 @@ TEST_F(TextfieldViewsModelTest, SelectWordTest_MixScripts) { TEST_F(TextfieldViewsModelTest, RangeTest) { TextfieldViewsModel model(NULL); model.Append(ASCIIToUTF16("HELLO WORLD")); - model.MoveCursorLeft(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); ui::Range range; model.GetSelectedRange(&range); EXPECT_TRUE(range.is_empty()); EXPECT_EQ(0U, range.start()); EXPECT_EQ(0U, range.end()); - model.MoveCursorRight(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, 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(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); model.GetSelectedRange(&range); EXPECT_FALSE(range.is_empty()); EXPECT_EQ(0U, range.start()); EXPECT_EQ(4U, range.end()); - model.MoveCursorLeft(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); model.GetSelectedRange(&range); EXPECT_TRUE(range.is_empty()); EXPECT_EQ(0U, range.start()); EXPECT_EQ(0U, range.end()); // now from the end. - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.GetSelectedRange(&range); EXPECT_TRUE(range.is_empty()); EXPECT_EQ(11U, range.start()); EXPECT_EQ(11U, range.end()); - model.MoveCursorLeft(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, 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(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, 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.MoveCursorRight(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); model.GetSelectedRange(&range); EXPECT_TRUE(range.is_empty()); EXPECT_EQ(11U, range.start()); EXPECT_EQ(11U, range.end()); // Select All - model.MoveCursorLeft(gfx::LINE_BREAK, true); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true); model.GetSelectedRange(&range); EXPECT_FALSE(range.is_empty()); EXPECT_TRUE(range.is_reversed()); @@ -760,61 +760,61 @@ TEST_F(TextfieldViewsModelTest, SelectRangeTest) { TEST_F(TextfieldViewsModelTest, SelectionModelTest) { TextfieldViewsModel model(NULL); model.Append(ASCIIToUTF16("HELLO WORLD")); - model.MoveCursorLeft(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); gfx::SelectionModel sel; model.GetSelectionModel(&sel); EXPECT_EQ(sel.selection_start(), sel.selection_end()); EXPECT_EQ(0U, sel.selection_start()); EXPECT_EQ(0U, sel.selection_end()); - model.MoveCursorRight(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); model.GetSelectionModel(&sel); EXPECT_NE(sel.selection_start(), sel.selection_end()); EXPECT_LE(sel.selection_start(), sel.selection_end()); EXPECT_EQ(0U, sel.selection_start()); EXPECT_EQ(5U, sel.selection_end()); - model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); model.GetSelectionModel(&sel); EXPECT_NE(sel.selection_start(), sel.selection_end()); EXPECT_EQ(0U, sel.selection_start()); EXPECT_EQ(4U, sel.selection_end()); - model.MoveCursorLeft(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); model.GetSelectionModel(&sel); EXPECT_EQ(sel.selection_start(), sel.selection_end()); EXPECT_EQ(0U, sel.selection_start()); EXPECT_EQ(0U, sel.selection_end()); // now from the end. - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.GetSelectionModel(&sel); EXPECT_EQ(sel.selection_start(), sel.selection_end()); EXPECT_EQ(11U, sel.selection_start()); EXPECT_EQ(11U, sel.selection_end()); - model.MoveCursorLeft(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); model.GetSelectionModel(&sel); EXPECT_NE(sel.selection_start(), sel.selection_end()); EXPECT_GT(sel.selection_start(), sel.selection_end()); EXPECT_EQ(11U, sel.selection_start()); EXPECT_EQ(6U, sel.selection_end()); - model.MoveCursorRight(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); model.GetSelectionModel(&sel); EXPECT_NE(sel.selection_start(), sel.selection_end()); EXPECT_GT(sel.selection_start(), sel.selection_end()); EXPECT_EQ(11U, sel.selection_start()); EXPECT_EQ(7U, sel.selection_end()); - model.MoveCursorRight(gfx::WORD_BREAK, true); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); model.GetSelectionModel(&sel); EXPECT_EQ(sel.selection_start(), sel.selection_end()); EXPECT_EQ(11U, sel.selection_start()); EXPECT_EQ(11U, sel.selection_end()); // Select All - model.MoveCursorLeft(gfx::LINE_BREAK, true); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true); model.GetSelectionModel(&sel); EXPECT_NE(sel.selection_start(), sel.selection_end()); EXPECT_GT(sel.selection_start(), sel.selection_end()); @@ -907,7 +907,7 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) { EXPECT_TRUE(model.SetText(ASCIIToUTF16("1234567890"))); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.SetCompositionText(composition); EXPECT_STR_EQ("1234567890678", model.GetText()); @@ -919,7 +919,7 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) { EXPECT_FALSE(model.HasCompositionText()); EXPECT_FALSE(model.HasSelection()); - model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); EXPECT_STR_EQ("-", model.GetSelectedText()); model.SetCompositionText(composition); EXPECT_STR_EQ("1234567890678", model.GetText()); @@ -951,39 +951,39 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) { model.SetText(string16()); model.SetCompositionText(composition); - model.MoveCursorLeft(gfx::CHARACTER_BREAK, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; EXPECT_STR_EQ("678", model.GetText()); EXPECT_EQ(2U, model.GetCursorPosition()); model.SetCompositionText(composition); - model.MoveCursorRight(gfx::CHARACTER_BREAK, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; EXPECT_STR_EQ("676788", model.GetText()); EXPECT_EQ(6U, model.GetCursorPosition()); model.SetCompositionText(composition); - model.MoveCursorLeft(gfx::WORD_BREAK, false); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, false); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; EXPECT_STR_EQ("676788678", model.GetText()); model.SetText(string16()); model.SetCompositionText(composition); - model.MoveCursorRight(gfx::WORD_BREAK, false); + model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; model.SetCompositionText(composition); - model.MoveCursorLeft(gfx::LINE_BREAK, true); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; EXPECT_STR_EQ("678678", model.GetText()); model.SetCompositionText(composition); - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; EXPECT_STR_EQ("678", model.GetText()); @@ -1098,7 +1098,7 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_BasicTest) { model.MoveCursorTo(sel); EXPECT_TRUE(model.Delete()); EXPECT_STR_EQ("ABDE", model.GetText()); - model.MoveCursorLeft(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); EXPECT_TRUE(model.Delete()); EXPECT_STR_EQ("BDE", model.GetText()); EXPECT_TRUE(model.Undo()); @@ -1194,7 +1194,7 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_BackspaceThenSetText) { EXPECT_EQ(1U, model.GetCursorPosition()); EXPECT_STR_EQ("www.google.com", model.GetText()); model.SetText(ASCIIToUTF16("www.google.com")); // Confirm the text. - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_EQ(14U, model.GetCursorPosition()); EXPECT_TRUE(model.Backspace()); EXPECT_TRUE(model.Backspace()); @@ -1282,7 +1282,7 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest) { EXPECT_EQ(1U, model.GetCursorPosition()); model.SelectRange(ui::Range(1, 1)); EXPECT_FALSE(model.Cut()); - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_TRUE(model.Paste()); EXPECT_STR_EQ("ABCBCDEBC", model.GetText()); EXPECT_EQ(9U, model.GetCursorPosition()); @@ -1336,7 +1336,7 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest) { model.SelectRange(ui::Range(1, 3)); model.Copy(); EXPECT_STR_EQ("1232345", model.GetText()); - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); EXPECT_TRUE(model.Paste()); EXPECT_STR_EQ("123234523", model.GetText()); EXPECT_EQ(9U, model.GetCursorPosition()); @@ -1348,8 +1348,8 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest) { TEST_F(TextfieldViewsModelTest, UndoRedo_CursorTest) { TextfieldViewsModel model(NULL); model.InsertChar('a'); - model.MoveCursorLeft(gfx::CHARACTER_BREAK, false); - model.MoveCursorRight(gfx::CHARACTER_BREAK, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); + model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); model.InsertChar('b'); // Moving the cursor shouldn't create a new edit. EXPECT_STR_EQ("ab", model.GetText()); @@ -1487,7 +1487,7 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CompositionText) { composition.selection = ui::Range(2, 3); model.SetText(ASCIIToUTF16("ABCDE")); - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.InsertChar('x'); EXPECT_STR_EQ("ABCDEx", model.GetText()); EXPECT_TRUE(model.Undo()); // set composition should forget undone edit. @@ -1510,7 +1510,7 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CompositionText) { EXPECT_FALSE(model.Redo()); // Canceling composition - model.MoveCursorLeft(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); model.SetCompositionText(composition); EXPECT_STR_EQ("abcABCDEabc", model.GetText()); model.CancelCompositionText(); @@ -1526,7 +1526,7 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CompositionText) { // SetText with the same text as the result. ResetModel(&model); model.SetText(ASCIIToUTF16("ABCDE")); - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.SetCompositionText(composition); EXPECT_STR_EQ("ABCDEabc", model.GetText()); model.SetText(ASCIIToUTF16("ABCDEabc")); @@ -1541,7 +1541,7 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_CompositionText) { // remember composition text. ResetModel(&model); model.SetText(ASCIIToUTF16("ABCDE")); - model.MoveCursorRight(gfx::LINE_BREAK, false); + model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); model.SetCompositionText(composition); EXPECT_STR_EQ("ABCDEabc", model.GetText()); model.SetText(ASCIIToUTF16("1234")); |