| // Copyright 2014 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. |
| |
| #include "ui/views/controls/textfield/textfield.h" |
| |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/pickle.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "ui/base/clipboard/clipboard.h" |
| #include "ui/base/clipboard/scoped_clipboard_writer.h" |
| #include "ui/base/dragdrop/drag_drop_types.h" |
| #include "ui/base/ime/text_input_client.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/ui_base_switches.h" |
| #include "ui/base/ui_base_switches_util.h" |
| #include "ui/events/event.h" |
| #include "ui/events/keycodes/keyboard_codes.h" |
| #include "ui/gfx/render_text.h" |
| #include "ui/strings/grit/ui_strings.h" |
| #include "ui/views/controls/textfield/textfield_controller.h" |
| #include "ui/views/controls/textfield/textfield_model.h" |
| #include "ui/views/controls/textfield/textfield_test_api.h" |
| #include "ui/views/focus/focus_manager.h" |
| #include "ui/views/ime/mock_input_method.h" |
| #include "ui/views/test/test_views_delegate.h" |
| #include "ui/views/test/views_test_base.h" |
| #include "ui/views/widget/widget.h" |
| #include "url/gurl.h" |
| |
| #if defined(OS_WIN) |
| #include "base/win/windows_version.h" |
| #endif |
| |
| #if defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| #include "ui/events/linux/text_edit_key_bindings_delegate_auralinux.h" |
| #endif |
| |
| #if defined(USE_X11) |
| #include "ui/events/event_utils.h" |
| #endif |
| |
| using base::ASCIIToUTF16; |
| using base::UTF8ToUTF16; |
| using base::WideToUTF16; |
| |
| #define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(ASCIIToUTF16(ascii), utf16) |
| |
| namespace { |
| |
| const base::char16 kHebrewLetterSamekh = 0x05E1; |
| |
| // A Textfield wrapper to intercept OnKey[Pressed|Released]() ressults. |
| class TestTextfield : public views::Textfield { |
| public: |
| TestTextfield() |
| : Textfield(), |
| key_handled_(false), |
| key_received_(false), |
| weak_ptr_factory_(this) {} |
| |
| virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE { |
| key_received_ = true; |
| |
| // Since OnKeyPressed() might destroy |this|, get a weak pointer and |
| // verify it isn't null before writing the bool value to key_handled_. |
| base::WeakPtr<TestTextfield> textfield(weak_ptr_factory_.GetWeakPtr()); |
| bool key = views::Textfield::OnKeyPressed(e); |
| |
| if (!textfield) |
| return key; |
| |
| key_handled_ = key; |
| |
| return key_handled_; |
| } |
| |
| virtual bool OnKeyReleased(const ui::KeyEvent& e) OVERRIDE { |
| key_received_ = true; |
| key_handled_ = views::Textfield::OnKeyReleased(e); |
| return key_handled_; |
| } |
| |
| bool key_handled() const { return key_handled_; } |
| bool key_received() const { return key_received_; } |
| |
| void clear() { key_received_ = key_handled_ = false; } |
| |
| private: |
| bool key_handled_; |
| bool key_received_; |
| |
| base::WeakPtrFactory<TestTextfield> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestTextfield); |
| }; |
| |
| // Convenience to make constructing a GestureEvent simpler. |
| class GestureEventForTest : public ui::GestureEvent { |
| public: |
| GestureEventForTest(int x, int y, ui::GestureEventDetails details) |
| : GestureEvent(x, y, 0, base::TimeDelta(), details) {} |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(GestureEventForTest); |
| }; |
| |
| // This controller will happily destroy the target textfield passed on |
| // construction when a key event is triggered. |
| class TextfieldDestroyerController : public views::TextfieldController { |
| public: |
| explicit TextfieldDestroyerController(views::Textfield* target) |
| : target_(target) { |
| target_->set_controller(this); |
| } |
| |
| views::Textfield* target() { return target_.get(); } |
| |
| // views::TextfieldController: |
| virtual bool HandleKeyEvent(views::Textfield* sender, |
| const ui::KeyEvent& key_event) OVERRIDE { |
| target_.reset(); |
| return false; |
| } |
| |
| private: |
| scoped_ptr<views::Textfield> target_; |
| }; |
| |
| base::string16 GetClipboardText(ui::ClipboardType type) { |
| base::string16 text; |
| ui::Clipboard::GetForCurrentThread()->ReadText(type, &text); |
| return text; |
| } |
| |
| void SetClipboardText(ui::ClipboardType type, const std::string& text) { |
| ui::ScopedClipboardWriter(ui::Clipboard::GetForCurrentThread(), type) |
| .WriteText(ASCIIToUTF16(text)); |
| } |
| |
| } // namespace |
| |
| namespace views { |
| |
| class TextfieldTest : public ViewsTestBase, public TextfieldController { |
| public: |
| TextfieldTest() |
| : widget_(NULL), |
| textfield_(NULL), |
| model_(NULL), |
| input_method_(NULL), |
| on_before_user_action_(0), |
| on_after_user_action_(0), |
| copied_to_clipboard_(ui::CLIPBOARD_TYPE_LAST) { |
| } |
| |
| // ::testing::Test: |
| virtual void SetUp() { |
| ViewsTestBase::SetUp(); |
| } |
| |
| virtual void TearDown() { |
| if (widget_) |
| widget_->Close(); |
| ViewsTestBase::TearDown(); |
| } |
| |
| ui::ClipboardType GetAndResetCopiedToClipboard() { |
| ui::ClipboardType clipboard_type = copied_to_clipboard_; |
| copied_to_clipboard_ = ui::CLIPBOARD_TYPE_LAST; |
| return clipboard_type; |
| } |
| |
| // TextfieldController: |
| virtual void ContentsChanged(Textfield* sender, |
| const base::string16& new_contents) OVERRIDE { |
| // Paste calls TextfieldController::ContentsChanged() explicitly even if the |
| // paste action did not change the content. So |new_contents| may match |
| // |last_contents_|. For more info, see http://crbug.com/79002 |
| last_contents_ = new_contents; |
| } |
| |
| virtual void OnBeforeUserAction(Textfield* sender) OVERRIDE { |
| ++on_before_user_action_; |
| } |
| |
| virtual void OnAfterUserAction(Textfield* sender) OVERRIDE { |
| ++on_after_user_action_; |
| } |
| |
| virtual void OnAfterCutOrCopy(ui::ClipboardType clipboard_type) OVERRIDE { |
| copied_to_clipboard_ = clipboard_type; |
| } |
| |
| void InitTextfield() { |
| InitTextfields(1); |
| } |
| |
| void InitTextfields(int count) { |
| ASSERT_FALSE(textfield_); |
| textfield_ = new TestTextfield(); |
| textfield_->set_controller(this); |
| widget_ = new Widget(); |
| Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
| params.bounds = gfx::Rect(100, 100, 100, 100); |
| widget_->Init(params); |
| View* container = new View(); |
| widget_->SetContentsView(container); |
| container->AddChildView(textfield_); |
| textfield_->SetBoundsRect(params.bounds); |
| textfield_->set_id(1); |
| test_api_.reset(new TextfieldTestApi(textfield_)); |
| |
| for (int i = 1; i < count; i++) { |
| Textfield* textfield = new Textfield(); |
| container->AddChildView(textfield); |
| textfield->set_id(i + 1); |
| } |
| |
| model_ = test_api_->model(); |
| model_->ClearEditHistory(); |
| |
| input_method_ = new MockInputMethod(); |
| widget_->ReplaceInputMethod(input_method_); |
| |
| // Activate the widget and focus the textfield for input handling. |
| widget_->Activate(); |
| textfield_->RequestFocus(); |
| } |
| |
| ui::MenuModel* GetContextMenuModel() { |
| test_api_->UpdateContextMenu(); |
| return test_api_->context_menu_contents(); |
| } |
| |
| protected: |
| void SendKeyEvent(ui::KeyboardCode key_code, |
| bool alt, |
| bool shift, |
| bool control, |
| bool caps_lock) { |
| int flags = (alt ? ui::EF_ALT_DOWN : 0) | |
| (shift ? ui::EF_SHIFT_DOWN : 0) | |
| (control ? ui::EF_CONTROL_DOWN : 0) | |
| (caps_lock ? ui::EF_CAPS_LOCK_DOWN : 0); |
| ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, flags); |
| input_method_->DispatchKeyEvent(event); |
| } |
| |
| void SendKeyEvent(ui::KeyboardCode key_code, bool shift, bool control) { |
| SendKeyEvent(key_code, false, shift, control, false); |
| } |
| |
| void SendKeyEvent(ui::KeyboardCode key_code) { |
| SendKeyEvent(key_code, false, false); |
| } |
| |
| void SendKeyEvent(base::char16 ch) { |
| if (ch < 0x80) { |
| ui::KeyboardCode code = |
| ch == ' ' ? ui::VKEY_SPACE : |
| static_cast<ui::KeyboardCode>(ui::VKEY_A + ch - 'a'); |
| SendKeyEvent(code); |
| } else { |
| ui::KeyEvent event(ch, ui::VKEY_UNKNOWN, ui::EF_NONE); |
| input_method_->DispatchKeyEvent(event); |
| } |
| } |
| |
| View* GetFocusedView() { |
| return widget_->GetFocusManager()->GetFocusedView(); |
| } |
| |
| int GetCursorPositionX(int cursor_pos) { |
| return test_api_->GetRenderText()->GetCursorBounds( |
| gfx::SelectionModel(cursor_pos, gfx::CURSOR_FORWARD), false).x(); |
| } |
| |
| // Get the current cursor bounds. |
| gfx::Rect GetCursorBounds() { |
| return test_api_->GetRenderText()->GetUpdatedCursorBounds(); |
| } |
| |
| // Get the cursor bounds of |sel|. |
| gfx::Rect GetCursorBounds(const gfx::SelectionModel& sel) { |
| return test_api_->GetRenderText()->GetCursorBounds(sel, true); |
| } |
| |
| gfx::Rect GetDisplayRect() { |
| return test_api_->GetRenderText()->display_rect(); |
| } |
| |
| // Mouse click on the point whose x-axis is |bound|'s x plus |x_offset| and |
| // y-axis is in the middle of |bound|'s vertical range. |
| void MouseClick(const gfx::Rect bound, int x_offset) { |
| gfx::Point point(bound.x() + x_offset, bound.y() + bound.height() / 2); |
| ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMousePressed(click); |
| ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMouseReleased(release); |
| } |
| |
| // This is to avoid double/triple click. |
| void NonClientMouseClick() { |
| ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), |
| ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT, |
| ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMousePressed(click); |
| ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), |
| ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT, |
| ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMouseReleased(release); |
| } |
| |
| // Simulates a complete tap. |
| void Tap(const gfx::Point& point) { |
| GestureEventForTest begin( |
| point.x(), point.y(), ui::GestureEventDetails(ui::ET_GESTURE_BEGIN)); |
| textfield_->OnGestureEvent(&begin); |
| |
| GestureEventForTest tap_down( |
| point.x(), point.y(), ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN)); |
| textfield_->OnGestureEvent(&tap_down); |
| |
| GestureEventForTest show_press( |
| point.x(), |
| point.y(), |
| ui::GestureEventDetails(ui::ET_GESTURE_SHOW_PRESS)); |
| textfield_->OnGestureEvent(&show_press); |
| |
| ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP); |
| tap_details.set_tap_count(1); |
| GestureEventForTest tap(point.x(), point.y(), tap_details); |
| textfield_->OnGestureEvent(&tap); |
| |
| GestureEventForTest end( |
| point.x(), point.y(), ui::GestureEventDetails(ui::ET_GESTURE_END)); |
| textfield_->OnGestureEvent(&end); |
| } |
| |
| void VerifyTextfieldContextMenuContents(bool textfield_has_selection, |
| bool can_undo, |
| ui::MenuModel* menu) { |
| EXPECT_EQ(can_undo, menu->IsEnabledAt(0 /* UNDO */)); |
| EXPECT_TRUE(menu->IsEnabledAt(1 /* Separator */)); |
| EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(2 /* CUT */)); |
| EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(3 /* COPY */)); |
| EXPECT_NE(GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE).empty(), |
| menu->IsEnabledAt(4 /* PASTE */)); |
| EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(5 /* DELETE */)); |
| EXPECT_TRUE(menu->IsEnabledAt(6 /* Separator */)); |
| EXPECT_TRUE(menu->IsEnabledAt(7 /* SELECT ALL */)); |
| } |
| |
| // We need widget to populate wrapper class. |
| Widget* widget_; |
| |
| TestTextfield* textfield_; |
| scoped_ptr<TextfieldTestApi> test_api_; |
| TextfieldModel* model_; |
| |
| // The string from Controller::ContentsChanged callback. |
| base::string16 last_contents_; |
| |
| // For testing input method related behaviors. |
| MockInputMethod* input_method_; |
| |
| // Indicates how many times OnBeforeUserAction() is called. |
| int on_before_user_action_; |
| |
| // Indicates how many times OnAfterUserAction() is called. |
| int on_after_user_action_; |
| |
| private: |
| ui::ClipboardType copied_to_clipboard_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TextfieldTest); |
| }; |
| |
| TEST_F(TextfieldTest, ModelChangesTest) { |
| InitTextfield(); |
| |
| // TextfieldController::ContentsChanged() shouldn't be called when changing |
| // text programmatically. |
| last_contents_.clear(); |
| textfield_->SetText(ASCIIToUTF16("this is")); |
| |
| EXPECT_STR_EQ("this is", model_->text()); |
| EXPECT_STR_EQ("this is", textfield_->text()); |
| EXPECT_TRUE(last_contents_.empty()); |
| |
| textfield_->AppendText(ASCIIToUTF16(" a test")); |
| EXPECT_STR_EQ("this is a test", model_->text()); |
| EXPECT_STR_EQ("this is a test", textfield_->text()); |
| EXPECT_TRUE(last_contents_.empty()); |
| |
| EXPECT_EQ(base::string16(), textfield_->GetSelectedText()); |
| textfield_->SelectAll(false); |
| EXPECT_STR_EQ("this is a test", textfield_->GetSelectedText()); |
| EXPECT_TRUE(last_contents_.empty()); |
| } |
| |
| TEST_F(TextfieldTest, KeyTest) { |
| InitTextfield(); |
| // Event flags: key, alt, shift, ctrl, caps-lock. |
| SendKeyEvent(ui::VKEY_T, false, true, false, false); |
| SendKeyEvent(ui::VKEY_E, false, false, false, false); |
| SendKeyEvent(ui::VKEY_X, false, true, false, true); |
| SendKeyEvent(ui::VKEY_T, false, false, false, true); |
| SendKeyEvent(ui::VKEY_1, false, true, false, false); |
| SendKeyEvent(ui::VKEY_1, false, false, false, false); |
| SendKeyEvent(ui::VKEY_1, false, true, false, true); |
| SendKeyEvent(ui::VKEY_1, false, false, false, true); |
| EXPECT_STR_EQ("TexT!1!1", textfield_->text()); |
| } |
| |
| TEST_F(TextfieldTest, ControlAndSelectTest) { |
| // Insert a test string in a textfield. |
| InitTextfield(); |
| textfield_->SetText(ASCIIToUTF16("one two three")); |
| SendKeyEvent(ui::VKEY_HOME, false /* shift */, false /* control */); |
| SendKeyEvent(ui::VKEY_RIGHT, true, false); |
| SendKeyEvent(ui::VKEY_RIGHT, true, false); |
| SendKeyEvent(ui::VKEY_RIGHT, true, false); |
| |
| EXPECT_STR_EQ("one", textfield_->GetSelectedText()); |
| |
| // Test word select. |
| SendKeyEvent(ui::VKEY_RIGHT, true, true); |
| EXPECT_STR_EQ("one two", textfield_->GetSelectedText()); |
| SendKeyEvent(ui::VKEY_RIGHT, true, true); |
| EXPECT_STR_EQ("one two three", textfield_->GetSelectedText()); |
| SendKeyEvent(ui::VKEY_LEFT, true, true); |
| EXPECT_STR_EQ("one two ", textfield_->GetSelectedText()); |
| SendKeyEvent(ui::VKEY_LEFT, true, true); |
| EXPECT_STR_EQ("one ", textfield_->GetSelectedText()); |
| |
| // Replace the selected text. |
| SendKeyEvent(ui::VKEY_Z, true, false); |
| SendKeyEvent(ui::VKEY_E, true, false); |
| SendKeyEvent(ui::VKEY_R, true, false); |
| SendKeyEvent(ui::VKEY_O, true, false); |
| SendKeyEvent(ui::VKEY_SPACE, false, false); |
| EXPECT_STR_EQ("ZERO two three", textfield_->text()); |
| |
| SendKeyEvent(ui::VKEY_END, true, false); |
| EXPECT_STR_EQ("two three", textfield_->GetSelectedText()); |
| SendKeyEvent(ui::VKEY_HOME, true, false); |
| EXPECT_STR_EQ("ZERO ", textfield_->GetSelectedText()); |
| } |
| |
| TEST_F(TextfieldTest, InsertionDeletionTest) { |
| // Insert a test string in a textfield. |
| InitTextfield(); |
| for (size_t i = 0; i < 10; i++) |
| SendKeyEvent(static_cast<ui::KeyboardCode>(ui::VKEY_A + i)); |
| EXPECT_STR_EQ("abcdefghij", textfield_->text()); |
| |
| // Test the delete and backspace keys. |
| textfield_->SelectRange(gfx::Range(5)); |
| for (int i = 0; i < 3; i++) |
| SendKeyEvent(ui::VKEY_BACK); |
| EXPECT_STR_EQ("abfghij", textfield_->text()); |
| for (int i = 0; i < 3; i++) |
| SendKeyEvent(ui::VKEY_DELETE); |
| EXPECT_STR_EQ("abij", textfield_->text()); |
| |
| // Select all and replace with "k". |
| textfield_->SelectAll(false); |
| SendKeyEvent(ui::VKEY_K); |
| EXPECT_STR_EQ("k", textfield_->text()); |
| |
| // Delete the previous word from cursor. |
| textfield_->SetText(ASCIIToUTF16("one two three four")); |
| SendKeyEvent(ui::VKEY_END); |
| SendKeyEvent(ui::VKEY_BACK, false, false, true, false); |
| EXPECT_STR_EQ("one two three ", textfield_->text()); |
| |
| // Delete to a line break on Linux and ChromeOS, to a word break on Windows. |
| SendKeyEvent(ui::VKEY_LEFT, false, false, true, false); |
| SendKeyEvent(ui::VKEY_BACK, false, true, true, false); |
| #if defined(OS_LINUX) |
| EXPECT_STR_EQ("three ", textfield_->text()); |
| #else |
| EXPECT_STR_EQ("one three ", textfield_->text()); |
| #endif |
| |
| // Delete the next word from cursor. |
| textfield_->SetText(ASCIIToUTF16("one two three four")); |
| SendKeyEvent(ui::VKEY_HOME); |
| SendKeyEvent(ui::VKEY_DELETE, false, false, true, false); |
| EXPECT_STR_EQ(" two three four", textfield_->text()); |
| |
| // Delete to a line break on Linux and ChromeOS, to a word break on Windows. |
| SendKeyEvent(ui::VKEY_RIGHT, false, false, true, false); |
| SendKeyEvent(ui::VKEY_DELETE, false, true, true, false); |
| #if defined(OS_LINUX) |
| EXPECT_STR_EQ(" two", textfield_->text()); |
| #else |
| EXPECT_STR_EQ(" two four", textfield_->text()); |
| #endif |
| } |
| |
| TEST_F(TextfieldTest, PasswordTest) { |
| InitTextfield(); |
| textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); |
| EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType()); |
| EXPECT_TRUE(textfield_->enabled()); |
| EXPECT_TRUE(textfield_->IsFocusable()); |
| |
| last_contents_.clear(); |
| textfield_->SetText(ASCIIToUTF16("password")); |
| // Ensure text() and the callback returns the actual text instead of "*". |
| EXPECT_STR_EQ("password", textfield_->text()); |
| EXPECT_TRUE(last_contents_.empty()); |
| model_->SelectAll(false); |
| SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "foo"); |
| |
| // Cut and copy should be disabled. |
| EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_CUT)); |
| textfield_->ExecuteCommand(IDS_APP_CUT, 0); |
| SendKeyEvent(ui::VKEY_X, false, true); |
| EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_COPY)); |
| textfield_->ExecuteCommand(IDS_APP_COPY, 0); |
| SendKeyEvent(ui::VKEY_C, false, true); |
| SendKeyEvent(ui::VKEY_INSERT, false, true); |
| EXPECT_STR_EQ("foo", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| EXPECT_STR_EQ("password", textfield_->text()); |
| // [Shift]+[Delete] should just delete without copying text to the clipboard. |
| textfield_->SelectAll(false); |
| SendKeyEvent(ui::VKEY_DELETE, true, false); |
| |
| // Paste should work normally. |
| EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE)); |
| textfield_->ExecuteCommand(IDS_APP_PASTE, 0); |
| SendKeyEvent(ui::VKEY_V, false, true); |
| SendKeyEvent(ui::VKEY_INSERT, true, false); |
| EXPECT_STR_EQ("foo", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| EXPECT_STR_EQ("foofoofoo", textfield_->text()); |
| } |
| |
| TEST_F(TextfieldTest, TextInputType) { |
| InitTextfield(); |
| |
| // Defaults to TEXT |
| EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, textfield_->GetTextInputType()); |
| |
| // And can be set. |
| textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_URL); |
| EXPECT_EQ(ui::TEXT_INPUT_TYPE_URL, textfield_->GetTextInputType()); |
| textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); |
| EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType()); |
| |
| // Readonly textfields have type NONE |
| textfield_->SetReadOnly(true); |
| EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, textfield_->GetTextInputType()); |
| |
| textfield_->SetReadOnly(false); |
| EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType()); |
| |
| // As do disabled textfields |
| textfield_->SetEnabled(false); |
| EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, textfield_->GetTextInputType()); |
| |
| textfield_->SetEnabled(true); |
| EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, textfield_->GetTextInputType()); |
| } |
| |
| TEST_F(TextfieldTest, OnKeyPress) { |
| InitTextfield(); |
| |
| // Character keys are handled by the input method. |
| SendKeyEvent(ui::VKEY_A); |
| EXPECT_TRUE(textfield_->key_received()); |
| EXPECT_FALSE(textfield_->key_handled()); |
| textfield_->clear(); |
| |
| // Arrow keys and home/end are handled by the textfield. |
| SendKeyEvent(ui::VKEY_LEFT); |
| EXPECT_TRUE(textfield_->key_received()); |
| EXPECT_TRUE(textfield_->key_handled()); |
| textfield_->clear(); |
| |
| SendKeyEvent(ui::VKEY_RIGHT); |
| EXPECT_TRUE(textfield_->key_received()); |
| EXPECT_TRUE(textfield_->key_handled()); |
| textfield_->clear(); |
| |
| SendKeyEvent(ui::VKEY_HOME); |
| EXPECT_TRUE(textfield_->key_received()); |
| EXPECT_TRUE(textfield_->key_handled()); |
| textfield_->clear(); |
| |
| SendKeyEvent(ui::VKEY_END); |
| EXPECT_TRUE(textfield_->key_received()); |
| EXPECT_TRUE(textfield_->key_handled()); |
| textfield_->clear(); |
| |
| // F24, up/down key won't be handled. |
| SendKeyEvent(ui::VKEY_F24); |
| EXPECT_TRUE(textfield_->key_received()); |
| EXPECT_FALSE(textfield_->key_handled()); |
| textfield_->clear(); |
| |
| SendKeyEvent(ui::VKEY_UP); |
| EXPECT_TRUE(textfield_->key_received()); |
| EXPECT_FALSE(textfield_->key_handled()); |
| textfield_->clear(); |
| |
| SendKeyEvent(ui::VKEY_DOWN); |
| EXPECT_TRUE(textfield_->key_received()); |
| EXPECT_FALSE(textfield_->key_handled()); |
| textfield_->clear(); |
| } |
| |
| // Tests that default key bindings are handled even with a delegate installed. |
| TEST_F(TextfieldTest, OnKeyPressBinding) { |
| InitTextfield(); |
| |
| #if defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| // Install a TextEditKeyBindingsDelegateAuraLinux that does nothing. |
| class TestDelegate : public ui::TextEditKeyBindingsDelegateAuraLinux { |
| public: |
| TestDelegate() {} |
| virtual ~TestDelegate() {} |
| |
| virtual bool MatchEvent( |
| const ui::Event& event, |
| std::vector<ui::TextEditCommandAuraLinux>* commands) OVERRIDE { |
| return false; |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(TestDelegate); |
| }; |
| |
| TestDelegate delegate; |
| ui::SetTextEditKeyBindingsDelegate(&delegate); |
| #endif |
| |
| SendKeyEvent(ui::VKEY_A, false, false); |
| EXPECT_STR_EQ("a", textfield_->text()); |
| textfield_->clear(); |
| |
| // Undo/Redo command keys are handled by the textfield. |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_TRUE(textfield_->key_received()); |
| EXPECT_TRUE(textfield_->key_handled()); |
| EXPECT_TRUE(textfield_->text().empty()); |
| textfield_->clear(); |
| |
| SendKeyEvent(ui::VKEY_Z, true, true); |
| EXPECT_TRUE(textfield_->key_received()); |
| EXPECT_TRUE(textfield_->key_handled()); |
| EXPECT_STR_EQ("a", textfield_->text()); |
| textfield_->clear(); |
| |
| #if defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| ui::SetTextEditKeyBindingsDelegate(NULL); |
| #endif |
| } |
| |
| TEST_F(TextfieldTest, CursorMovement) { |
| InitTextfield(); |
| |
| // Test with trailing whitespace. |
| textfield_->SetText(ASCIIToUTF16("one two hre ")); |
| |
| // Send the cursor at the end. |
| SendKeyEvent(ui::VKEY_END); |
| |
| // Ctrl+Left should move the cursor just before the last word. |
| SendKeyEvent(ui::VKEY_LEFT, false, true); |
| SendKeyEvent(ui::VKEY_T); |
| EXPECT_STR_EQ("one two thre ", textfield_->text()); |
| EXPECT_STR_EQ("one two thre ", last_contents_); |
| |
| // Ctrl+Right should move the cursor to the end of the last word. |
| SendKeyEvent(ui::VKEY_RIGHT, false, true); |
| SendKeyEvent(ui::VKEY_E); |
| EXPECT_STR_EQ("one two three ", textfield_->text()); |
| EXPECT_STR_EQ("one two three ", last_contents_); |
| |
| // Ctrl+Right again should move the cursor to the end. |
| SendKeyEvent(ui::VKEY_RIGHT, false, true); |
| SendKeyEvent(ui::VKEY_BACK); |
| EXPECT_STR_EQ("one two three", textfield_->text()); |
| EXPECT_STR_EQ("one two three", last_contents_); |
| |
| // Test with leading whitespace. |
| textfield_->SetText(ASCIIToUTF16(" ne two")); |
| |
| // Send the cursor at the beginning. |
| SendKeyEvent(ui::VKEY_HOME); |
| |
| // Ctrl+Right, then Ctrl+Left should move the cursor to the beginning of the |
| // first word. |
| SendKeyEvent(ui::VKEY_RIGHT, false, true); |
| SendKeyEvent(ui::VKEY_LEFT, false, true); |
| SendKeyEvent(ui::VKEY_O); |
| EXPECT_STR_EQ(" one two", textfield_->text()); |
| EXPECT_STR_EQ(" one two", last_contents_); |
| |
| // Ctrl+Left to move the cursor to the beginning of the first word. |
| SendKeyEvent(ui::VKEY_LEFT, false, true); |
| // Ctrl+Left again should move the cursor back to the very beginning. |
| SendKeyEvent(ui::VKEY_LEFT, false, true); |
| SendKeyEvent(ui::VKEY_DELETE); |
| EXPECT_STR_EQ("one two", textfield_->text()); |
| EXPECT_STR_EQ("one two", last_contents_); |
| } |
| |
| TEST_F(TextfieldTest, FocusTraversalTest) { |
| InitTextfields(3); |
| textfield_->RequestFocus(); |
| |
| EXPECT_EQ(1, GetFocusedView()->id()); |
| widget_->GetFocusManager()->AdvanceFocus(false); |
| EXPECT_EQ(2, GetFocusedView()->id()); |
| widget_->GetFocusManager()->AdvanceFocus(false); |
| EXPECT_EQ(3, GetFocusedView()->id()); |
| // Cycle back to the first textfield. |
| widget_->GetFocusManager()->AdvanceFocus(false); |
| EXPECT_EQ(1, GetFocusedView()->id()); |
| |
| widget_->GetFocusManager()->AdvanceFocus(true); |
| EXPECT_EQ(3, GetFocusedView()->id()); |
| widget_->GetFocusManager()->AdvanceFocus(true); |
| EXPECT_EQ(2, GetFocusedView()->id()); |
| widget_->GetFocusManager()->AdvanceFocus(true); |
| EXPECT_EQ(1, GetFocusedView()->id()); |
| // Cycle back to the last textfield. |
| widget_->GetFocusManager()->AdvanceFocus(true); |
| EXPECT_EQ(3, GetFocusedView()->id()); |
| |
| // Request focus should still work. |
| textfield_->RequestFocus(); |
| EXPECT_EQ(1, GetFocusedView()->id()); |
| |
| // Test if clicking on textfield view sets the focus. |
| widget_->GetFocusManager()->AdvanceFocus(true); |
| EXPECT_EQ(3, GetFocusedView()->id()); |
| ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMousePressed(click); |
| EXPECT_EQ(1, GetFocusedView()->id()); |
| } |
| |
| TEST_F(TextfieldTest, ContextMenuDisplayTest) { |
| InitTextfield(); |
| EXPECT_TRUE(textfield_->context_menu_controller()); |
| textfield_->SetText(ASCIIToUTF16("hello world")); |
| ui::Clipboard::GetForCurrentThread()->Clear(ui::CLIPBOARD_TYPE_COPY_PASTE); |
| textfield_->ClearEditHistory(); |
| EXPECT_TRUE(GetContextMenuModel()); |
| VerifyTextfieldContextMenuContents(false, false, GetContextMenuModel()); |
| |
| textfield_->SelectAll(false); |
| VerifyTextfieldContextMenuContents(true, false, GetContextMenuModel()); |
| |
| SendKeyEvent(ui::VKEY_T); |
| VerifyTextfieldContextMenuContents(false, true, GetContextMenuModel()); |
| |
| textfield_->SelectAll(false); |
| VerifyTextfieldContextMenuContents(true, true, GetContextMenuModel()); |
| |
| // Exercise the "paste enabled?" check in the verifier. |
| SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test"); |
| VerifyTextfieldContextMenuContents(true, true, GetContextMenuModel()); |
| } |
| |
| TEST_F(TextfieldTest, DoubleAndTripleClickTest) { |
| InitTextfield(); |
| textfield_->SetText(ASCIIToUTF16("hello world")); |
| ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| ui::MouseEvent double_click( |
| ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), |
| ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK, |
| ui::EF_LEFT_MOUSE_BUTTON); |
| |
| // Test for double click. |
| textfield_->OnMousePressed(click); |
| textfield_->OnMouseReleased(release); |
| EXPECT_TRUE(textfield_->GetSelectedText().empty()); |
| textfield_->OnMousePressed(double_click); |
| textfield_->OnMouseReleased(release); |
| EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); |
| |
| // Test for triple click. |
| textfield_->OnMousePressed(click); |
| textfield_->OnMouseReleased(release); |
| EXPECT_STR_EQ("hello world", textfield_->GetSelectedText()); |
| |
| // Another click should reset back to double click. |
| textfield_->OnMousePressed(click); |
| textfield_->OnMouseReleased(release); |
| EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); |
| } |
| |
| TEST_F(TextfieldTest, DragToSelect) { |
| InitTextfield(); |
| textfield_->SetText(ASCIIToUTF16("hello world")); |
| const int kStart = GetCursorPositionX(5); |
| const int kEnd = 500; |
| gfx::Point start_point(kStart, 0); |
| gfx::Point end_point(kEnd, 0); |
| ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, start_point, start_point, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| ui::MouseEvent click_b(ui::ET_MOUSE_PRESSED, end_point, end_point, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| ui::MouseEvent drag_left(ui::ET_MOUSE_DRAGGED, gfx::Point(), gfx::Point(), |
| ui::EF_LEFT_MOUSE_BUTTON, 0); |
| ui::MouseEvent drag_right(ui::ET_MOUSE_DRAGGED, end_point, end_point, |
| ui::EF_LEFT_MOUSE_BUTTON, 0); |
| ui::MouseEvent release(ui::ET_MOUSE_RELEASED, end_point, end_point, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMousePressed(click_a); |
| EXPECT_TRUE(textfield_->GetSelectedText().empty()); |
| // Check that dragging left selects the beginning of the string. |
| textfield_->OnMouseDragged(drag_left); |
| base::string16 text_left = textfield_->GetSelectedText(); |
| EXPECT_STR_EQ("hello", text_left); |
| // Check that dragging right selects the rest of the string. |
| textfield_->OnMouseDragged(drag_right); |
| base::string16 text_right = textfield_->GetSelectedText(); |
| EXPECT_STR_EQ(" world", text_right); |
| // Check that releasing in the same location does not alter the selection. |
| textfield_->OnMouseReleased(release); |
| EXPECT_EQ(text_right, textfield_->GetSelectedText()); |
| // Check that dragging from beyond the text length works too. |
| textfield_->OnMousePressed(click_b); |
| textfield_->OnMouseDragged(drag_left); |
| textfield_->OnMouseReleased(release); |
| EXPECT_EQ(textfield_->text(), textfield_->GetSelectedText()); |
| } |
| |
| #if defined(OS_WIN) |
| TEST_F(TextfieldTest, DragAndDrop_AcceptDrop) { |
| InitTextfield(); |
| textfield_->SetText(ASCIIToUTF16("hello world")); |
| |
| ui::OSExchangeData data; |
| base::string16 string(ASCIIToUTF16("string ")); |
| data.SetString(string); |
| int formats = 0; |
| std::set<OSExchangeData::CustomFormat> custom_formats; |
| |
| // Ensure that disabled textfields do not accept drops. |
| textfield_->SetEnabled(false); |
| EXPECT_FALSE(textfield_->GetDropFormats(&formats, &custom_formats)); |
| EXPECT_EQ(0, formats); |
| EXPECT_TRUE(custom_formats.empty()); |
| EXPECT_FALSE(textfield_->CanDrop(data)); |
| textfield_->SetEnabled(true); |
| |
| // Ensure that read-only textfields do not accept drops. |
| textfield_->SetReadOnly(true); |
| EXPECT_FALSE(textfield_->GetDropFormats(&formats, &custom_formats)); |
| EXPECT_EQ(0, formats); |
| EXPECT_TRUE(custom_formats.empty()); |
| EXPECT_FALSE(textfield_->CanDrop(data)); |
| textfield_->SetReadOnly(false); |
| |
| // Ensure that enabled and editable textfields do accept drops. |
| EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats)); |
| EXPECT_EQ(ui::OSExchangeData::STRING, formats); |
| EXPECT_TRUE(custom_formats.empty()); |
| EXPECT_TRUE(textfield_->CanDrop(data)); |
| gfx::Point drop_point(GetCursorPositionX(6), 0); |
| ui::DropTargetEvent drop(data, drop_point, drop_point, |
| ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE, |
| textfield_->OnDragUpdated(drop)); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, textfield_->OnPerformDrop(drop)); |
| EXPECT_STR_EQ("hello string world", textfield_->text()); |
| |
| // Ensure that textfields do not accept non-OSExchangeData::STRING types. |
| ui::OSExchangeData bad_data; |
| bad_data.SetFilename(base::FilePath(FILE_PATH_LITERAL("x"))); |
| ui::OSExchangeData::CustomFormat fmt = ui::Clipboard::GetBitmapFormatType(); |
| bad_data.SetPickledData(fmt, Pickle()); |
| bad_data.SetFileContents(base::FilePath(L"x"), "x"); |
| bad_data.SetHtml(base::string16(ASCIIToUTF16("x")), GURL("x.org")); |
| ui::OSExchangeData::DownloadFileInfo download(base::FilePath(), NULL); |
| bad_data.SetDownloadFileInfo(download); |
| EXPECT_FALSE(textfield_->CanDrop(bad_data)); |
| } |
| #endif |
| |
| TEST_F(TextfieldTest, DragAndDrop_InitiateDrag) { |
| InitTextfield(); |
| textfield_->SetText(ASCIIToUTF16("hello string world")); |
| |
| // Ensure the textfield will provide selected text for drag data. |
| base::string16 string; |
| ui::OSExchangeData data; |
| const gfx::Range kStringRange(6, 12); |
| textfield_->SelectRange(kStringRange); |
| const gfx::Point kStringPoint(GetCursorPositionX(9), 0); |
| textfield_->WriteDragDataForView(NULL, kStringPoint, &data); |
| EXPECT_TRUE(data.GetString(&string)); |
| EXPECT_EQ(textfield_->GetSelectedText(), string); |
| |
| // Ensure that disabled textfields do not support drag operations. |
| textfield_->SetEnabled(false); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, |
| textfield_->GetDragOperationsForView(NULL, kStringPoint)); |
| textfield_->SetEnabled(true); |
| // Ensure that textfields without selections do not support drag operations. |
| textfield_->ClearSelection(); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, |
| textfield_->GetDragOperationsForView(NULL, kStringPoint)); |
| textfield_->SelectRange(kStringRange); |
| // Ensure that password textfields do not support drag operations. |
| textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, |
| textfield_->GetDragOperationsForView(NULL, kStringPoint)); |
| textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT); |
| // Ensure that textfields only initiate drag operations inside the selection. |
| ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, kStringPoint, kStringPoint, |
| ui::EF_LEFT_MOUSE_BUTTON, |
| ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMousePressed(press_event); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, |
| textfield_->GetDragOperationsForView(NULL, gfx::Point())); |
| EXPECT_FALSE(textfield_->CanStartDragForView(NULL, gfx::Point(), |
| gfx::Point())); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, |
| textfield_->GetDragOperationsForView(NULL, kStringPoint)); |
| EXPECT_TRUE(textfield_->CanStartDragForView(NULL, kStringPoint, |
| gfx::Point())); |
| // Ensure that textfields support local moves. |
| EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY, |
| textfield_->GetDragOperationsForView(textfield_, kStringPoint)); |
| } |
| |
| TEST_F(TextfieldTest, DragAndDrop_ToTheRight) { |
| InitTextfield(); |
| textfield_->SetText(ASCIIToUTF16("hello world")); |
| |
| base::string16 string; |
| ui::OSExchangeData data; |
| int formats = 0; |
| int operations = 0; |
| std::set<OSExchangeData::CustomFormat> custom_formats; |
| |
| // Start dragging "ello". |
| textfield_->SelectRange(gfx::Range(1, 5)); |
| gfx::Point point(GetCursorPositionX(3), 0); |
| ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMousePressed(click_a); |
| EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, click_a.location(), |
| gfx::Point())); |
| operations = textfield_->GetDragOperationsForView(textfield_, |
| click_a.location()); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY, |
| operations); |
| textfield_->WriteDragDataForView(NULL, click_a.location(), &data); |
| EXPECT_TRUE(data.GetString(&string)); |
| EXPECT_EQ(textfield_->GetSelectedText(), string); |
| EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats)); |
| EXPECT_EQ(ui::OSExchangeData::STRING, formats); |
| EXPECT_TRUE(custom_formats.empty()); |
| |
| // Drop "ello" after "w". |
| const gfx::Point kDropPoint(GetCursorPositionX(7), 0); |
| EXPECT_TRUE(textfield_->CanDrop(data)); |
| ui::DropTargetEvent drop_a(data, kDropPoint, kDropPoint, operations); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a)); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnPerformDrop(drop_a)); |
| EXPECT_STR_EQ("h welloorld", textfield_->text()); |
| textfield_->OnDragDone(); |
| |
| // Undo/Redo the drag&drop change. |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("hello world", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("hello world", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("h welloorld", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("h welloorld", textfield_->text()); |
| } |
| |
| TEST_F(TextfieldTest, DragAndDrop_ToTheLeft) { |
| InitTextfield(); |
| textfield_->SetText(ASCIIToUTF16("hello world")); |
| |
| base::string16 string; |
| ui::OSExchangeData data; |
| int formats = 0; |
| int operations = 0; |
| std::set<OSExchangeData::CustomFormat> custom_formats; |
| |
| // Start dragging " worl". |
| textfield_->SelectRange(gfx::Range(5, 10)); |
| gfx::Point point(GetCursorPositionX(7), 0); |
| ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMousePressed(click_a); |
| EXPECT_TRUE(textfield_->CanStartDragForView(textfield_, click_a.location(), |
| gfx::Point())); |
| operations = textfield_->GetDragOperationsForView(textfield_, |
| click_a.location()); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY, |
| operations); |
| textfield_->WriteDragDataForView(NULL, click_a.location(), &data); |
| EXPECT_TRUE(data.GetString(&string)); |
| EXPECT_EQ(textfield_->GetSelectedText(), string); |
| EXPECT_TRUE(textfield_->GetDropFormats(&formats, &custom_formats)); |
| EXPECT_EQ(ui::OSExchangeData::STRING, formats); |
| EXPECT_TRUE(custom_formats.empty()); |
| |
| // Drop " worl" after "h". |
| EXPECT_TRUE(textfield_->CanDrop(data)); |
| gfx::Point drop_point(GetCursorPositionX(1), 0); |
| ui::DropTargetEvent drop_a(data, drop_point, drop_point, operations); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop_a)); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnPerformDrop(drop_a)); |
| EXPECT_STR_EQ("h worlellod", textfield_->text()); |
| textfield_->OnDragDone(); |
| |
| // Undo/Redo the drag&drop change. |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("hello world", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("hello world", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("h worlellod", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("h worlellod", textfield_->text()); |
| } |
| |
| TEST_F(TextfieldTest, DragAndDrop_Canceled) { |
| InitTextfield(); |
| textfield_->SetText(ASCIIToUTF16("hello world")); |
| |
| // Start dragging "worl". |
| textfield_->SelectRange(gfx::Range(6, 10)); |
| gfx::Point point(GetCursorPositionX(8), 0); |
| ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMousePressed(click); |
| ui::OSExchangeData data; |
| textfield_->WriteDragDataForView(NULL, click.location(), &data); |
| EXPECT_TRUE(textfield_->CanDrop(data)); |
| // Drag the text over somewhere valid, outside the current selection. |
| gfx::Point drop_point(GetCursorPositionX(2), 0); |
| ui::DropTargetEvent drop(data, drop_point, drop_point, |
| ui::DragDropTypes::DRAG_MOVE); |
| EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_->OnDragUpdated(drop)); |
| // "Cancel" the drag, via move and release over the selection, and OnDragDone. |
| gfx::Point drag_point(GetCursorPositionX(9), 0); |
| ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, drag_point, drag_point, |
| ui::EF_LEFT_MOUSE_BUTTON, 0); |
| ui::MouseEvent release(ui::ET_MOUSE_RELEASED, drag_point, drag_point, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMouseDragged(drag); |
| textfield_->OnMouseReleased(release); |
| textfield_->OnDragDone(); |
| EXPECT_EQ(ASCIIToUTF16("hello world"), textfield_->text()); |
| } |
| |
| TEST_F(TextfieldTest, ReadOnlyTest) { |
| InitTextfield(); |
| textfield_->SetText(ASCIIToUTF16("read only")); |
| textfield_->SetReadOnly(true); |
| EXPECT_TRUE(textfield_->enabled()); |
| EXPECT_TRUE(textfield_->IsFocusable()); |
| |
| SendKeyEvent(ui::VKEY_HOME); |
| EXPECT_EQ(0U, textfield_->GetCursorPosition()); |
| SendKeyEvent(ui::VKEY_END); |
| EXPECT_EQ(9U, textfield_->GetCursorPosition()); |
| |
| SendKeyEvent(ui::VKEY_LEFT, false, false); |
| EXPECT_EQ(8U, textfield_->GetCursorPosition()); |
| SendKeyEvent(ui::VKEY_LEFT, false, true); |
| EXPECT_EQ(5U, textfield_->GetCursorPosition()); |
| SendKeyEvent(ui::VKEY_LEFT, true, true); |
| EXPECT_EQ(0U, textfield_->GetCursorPosition()); |
| EXPECT_STR_EQ("read ", textfield_->GetSelectedText()); |
| textfield_->SelectAll(false); |
| EXPECT_STR_EQ("read only", textfield_->GetSelectedText()); |
| |
| // Cut should be disabled. |
| SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test"); |
| EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_CUT)); |
| textfield_->ExecuteCommand(IDS_APP_CUT, 0); |
| SendKeyEvent(ui::VKEY_X, false, true); |
| SendKeyEvent(ui::VKEY_DELETE, true, false); |
| EXPECT_STR_EQ("Test", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| EXPECT_STR_EQ("read only", textfield_->text()); |
| |
| // Paste should be disabled. |
| EXPECT_FALSE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE)); |
| textfield_->ExecuteCommand(IDS_APP_PASTE, 0); |
| SendKeyEvent(ui::VKEY_V, false, true); |
| SendKeyEvent(ui::VKEY_INSERT, true, false); |
| EXPECT_STR_EQ("read only", textfield_->text()); |
| |
| // Copy should work normally. |
| SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test"); |
| EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_COPY)); |
| textfield_->ExecuteCommand(IDS_APP_COPY, 0); |
| EXPECT_STR_EQ("read only", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test"); |
| SendKeyEvent(ui::VKEY_C, false, true); |
| EXPECT_STR_EQ("read only", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "Test"); |
| SendKeyEvent(ui::VKEY_INSERT, false, true); |
| EXPECT_STR_EQ("read only", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| |
| // SetText should work even in read only mode. |
| textfield_->SetText(ASCIIToUTF16(" four five six ")); |
| EXPECT_STR_EQ(" four five six ", textfield_->text()); |
| |
| textfield_->SelectAll(false); |
| EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText()); |
| |
| // Text field is unmodifiable and selection shouldn't change. |
| SendKeyEvent(ui::VKEY_DELETE); |
| EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText()); |
| SendKeyEvent(ui::VKEY_BACK); |
| EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText()); |
| SendKeyEvent(ui::VKEY_T); |
| EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText()); |
| } |
| |
| TEST_F(TextfieldTest, TextInputClientTest) { |
| InitTextfield(); |
| ui::TextInputClient* client = textfield_->GetTextInputClient(); |
| EXPECT_TRUE(client); |
| EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, client->GetTextInputType()); |
| |
| textfield_->SetText(ASCIIToUTF16("0123456789")); |
| gfx::Range range; |
| EXPECT_TRUE(client->GetTextRange(&range)); |
| EXPECT_EQ(0U, range.start()); |
| EXPECT_EQ(10U, range.end()); |
| |
| EXPECT_TRUE(client->SetSelectionRange(gfx::Range(1, 4))); |
| EXPECT_TRUE(client->GetSelectionRange(&range)); |
| EXPECT_EQ(gfx::Range(1, 4), range); |
| |
| base::string16 substring; |
| EXPECT_TRUE(client->GetTextFromRange(range, &substring)); |
| EXPECT_STR_EQ("123", substring); |
| |
| EXPECT_TRUE(client->DeleteRange(range)); |
| EXPECT_STR_EQ("0456789", textfield_->text()); |
| |
| ui::CompositionText composition; |
| composition.text = UTF8ToUTF16("321"); |
| // Set composition through input method. |
| input_method_->Clear(); |
| input_method_->SetCompositionTextForNextKey(composition); |
| textfield_->clear(); |
| |
| on_before_user_action_ = on_after_user_action_ = 0; |
| SendKeyEvent(ui::VKEY_A); |
| EXPECT_TRUE(textfield_->key_received()); |
| EXPECT_FALSE(textfield_->key_handled()); |
| EXPECT_TRUE(client->HasCompositionText()); |
| EXPECT_TRUE(client->GetCompositionTextRange(&range)); |
| EXPECT_STR_EQ("0321456789", textfield_->text()); |
| EXPECT_EQ(gfx::Range(1, 4), range); |
| EXPECT_EQ(1, on_before_user_action_); |
| EXPECT_EQ(1, on_after_user_action_); |
| |
| input_method_->SetResultTextForNextKey(UTF8ToUTF16("123")); |
| on_before_user_action_ = on_after_user_action_ = 0; |
| textfield_->clear(); |
| SendKeyEvent(ui::VKEY_A); |
| EXPECT_TRUE(textfield_->key_received()); |
| EXPECT_FALSE(textfield_->key_handled()); |
| EXPECT_FALSE(client->HasCompositionText()); |
| EXPECT_FALSE(input_method_->cancel_composition_called()); |
| EXPECT_STR_EQ("0123456789", textfield_->text()); |
| EXPECT_EQ(1, on_before_user_action_); |
| EXPECT_EQ(1, on_after_user_action_); |
| |
| input_method_->Clear(); |
| input_method_->SetCompositionTextForNextKey(composition); |
| textfield_->clear(); |
| SendKeyEvent(ui::VKEY_A); |
| EXPECT_TRUE(client->HasCompositionText()); |
| EXPECT_STR_EQ("0123321456789", textfield_->text()); |
| |
| on_before_user_action_ = on_after_user_action_ = 0; |
| textfield_->clear(); |
| SendKeyEvent(ui::VKEY_RIGHT); |
| EXPECT_FALSE(client->HasCompositionText()); |
| EXPECT_TRUE(input_method_->cancel_composition_called()); |
| EXPECT_TRUE(textfield_->key_received()); |
| EXPECT_TRUE(textfield_->key_handled()); |
| EXPECT_STR_EQ("0123321456789", textfield_->text()); |
| EXPECT_EQ(8U, textfield_->GetCursorPosition()); |
| EXPECT_EQ(1, on_before_user_action_); |
| EXPECT_EQ(1, on_after_user_action_); |
| |
| textfield_->clear(); |
| textfield_->SetText(ASCIIToUTF16("0123456789")); |
| EXPECT_TRUE(client->SetSelectionRange(gfx::Range(5, 5))); |
| client->ExtendSelectionAndDelete(4, 2); |
| EXPECT_STR_EQ("0789", textfield_->text()); |
| |
| // On{Before,After}UserAction should be called by whatever user action |
| // triggers clearing or setting a selection if appropriate. |
| on_before_user_action_ = on_after_user_action_ = 0; |
| textfield_->clear(); |
| textfield_->ClearSelection(); |
| textfield_->SelectAll(false); |
| EXPECT_EQ(0, on_before_user_action_); |
| EXPECT_EQ(0, on_after_user_action_); |
| |
| input_method_->Clear(); |
| textfield_->SetReadOnly(true); |
| EXPECT_TRUE(input_method_->text_input_type_changed()); |
| EXPECT_FALSE(textfield_->GetTextInputClient()); |
| |
| textfield_->SetReadOnly(false); |
| input_method_->Clear(); |
| textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); |
| EXPECT_TRUE(input_method_->text_input_type_changed()); |
| EXPECT_TRUE(textfield_->GetTextInputClient()); |
| } |
| |
| TEST_F(TextfieldTest, UndoRedoTest) { |
| InitTextfield(); |
| SendKeyEvent(ui::VKEY_A); |
| EXPECT_STR_EQ("a", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("a", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("a", textfield_->text()); |
| |
| // AppendText |
| textfield_->AppendText(ASCIIToUTF16("b")); |
| last_contents_.clear(); // AppendText doesn't call ContentsChanged. |
| EXPECT_STR_EQ("ab", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("a", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("ab", textfield_->text()); |
| |
| // SetText |
| SendKeyEvent(ui::VKEY_C); |
| // Undo'ing append moves the cursor to the end for now. |
| // A no-op SetText won't add a new edit; see TextfieldModel::SetText. |
| EXPECT_STR_EQ("abc", textfield_->text()); |
| textfield_->SetText(ASCIIToUTF16("abc")); |
| EXPECT_STR_EQ("abc", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("ab", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("abc", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("abc", textfield_->text()); |
| textfield_->SetText(ASCIIToUTF16("123")); |
| textfield_->SetText(ASCIIToUTF16("123")); |
| EXPECT_STR_EQ("123", textfield_->text()); |
| SendKeyEvent(ui::VKEY_END, false, false); |
| SendKeyEvent(ui::VKEY_4, false, false); |
| EXPECT_STR_EQ("1234", textfield_->text()); |
| last_contents_.clear(); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("123", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| // the insert edit "c" and set edit "123" are merged to single edit, |
| // so text becomes "ab" after undo. |
| EXPECT_STR_EQ("ab", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("a", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("ab", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("123", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("1234", textfield_->text()); |
| |
| // Undoing to the same text shouldn't call ContentsChanged. |
| SendKeyEvent(ui::VKEY_A, false, true); // select all |
| SendKeyEvent(ui::VKEY_A); |
| EXPECT_STR_EQ("a", textfield_->text()); |
| SendKeyEvent(ui::VKEY_B); |
| SendKeyEvent(ui::VKEY_C); |
| EXPECT_STR_EQ("abc", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("1234", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("abc", textfield_->text()); |
| |
| // Delete/Backspace |
| SendKeyEvent(ui::VKEY_BACK); |
| EXPECT_STR_EQ("ab", textfield_->text()); |
| SendKeyEvent(ui::VKEY_HOME); |
| SendKeyEvent(ui::VKEY_DELETE); |
| EXPECT_STR_EQ("b", textfield_->text()); |
| SendKeyEvent(ui::VKEY_A, false, true); |
| SendKeyEvent(ui::VKEY_DELETE); |
| EXPECT_STR_EQ("", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("b", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("ab", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Z, false, true); |
| EXPECT_STR_EQ("abc", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("ab", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("b", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("", textfield_->text()); |
| SendKeyEvent(ui::VKEY_Y, false, true); |
| EXPECT_STR_EQ("", textfield_->text()); |
| } |
| |
| TEST_F(TextfieldTest, CutCopyPaste) { |
| InitTextfield(); |
| |
| // Ensure IDS_APP_CUT cuts. |
| textfield_->SetText(ASCIIToUTF16("123")); |
| textfield_->SelectAll(false); |
| EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_CUT)); |
| textfield_->ExecuteCommand(IDS_APP_CUT, 0); |
| EXPECT_STR_EQ("123", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| EXPECT_STR_EQ("", textfield_->text()); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard()); |
| |
| // Ensure [Ctrl]+[x] cuts and [Ctrl]+[Alt][x] does nothing. |
| textfield_->SetText(ASCIIToUTF16("456")); |
| textfield_->SelectAll(false); |
| SendKeyEvent(ui::VKEY_X, true, false, true, false); |
| EXPECT_STR_EQ("123", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| EXPECT_STR_EQ("456", textfield_->text()); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard()); |
| SendKeyEvent(ui::VKEY_X, false, true); |
| EXPECT_STR_EQ("456", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| EXPECT_STR_EQ("", textfield_->text()); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard()); |
| |
| // Ensure [Shift]+[Delete] cuts. |
| textfield_->SetText(ASCIIToUTF16("123")); |
| textfield_->SelectAll(false); |
| SendKeyEvent(ui::VKEY_DELETE, true, false); |
| EXPECT_STR_EQ("123", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| EXPECT_STR_EQ("", textfield_->text()); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard()); |
| |
| // Ensure IDS_APP_COPY copies. |
| textfield_->SetText(ASCIIToUTF16("789")); |
| textfield_->SelectAll(false); |
| EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_COPY)); |
| textfield_->ExecuteCommand(IDS_APP_COPY, 0); |
| EXPECT_STR_EQ("789", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard()); |
| |
| // Ensure [Ctrl]+[c] copies and [Ctrl]+[Alt][c] does nothing. |
| textfield_->SetText(ASCIIToUTF16("012")); |
| textfield_->SelectAll(false); |
| SendKeyEvent(ui::VKEY_C, true, false, true, false); |
| EXPECT_STR_EQ("789", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard()); |
| SendKeyEvent(ui::VKEY_C, false, true); |
| EXPECT_STR_EQ("012", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard()); |
| |
| // Ensure [Ctrl]+[Insert] copies. |
| textfield_->SetText(ASCIIToUTF16("345")); |
| textfield_->SelectAll(false); |
| SendKeyEvent(ui::VKEY_INSERT, false, true); |
| EXPECT_STR_EQ("345", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| EXPECT_STR_EQ("345", textfield_->text()); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_COPY_PASTE, GetAndResetCopiedToClipboard()); |
| |
| // Ensure IDS_APP_PASTE, [Ctrl]+[V], and [Shift]+[Insert] pastes; |
| // also ensure that [Ctrl]+[Alt]+[V] does nothing. |
| SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE, "abc"); |
| textfield_->SetText(base::string16()); |
| EXPECT_TRUE(textfield_->IsCommandIdEnabled(IDS_APP_PASTE)); |
| textfield_->ExecuteCommand(IDS_APP_PASTE, 0); |
| EXPECT_STR_EQ("abc", textfield_->text()); |
| SendKeyEvent(ui::VKEY_V, false, true); |
| EXPECT_STR_EQ("abcabc", textfield_->text()); |
| SendKeyEvent(ui::VKEY_INSERT, true, false); |
| EXPECT_STR_EQ("abcabcabc", textfield_->text()); |
| SendKeyEvent(ui::VKEY_V, true, false, true, false); |
| EXPECT_STR_EQ("abcabcabc", textfield_->text()); |
| |
| // Ensure [Ctrl]+[Shift]+[Insert] is a no-op. |
| textfield_->SelectAll(false); |
| SendKeyEvent(ui::VKEY_INSERT, true, true); |
| EXPECT_STR_EQ("abc", GetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE)); |
| EXPECT_STR_EQ("abcabcabc", textfield_->text()); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard()); |
| } |
| |
| TEST_F(TextfieldTest, OvertypeMode) { |
| InitTextfield(); |
| // Overtype mode should be disabled (no-op [Insert]). |
| textfield_->SetText(ASCIIToUTF16("2")); |
| SendKeyEvent(ui::VKEY_HOME); |
| SendKeyEvent(ui::VKEY_INSERT); |
| SendKeyEvent(ui::VKEY_1, false, false); |
| EXPECT_STR_EQ("12", textfield_->text()); |
| } |
| |
| TEST_F(TextfieldTest, TextCursorDisplayTest) { |
| InitTextfield(); |
| // LTR-RTL string in LTR context. |
| SendKeyEvent('a'); |
| EXPECT_STR_EQ("a", textfield_->text()); |
| int x = GetCursorBounds().x(); |
| int prev_x = x; |
| |
| SendKeyEvent('b'); |
| EXPECT_STR_EQ("ab", textfield_->text()); |
| x = GetCursorBounds().x(); |
| EXPECT_LT(prev_x, x); |
| prev_x = x; |
| |
| SendKeyEvent(0x05E1); |
| EXPECT_EQ(WideToUTF16(L"ab\x05E1"), textfield_->text()); |
| x = GetCursorBounds().x(); |
| EXPECT_EQ(prev_x, x); |
| |
| SendKeyEvent(0x05E2); |
| EXPECT_EQ(WideToUTF16(L"ab\x05E1\x5E2"), textfield_->text()); |
| x = GetCursorBounds().x(); |
| EXPECT_EQ(prev_x, x); |
| |
| // Clear text. |
| SendKeyEvent(ui::VKEY_A, false, true); |
| SendKeyEvent('\n'); |
| |
| // RTL-LTR string in LTR context. |
| SendKeyEvent(0x05E1); |
| EXPECT_EQ(WideToUTF16(L"\x05E1"), textfield_->text()); |
| x = GetCursorBounds().x(); |
| EXPECT_EQ(GetDisplayRect().x(), x); |
| prev_x = x; |
| |
| SendKeyEvent(0x05E2); |
| EXPECT_EQ(WideToUTF16(L"\x05E1\x05E2"), textfield_->text()); |
| x = GetCursorBounds().x(); |
| EXPECT_EQ(prev_x, x); |
| |
| SendKeyEvent('a'); |
| EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"a"), textfield_->text()); |
| x = GetCursorBounds().x(); |
| EXPECT_LT(prev_x, x); |
| prev_x = x; |
| |
| SendKeyEvent('b'); |
| EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"ab"), textfield_->text()); |
| x = GetCursorBounds().x(); |
| EXPECT_LT(prev_x, x); |
| } |
| |
| TEST_F(TextfieldTest, TextCursorDisplayInRTLTest) { |
| std::string locale = l10n_util::GetApplicationLocale(""); |
| base::i18n::SetICUDefaultLocale("he"); |
| |
| InitTextfield(); |
| // LTR-RTL string in RTL context. |
| SendKeyEvent('a'); |
| EXPECT_STR_EQ("a", textfield_->text()); |
| int x = GetCursorBounds().x(); |
| EXPECT_EQ(GetDisplayRect().right() - 1, x); |
| int prev_x = x; |
| |
| SendKeyEvent('b'); |
| EXPECT_STR_EQ("ab", textfield_->text()); |
| x = GetCursorBounds().x(); |
| EXPECT_EQ(prev_x, x); |
| |
| SendKeyEvent(0x05E1); |
| EXPECT_EQ(WideToUTF16(L"ab\x05E1"), textfield_->text()); |
| x = GetCursorBounds().x(); |
| EXPECT_GT(prev_x, x); |
| prev_x = x; |
| |
| SendKeyEvent(0x05E2); |
| EXPECT_EQ(WideToUTF16(L"ab\x05E1\x5E2"), textfield_->text()); |
| x = GetCursorBounds().x(); |
| EXPECT_GT(prev_x, x); |
| |
| SendKeyEvent(ui::VKEY_A, false, true); |
| SendKeyEvent('\n'); |
| |
| // RTL-LTR string in RTL context. |
| SendKeyEvent(0x05E1); |
| EXPECT_EQ(WideToUTF16(L"\x05E1"), textfield_->text()); |
| x = GetCursorBounds().x(); |
| prev_x = x; |
| |
| SendKeyEvent(0x05E2); |
| EXPECT_EQ(WideToUTF16(L"\x05E1\x05E2"), textfield_->text()); |
| x = GetCursorBounds().x(); |
| EXPECT_GT(prev_x, x); |
| prev_x = x; |
| |
| SendKeyEvent('a'); |
| EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"a"), textfield_->text()); |
| x = GetCursorBounds().x(); |
| EXPECT_EQ(prev_x, x); |
| prev_x = x; |
| |
| SendKeyEvent('b'); |
| EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"ab"), textfield_->text()); |
| x = GetCursorBounds().x(); |
| EXPECT_EQ(prev_x, x); |
| |
| // Reset locale. |
| base::i18n::SetICUDefaultLocale(locale); |
| } |
| |
| TEST_F(TextfieldTest, HitInsideTextAreaTest) { |
| InitTextfield(); |
| textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2")); |
| std::vector<gfx::Rect> cursor_bounds; |
| |
| // Save each cursor bound. |
| gfx::SelectionModel sel(0, gfx::CURSOR_FORWARD); |
| cursor_bounds.push_back(GetCursorBounds(sel)); |
| |
| sel = gfx::SelectionModel(1, gfx::CURSOR_BACKWARD); |
| gfx::Rect bound = GetCursorBounds(sel); |
| sel = gfx::SelectionModel(1, gfx::CURSOR_FORWARD); |
| EXPECT_EQ(bound.x(), GetCursorBounds(sel).x()); |
| cursor_bounds.push_back(bound); |
| |
| // Check that a cursor at the end of the Latin portion of the text is at the |
| // same position as a cursor placed at the end of the RTL Hebrew portion. |
| sel = gfx::SelectionModel(2, gfx::CURSOR_BACKWARD); |
| bound = GetCursorBounds(sel); |
| sel = gfx::SelectionModel(4, gfx::CURSOR_BACKWARD); |
| EXPECT_EQ(bound.x(), GetCursorBounds(sel).x()); |
| cursor_bounds.push_back(bound); |
| |
| sel = gfx::SelectionModel(3, gfx::CURSOR_BACKWARD); |
| bound = GetCursorBounds(sel); |
| sel = gfx::SelectionModel(3, gfx::CURSOR_FORWARD); |
| EXPECT_EQ(bound.x(), GetCursorBounds(sel).x()); |
| cursor_bounds.push_back(bound); |
| |
| sel = gfx::SelectionModel(2, gfx::CURSOR_FORWARD); |
| bound = GetCursorBounds(sel); |
| sel = gfx::SelectionModel(4, gfx::CURSOR_FORWARD); |
| EXPECT_EQ(bound.x(), GetCursorBounds(sel).x()); |
| cursor_bounds.push_back(bound); |
| |
| // Expected cursor position when clicking left and right of each character. |
| size_t cursor_pos_expected[] = {0, 1, 1, 2, 4, 3, 3, 2}; |
| |
| int index = 0; |
| for (int i = 0; i < static_cast<int>(cursor_bounds.size() - 1); ++i) { |
| int half_width = (cursor_bounds[i + 1].x() - cursor_bounds[i].x()) / 2; |
| MouseClick(cursor_bounds[i], half_width / 2); |
| EXPECT_EQ(cursor_pos_expected[index++], textfield_->GetCursorPosition()); |
| |
| // To avoid trigger double click. Not using sleep() since it takes longer |
| // for the test to run if using sleep(). |
| NonClientMouseClick(); |
| |
| MouseClick(cursor_bounds[i + 1], - (half_width / 2)); |
| EXPECT_EQ(cursor_pos_expected[index++], textfield_->GetCursorPosition()); |
| |
| NonClientMouseClick(); |
| } |
| } |
| |
| TEST_F(TextfieldTest, HitOutsideTextAreaTest) { |
| InitTextfield(); |
| |
| // LTR-RTL string in LTR context. |
| textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2")); |
| |
| SendKeyEvent(ui::VKEY_HOME); |
| gfx::Rect bound = GetCursorBounds(); |
| MouseClick(bound, -10); |
| EXPECT_EQ(bound, GetCursorBounds()); |
| |
| SendKeyEvent(ui::VKEY_END); |
| bound = GetCursorBounds(); |
| MouseClick(bound, 10); |
| EXPECT_EQ(bound, GetCursorBounds()); |
| |
| NonClientMouseClick(); |
| |
| // RTL-LTR string in LTR context. |
| textfield_->SetText(WideToUTF16(L"\x05E1\x5E2" L"ab")); |
| |
| SendKeyEvent(ui::VKEY_HOME); |
| bound = GetCursorBounds(); |
| MouseClick(bound, 10); |
| EXPECT_EQ(bound, GetCursorBounds()); |
| |
| SendKeyEvent(ui::VKEY_END); |
| bound = GetCursorBounds(); |
| MouseClick(bound, -10); |
| EXPECT_EQ(bound, GetCursorBounds()); |
| } |
| |
| TEST_F(TextfieldTest, HitOutsideTextAreaInRTLTest) { |
| std::string locale = l10n_util::GetApplicationLocale(""); |
| base::i18n::SetICUDefaultLocale("he"); |
| |
| InitTextfield(); |
| |
| // RTL-LTR string in RTL context. |
| textfield_->SetText(WideToUTF16(L"\x05E1\x5E2" L"ab")); |
| SendKeyEvent(ui::VKEY_HOME); |
| gfx::Rect bound = GetCursorBounds(); |
| MouseClick(bound, 10); |
| EXPECT_EQ(bound, GetCursorBounds()); |
| |
| SendKeyEvent(ui::VKEY_END); |
| bound = GetCursorBounds(); |
| MouseClick(bound, -10); |
| EXPECT_EQ(bound, GetCursorBounds()); |
| |
| NonClientMouseClick(); |
| |
| // LTR-RTL string in RTL context. |
| textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2")); |
| SendKeyEvent(ui::VKEY_HOME); |
| bound = GetCursorBounds(); |
| MouseClick(bound, -10); |
| EXPECT_EQ(bound, GetCursorBounds()); |
| |
| SendKeyEvent(ui::VKEY_END); |
| bound = GetCursorBounds(); |
| MouseClick(bound, 10); |
| EXPECT_EQ(bound, GetCursorBounds()); |
| |
| // Reset locale. |
| base::i18n::SetICUDefaultLocale(locale); |
| } |
| |
| TEST_F(TextfieldTest, OverflowTest) { |
| InitTextfield(); |
| |
| base::string16 str; |
| for (int i = 0; i < 500; ++i) |
| SendKeyEvent('a'); |
| SendKeyEvent(kHebrewLetterSamekh); |
| EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds())); |
| |
| // Test mouse pointing. |
| MouseClick(GetCursorBounds(), -1); |
| EXPECT_EQ(500U, textfield_->GetCursorPosition()); |
| |
| // Clear text. |
| SendKeyEvent(ui::VKEY_A, false, true); |
| SendKeyEvent('\n'); |
| |
| for (int i = 0; i < 500; ++i) |
| SendKeyEvent(kHebrewLetterSamekh); |
| SendKeyEvent('a'); |
| EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds())); |
| |
| MouseClick(GetCursorBounds(), -1); |
| EXPECT_EQ(501U, textfield_->GetCursorPosition()); |
| } |
| |
| TEST_F(TextfieldTest, OverflowInRTLTest) { |
| std::string locale = l10n_util::GetApplicationLocale(""); |
| base::i18n::SetICUDefaultLocale("he"); |
| |
| InitTextfield(); |
| |
| base::string16 str; |
| for (int i = 0; i < 500; ++i) |
| SendKeyEvent('a'); |
| SendKeyEvent(kHebrewLetterSamekh); |
| EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds())); |
| |
| MouseClick(GetCursorBounds(), 1); |
| EXPECT_EQ(501U, textfield_->GetCursorPosition()); |
| |
| // Clear text. |
| SendKeyEvent(ui::VKEY_A, false, true); |
| SendKeyEvent('\n'); |
| |
| for (int i = 0; i < 500; ++i) |
| SendKeyEvent(kHebrewLetterSamekh); |
| SendKeyEvent('a'); |
| EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds())); |
| |
| MouseClick(GetCursorBounds(), 1); |
| EXPECT_EQ(500U, textfield_->GetCursorPosition()); |
| |
| // Reset locale. |
| base::i18n::SetICUDefaultLocale(locale); |
| } |
| |
| TEST_F(TextfieldTest, GetCompositionCharacterBoundsTest) { |
| InitTextfield(); |
| ui::CompositionText composition; |
| composition.text = UTF8ToUTF16("abc123"); |
| const uint32 char_count = static_cast<uint32>(composition.text.length()); |
| ui::TextInputClient* client = textfield_->GetTextInputClient(); |
| |
| // Compare the composition character bounds with surrounding cursor bounds. |
| for (uint32 i = 0; i < char_count; ++i) { |
| composition.selection = gfx::Range(i); |
| client->SetCompositionText(composition); |
| gfx::Point cursor_origin = GetCursorBounds().origin(); |
| views::View::ConvertPointToScreen(textfield_, &cursor_origin); |
| |
| composition.selection = gfx::Range(i + 1); |
| client->SetCompositionText(composition); |
| gfx::Point next_cursor_bottom_left = GetCursorBounds().bottom_left(); |
| views::View::ConvertPointToScreen(textfield_, &next_cursor_bottom_left); |
| |
| gfx::Rect character; |
| EXPECT_TRUE(client->GetCompositionCharacterBounds(i, &character)); |
| EXPECT_EQ(character.origin(), cursor_origin) << " i=" << i; |
| EXPECT_EQ(character.bottom_right(), next_cursor_bottom_left) << " i=" << i; |
| } |
| |
| // Return false if the index is out of range. |
| gfx::Rect rect; |
| EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count, &rect)); |
| EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 1, &rect)); |
| EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 100, &rect)); |
| } |
| |
| TEST_F(TextfieldTest, GetCompositionCharacterBounds_ComplexText) { |
| InitTextfield(); |
| |
| const base::char16 kUtf16Chars[] = { |
| // U+0020 SPACE |
| 0x0020, |
| // U+1F408 (CAT) as surrogate pair |
| 0xd83d, 0xdc08, |
| // U+5642 as Ideographic Variation Sequences |
| 0x5642, 0xDB40, 0xDD00, |
| // U+260E (BLACK TELEPHONE) as Emoji Variation Sequences |
| 0x260E, 0xFE0F, |
| // U+0020 SPACE |
| 0x0020, |
| }; |
| const size_t kUtf16CharsCount = arraysize(kUtf16Chars); |
| |
| ui::CompositionText composition; |
| composition.text.assign(kUtf16Chars, kUtf16Chars + kUtf16CharsCount); |
| ui::TextInputClient* client = textfield_->GetTextInputClient(); |
| client->SetCompositionText(composition); |
| |
| // Make sure GetCompositionCharacterBounds never fails for index. |
| gfx::Rect rects[kUtf16CharsCount]; |
| gfx::Rect prev_cursor = GetCursorBounds(); |
| for (uint32 i = 0; i < kUtf16CharsCount; ++i) |
| EXPECT_TRUE(client->GetCompositionCharacterBounds(i, &rects[i])); |
| |
| // Here we might expect the following results but it actually depends on how |
| // Uniscribe or HarfBuzz treats them with given font. |
| // - rects[1] == rects[2] |
| // - rects[3] == rects[4] == rects[5] |
| // - rects[6] == rects[7] |
| } |
| |
| // The word we select by double clicking should remain selected regardless of |
| // where we drag the mouse afterwards without releasing the left button. |
| TEST_F(TextfieldTest, KeepInitiallySelectedWord) { |
| InitTextfield(); |
| |
| textfield_->SetText(ASCIIToUTF16("abc def ghi")); |
| |
| textfield_->SelectRange(gfx::Range(5, 5)); |
| const gfx::Rect middle_cursor = GetCursorBounds(); |
| textfield_->SelectRange(gfx::Range(0, 0)); |
| const gfx::Point beginning = GetCursorBounds().origin(); |
| |
| // Double click, but do not release the left button. |
| MouseClick(middle_cursor, 0); |
| const gfx::Point middle(middle_cursor.x(), |
| middle_cursor.y() + middle_cursor.height() / 2); |
| ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, middle, middle, |
| ui::EF_LEFT_MOUSE_BUTTON, |
| ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMousePressed(press_event); |
| EXPECT_EQ(gfx::Range(4, 7), textfield_->GetSelectedRange()); |
| |
| // Drag the mouse to the beginning of the textfield. |
| ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, beginning, beginning, |
| ui::EF_LEFT_MOUSE_BUTTON, 0); |
| textfield_->OnMouseDragged(drag_event); |
| EXPECT_EQ(gfx::Range(7, 0), textfield_->GetSelectedRange()); |
| } |
| |
| #if defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| // flaky: http://crbug.com/396477 |
| TEST_F(TextfieldTest, DISABLED_SelectionClipboard) { |
| InitTextfield(); |
| textfield_->SetText(ASCIIToUTF16("0123")); |
| gfx::Point point_1(GetCursorPositionX(1), 0); |
| gfx::Point point_2(GetCursorPositionX(2), 0); |
| gfx::Point point_3(GetCursorPositionX(3), 0); |
| gfx::Point point_4(GetCursorPositionX(4), 0); |
| |
| // Text selected by the mouse should be placed on the selection clipboard. |
| ui::MouseEvent press(ui::ET_MOUSE_PRESSED, point_1, point_1, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMousePressed(press); |
| ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, point_3, point_3, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMouseDragged(drag); |
| ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point_3, point_3, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMouseReleased(release); |
| EXPECT_EQ(gfx::Range(1, 3), textfield_->GetSelectedRange()); |
| EXPECT_STR_EQ("12", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); |
| |
| // Select-all should update the selection clipboard. |
| SendKeyEvent(ui::VKEY_A, false, true); |
| EXPECT_EQ(gfx::Range(0, 4), textfield_->GetSelectedRange()); |
| EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard()); |
| |
| // Shift-click selection modifications should update the clipboard. |
| NonClientMouseClick(); |
| ui::MouseEvent press_2(ui::ET_MOUSE_PRESSED, point_2, point_2, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| press_2.set_flags(press_2.flags() | ui::EF_SHIFT_DOWN); |
| #if defined(USE_X11) |
| ui::UpdateX11EventForFlags(&press_2); |
| #endif |
| textfield_->OnMousePressed(press_2); |
| ui::MouseEvent release_2(ui::ET_MOUSE_RELEASED, point_2, point_2, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMouseReleased(release_2); |
| EXPECT_EQ(gfx::Range(0, 2), textfield_->GetSelectedRange()); |
| EXPECT_STR_EQ("01", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard()); |
| |
| // Shift-Left/Right should update the selection clipboard. |
| SendKeyEvent(ui::VKEY_RIGHT, true, false); |
| EXPECT_STR_EQ("012", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard()); |
| SendKeyEvent(ui::VKEY_LEFT, true, false); |
| EXPECT_STR_EQ("01", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard()); |
| SendKeyEvent(ui::VKEY_RIGHT, true, true); |
| EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard()); |
| |
| // Moving the cursor without a selection should not change the clipboard. |
| SendKeyEvent(ui::VKEY_LEFT, false, false); |
| EXPECT_EQ(gfx::Range(0, 0), textfield_->GetSelectedRange()); |
| EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard()); |
| |
| // Middle clicking should paste at the mouse (not cursor) location. |
| ui::MouseEvent middle(ui::ET_MOUSE_PRESSED, point_4, point_4, |
| ui::EF_MIDDLE_MOUSE_BUTTON, ui::EF_MIDDLE_MOUSE_BUTTON); |
| textfield_->OnMousePressed(middle); |
| EXPECT_STR_EQ("01230123", textfield_->text()); |
| EXPECT_EQ(gfx::Range(0, 0), textfield_->GetSelectedRange()); |
| EXPECT_STR_EQ("0123", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); |
| |
| // Middle click pasting should adjust trailing cursors. |
| textfield_->SelectRange(gfx::Range(5, 5)); |
| textfield_->OnMousePressed(middle); |
| EXPECT_STR_EQ("012301230123", textfield_->text()); |
| EXPECT_EQ(gfx::Range(9, 9), textfield_->GetSelectedRange()); |
| |
| // Middle click pasting should adjust trailing selections. |
| textfield_->SelectRange(gfx::Range(7, 9)); |
| textfield_->OnMousePressed(middle); |
| EXPECT_STR_EQ("0123012301230123", textfield_->text()); |
| EXPECT_EQ(gfx::Range(11, 13), textfield_->GetSelectedRange()); |
| |
| // Middle clicking in the selection should clear the clipboard and selection. |
| textfield_->SelectRange(gfx::Range(2, 6)); |
| textfield_->OnMousePressed(middle); |
| EXPECT_STR_EQ("0123012301230123", textfield_->text()); |
| EXPECT_EQ(gfx::Range(6, 6), textfield_->GetSelectedRange()); |
| EXPECT_TRUE(GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION).empty()); |
| |
| // Double and triple clicking should update the clipboard contents. |
| textfield_->SetText(ASCIIToUTF16("ab cd ef")); |
| gfx::Point word(GetCursorPositionX(4), 0); |
| ui::MouseEvent press_word(ui::ET_MOUSE_PRESSED, word, word, |
| ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMousePressed(press_word); |
| ui::MouseEvent release_word(ui::ET_MOUSE_RELEASED, word, word, |
| ui::EF_LEFT_MOUSE_BUTTON, |
| ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMouseReleased(release_word); |
| ui::MouseEvent double_click(ui::ET_MOUSE_PRESSED, word, word, |
| ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK, |
| ui::EF_LEFT_MOUSE_BUTTON); |
| textfield_->OnMousePressed(double_click); |
| textfield_->OnMouseReleased(release_word); |
| EXPECT_EQ(gfx::Range(3, 5), textfield_->GetSelectedRange()); |
| EXPECT_STR_EQ("cd", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard()); |
| textfield_->OnMousePressed(press_word); |
| textfield_->OnMouseReleased(release_word); |
| EXPECT_EQ(gfx::Range(0, 8), textfield_->GetSelectedRange()); |
| EXPECT_STR_EQ("ab cd ef", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_SELECTION, GetAndResetCopiedToClipboard()); |
| |
| // Selecting a range of text without any user interaction should not change |
| // the clipboard content. |
| textfield_->SelectRange(gfx::Range(0, 3)); |
| EXPECT_STR_EQ("ab ", textfield_->GetSelectedText()); |
| EXPECT_STR_EQ("ab cd ef", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard()); |
| |
| SetClipboardText(ui::CLIPBOARD_TYPE_SELECTION, "other"); |
| textfield_->SelectAll(false); |
| EXPECT_STR_EQ("other", GetClipboardText(ui::CLIPBOARD_TYPE_SELECTION)); |
| EXPECT_EQ(ui::CLIPBOARD_TYPE_LAST, GetAndResetCopiedToClipboard()); |
| } |
| #endif |
| |
| // Touch selection and dragging currently only works for chromeos. |
| #if defined(OS_CHROMEOS) |
| TEST_F(TextfieldTest, TouchSelectionAndDraggingTest) { |
| InitTextfield(); |
| textfield_->SetText(ASCIIToUTF16("hello world")); |
| EXPECT_FALSE(test_api_->touch_selection_controller()); |
| const int x = GetCursorPositionX(2); |
| CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing); |
| |
| // Tapping on the textfield should turn on the TouchSelectionController. |
| ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP); |
| tap_details.set_tap_count(1); |
| GestureEventForTest tap(x, 0, tap_details); |
| textfield_->OnGestureEvent(&tap); |
| EXPECT_TRUE(test_api_->touch_selection_controller()); |
| |
| // Un-focusing the textfield should reset the TouchSelectionController |
| textfield_->GetFocusManager()->ClearFocus(); |
| EXPECT_FALSE(test_api_->touch_selection_controller()); |
| textfield_->RequestFocus(); |
| |
| // With touch editing enabled, long press should not show context menu. |
| // Instead, select word and invoke TouchSelectionController. |
| GestureEventForTest long_press_1( |
| x, 0, ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); |
| textfield_->OnGestureEvent(&long_press_1); |
| EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); |
| EXPECT_TRUE(test_api_->touch_selection_controller()); |
| EXPECT_TRUE(long_press_1.handled()); |
| |
| // With touch drag drop enabled, long pressing in the selected region should |
| // start a drag and remove TouchSelectionController. |
| ASSERT_TRUE(switches::IsTouchDragDropEnabled()); |
| GestureEventForTest long_press_2( |
| x, 0, ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); |
| textfield_->OnGestureEvent(&long_press_2); |
| EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); |
| EXPECT_FALSE(test_api_->touch_selection_controller()); |
| EXPECT_FALSE(long_press_2.handled()); |
| |
| // After disabling touch drag drop, long pressing again in the selection |
| // region should not do anything. |
| CommandLine::ForCurrentProcess()->AppendSwitch( |
| switches::kDisableTouchDragDrop); |
| ASSERT_FALSE(switches::IsTouchDragDropEnabled()); |
| GestureEventForTest long_press_3( |
| x, 0, ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); |
| textfield_->OnGestureEvent(&long_press_3); |
| EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); |
| EXPECT_FALSE(test_api_->touch_selection_controller()); |
| EXPECT_FALSE(long_press_3.handled()); |
| } |
| #endif |
| |
| TEST_F(TextfieldTest, TouchSelectionInUnfocusableTextfield) { |
| CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing); |
| |
| InitTextfield(); |
| textfield_->SetText(ASCIIToUTF16("hello world")); |
| gfx::Point touch_point(GetCursorPositionX(2), 0); |
| |
| // Disable textfield and tap on it. Touch text selection should not get |
| // activated. |
| textfield_->SetEnabled(false); |
| Tap(touch_point); |
| EXPECT_FALSE(test_api_->touch_selection_controller()); |
| textfield_->SetEnabled(true); |
| |
| // Make textfield unfocusable and tap on it. Touch text selection should not |
| // get activated. |
| textfield_->SetFocusable(false); |
| Tap(touch_point); |
| EXPECT_FALSE(textfield_->HasFocus()); |
| EXPECT_FALSE(test_api_->touch_selection_controller()); |
| textfield_->SetFocusable(true); |
| } |
| |
| // Long_Press gesture in Textfield can initiate a drag and drop now. |
| TEST_F(TextfieldTest, TestLongPressInitiatesDragDrop) { |
| InitTextfield(); |
| textfield_->SetText(ASCIIToUTF16("Hello string world")); |
| |
| // Ensure the textfield will provide selected text for drag data. |
| textfield_->SelectRange(gfx::Range(6, 12)); |
| const gfx::Point kStringPoint(GetCursorPositionX(9), 0); |
| |
| // Enable touch-drag-drop to make long press effective. |
| CommandLine::ForCurrentProcess()->AppendSwitch( |
| switches::kEnableTouchDragDrop); |
| |
| // Create a long press event in the selected region should start a drag. |
| GestureEventForTest long_press( |
| kStringPoint.x(), |
| kStringPoint.y(), |
| ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); |
| textfield_->OnGestureEvent(&long_press); |
| EXPECT_TRUE(textfield_->CanStartDragForView(NULL, kStringPoint, |
| kStringPoint)); |
| } |
| |
| TEST_F(TextfieldTest, GetTextfieldBaseline_FontFallbackTest) { |
| InitTextfield(); |
| textfield_->SetText(UTF8ToUTF16("abc")); |
| const int old_baseline = textfield_->GetBaseline(); |
| |
| // Set text which may fall back to a font which has taller baseline than |
| // the default font. |
| textfield_->SetText(UTF8ToUTF16("\xE0\xB9\x91")); |
| const int new_baseline = textfield_->GetBaseline(); |
| |
| // Regardless of the text, the baseline must be the same. |
| EXPECT_EQ(new_baseline, old_baseline); |
| } |
| |
| // Tests that a textfield view can be destroyed from OnKeyEvent() on its |
| // controller and it does not crash. |
| TEST_F(TextfieldTest, DestroyingTextfieldFromOnKeyEvent) { |
| InitTextfield(); |
| |
| // The controller assumes ownership of the textfield. |
| TextfieldDestroyerController controller(textfield_); |
| EXPECT_TRUE(controller.target()); |
| |
| // Send a key to trigger OnKeyEvent(). |
| SendKeyEvent('X'); |
| |
| EXPECT_FALSE(controller.target()); |
| } |
| |
| } // namespace views |