summaryrefslogtreecommitdiffstats
path: root/ui/gfx/render_text.cc
diff options
context:
space:
mode:
authorxji@google.com <xji@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-21 20:32:29 +0000
committerxji@google.com <xji@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-21 20:32:29 +0000
commit53c0b1ba80612d92849dc02e2e7a1aa97df0e6a1 (patch)
tree28201e71c8163fc73b4b849925bdf87d51bf1636 /ui/gfx/render_text.cc
parentdf09e1b4e119de37af4226a20cd745c209b75f70 (diff)
downloadchromium_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.cc69
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() {