Commit ec7f48d5 authored by msw@chromium.org's avatar msw@chromium.org

Rename GetLeft/RightCursorPosition to GetLeft/RightSelectionModel.

Discard selection from the the GetLeft/RightSelectionModel return value.
Update the cursor properly on edits.

BUG=90426
TEST=--use-pure-views cursor movement, position after editing.

Review URL: http://codereview.chromium.org/7598014

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@95945 0039d316-1c4b-4281-b951-d872f2087c98
parent 62f6b6dd
...@@ -182,64 +182,52 @@ void RenderText::SetCursorPosition(const size_t position) { ...@@ -182,64 +182,52 @@ void RenderText::SetCursorPosition(const size_t position) {
SelectionModel sel(selection_model()); SelectionModel sel(selection_model());
sel.set_selection_start(position); sel.set_selection_start(position);
sel.set_selection_end(position); sel.set_selection_end(position);
sel.set_caret_pos(GetIndexOfPreviousGrapheme(position));
sel.set_caret_placement(SelectionModel::TRAILING);
SetSelectionModel(sel); SetSelectionModel(sel);
} }
void RenderText::MoveCursorLeft(BreakType break_type, bool select) { void RenderText::MoveCursorLeft(BreakType break_type, bool select) {
if (break_type == LINE_BREAK) { SelectionModel position(selection_model());
SelectionModel selection(GetSelectionStart(), 0, position.set_selection_start(GetCursorPosition());
0, SelectionModel::LEADING);
if (!select)
selection.set_selection_start(selection.selection_end());
MoveCursorTo(selection);
return;
}
SelectionModel position = selection_model_;
// Cancelling a selection moves to the edge of the selection. // Cancelling a selection moves to the edge of the selection.
if (!EmptySelection() && !select) { if (break_type != LINE_BREAK && !EmptySelection() && !select) {
// Use the selection start if it is left of the selection end. // Use the selection start if it is left of the selection end.
SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(),
GetSelectionStart(), SelectionModel::LEADING); SelectionModel::LEADING);
if (GetCursorBounds(selection_start, false).x() < if (GetCursorBounds(selection_start, false).x() <
GetCursorBounds(position, false).x()) GetCursorBounds(position, false).x())
position = selection_start; position = selection_start;
// If |move_by_word|, use the nearest word boundary left of the selection. // For word breaks, use the nearest word boundary left of the selection.
if (break_type == WORD_BREAK) if (break_type == WORD_BREAK)
position = GetLeftCursorPosition(position, true); position = GetLeftSelectionModel(position, break_type);
} else { } else {
position = GetLeftCursorPosition(position, break_type == WORD_BREAK); position = GetLeftSelectionModel(position, break_type);
} }
if (!select) if (select)
position.set_selection_start(position.selection_end()); position.set_selection_start(GetSelectionStart());
MoveCursorTo(position); MoveCursorTo(position);
} }
void RenderText::MoveCursorRight(BreakType break_type, bool select) { void RenderText::MoveCursorRight(BreakType break_type, bool select) {
if (break_type == LINE_BREAK) { SelectionModel position(selection_model());
SelectionModel selection(GetSelectionStart(), text().length(), position.set_selection_start(GetCursorPosition());
text().length(), SelectionModel::PREVIOUS_GRAPHEME_TRAILING);
if (!select)
selection.set_selection_start(selection.selection_end());
MoveCursorTo(selection);
return;
}
SelectionModel position = selection_model_;
// Cancelling a selection moves to the edge of the selection. // Cancelling a selection moves to the edge of the selection.
if (!EmptySelection() && !select) { if (break_type != LINE_BREAK && !EmptySelection() && !select) {
// Use the selection start if it is right of the selection end. // Use the selection start if it is right of the selection end.
SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(),
GetSelectionStart(), SelectionModel::LEADING); SelectionModel::LEADING);
if (GetCursorBounds(selection_start, false).x() > if (GetCursorBounds(selection_start, false).x() >
GetCursorBounds(position, false).x()) GetCursorBounds(position, false).x())
position = selection_start; position = selection_start;
// If |move_by_word|, use the nearest word boundary right of the selection. // For word breaks, use the nearest word boundary right of the selection.
if (break_type == WORD_BREAK) if (break_type == WORD_BREAK)
position = GetRightCursorPosition(position, true); position = GetRightSelectionModel(position, break_type);
} else { } else {
position = GetRightCursorPosition(position, break_type == WORD_BREAK); position = GetRightSelectionModel(position, break_type);
} }
if (!select) if (select)
position.set_selection_start(position.selection_end()); position.set_selection_start(GetSelectionStart());
MoveCursorTo(position); MoveCursorTo(position);
} }
...@@ -253,8 +241,6 @@ bool RenderText::MoveCursorTo(const Point& point, bool select) { ...@@ -253,8 +241,6 @@ bool RenderText::MoveCursorTo(const Point& point, bool select) {
SelectionModel selection = FindCursorPosition(point); SelectionModel selection = FindCursorPosition(point);
if (select) if (select)
selection.set_selection_start(GetSelectionStart()); selection.set_selection_start(GetSelectionStart());
else
selection.set_selection_start(selection.selection_end());
return MoveCursorTo(selection); return MoveCursorTo(selection);
} }
...@@ -267,7 +253,9 @@ bool RenderText::IsPointInSelection(const Point& point) { ...@@ -267,7 +253,9 @@ bool RenderText::IsPointInSelection(const Point& point) {
} }
void RenderText::ClearSelection() { void RenderText::ClearSelection() {
SetCursorPosition(GetCursorPosition()); SelectionModel sel(selection_model());
sel.set_selection_start(GetCursorPosition());
SetSelectionModel(sel);
} }
void RenderText::SelectAll() { void RenderText::SelectAll() {
...@@ -503,15 +491,15 @@ RenderText::RenderText() ...@@ -503,15 +491,15 @@ RenderText::RenderText()
display_offset_() { display_offset_() {
} }
SelectionModel RenderText::GetLeftCursorPosition(const SelectionModel& current, SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current,
bool move_by_word) { BreakType break_type) {
size_t position = current.selection_end(); if (break_type == LINE_BREAK)
SelectionModel left = current; return SelectionModel(0, 0, SelectionModel::LEADING);
if (!move_by_word) { size_t pos = std::max(static_cast<long>(current.selection_end() - 1),
left.set_selection_end(std::max(static_cast<long>(position - 1), static_cast<long>(0));
static_cast<long>(0))); if (break_type == CHARACTER_BREAK)
return left; return SelectionModel(pos, pos, SelectionModel::LEADING);
}
// Notes: We always iterate words from the begining. // Notes: We always iterate words from the begining.
// This is probably fast enough for our usage, but we may // This is probably fast enough for our usage, but we may
// want to modify WordIterator so that it can start from the // want to modify WordIterator so that it can start from the
...@@ -519,59 +507,54 @@ SelectionModel RenderText::GetLeftCursorPosition(const SelectionModel& current, ...@@ -519,59 +507,54 @@ SelectionModel RenderText::GetLeftCursorPosition(const SelectionModel& current,
base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
bool success = iter.Init(); bool success = iter.Init();
DCHECK(success); DCHECK(success);
if (!success) { if (!success)
left.set_selection_end(position); return current;
return left;
}
int last = 0;
while (iter.Advance()) { while (iter.Advance()) {
if (iter.IsWord()) { if (iter.IsWord()) {
size_t begin = iter.pos() - iter.GetString().length(); size_t begin = iter.pos() - iter.GetString().length();
if (begin == position) { if (begin == current.selection_end()) {
// The cursor is at the beginning of a word. // The cursor is at the beginning of a word.
// Move to previous word. // Move to previous word.
break; break;
} else if (iter.pos() >= position) { } else if (iter.pos() >= current.selection_end()) {
// The cursor is in the middle or at the end of a word. // The cursor is in the middle or at the end of a word.
// Move to the top of current word. // Move to the top of current word.
last = begin; pos = begin;
break; break;
} else { } else {
last = iter.pos() - iter.GetString().length(); pos = iter.pos() - iter.GetString().length();
} }
} }
} }
left.set_selection_end(last); return SelectionModel(pos, pos, SelectionModel::LEADING);
return left;
} }
SelectionModel RenderText::GetRightCursorPosition(const SelectionModel& current, SelectionModel RenderText::GetRightSelectionModel(const SelectionModel& current,
bool move_by_word) { BreakType break_type) {
size_t position = current.selection_end(); if (break_type == LINE_BREAK)
SelectionModel right = current; return SelectionModel(text().length(),
GetIndexOfPreviousGrapheme(text().length()), SelectionModel::TRAILING);
if (!move_by_word) { size_t pos = std::min(current.selection_end() + 1, text().length());
right.set_selection_end(std::min(position + 1, text().length())); if (break_type == CHARACTER_BREAK)
return right; return SelectionModel(pos, pos, SelectionModel::LEADING);
}
base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
bool success = iter.Init(); bool success = iter.Init();
DCHECK(success); DCHECK(success);
if (!success) { if (!success)
right.set_selection_end(position); return current;
return right;
}
size_t pos = 0;
while (iter.Advance()) { while (iter.Advance()) {
pos = iter.pos(); pos = iter.pos();
if (iter.IsWord() && pos > position) { if (iter.IsWord() && pos > current.selection_end())
break; break;
}
} }
right.set_selection_end(pos); return SelectionModel(pos, pos, SelectionModel::LEADING);
return right; }
size_t RenderText::GetIndexOfPreviousGrapheme(size_t position) const {
// TODO(msw): Handle complex script.
return std::max(static_cast<int>(position - 1), static_cast<int>(0));
} }
void RenderText::ApplyCompositionAndSelectionStyles( void RenderText::ApplyCompositionAndSelectionStyles(
......
...@@ -49,7 +49,10 @@ struct UI_EXPORT StyleRange { ...@@ -49,7 +49,10 @@ struct UI_EXPORT StyleRange {
typedef std::vector<StyleRange> StyleRanges; typedef std::vector<StyleRange> StyleRanges;
// TODO(msw): Distinguish between logical character and glyph? // TODO(msw): Distinguish between logical character stops and glyph stops?
// CHARACTER_BREAK cursor movements should stop at neighboring characters.
// WORD_BREAK cursor movements should stop at the nearest word boundaries.
// LINE_BREAK cursor movements should stop at the text ends as shown on screen.
enum BreakType { enum BreakType {
CHARACTER_BREAK, CHARACTER_BREAK,
WORD_BREAK, WORD_BREAK,
...@@ -186,9 +189,6 @@ class UI_EXPORT RenderText { ...@@ -186,9 +189,6 @@ class UI_EXPORT RenderText {
// Moves the cursor left or right. Cursor movement is visual, meaning that // 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. // left and right are relative to screen, not the directionality of the text.
// If |select| is false, the selection range is emptied at the new position. // If |select| is false, the selection range is emptied at the new position.
// If |break_type| is CHARACTER_BREAK, move to the neighboring character.
// If |break_type| is WORD_BREAK, move to the nearest word boundary.
// If |break_type| is LINE_BREAK, move to text edge as shown on screen.
void MoveCursorLeft(BreakType break_type, bool select); void MoveCursorLeft(BreakType break_type, bool select);
void MoveCursorRight(BreakType break_type, bool select); void MoveCursorRight(BreakType break_type, bool select);
...@@ -263,12 +263,15 @@ class UI_EXPORT RenderText { ...@@ -263,12 +263,15 @@ class UI_EXPORT RenderText {
const StyleRanges& style_ranges() const { return style_ranges_; } const StyleRanges& style_ranges() const { return style_ranges_; }
// Get the cursor position that visually neighbors |position|. // Get the selection model that visually neighbors |position| by |break_type|.
// If |move_by_word| is true, return the neighboring word delimiter position. // The returned value represents a cursor/caret position without a selection.
virtual SelectionModel GetLeftCursorPosition(const SelectionModel& current, virtual SelectionModel GetLeftSelectionModel(const SelectionModel& current,
bool move_by_word); BreakType break_type);
virtual SelectionModel GetRightCursorPosition(const SelectionModel& current, virtual SelectionModel GetRightSelectionModel(const SelectionModel& current,
bool move_by_word); BreakType break_type);
// Get the logical index of the grapheme preceeding the argument |position|.
virtual size_t GetIndexOfPreviousGrapheme(size_t position) const;
// Apply composition style (underline) to composition range and selection // Apply composition style (underline) to composition range and selection
// style (foreground) to selection range. // style (foreground) to selection range.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment