diff options
author | xji@google.com <xji@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-12 20:03:45 +0000 |
---|---|---|
committer | xji@google.com <xji@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-12 20:03:45 +0000 |
commit | 67e85519340234bbf3e3981caa8d68e4663aff07 (patch) | |
tree | 7cdffd782898ecc01232ac6f6c9406d9725690cf | |
parent | 679a41d1084397c7ca9cdd7956ed2edbf9aa0784 (diff) | |
download | chromium_src-67e85519340234bbf3e3981caa8d68e4663aff07.zip chromium_src-67e85519340234bbf3e3981caa8d68e4663aff07.tar.gz chromium_src-67e85519340234bbf3e3981caa8d68e4663aff07.tar.bz2 |
1. change the setters of gfx::SelectionModel to be private. Set one alone might make SelectionModel into un-stable state, which should not be allowed.
2. Removing SelectionModel(size_t, size_t) constructor. Introduce RenderText::SelectRange(const ui::Range&) to handle range.
3. revert removal of SelectRange/GetSelectedRange in r103188.
BUG=90426
TEST=view_unittests.
Review URL: http://codereview.chromium.org/8044004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@105138 0039d316-1c4b-4281-b951-d872f2087c98
19 files changed, 467 insertions, 161 deletions
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index 30b0631..d8988d1 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc @@ -241,7 +241,7 @@ bool OmniboxViewViews::HandleAfterKeyEvent(const views::KeyEvent& event, GetSelectionBounds(&start, &end); if (start != end || start < length) { OnBeforePossibleChange(); - textfield_->SelectSelectionModel(gfx::SelectionModel(length, length)); + textfield_->SelectRange(ui::Range(length, length)); OnAfterPossibleChange(); handled = true; } @@ -413,12 +413,10 @@ void OmniboxViewViews::SetWindowTextAndCaretPos(const string16& text, void OmniboxViewViews::SetForcedQuery() { const string16 current_text(GetText()); const size_t start = current_text.find_first_not_of(kWhitespaceUTF16); - if (start == string16::npos || (current_text[start] != '?')) { + if (start == string16::npos || (current_text[start] != '?')) SetUserText(ASCIIToUTF16("?")); - } else { - textfield_->SelectSelectionModel(gfx::SelectionModel(current_text.size(), - start + 1)); - } + else + textfield_->SelectRange(ui::Range(current_text.size(), start + 1)); } bool OmniboxViewViews::IsSelectAll() { @@ -432,17 +430,17 @@ bool OmniboxViewViews::DeleteAtEndPressed() { void OmniboxViewViews::GetSelectionBounds(string16::size_type* start, string16::size_type* end) { - gfx::SelectionModel sel; - textfield_->GetSelectionModel(&sel); - *start = static_cast<size_t>(sel.selection_end()); - *end = static_cast<size_t>(sel.selection_start()); + ui::Range range; + textfield_->GetSelectedRange(&range); + *start = static_cast<size_t>(range.end()); + *end = static_cast<size_t>(range.start()); } void OmniboxViewViews::SelectAll(bool reversed) { if (reversed) - textfield_->SelectSelectionModel(gfx::SelectionModel(GetTextLength(), 0)); + textfield_->SelectRange(ui::Range(GetTextLength(), 0)); else - textfield_->SelectSelectionModel(gfx::SelectionModel(0, GetTextLength())); + textfield_->SelectRange(ui::Range(0, GetTextLength())); } void OmniboxViewViews::RevertAll() { @@ -458,15 +456,12 @@ void OmniboxViewViews::UpdatePopup() { // Don't inline autocomplete when the caret/selection isn't at the end of // the text, or in the middle of composition. - gfx::SelectionModel sel; - textfield_->GetSelectionModel(&sel); - size_t max_of_selection = std::max(sel.selection_start(), - sel.selection_end()); + ui::Range sel; + textfield_->GetSelectedRange(&sel); bool no_inline_autocomplete = - max_of_selection < GetTextLength() || textfield_->IsIMEComposing(); + sel.GetMax() < GetTextLength() || textfield_->IsIMEComposing(); - bool is_sel_empty = (sel.selection_start() == sel.selection_end()); - model_->StartAutocomplete(!is_sel_empty, no_inline_autocomplete); + model_->StartAutocomplete(!sel.is_empty(), no_inline_autocomplete); } void OmniboxViewViews::ClosePopup() { @@ -481,12 +476,8 @@ void OmniboxViewViews::SetFocus() { void OmniboxViewViews::OnTemporaryTextMaybeChanged( const string16& display_text, bool save_original_selection) { - if (save_original_selection) { - gfx::SelectionModel sel; - textfield_->GetSelectionModel(&sel); - saved_temporary_selection_.set_start(sel.selection_start()); - saved_temporary_selection_.set_end(sel.selection_end()); - } + if (save_original_selection) + textfield_->GetSelectedRange(&saved_temporary_selection_); SetWindowTextAndCaretPos(display_text, display_text.length()); TextChanged(); @@ -504,28 +495,20 @@ bool OmniboxViewViews::OnInlineAutocompleteTextMaybeChanged( } void OmniboxViewViews::OnRevertTemporaryText() { - gfx::SelectionModel sel(saved_temporary_selection_.start(), - saved_temporary_selection_.end()); - textfield_->SelectSelectionModel(sel); + textfield_->SelectRange(saved_temporary_selection_); TextChanged(); } void OmniboxViewViews::OnBeforePossibleChange() { // Record our state. text_before_change_ = GetText(); - gfx::SelectionModel sel; - textfield_->GetSelectionModel(&sel); - sel_before_change_.set_start(sel.selection_start()); - sel_before_change_.set_end(sel.selection_end()); + textfield_->GetSelectedRange(&sel_before_change_); ime_composing_before_change_ = textfield_->IsIMEComposing(); } bool OmniboxViewViews::OnAfterPossibleChange() { - gfx::SelectionModel sel; - textfield_->GetSelectionModel(&sel); ui::Range new_sel; - new_sel.set_start(sel.selection_start()); - new_sel.set_end(sel.selection_end()); + textfield_->GetSelectedRange(&new_sel); // See if the text or selection have changed since OnBeforePossibleChange(). const string16 new_text = GetText(); @@ -714,8 +697,7 @@ void OmniboxViewViews::SetTextAndSelectedRange(const string16& text, const ui::Range& range) { if (text != GetText()) textfield_->SetText(text); - textfield_->SelectSelectionModel(gfx::SelectionModel( - range.start(), range.end())); + textfield_->SelectRange(range); } string16 OmniboxViewViews::GetSelectedText() const { @@ -723,7 +705,6 @@ string16 OmniboxViewViews::GetSelectedText() const { return textfield_->GetSelectedText(); } - AutocompletePopupView* OmniboxViewViews::CreatePopupView( View* location_bar) { #if defined(TOUCH_UI) diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc index 001b4b2..6d360b7 100644 --- a/ui/gfx/render_text.cc +++ b/ui/gfx/render_text.cc @@ -220,6 +220,30 @@ bool RenderText::MoveCursorTo(const Point& point, bool select) { return MoveCursorTo(selection); } +bool RenderText::SelectRange(const ui::Range& range) { + size_t text_length = text().length(); + size_t start = std::min(range.start(), text_length); + size_t end = std::min(range.end(), text_length); + + if (!IsCursorablePosition(start) || !IsCursorablePosition(end)) + return false; + + size_t pos = end; + SelectionModel::CaretPlacement placement = SelectionModel::LEADING; + if (start < end) { + pos = GetIndexOfPreviousGrapheme(end); + 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(); + } + SetSelectionModel(SelectionModel(start, end, pos, placement)); + return true; +} + bool RenderText::IsPointInSelection(const Point& point) { if (EmptySelection()) return false; @@ -450,7 +474,7 @@ const Point& RenderText::GetUpdatedDisplayOffset() { SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current, BreakType break_type) { if (break_type == LINE_BREAK) - return SelectionModel(0, 0, SelectionModel::LEADING); + return LeftEndSelectionModel(); size_t pos = std::max(static_cast<long>(current.selection_end() - 1), static_cast<long>(0)); if (break_type == CHARACTER_BREAK) @@ -491,8 +515,7 @@ SelectionModel RenderText::GetRightSelectionModel(const SelectionModel& current, if (text_.empty()) return SelectionModel(0, 0, SelectionModel::LEADING); if (break_type == LINE_BREAK) - return SelectionModel(text().length(), - GetIndexOfPreviousGrapheme(text().length()), SelectionModel::TRAILING); + return RightEndSelectionModel(); size_t pos = std::min(current.selection_end() + 1, text().length()); if (break_type == CHARACTER_BREAK) return SelectionModel(pos, pos, SelectionModel::LEADING); diff --git a/ui/gfx/render_text.h b/ui/gfx/render_text.h index 7e98b0c..b6c6342 100644 --- a/ui/gfx/render_text.h +++ b/ui/gfx/render_text.h @@ -100,10 +100,6 @@ class UI_EXPORT RenderText { size_t GetCursorPosition() const; void SetCursorPosition(size_t position); - void SetCaretPlacement(SelectionModel::CaretPlacement placement) { - selection_model_.set_caret_placement(placement); - } - // 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. @@ -123,6 +119,13 @@ class UI_EXPORT RenderText { // Returns true if the cursor position or selection range changed. bool MoveCursorTo(const Point& point, bool select); + // Set the selection_model_ based on |range|. + // If the |range| start or end is greater than text length, it is modified + // to be the text length. + // If the |range| start or end is not a cursorable position (not on grapheme + // boundary), it is a NO-OP and returns false. Otherwise, returns true. + bool SelectRange(const ui::Range& range); + size_t GetSelectionStart() const { return selection_model_.selection_start(); } diff --git a/ui/gfx/selection_model.cc b/ui/gfx/selection_model.cc index 743f35d..3dec8be 100644 --- a/ui/gfx/selection_model.cc +++ b/ui/gfx/selection_model.cc @@ -14,10 +14,6 @@ SelectionModel::SelectionModel(size_t pos) { Init(pos, pos, pos, LEADING); } -SelectionModel::SelectionModel(size_t start, size_t end) { - Init(start, end, end, LEADING); -} - SelectionModel::SelectionModel(size_t end, size_t pos, CaretPlacement placement) { diff --git a/ui/gfx/selection_model.h b/ui/gfx/selection_model.h index 3e7cf9f..4ef3ca0 100644 --- a/ui/gfx/selection_model.h +++ b/ui/gfx/selection_model.h @@ -49,31 +49,30 @@ class UI_EXPORT SelectionModel { SelectionModel(); explicit SelectionModel(size_t pos); - SelectionModel(size_t start, size_t end); SelectionModel(size_t end, size_t pos, CaretPlacement status); SelectionModel(size_t start, size_t end, size_t pos, CaretPlacement status); virtual ~SelectionModel(); size_t selection_start() const { return selection_start_; } - void set_selection_start(size_t pos) { selection_start_ = pos; } - size_t selection_end() const { return selection_end_; } - void set_selection_end(size_t pos) { selection_end_ = pos; } - size_t caret_pos() const { return caret_pos_; } - void set_caret_pos(size_t pos) { caret_pos_ = pos; } - CaretPlacement caret_placement() const { return caret_placement_; } - void set_caret_placement(CaretPlacement placement) { - caret_placement_ = placement; - } bool Equals(const SelectionModel& sel) const; private: + friend class RenderText; + void Init(size_t start, size_t end, size_t pos, CaretPlacement status); + void set_selection_start(size_t pos) { selection_start_ = pos; } + void set_selection_end(size_t pos) { selection_end_ = pos; } + void set_caret_pos(size_t pos) { caret_pos_ = pos; } + void set_caret_placement(CaretPlacement placement) { + caret_placement_ = placement; + } + // Logical selection start. If there is non-empty selection, if // selection_start_ is less than selection_end_, the selection starts visually // at the leading edge of the selection_start_. If selection_start_ is greater diff --git a/views/controls/textfield/native_textfield_gtk.cc b/views/controls/textfield/native_textfield_gtk.cc index 9fe5784c..b4a98f8 100644 --- a/views/controls/textfield/native_textfield_gtk.cc +++ b/views/controls/textfield/native_textfield_gtk.cc @@ -249,12 +249,20 @@ bool NativeTextfieldGtk::IsIMEComposing() const { return false; } -void NativeTextfieldGtk::GetSelectionModel(gfx::SelectionModel* sel) const { +void NativeTextfieldGtk::GetSelectedRange(ui::Range* range) const { gint start_pos; gint end_pos; gtk_editable_get_selection_bounds( GTK_EDITABLE(native_view()), &start_pos, &end_pos); - *sel = gfx::SelectionModel(start_pos, end_pos); + *range = ui::Range(start_pos, end_pos); +} + +void NativeTextfieldGtk::SelectRange(const ui::Range& range) { + NOTREACHED(); +} + +void NativeTextfieldGtk::GetSelectionModel(gfx::SelectionModel* sel) const { + NOTREACHED(); } void NativeTextfieldGtk::SelectSelectionModel(const gfx::SelectionModel& sel) { diff --git a/views/controls/textfield/native_textfield_gtk.h b/views/controls/textfield/native_textfield_gtk.h index 2a6190b..e7be873 100644 --- a/views/controls/textfield/native_textfield_gtk.h +++ b/views/controls/textfield/native_textfield_gtk.h @@ -53,6 +53,8 @@ class NativeTextfieldGtk : public NativeControlGtk, virtual View* GetView() OVERRIDE; virtual gfx::NativeView GetTestingHandle() const OVERRIDE; virtual bool IsIMEComposing() const OVERRIDE; + virtual void GetSelectedRange(ui::Range* range) const OVERRIDE; + virtual void SelectRange(const ui::Range& range) OVERRIDE; virtual void GetSelectionModel(gfx::SelectionModel* sel) const OVERRIDE; virtual void SelectSelectionModel(const gfx::SelectionModel& sel) OVERRIDE; virtual size_t GetCursorPosition() const OVERRIDE; diff --git a/views/controls/textfield/native_textfield_views.cc b/views/controls/textfield/native_textfield_views.cc index 8d8f609..20ebbc7 100644 --- a/views/controls/textfield/native_textfield_views.cc +++ b/views/controls/textfield/native_textfield_views.cc @@ -226,15 +226,13 @@ int NativeTextfieldViews::OnPerformDrop(const DropTargetEvent& event) { selected.selection_end()); size_t selected_range_length = max_of_selected_range - min_of_selected_range; - if (max_of_selected_range <= drop_destination.selection_end()) - drop_destination.set_selection_end( - drop_destination.selection_end() - selected_range_length); - else if (min_of_selected_range <= drop_destination.selection_end()) - drop_destination.set_selection_end(min_of_selected_range); - model_->DeleteSelectionAndInsertTextAt(text, - drop_destination.selection_end()); + size_t drop_destination_end = drop_destination.selection_end(); + if (max_of_selected_range <= drop_destination_end) + drop_destination_end -= selected_range_length; + else if (min_of_selected_range <= drop_destination_end) + drop_destination_end = min_of_selected_range; + model_->DeleteSelectionAndInsertTextAt(text, drop_destination_end); } else { - drop_destination.set_selection_start(drop_destination.selection_end()); model_->MoveCursorTo(drop_destination); // Drop always inserts text even if the textfield is not in insert mode. model_->InsertText(text); @@ -278,9 +276,11 @@ void NativeTextfieldViews::SelectRect(const gfx::Point& start, // Merge selection models of "start_pos" and "end_pos" so that // selection start is the value from "start_pos", while selection end, // caret position, and caret placement are values from "end_pos". - gfx::SelectionModel sel(end_pos); - sel.set_selection_start(start_pos.selection_start()); - model_->SelectSelectionModel(sel); + if (start_pos.selection_start() == end_pos.selection_end()) + model_->SelectSelectionModel(end_pos); + else + model_->SelectRange(ui::Range(start_pos.selection_start(), + end_pos.selection_end())); OnCaretBoundsChanged(); SchedulePaint(); @@ -490,6 +490,16 @@ bool NativeTextfieldViews::IsIMEComposing() const { return model_->HasCompositionText(); } +void NativeTextfieldViews::GetSelectedRange(ui::Range* range) const { + model_->GetSelectedRange(range); +} + +void NativeTextfieldViews::SelectRange(const ui::Range& range) { + model_->SelectRange(range); + OnCaretBoundsChanged(); + SchedulePaint(); +} + void NativeTextfieldViews::GetSelectionModel(gfx::SelectionModel* sel) const { model_->GetSelectionModel(sel); } @@ -758,7 +768,7 @@ bool NativeTextfieldViews::SetSelectionRange(const ui::Range& range) { return false; OnBeforeUserAction(); - SelectSelectionModel(gfx::SelectionModel(range.start(), range.end())); + SelectRange(range); OnAfterUserAction(); return true; } @@ -768,8 +778,7 @@ bool NativeTextfieldViews::DeleteRange(const ui::Range& range) { return false; OnBeforeUserAction(); - gfx::SelectionModel selection(range.start(), range.end()); - model_->SelectSelectionModel(selection); + model_->SelectRange(range); if (model_->HasSelection()) { model_->DeleteSelection(); UpdateAfterChange(true, true); diff --git a/views/controls/textfield/native_textfield_views.h b/views/controls/textfield/native_textfield_views.h index f646e7f..d6c00a3 100644 --- a/views/controls/textfield/native_textfield_views.h +++ b/views/controls/textfield/native_textfield_views.h @@ -110,6 +110,8 @@ class VIEWS_EXPORT NativeTextfieldViews : public TouchSelectionClientView, virtual View* GetView() OVERRIDE; virtual gfx::NativeView GetTestingHandle() const OVERRIDE; virtual bool IsIMEComposing() const OVERRIDE; + virtual void GetSelectedRange(ui::Range* range) const OVERRIDE; + virtual void SelectRange(const ui::Range& range) OVERRIDE; virtual void GetSelectionModel(gfx::SelectionModel* sel) const OVERRIDE; virtual void SelectSelectionModel(const gfx::SelectionModel& sel) OVERRIDE; virtual size_t GetCursorPosition() const OVERRIDE; diff --git a/views/controls/textfield/native_textfield_views_unittest.cc b/views/controls/textfield/native_textfield_views_unittest.cc index 05c3d41..f0c24b7 100644 --- a/views/controls/textfield/native_textfield_views_unittest.cc +++ b/views/controls/textfield/native_textfield_views_unittest.cc @@ -794,7 +794,8 @@ TEST_F(NativeTextfieldViewsTest, MAYBE_DragAndDrop_InitiateDrag) { // Ensure the textfield will provide selected text for drag data. string16 string; ui::OSExchangeData data; - textfield_->SelectSelectionModel(gfx::SelectionModel(6, 12)); + const ui::Range kStringRange(6, 12); + textfield_->SelectRange(kStringRange); const gfx::Point kStringPoint(GetCursorPositionX(9), 0); textfield_view_->WriteDragDataForView(NULL, kStringPoint, &data); EXPECT_TRUE(data.GetString(&string)); @@ -809,7 +810,7 @@ TEST_F(NativeTextfieldViewsTest, MAYBE_DragAndDrop_InitiateDrag) { textfield_->ClearSelection(); EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, textfield_view_->GetDragOperationsForView(NULL, kStringPoint)); - textfield_->SelectSelectionModel(gfx::SelectionModel(6, 12)); + textfield_->SelectRange(kStringRange); // Ensure that textfields only initiate drag operations inside the selection. EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, textfield_view_->GetDragOperationsForView(NULL, gfx::Point())); @@ -835,7 +836,7 @@ TEST_F(NativeTextfieldViewsTest, MAYBE_DragAndDrop_ToTheRight) { std::set<OSExchangeData::CustomFormat> custom_formats; // Start dragging "ello". - textfield_->SelectSelectionModel(gfx::SelectionModel(1, 5)); + textfield_->SelectRange(ui::Range(1, 5)); MouseEvent click_a(ui::ET_MOUSE_PRESSED, GetCursorPositionX(3), 0, ui::EF_LEFT_BUTTON_DOWN); textfield_view_->OnMousePressed(click_a); @@ -889,7 +890,7 @@ TEST_F(NativeTextfieldViewsTest, MAYBE_DragAndDrop_ToTheLeft) { std::set<OSExchangeData::CustomFormat> custom_formats; // Start dragging " worl". - textfield_->SelectSelectionModel(gfx::SelectionModel(5, 10)); + textfield_->SelectRange(ui::Range(5, 10)); MouseEvent click_a(ui::ET_MOUSE_PRESSED, GetCursorPositionX(7), 0, ui::EF_LEFT_BUTTON_DOWN); textfield_view_->OnMousePressed(click_a); @@ -936,7 +937,7 @@ TEST_F(NativeTextfieldViewsTest, MAYBE_DragAndDrop_Canceled) { textfield_->SetText(ASCIIToUTF16("hello world")); // Start dragging "worl". - textfield_->SelectSelectionModel(gfx::SelectionModel(6, 10)); + textfield_->SelectRange(ui::Range(6, 10)); MouseEvent click(ui::ET_MOUSE_PRESSED, GetCursorPositionX(8), 0, ui::EF_LEFT_BUTTON_DOWN); textfield_view_->OnMousePressed(click); diff --git a/views/controls/textfield/native_textfield_win.cc b/views/controls/textfield/native_textfield_win.cc index 95a5ec2..8e29ebc 100644 --- a/views/controls/textfield/native_textfield_win.cc +++ b/views/controls/textfield/native_textfield_win.cc @@ -336,6 +336,14 @@ bool NativeTextfieldWin::IsIMEComposing() const { return composition_size > 0; } +void NativeTextfieldWin::GetSelectedRange(ui::Range* range) const { + NOTREACHED(); +} + +void NativeTextfieldWin::SelectRange(const ui::Range& range) { + NOTREACHED(); +} + void NativeTextfieldWin::GetSelectionModel(gfx::SelectionModel* sel) const { NOTREACHED(); } diff --git a/views/controls/textfield/native_textfield_win.h b/views/controls/textfield/native_textfield_win.h index 26dc627..7c4880b 100644 --- a/views/controls/textfield/native_textfield_win.h +++ b/views/controls/textfield/native_textfield_win.h @@ -82,6 +82,8 @@ class NativeTextfieldWin virtual View* GetView() OVERRIDE; virtual gfx::NativeView GetTestingHandle() const OVERRIDE; virtual bool IsIMEComposing() const OVERRIDE; + virtual void GetSelectedRange(ui::Range* range) const OVERRIDE; + virtual void SelectRange(const ui::Range& range) OVERRIDE; virtual void GetSelectionModel(gfx::SelectionModel* sel) const OVERRIDE; virtual void SelectSelectionModel(const gfx::SelectionModel& sel) OVERRIDE; virtual size_t GetCursorPosition() const OVERRIDE; diff --git a/views/controls/textfield/native_textfield_wrapper.h b/views/controls/textfield/native_textfield_wrapper.h index 4e37d84..f6b0f8a 100644 --- a/views/controls/textfield/native_textfield_wrapper.h +++ b/views/controls/textfield/native_textfield_wrapper.h @@ -99,6 +99,12 @@ class VIEWS_EXPORT NativeTextfieldWrapper { // Returns whether or not an IME is composing text. virtual bool IsIMEComposing() const = 0; + // Gets the selected range. + virtual void GetSelectedRange(ui::Range* range) const = 0; + + // Selects the text given by |range|. + virtual void SelectRange(const ui::Range& range) = 0; + // Gets the selection model. virtual void GetSelectionModel(gfx::SelectionModel* sel) const = 0; diff --git a/views/controls/textfield/textfield.cc b/views/controls/textfield/textfield.cc index 435e637..8eaa0de 100644 --- a/views/controls/textfield/textfield.cc +++ b/views/controls/textfield/textfield.cc @@ -158,10 +158,10 @@ void Textfield::ClearSelection() const { } bool Textfield::HasSelection() const { - gfx::SelectionModel sel; + ui::Range range; if (native_wrapper_) - native_wrapper_->GetSelectionModel(&sel); - return sel.selection_start() != sel.selection_end(); + native_wrapper_->GetSelectedRange(&range); + return !range.is_empty(); } void Textfield::SetTextColor(SkColor color) { @@ -268,6 +268,16 @@ bool Textfield::IsIMEComposing() const { return native_wrapper_ && native_wrapper_->IsIMEComposing(); } +void Textfield::GetSelectedRange(ui::Range* range) const { + DCHECK(native_wrapper_); + native_wrapper_->GetSelectedRange(range); +} + +void Textfield::SelectRange(const ui::Range& range) { + DCHECK(native_wrapper_); + native_wrapper_->SelectRange(range); +} + void Textfield::GetSelectionModel(gfx::SelectionModel* sel) const { DCHECK(native_wrapper_); native_wrapper_->GetSelectionModel(sel); @@ -394,10 +404,10 @@ void Textfield::GetAccessibleState(ui::AccessibleViewState* state) { state->value = text_; DCHECK(native_wrapper_); - gfx::SelectionModel sel; - native_wrapper_->GetSelectionModel(&sel); - state->selection_start = sel.selection_start(); - state->selection_end = sel.selection_end(); + ui::Range range; + native_wrapper_->GetSelectedRange(&range); + state->selection_start = range.start(); + state->selection_end = range.end(); } TextInputClient* Textfield::GetTextInputClient() { diff --git a/views/controls/textfield/textfield.h b/views/controls/textfield/textfield.h index 20d3b43..7e73caf 100644 --- a/views/controls/textfield/textfield.h +++ b/views/controls/textfield/textfield.h @@ -178,6 +178,14 @@ class VIEWS_EXPORT Textfield : public View { // Returns whether or not an IME is composing text. bool IsIMEComposing() const; + // Gets the selected range. This is views-implementation only and + // has to be called after the wrapper is created. + void GetSelectedRange(ui::Range* range) const; + + // Selects the text given by |range|. This is views-implementation only and + // has to be called after the wrapper is created. + void SelectRange(const ui::Range& range); + // Gets the selection model. This is views-implementation only and // has to be called after the wrapper is created. void GetSelectionModel(gfx::SelectionModel* sel) const; diff --git a/views/controls/textfield/textfield_views_model.cc b/views/controls/textfield/textfield_views_model.cc index bfe0349..7c5ee0b 100644 --- a/views/controls/textfield/textfield_views_model.cc +++ b/views/controls/textfield/textfield_views_model.cc @@ -390,8 +390,12 @@ bool TextfieldViewsModel::MoveCursorTo(const gfx::SelectionModel& selection) { ConfirmCompositionText(); // ConfirmCompositionText() updates cursor position. Need to reflect it in // the SelectionModel parameter of MoveCursorTo(). - gfx::SelectionModel sel(selection); - sel.set_selection_start(render_text_->GetSelectionStart()); + if (render_text_->GetSelectionStart() != selection.selection_end()) + return render_text_->SelectRange(ui::Range( + render_text_->GetSelectionStart(), selection.selection_end())); + gfx::SelectionModel sel(selection.selection_end(), + selection.caret_pos(), + selection.caret_placement()); return render_text_->MoveCursorTo(sel); } return render_text_->MoveCursorTo(selection); @@ -408,6 +412,17 @@ string16 TextfieldViewsModel::GetSelectedText() const { (render_text_->MaxOfSelection() - render_text_->MinOfSelection())); } +void TextfieldViewsModel::GetSelectedRange(ui::Range* range) const { + range->set_start(render_text_->GetSelectionStart()); + range->set_end(render_text_->GetCursorPosition()); +} + +void TextfieldViewsModel::SelectRange(const ui::Range& range) { + if (HasCompositionText()) + ConfirmCompositionText(); + render_text_->SelectRange(range); +} + void TextfieldViewsModel::GetSelectionModel(gfx::SelectionModel* sel) const { *sel = render_text_->selection_model(); } @@ -499,11 +514,8 @@ bool TextfieldViewsModel::Cut() { // than beginning, unlike Delete/Backspace. // TODO(oshima): Change Delete/Backspace to use DeleteSelection, // update DeleteEdit and remove this trick. - gfx::SelectionModel sel(render_text_->GetCursorPosition(), - render_text_->GetSelectionStart(), - render_text_->GetSelectionStart(), - gfx::SelectionModel::LEADING); - render_text_->MoveCursorTo(sel); + render_text_->SelectRange(ui::Range(render_text_->GetCursorPosition(), + render_text_->GetSelectionStart())); DeleteSelection(); return true; } @@ -582,8 +594,7 @@ void TextfieldViewsModel::SetCompositionText( std::min(range.start() + composition.selection.start(), range.end()); size_t end = std::min(range.start() + composition.selection.end(), range.end()); - gfx::SelectionModel sel(start, end); - render_text_->MoveCursorTo(sel); + render_text_->SelectRange(ui::Range(start, end)); } else { render_text_->SetCursorPosition(range.end()); } @@ -654,9 +665,14 @@ void TextfieldViewsModel::ReplaceTextInternal(const string16& text, CancelCompositionText(); } else if (!HasSelection()) { size_t cursor = GetCursorPosition(); - gfx::SelectionModel sel(render_text_->selection_model()); - sel.set_selection_start(render_text_->GetIndexOfNextGrapheme(cursor)); - render_text_->MoveCursorTo(sel); + 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); + if (next == model.selection_end()) + render_text_->MoveCursorTo(model); + else + render_text_->SelectRange(ui::Range(next, model.selection_end())); } // Edit history is recorded in InsertText. InsertTextInternal(text, mergeable); diff --git a/views/controls/textfield/textfield_views_model.h b/views/controls/textfield/textfield_views_model.h index e178c23..103673b 100644 --- a/views/controls/textfield/textfield_views_model.h +++ b/views/controls/textfield/textfield_views_model.h @@ -148,6 +148,14 @@ class VIEWS_EXPORT TextfieldViewsModel { // Returns the selected text. string16 GetSelectedText() const; + // Gets the selected range. + void GetSelectedRange(ui::Range* range) const; + + // The current composition text will be confirmed. The selection starts with + // the range's start position, and ends with the range's end position, + // therefore the cursor position becomes the end position. + void SelectRange(const ui::Range& range); + void GetSelectionModel(gfx::SelectionModel* sel) const; // The current composition text will be confirmed. diff --git a/views/controls/textfield/textfield_views_model_unittest.cc b/views/controls/textfield/textfield_views_model_unittest.cc index 36f8fe6..5e02185 100644 --- a/views/controls/textfield/textfield_views_model_unittest.cc +++ b/views/controls/textfield/textfield_views_model_unittest.cc @@ -280,11 +280,11 @@ TEST_F(TextfieldViewsModelTest, Selection) { EXPECT_EQ(5U, sel.selection_end()); // Select and move cursor - model.MoveCursorTo(gfx::SelectionModel(1U, 3U)); + model.SelectRange(ui::Range(1U, 3U)); EXPECT_STR_EQ("EL", model.GetSelectedText()); model.MoveCursorLeft(gfx::CHARACTER_BREAK, false); EXPECT_EQ(1U, model.GetCursorPosition()); - model.MoveCursorTo(gfx::SelectionModel(1U, 3U)); + model.SelectRange(ui::Range(1U, 3U)); model.MoveCursorRight(gfx::CHARACTER_BREAK, false); EXPECT_EQ(3U, model.GetCursorPosition()); @@ -641,6 +641,115 @@ TEST_F(TextfieldViewsModelTest, SelectWordTest_MixScripts) { } #endif +TEST_F(TextfieldViewsModelTest, RangeTest) { + TextfieldViewsModel model(NULL); + model.Append(ASCIIToUTF16("HELLO WORLD")); + model.MoveCursorLeft(gfx::LINE_BREAK, false); + ui::Range range; + model.GetSelectedRange(&range); + EXPECT_TRUE(range.is_empty()); + EXPECT_EQ(0U, range.start()); + EXPECT_EQ(0U, range.end()); + + model.MoveCursorRight(gfx::WORD_BREAK, true); + model.GetSelectedRange(&range); + EXPECT_FALSE(range.is_empty()); + EXPECT_FALSE(range.is_reversed()); + EXPECT_EQ(0U, range.start()); + EXPECT_EQ(5U, range.end()); + + model.MoveCursorLeft(gfx::CHARACTER_BREAK, 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.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.GetSelectedRange(&range); + EXPECT_TRUE(range.is_empty()); + EXPECT_EQ(11U, range.start()); + EXPECT_EQ(11U, range.end()); + + model.MoveCursorLeft(gfx::WORD_BREAK, true); + model.GetSelectedRange(&range); + EXPECT_FALSE(range.is_empty()); + EXPECT_TRUE(range.is_reversed()); + EXPECT_EQ(11U, range.start()); + EXPECT_EQ(6U, range.end()); + + model.MoveCursorRight(gfx::CHARACTER_BREAK, true); + model.GetSelectedRange(&range); + EXPECT_FALSE(range.is_empty()); + EXPECT_TRUE(range.is_reversed()); + EXPECT_EQ(11U, range.start()); + EXPECT_EQ(7U, range.end()); + + model.MoveCursorRight(gfx::WORD_BREAK, true); + model.GetSelectedRange(&range); + EXPECT_TRUE(range.is_empty()); + EXPECT_EQ(11U, range.start()); + EXPECT_EQ(11U, range.end()); + + // Select All + model.MoveCursorLeft(gfx::LINE_BREAK, true); + model.GetSelectedRange(&range); + EXPECT_FALSE(range.is_empty()); + EXPECT_TRUE(range.is_reversed()); + EXPECT_EQ(11U, range.start()); + EXPECT_EQ(0U, range.end()); +} + +TEST_F(TextfieldViewsModelTest, SelectRangeTest) { + TextfieldViewsModel model(NULL); + model.Append(ASCIIToUTF16("HELLO WORLD")); + ui::Range range(0, 6); + EXPECT_FALSE(range.is_reversed()); + model.SelectRange(range); + EXPECT_STR_EQ("HELLO ", model.GetSelectedText()); + + range = ui::Range(6, 1); + EXPECT_TRUE(range.is_reversed()); + model.SelectRange(range); + EXPECT_STR_EQ("ELLO ", model.GetSelectedText()); + + range = ui::Range(2, 1000); + EXPECT_FALSE(range.is_reversed()); + model.SelectRange(range); + EXPECT_STR_EQ("LLO WORLD", model.GetSelectedText()); + + range = ui::Range(1000, 3); + EXPECT_TRUE(range.is_reversed()); + model.SelectRange(range); + EXPECT_STR_EQ("LO WORLD", model.GetSelectedText()); + + range = ui::Range(0, 0); + EXPECT_TRUE(range.is_empty()); + model.SelectRange(range); + EXPECT_TRUE(model.GetSelectedText().empty()); + + range = ui::Range(3, 3); + EXPECT_TRUE(range.is_empty()); + model.SelectRange(range); + EXPECT_TRUE(model.GetSelectedText().empty()); + + range = ui::Range(1000, 100); + EXPECT_FALSE(range.is_empty()); + model.SelectRange(range); + EXPECT_TRUE(model.GetSelectedText().empty()); + + range = ui::Range(1000, 1000); + EXPECT_TRUE(range.is_empty()); + model.SelectRange(range); + EXPECT_TRUE(model.GetSelectedText().empty()); +} + TEST_F(TextfieldViewsModelTest, SelectionModelTest) { TextfieldViewsModel model(NULL); model.Append(ASCIIToUTF16("HELLO WORLD")); @@ -709,35 +818,43 @@ TEST_F(TextfieldViewsModelTest, SelectionModelTest) { TEST_F(TextfieldViewsModelTest, SelectSelectionModelTest) { TextfieldViewsModel model(NULL); model.Append(ASCIIToUTF16("HELLO WORLD")); - model.SelectSelectionModel(gfx::SelectionModel(0, 6)); + model.SelectSelectionModel(gfx::SelectionModel(0, 6, 5, + gfx::SelectionModel::TRAILING)); EXPECT_STR_EQ("HELLO ", model.GetSelectedText()); - model.SelectSelectionModel(gfx::SelectionModel(6, 1)); + model.SelectSelectionModel(gfx::SelectionModel(6, 1, 1, + gfx::SelectionModel::LEADING)); EXPECT_STR_EQ("ELLO ", model.GetSelectedText()); - model.SelectSelectionModel(gfx::SelectionModel(2, 1000)); + model.SelectSelectionModel(gfx::SelectionModel(2, 1000, 999, + gfx::SelectionModel::TRAILING)); EXPECT_STR_EQ("LLO WORLD", model.GetSelectedText()); - model.SelectSelectionModel(gfx::SelectionModel(1000, 3)); + model.SelectSelectionModel(gfx::SelectionModel(1000, 3, 3, + gfx::SelectionModel::LEADING)); EXPECT_STR_EQ("LO WORLD", model.GetSelectedText()); - model.SelectSelectionModel(gfx::SelectionModel(0, 0)); + model.SelectSelectionModel(gfx::SelectionModel(0, 0, 0, + gfx::SelectionModel::LEADING)); EXPECT_TRUE(model.GetSelectedText().empty()); - model.SelectSelectionModel(gfx::SelectionModel(3, 3)); + model.SelectSelectionModel(gfx::SelectionModel(3, 3, 3, + gfx::SelectionModel::LEADING)); EXPECT_TRUE(model.GetSelectedText().empty()); - model.SelectSelectionModel(gfx::SelectionModel(1000, 100)); + model.SelectSelectionModel(gfx::SelectionModel(1000, 100, 100, + gfx::SelectionModel::LEADING)); EXPECT_TRUE(model.GetSelectedText().empty()); - model.SelectSelectionModel(gfx::SelectionModel(1000, 1000)); + model.SelectSelectionModel(gfx::SelectionModel(1000, 1000, 1000, + gfx::SelectionModel::TRAILING)); EXPECT_TRUE(model.GetSelectedText().empty()); } TEST_F(TextfieldViewsModelTest, CompositionTextTest) { TextfieldViewsModel model(this); model.Append(ASCIIToUTF16("1234590")); - model.SelectSelectionModel(gfx::SelectionModel(5, 5)); + model.SelectRange(ui::Range(5, 5)); EXPECT_FALSE(model.HasSelection()); EXPECT_EQ(5U, model.GetCursorPosition()); @@ -865,15 +982,15 @@ TEST_F(TextfieldViewsModelTest, CompositionTextTest) { EXPECT_STR_EQ("678", model.GetText()); model.SetCompositionText(composition); - gfx::SelectionModel sel(0); - sel.set_selection_start(model.render_text()->GetSelectionStart()); + gfx::SelectionModel sel(model.render_text()->GetSelectionStart(), + 0, 0, gfx::SelectionModel::LEADING); model.MoveCursorTo(sel); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; EXPECT_STR_EQ("678678", model.GetText()); model.SetCompositionText(composition); - model.SelectSelectionModel(gfx::SelectionModel(0, 3)); + model.SelectRange(ui::Range(0, 3)); EXPECT_TRUE(composition_text_confirmed_or_cleared_); composition_text_confirmed_or_cleared_ = false; EXPECT_STR_EQ("678", model.GetText()); @@ -1007,19 +1124,19 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_SetText) { model.SetText(ASCIIToUTF16("www.google.com")); EXPECT_EQ(1U, model.GetCursorPosition()); EXPECT_STR_EQ("www.google.com", model.GetText()); - model.SelectSelectionModel(gfx::SelectionModel(14, 1)); + model.SelectRange(ui::Range(14, 1)); model.InsertChar('w'); EXPECT_STR_EQ("ww", model.GetText()); model.SetText(ASCIIToUTF16("www.google.com")); - model.SelectSelectionModel(gfx::SelectionModel(14, 2)); + model.SelectRange(ui::Range(14, 2)); model.InsertChar('w'); EXPECT_STR_EQ("www", model.GetText()); model.SetText(ASCIIToUTF16("www.google.com")); - model.SelectSelectionModel(gfx::SelectionModel(14, 3)); + model.SelectRange(ui::Range(14, 3)); model.InsertChar('.'); EXPECT_STR_EQ("www.", model.GetText()); model.SetText(ASCIIToUTF16("www.google.com")); - model.SelectSelectionModel(gfx::SelectionModel(14, 4)); + model.SelectRange(ui::Range(14, 4)); model.InsertChar('y'); EXPECT_STR_EQ("www.y", model.GetText()); model.SetText(ASCIIToUTF16("www.youtube.com")); @@ -1072,7 +1189,7 @@ TEST_F(TextfieldViewsModelTest, MAYBE_UndoRedo_CutCopyPasteTest) { model.SetText(ASCIIToUTF16("ABCDE")); EXPECT_FALSE(model.Redo()); // nothing to redo // Cut - model.MoveCursorTo(gfx::SelectionModel(1, 3)); + model.SelectRange(ui::Range(1, 3)); model.Cut(); EXPECT_STR_EQ("ADE", model.GetText()); EXPECT_EQ(1U, model.GetCursorPosition()); @@ -1134,12 +1251,12 @@ TEST_F(TextfieldViewsModelTest, MAYBE_UndoRedo_CutCopyPasteTest) { EXPECT_EQ(7U, model.GetCursorPosition()); EXPECT_FALSE(model.Redo()); - // with SelectSelectionModel - model.SelectSelectionModel(gfx::SelectionModel(1, 3)); + // with SelectRange + model.SelectRange(ui::Range(1, 3)); EXPECT_TRUE(model.Cut()); EXPECT_STR_EQ("ABCBCDE", model.GetText()); EXPECT_EQ(1U, model.GetCursorPosition()); - model.SelectSelectionModel(gfx::SelectionModel(1, 1)); + model.SelectRange(ui::Range(1, 1)); EXPECT_FALSE(model.Cut()); model.MoveCursorRight(gfx::LINE_BREAK, false); EXPECT_TRUE(model.Paste()); @@ -1158,7 +1275,7 @@ TEST_F(TextfieldViewsModelTest, MAYBE_UndoRedo_CutCopyPasteTest) { model.SetText(ASCIIToUTF16("12345")); EXPECT_STR_EQ("12345", model.GetText()); EXPECT_EQ(0U, model.GetCursorPosition()); - model.MoveCursorTo(gfx::SelectionModel(1, 3)); + model.SelectRange(ui::Range(1, 3)); model.Copy(); // Copy "23" EXPECT_STR_EQ("12345", model.GetText()); EXPECT_EQ(3U, model.GetCursorPosition()); @@ -1191,8 +1308,8 @@ TEST_F(TextfieldViewsModelTest, MAYBE_UndoRedo_CutCopyPasteTest) { EXPECT_FALSE(model.Redo()); EXPECT_STR_EQ("1232345", model.GetText()); - // Test using SelectSelectionModel - model.SelectSelectionModel(gfx::SelectionModel(1, 3)); + // Test using SelectRange + model.SelectRange(ui::Range(1, 3)); model.Copy(); EXPECT_STR_EQ("1232345", model.GetText()); model.MoveCursorRight(gfx::LINE_BREAK, false); @@ -1282,57 +1399,57 @@ TEST_F(TextfieldViewsModelTest, UndoRedo_ReplaceTest) { SCOPED_TRACE("forward & insert by cursor"); TextfieldViewsModel model(NULL); model.SetText(ASCIIToUTF16("abcd")); - model.MoveCursorTo(gfx::SelectionModel(1, 3)); + model.SelectRange(ui::Range(1, 3)); RunInsertReplaceTest(model); } { SCOPED_TRACE("backward & insert by cursor"); TextfieldViewsModel model(NULL); model.SetText(ASCIIToUTF16("abcd")); - model.MoveCursorTo(gfx::SelectionModel(3, 1)); + model.SelectRange(ui::Range(3, 1)); RunInsertReplaceTest(model); } { SCOPED_TRACE("forward & overwrite by cursor"); TextfieldViewsModel model(NULL); model.SetText(ASCIIToUTF16("abcd")); - model.MoveCursorTo(gfx::SelectionModel(1, 3)); + model.SelectRange(ui::Range(1, 3)); RunOverwriteReplaceTest(model); } { SCOPED_TRACE("backward & overwrite by cursor"); TextfieldViewsModel model(NULL); model.SetText(ASCIIToUTF16("abcd")); - model.MoveCursorTo(gfx::SelectionModel(3, 1)); + model.SelectRange(ui::Range(3, 1)); RunOverwriteReplaceTest(model); } - // By SelectSelectionModel API + // By SelectRange API { - SCOPED_TRACE("forward & insert by SelectSelectionModel"); + SCOPED_TRACE("forward & insert by SelectRange"); TextfieldViewsModel model(NULL); model.SetText(ASCIIToUTF16("abcd")); - model.SelectSelectionModel(gfx::SelectionModel(1, 3)); + model.SelectRange(ui::Range(1, 3)); RunInsertReplaceTest(model); } { - SCOPED_TRACE("backward & insert by SelectSelectionModel"); + SCOPED_TRACE("backward & insert by SelectRange"); TextfieldViewsModel model(NULL); model.SetText(ASCIIToUTF16("abcd")); - model.SelectSelectionModel(gfx::SelectionModel(3, 1)); + model.SelectRange(ui::Range(3, 1)); RunInsertReplaceTest(model); } { - SCOPED_TRACE("forward & overwrite by SelectSelectionModel"); + SCOPED_TRACE("forward & overwrite by SelectRange"); TextfieldViewsModel model(NULL); model.SetText(ASCIIToUTF16("abcd")); - model.SelectSelectionModel(gfx::SelectionModel(1, 3)); + model.SelectRange(ui::Range(1, 3)); RunOverwriteReplaceTest(model); } { - SCOPED_TRACE("backward & overwrite by SelectSelectionModel"); + SCOPED_TRACE("backward & overwrite by SelectRange"); TextfieldViewsModel model(NULL); model.SetText(ASCIIToUTF16("abcd")); - model.SelectSelectionModel(gfx::SelectionModel(3, 1)); + model.SelectRange(ui::Range(3, 1)); RunOverwriteReplaceTest(model); } } diff --git a/views/touchui/touch_selection_controller_impl_unittest.cc b/views/touchui/touch_selection_controller_impl_unittest.cc index 3780b4a..9741c26 100644 --- a/views/touchui/touch_selection_controller_impl_unittest.cc +++ b/views/touchui/touch_selection_controller_impl_unittest.cc @@ -122,7 +122,7 @@ TEST_F(TouchSelectionControllerImplTest, SelectionInTextfieldTest) { textfield_->SetText(ASCIIToUTF16("some text")); // Test selecting a range. - textfield_->SelectSelectionModel(gfx::SelectionModel(3, 7)); + textfield_->SelectRange(ui::Range(3, 7)); VerifySelectionHandlePositions(false); // Test selecting everything. @@ -153,46 +153,35 @@ TEST_F(TouchSelectionControllerImplTest, SelectionInBidiTextfieldTest) { VerifySelectionHandlePositions(false); // Test selection range inside one run and starts or ends at run boundary. - textfield_->SelectSelectionModel( - gfx::SelectionModel(2, 3, 2, gfx::SelectionModel::TRAILING)); + textfield_->SelectRange(ui::Range(2, 3)); VerifySelectionHandlePositions(false); - // TODO(xji): change to textfield_->SelectRange(3, 2). - textfield_->SelectSelectionModel( - gfx::SelectionModel(3, 2, 2, gfx::SelectionModel::LEADING)); + textfield_->SelectRange(ui::Range(3, 2)); VerifySelectionHandlePositions(false); - textfield_->SelectSelectionModel( - gfx::SelectionModel(3, 4, 3, gfx::SelectionModel::TRAILING)); + textfield_->SelectRange(ui::Range(3, 4)); VerifySelectionHandlePositions(false); - textfield_->SelectSelectionModel( - gfx::SelectionModel(4, 3, 3, gfx::SelectionModel::LEADING)); + textfield_->SelectRange(ui::Range(4, 3)); VerifySelectionHandlePositions(false); - textfield_->SelectSelectionModel( - gfx::SelectionModel(3, 6, 5, gfx::SelectionModel::TRAILING)); + textfield_->SelectRange(ui::Range(3, 6)); VerifySelectionHandlePositions(false); - textfield_->SelectSelectionModel( - gfx::SelectionModel(6, 3, 3, gfx::SelectionModel::LEADING)); + textfield_->SelectRange(ui::Range(6, 3)); VerifySelectionHandlePositions(false); // Test selection range accross runs. - textfield_->SelectSelectionModel( - gfx::SelectionModel(0, 6, 5, gfx::SelectionModel::TRAILING)); + textfield_->SelectRange(ui::Range(0, 6)); VerifySelectionHandlePositions(false); - textfield_->SelectSelectionModel( - gfx::SelectionModel(6, 0, 0, gfx::SelectionModel::LEADING)); + textfield_->SelectRange(ui::Range(6, 0)); VerifySelectionHandlePositions(false); - textfield_->SelectSelectionModel( - gfx::SelectionModel(1, 4, 3, gfx::SelectionModel::TRAILING)); + textfield_->SelectRange(ui::Range(1, 4)); VerifySelectionHandlePositions(false); - textfield_->SelectSelectionModel( - gfx::SelectionModel(4, 1, 1, gfx::SelectionModel::LEADING)); + textfield_->SelectRange(ui::Range(4, 1)); VerifySelectionHandlePositions(false); } @@ -201,7 +190,7 @@ TEST_F(TouchSelectionControllerImplTest, SelectionInBidiTextfieldTest) { TEST_F(TouchSelectionControllerImplTest, SelectRectCallbackTest) { CreateTextfield(); textfield_->SetText(ASCIIToUTF16("textfield with selected text")); - textfield_->SelectSelectionModel(gfx::SelectionModel(3, 7)); + textfield_->SelectRange(ui::Range(3, 7)); EXPECT_EQ(UTF16ToUTF8(textfield_->GetSelectedText()), "tfie"); VerifySelectionHandlePositions(false); @@ -231,4 +220,122 @@ TEST_F(TouchSelectionControllerImplTest, SelectRectCallbackTest) { VerifySelectionHandlePositions(false); } +TEST_F(TouchSelectionControllerImplTest, SelectRectInBidiCallbackTest) { + CreateTextfield(); + textfield_->SetText(WideToUTF16(L"abc\x05e1\x05e2\x05e3"L"def")); + + // Select [c] from left to right. + textfield_->SelectRange(ui::Range(2, 3)); + EXPECT_EQ(WideToUTF16(L"c"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(false); + + // Drag selection handle 2 to right by 1 char. + int x = textfield_->font().GetStringWidth(WideToUTF16(L"\x05e3")); + SimulateSelectionHandleDrag(gfx::Point(x, 0), 2); + EXPECT_EQ(WideToUTF16(L"c\x05e1\x05e2"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(false); + + // Drag selection handle 1 to left by 1 char. + x = textfield_->font().GetStringWidth(WideToUTF16(L"b")); + SimulateSelectionHandleDrag(gfx::Point(-x, 0), 1); + EXPECT_EQ(WideToUTF16(L"bc\x05e1\x05e2"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(true); + + // Select [c] from right to left. + textfield_->SelectRange(ui::Range(3, 2)); + EXPECT_EQ(WideToUTF16(L"c"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(false); + + // Drag selection handle 1 to right by 1 char. + x = textfield_->font().GetStringWidth(WideToUTF16(L"\x05e3")); + SimulateSelectionHandleDrag(gfx::Point(x, 0), 1); + EXPECT_EQ(WideToUTF16(L"c\x05e1\x05e2"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(true); + + // Drag selection handle 2 to left by 1 char. + x = textfield_->font().GetStringWidth(WideToUTF16(L"b")); + SimulateSelectionHandleDrag(gfx::Point(-x, 0), 2); + EXPECT_EQ(WideToUTF16(L"bc\x05e1\x05e2"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(false); + + // Select [\x5e1] from right to left. + textfield_->SelectRange(ui::Range(3, 4)); + EXPECT_EQ(WideToUTF16(L"\x05e1"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(false); + + /* TODO(xji): for bidi text "abcDEF" whose display is "abcFEDhij", when click + right of 'D' and select [D] then move the left selection handle to left + by one character, it should select [ED], instead it selects [F]. + Reason: click right of 'D' and left of 'h' return the same x-axis position, + pass this position to FindCursorPosition() returns index of 'h'. which + means the selection start changed from 3 to 6. + Need further investigation on whether this is a bug in Pango and how to + work around it. + // Drag selection handle 2 to left by 1 char. + x = textfield_->font().GetStringWidth(WideToUTF16(L"\x05e2")); + SimulateSelectionHandleDrag(gfx::Point(-x, 0), 2); + EXPECT_EQ(WideToUTF16(L"\x05e1\x05e2"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(false); + */ + + // Drag selection handle 1 to right by 1 char. + x = textfield_->font().GetStringWidth(WideToUTF16(L"d")); + SimulateSelectionHandleDrag(gfx::Point(x, 0), 1); + EXPECT_EQ(WideToUTF16(L"\x05e2\x05e3"L"d"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(true); + + // Select [\x5e1] from left to right. + textfield_->SelectRange(ui::Range(4, 3)); + EXPECT_EQ(WideToUTF16(L"\x05e1"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(false); + + /* TODO(xji): see detail of above commented out test case. + // Drag selection handle 1 to left by 1 char. + x = textfield_->font().GetStringWidth(WideToUTF16(L"\x05e2")); + SimulateSelectionHandleDrag(gfx::Point(-x, 0), 1); + EXPECT_EQ(WideToUTF16(L"\x05e1\x05e2"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(true); + */ + + // Drag selection handle 2 to right by 1 char. + x = textfield_->font().GetStringWidth(WideToUTF16(L"d")); + SimulateSelectionHandleDrag(gfx::Point(x, 0), 2); + EXPECT_EQ(WideToUTF16(L"\x05e2\x05e3"L"d"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(false); + + // Select [\x05r3] from right to left. + textfield_->SelectRange(ui::Range(5, 6)); + EXPECT_EQ(WideToUTF16(L"\x05e3"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(false); + + // Drag selection handle 2 to left by 1 char. + x = textfield_->font().GetStringWidth(WideToUTF16(L"c")); + SimulateSelectionHandleDrag(gfx::Point(-x, 0), 2); + EXPECT_EQ(WideToUTF16(L"c\x05e1\x05e2"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(false); + + // Drag selection handle 1 to right by 1 char. + x = textfield_->font().GetStringWidth(WideToUTF16(L"\x05e2")); + SimulateSelectionHandleDrag(gfx::Point(x, 0), 1); + EXPECT_EQ(WideToUTF16(L"c\x05e1"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(true); + + // Select [\x05r3] from left to right. + textfield_->SelectRange(ui::Range(6, 5)); + EXPECT_EQ(WideToUTF16(L"\x05e3"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(false); + + // Drag selection handle 1 to left by 1 char. + x = textfield_->font().GetStringWidth(WideToUTF16(L"c")); + SimulateSelectionHandleDrag(gfx::Point(-x, 0), 1); + EXPECT_EQ(WideToUTF16(L"c\x05e1\x05e2"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(true); + + // Drag selection handle 2 to right by 1 char. + x = textfield_->font().GetStringWidth(WideToUTF16(L"\x05e2")); + SimulateSelectionHandleDrag(gfx::Point(x, 0), 2); + EXPECT_EQ(WideToUTF16(L"c\x05e1"), textfield_->GetSelectedText()); + VerifySelectionHandlePositions(false); +} + } // namespace views |