diff options
author | xji@google.com <xji@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-21 20:32:29 +0000 |
---|---|---|
committer | xji@google.com <xji@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-21 20:32:29 +0000 |
commit | 53c0b1ba80612d92849dc02e2e7a1aa97df0e6a1 (patch) | |
tree | 28201e71c8163fc73b4b849925bdf87d51bf1636 /ui/gfx/render_text.cc | |
parent | df09e1b4e119de37af4226a20cd745c209b75f70 (diff) | |
download | chromium_src-53c0b1ba80612d92849dc02e2e7a1aa97df0e6a1.zip chromium_src-53c0b1ba80612d92849dc02e2e7a1aa97df0e6a1.tar.gz chromium_src-53c0b1ba80612d92849dc02e2e7a1aa97df0e6a1.tar.bz2 |
This is a reapply of
http://src.chromium.org/viewvc/chrome?view=rev&revision=102006
fix know issues in RenderText
1. add tests.
2. change SelectWord() to use BreakIterator, so it works for Chinese and Complex script.
3. DELETE/ReplaceChar delete/replace a whole grapheme. ReplaceTextInternal should only replace one grapheme when there is no selection.
4. pointing to position outside of text returns HOME/END position.
5. based on Chrome Linux omnibox and gedit, given
"abc| def", double click should select " " instead of "abc". Change test expectation.
BUG=90426
TEST=compile with touchui=1 test omnibox. run views_unittests.NativeTextfieldViewsTest/TextfieldViewsModelTest
Review URL: http://codereview.chromium.org/7841056
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@102160 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/gfx/render_text.cc')
-rw-r--r-- | ui/gfx/render_text.cc | 69 |
1 files changed, 31 insertions, 38 deletions
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc index 1111842..6d15e5c 100644 --- a/ui/gfx/render_text.cc +++ b/ui/gfx/render_text.cc @@ -247,6 +247,12 @@ bool RenderText::MoveCursorTo(const SelectionModel& selection_model) { sel.set_caret_pos(end.caret_pos()); sel.set_caret_placement(end.caret_placement()); } + + if (!IsCursorablePosition(sel.selection_start()) || + !IsCursorablePosition(sel.selection_end()) || + !IsCursorablePosition(sel.caret_pos())) + return false; + bool changed = !sel.Equals(selection_model_); SetSelectionModel(sel); return changed; @@ -281,41 +287,28 @@ void RenderText::SelectAll() { SetSelectionModel(sel); } -// TODO(xji): it does not work for languages do not use space as word breaker, -// such as Chinese. Should use BreakIterator. void RenderText::SelectWord() { - size_t selection_start = GetSelectionStart(); size_t cursor_position = GetCursorPosition(); - // First we setup selection_start_ and selection_end_. There are so many cases - // because we try to emulate what select-word looks like in a gtk textfield. - // See associated testcase for different cases. - if (cursor_position > 0 && cursor_position < text().length()) { - if (u_isalnum(text()[cursor_position])) { - selection_start = cursor_position; - cursor_position++; - } else - selection_start = cursor_position - 1; - } else if (cursor_position == 0) { - selection_start = cursor_position; - if (text().length() > 0) - cursor_position++; - } else { - selection_start = cursor_position - 1; - } - // Now we move selection_start_ to beginning of selection. Selection boundary - // is defined as the position where we have alpha-num character on one side - // and non-alpha-num char on the other side. - for (; selection_start > 0; selection_start--) { - if (IsPositionAtWordSelectionBoundary(selection_start)) + base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); + bool success = iter.Init(); + DCHECK(success); + if (!success) + return; + + size_t selection_start = cursor_position; + for (; selection_start != 0; --selection_start) { + if (iter.IsStartOfWord(selection_start) || + iter.IsEndOfWord(selection_start)) break; } - // Now we move selection_end_ to end of selection. Selection boundary - // is defined as the position where we have alpha-num character on one side - // and non-alpha-num char on the other side. - for (; cursor_position < text().length(); cursor_position++) { - if (IsPositionAtWordSelectionBoundary(cursor_position)) + if (selection_start == cursor_position) + ++cursor_position; + + for (; cursor_position < text().length(); ++cursor_position) { + if (iter.IsEndOfWord(cursor_position) || + iter.IsStartOfWord(cursor_position)) break; } @@ -462,6 +455,10 @@ const Rect& RenderText::GetUpdatedCursorBounds() { return cursor_bounds_; } +size_t RenderText::GetIndexOfNextGrapheme(size_t position) { + return IndexOfAdjacentGrapheme(position, true); +} + RenderText::RenderText() : text_(), selection_model_(), @@ -557,8 +554,7 @@ SelectionModel RenderText::RightEndSelectionModel() { } size_t RenderText::GetIndexOfPreviousGrapheme(size_t position) { - // TODO(msw): Handle complex script. - return std::max(static_cast<long>(position - 1), static_cast<long>(0)); + return IndexOfAdjacentGrapheme(position, false); } std::vector<Rect> RenderText::GetSubstringBounds(size_t from, size_t to) { @@ -632,13 +628,10 @@ void RenderText::MoveCursorTo(size_t position, bool select) { SelectionModel::CaretPlacement placement = (caret_pos == cursor) ? SelectionModel::LEADING : SelectionModel::TRAILING; size_t selection_start = select ? GetSelectionStart() : cursor; - SelectionModel sel(selection_start, cursor, caret_pos, placement); - SetSelectionModel(sel); -} - -bool RenderText::IsPositionAtWordSelectionBoundary(size_t pos) { - return pos == 0 || (u_isalnum(text()[pos - 1]) && !u_isalnum(text()[pos])) || - (!u_isalnum(text()[pos - 1]) && u_isalnum(text()[pos])); + if (IsCursorablePosition(cursor)) { + SelectionModel sel(selection_start, cursor, caret_pos, placement); + SetSelectionModel(sel); + } } void RenderText::UpdateCachedBoundsAndOffset() { |