OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "ui/views/controls/textfield/native_textfield_views.h" |
| 6 |
| 7 #include <set> |
| 8 #include <string> |
| 9 #include <vector> |
| 10 |
| 11 #include "base/auto_reset.h" |
| 12 #include "base/bind.h" |
| 13 #include "base/bind_helpers.h" |
| 14 #include "base/callback.h" |
| 15 #include "base/command_line.h" |
| 16 #include "base/message_loop/message_loop.h" |
| 17 #include "base/pickle.h" |
| 18 #include "base/strings/string16.h" |
| 19 #include "base/strings/utf_string_conversions.h" |
| 20 #include "grit/ui_strings.h" |
| 21 #include "testing/gtest/include/gtest/gtest.h" |
| 22 #include "ui/base/clipboard/clipboard.h" |
| 23 #include "ui/base/clipboard/scoped_clipboard_writer.h" |
| 24 #include "ui/base/dragdrop/drag_drop_types.h" |
| 25 #include "ui/base/ime/text_input_client.h" |
| 26 #include "ui/base/l10n/l10n_util.h" |
| 27 #include "ui/base/ui_base_switches.h" |
| 28 #include "ui/events/event.h" |
| 29 #include "ui/events/keycodes/keyboard_codes.h" |
| 30 #include "ui/gfx/render_text.h" |
| 31 #include "ui/views/controls/textfield/textfield.h" |
| 32 #include "ui/views/controls/textfield/textfield_controller.h" |
| 33 #include "ui/views/controls/textfield/textfield_views_model.h" |
| 34 #include "ui/views/focus/focus_manager.h" |
| 35 #include "ui/views/ime/mock_input_method.h" |
| 36 #include "ui/views/test/test_views_delegate.h" |
| 37 #include "ui/views/test/views_test_base.h" |
| 38 #include "ui/views/widget/native_widget_private.h" |
| 39 #include "ui/views/widget/widget.h" |
| 40 #include "url/gurl.h" |
| 41 |
| 42 #if defined(OS_WIN) |
| 43 #include "base/win/windows_version.h" |
| 44 #endif |
| 45 |
| 46 using base::ASCIIToUTF16; |
| 47 using base::UTF8ToUTF16; |
| 48 using base::WideToUTF16; |
| 49 |
| 50 #define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(ASCIIToUTF16(ascii), utf16) |
| 51 |
| 52 namespace { |
| 53 |
| 54 const base::char16 kHebrewLetterSamekh = 0x05E1; |
| 55 |
| 56 // A Textfield wrapper to intercept OnKey[Pressed|Released]() ressults. |
| 57 class TestTextfield : public views::Textfield { |
| 58 public: |
| 59 explicit TestTextfield(StyleFlags style) |
| 60 : Textfield(style), |
| 61 key_handled_(false), |
| 62 key_received_(false) { |
| 63 } |
| 64 |
| 65 virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE { |
| 66 key_received_ = true; |
| 67 key_handled_ = views::Textfield::OnKeyPressed(e); |
| 68 return key_handled_; |
| 69 } |
| 70 |
| 71 virtual bool OnKeyReleased(const ui::KeyEvent& e) OVERRIDE { |
| 72 key_received_ = true; |
| 73 key_handled_ = views::Textfield::OnKeyReleased(e); |
| 74 return key_handled_; |
| 75 } |
| 76 |
| 77 bool key_handled() const { return key_handled_; } |
| 78 bool key_received() const { return key_received_; } |
| 79 |
| 80 void clear() { key_received_ = key_handled_ = false; } |
| 81 |
| 82 private: |
| 83 bool key_handled_; |
| 84 bool key_received_; |
| 85 |
| 86 DISALLOW_COPY_AND_ASSIGN(TestTextfield); |
| 87 }; |
| 88 |
| 89 // A helper class for use with ui::TextInputClient::GetTextFromRange(). |
| 90 class GetTextHelper { |
| 91 public: |
| 92 GetTextHelper() {} |
| 93 |
| 94 void set_text(const base::string16& text) { text_ = text; } |
| 95 const base::string16& text() const { return text_; } |
| 96 |
| 97 private: |
| 98 base::string16 text_; |
| 99 |
| 100 DISALLOW_COPY_AND_ASSIGN(GetTextHelper); |
| 101 }; |
| 102 |
| 103 // Convenience to make constructing a GestureEvent simpler. |
| 104 class GestureEventForTest : public ui::GestureEvent { |
| 105 public: |
| 106 GestureEventForTest(ui::EventType type, int x, int y, float delta_x, |
| 107 float delta_y) |
| 108 : GestureEvent(type, x, y, 0, base::TimeDelta(), |
| 109 ui::GestureEventDetails(type, delta_x, delta_y), 0) { |
| 110 } |
| 111 |
| 112 private: |
| 113 DISALLOW_COPY_AND_ASSIGN(GestureEventForTest); |
| 114 }; |
| 115 |
| 116 } // namespace |
| 117 |
| 118 namespace views { |
| 119 |
| 120 // TODO(oshima): Move tests that are independent of TextfieldViews to |
| 121 // textfield_unittests.cc once we move the test utility functions |
| 122 // from chrome/browser/automation/ to ui/base/test/. |
| 123 class NativeTextfieldViewsTest : public ViewsTestBase, |
| 124 public TextfieldController { |
| 125 public: |
| 126 NativeTextfieldViewsTest() |
| 127 : widget_(NULL), |
| 128 textfield_(NULL), |
| 129 textfield_view_(NULL), |
| 130 model_(NULL), |
| 131 input_method_(NULL), |
| 132 on_before_user_action_(0), |
| 133 on_after_user_action_(0) { |
| 134 } |
| 135 |
| 136 // ::testing::Test: |
| 137 virtual void SetUp() { |
| 138 ViewsTestBase::SetUp(); |
| 139 } |
| 140 |
| 141 virtual void TearDown() { |
| 142 if (widget_) |
| 143 widget_->Close(); |
| 144 ViewsTestBase::TearDown(); |
| 145 } |
| 146 |
| 147 // TextfieldController: |
| 148 virtual void ContentsChanged(Textfield* sender, |
| 149 const base::string16& new_contents) OVERRIDE { |
| 150 // Paste calls TextfieldController::ContentsChanged() explicitly even if the |
| 151 // paste action did not change the content. So |new_contents| may match |
| 152 // |last_contents_|. For more info, see http://crbug.com/79002 |
| 153 last_contents_ = new_contents; |
| 154 } |
| 155 |
| 156 virtual bool HandleKeyEvent(Textfield* sender, |
| 157 const ui::KeyEvent& key_event) OVERRIDE { |
| 158 // TODO(oshima): figure out how to test the keystroke. |
| 159 return false; |
| 160 } |
| 161 |
| 162 virtual void OnBeforeUserAction(Textfield* sender) OVERRIDE { |
| 163 ++on_before_user_action_; |
| 164 } |
| 165 |
| 166 virtual void OnAfterUserAction(Textfield* sender) OVERRIDE { |
| 167 ++on_after_user_action_; |
| 168 } |
| 169 |
| 170 void InitTextfield(Textfield::StyleFlags style) { |
| 171 InitTextfields(style, 1); |
| 172 } |
| 173 |
| 174 void InitTextfields(Textfield::StyleFlags style, int count) { |
| 175 ASSERT_FALSE(textfield_); |
| 176 textfield_ = new TestTextfield(style); |
| 177 textfield_->SetController(this); |
| 178 widget_ = new Widget(); |
| 179 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
| 180 params.bounds = gfx::Rect(100, 100, 100, 100); |
| 181 widget_->Init(params); |
| 182 View* container = new View(); |
| 183 widget_->SetContentsView(container); |
| 184 container->AddChildView(textfield_); |
| 185 |
| 186 textfield_view_ = textfield_->GetTextfieldViewForTesting(); |
| 187 DCHECK(textfield_view_); |
| 188 textfield_view_->SetBoundsRect(params.bounds); |
| 189 textfield_->set_id(1); |
| 190 |
| 191 for (int i = 1; i < count; i++) { |
| 192 Textfield* textfield = new Textfield(style); |
| 193 container->AddChildView(textfield); |
| 194 textfield->set_id(i + 1); |
| 195 } |
| 196 |
| 197 model_ = textfield_view_->model_.get(); |
| 198 model_->ClearEditHistory(); |
| 199 |
| 200 input_method_ = new MockInputMethod(); |
| 201 widget_->ReplaceInputMethod(input_method_); |
| 202 |
| 203 // Activate the widget and focus the textfield for input handling. |
| 204 widget_->Activate(); |
| 205 textfield_->RequestFocus(); |
| 206 } |
| 207 |
| 208 ui::MenuModel* GetContextMenuModel() { |
| 209 textfield_view_->UpdateContextMenu(); |
| 210 return textfield_view_->context_menu_contents_.get(); |
| 211 } |
| 212 |
| 213 ui::TouchSelectionController* GetTouchSelectionController() { |
| 214 return textfield_view_->touch_selection_controller_.get(); |
| 215 } |
| 216 |
| 217 protected: |
| 218 void SendKeyEvent(ui::KeyboardCode key_code, |
| 219 bool alt, |
| 220 bool shift, |
| 221 bool control, |
| 222 bool caps_lock) { |
| 223 int flags = (alt ? ui::EF_ALT_DOWN : 0) | |
| 224 (shift ? ui::EF_SHIFT_DOWN : 0) | |
| 225 (control ? ui::EF_CONTROL_DOWN : 0) | |
| 226 (caps_lock ? ui::EF_CAPS_LOCK_DOWN : 0); |
| 227 ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, flags, false); |
| 228 input_method_->DispatchKeyEvent(event); |
| 229 } |
| 230 |
| 231 void SendKeyEvent(ui::KeyboardCode key_code, bool shift, bool control) { |
| 232 SendKeyEvent(key_code, false, shift, control, false); |
| 233 } |
| 234 |
| 235 void SendKeyEvent(ui::KeyboardCode key_code) { |
| 236 SendKeyEvent(key_code, false, false); |
| 237 } |
| 238 |
| 239 void SendKeyEvent(base::char16 ch) { |
| 240 if (ch < 0x80) { |
| 241 ui::KeyboardCode code = |
| 242 ch == ' ' ? ui::VKEY_SPACE : |
| 243 static_cast<ui::KeyboardCode>(ui::VKEY_A + ch - 'a'); |
| 244 SendKeyEvent(code); |
| 245 } else { |
| 246 ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, 0, false); |
| 247 event.set_character(ch); |
| 248 input_method_->DispatchKeyEvent(event); |
| 249 } |
| 250 } |
| 251 |
| 252 base::string16 GetClipboardText() const { |
| 253 base::string16 text; |
| 254 ui::Clipboard::GetForCurrentThread()-> |
| 255 ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &text); |
| 256 return text; |
| 257 } |
| 258 |
| 259 void SetClipboardText(const std::string& text) { |
| 260 ui::ScopedClipboardWriter clipboard_writer( |
| 261 ui::Clipboard::GetForCurrentThread(), |
| 262 ui::CLIPBOARD_TYPE_COPY_PASTE); |
| 263 clipboard_writer.WriteText(ASCIIToUTF16(text)); |
| 264 } |
| 265 |
| 266 View* GetFocusedView() { |
| 267 return widget_->GetFocusManager()->GetFocusedView(); |
| 268 } |
| 269 |
| 270 int GetCursorPositionX(int cursor_pos) { |
| 271 gfx::RenderText* render_text = textfield_view_->GetRenderText(); |
| 272 return render_text->GetCursorBounds( |
| 273 gfx::SelectionModel(cursor_pos, gfx::CURSOR_FORWARD), false).x(); |
| 274 } |
| 275 |
| 276 // Get the current cursor bounds. |
| 277 gfx::Rect GetCursorBounds() { |
| 278 gfx::RenderText* render_text = textfield_view_->GetRenderText(); |
| 279 gfx::Rect bounds = render_text->GetUpdatedCursorBounds(); |
| 280 return bounds; |
| 281 } |
| 282 |
| 283 // Get the cursor bounds of |sel|. |
| 284 gfx::Rect GetCursorBounds(const gfx::SelectionModel& sel) { |
| 285 gfx::RenderText* render_text = textfield_view_->GetRenderText(); |
| 286 gfx::Rect bounds = render_text->GetCursorBounds(sel, true); |
| 287 return bounds; |
| 288 } |
| 289 |
| 290 gfx::Rect GetDisplayRect() { |
| 291 return textfield_view_->GetRenderText()->display_rect(); |
| 292 } |
| 293 |
| 294 // Mouse click on the point whose x-axis is |bound|'s x plus |x_offset| and |
| 295 // y-axis is in the middle of |bound|'s vertical range. |
| 296 void MouseClick(const gfx::Rect bound, int x_offset) { |
| 297 gfx::Point point(bound.x() + x_offset, bound.y() + bound.height() / 2); |
| 298 ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point, |
| 299 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 300 textfield_view_->OnMousePressed(click); |
| 301 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point, |
| 302 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 303 textfield_view_->OnMouseReleased(release); |
| 304 } |
| 305 |
| 306 // This is to avoid double/triple click. |
| 307 void NonClientMouseClick() { |
| 308 ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), |
| 309 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT, |
| 310 ui::EF_LEFT_MOUSE_BUTTON); |
| 311 textfield_view_->OnMousePressed(click); |
| 312 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), |
| 313 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_NON_CLIENT, |
| 314 ui::EF_LEFT_MOUSE_BUTTON); |
| 315 textfield_view_->OnMouseReleased(release); |
| 316 } |
| 317 |
| 318 // Wrap for visibility in test classes. |
| 319 ui::TextInputType GetTextInputType() { |
| 320 return textfield_view_->GetTextInputType(); |
| 321 } |
| 322 |
| 323 void VerifyTextfieldContextMenuContents(bool textfield_has_selection, |
| 324 bool can_undo, |
| 325 ui::MenuModel* menu) { |
| 326 EXPECT_EQ(can_undo, menu->IsEnabledAt(0 /* UNDO */)); |
| 327 EXPECT_TRUE(menu->IsEnabledAt(1 /* Separator */)); |
| 328 EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(2 /* CUT */)); |
| 329 EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(3 /* COPY */)); |
| 330 EXPECT_NE(GetClipboardText().empty(), menu->IsEnabledAt(4 /* PASTE */)); |
| 331 EXPECT_EQ(textfield_has_selection, menu->IsEnabledAt(5 /* DELETE */)); |
| 332 EXPECT_TRUE(menu->IsEnabledAt(6 /* Separator */)); |
| 333 EXPECT_TRUE(menu->IsEnabledAt(7 /* SELECT ALL */)); |
| 334 } |
| 335 |
| 336 // We need widget to populate wrapper class. |
| 337 Widget* widget_; |
| 338 |
| 339 TestTextfield* textfield_; |
| 340 NativeTextfieldViews* textfield_view_; |
| 341 TextfieldViewsModel* model_; |
| 342 |
| 343 // The string from Controller::ContentsChanged callback. |
| 344 base::string16 last_contents_; |
| 345 |
| 346 // For testing input method related behaviors. |
| 347 MockInputMethod* input_method_; |
| 348 |
| 349 // Indicates how many times OnBeforeUserAction() is called. |
| 350 int on_before_user_action_; |
| 351 |
| 352 // Indicates how many times OnAfterUserAction() is called. |
| 353 int on_after_user_action_; |
| 354 |
| 355 private: |
| 356 DISALLOW_COPY_AND_ASSIGN(NativeTextfieldViewsTest); |
| 357 }; |
| 358 |
| 359 TEST_F(NativeTextfieldViewsTest, ModelChangesTest) { |
| 360 InitTextfield(Textfield::STYLE_DEFAULT); |
| 361 |
| 362 // TextfieldController::ContentsChanged() shouldn't be called when changing |
| 363 // text programmatically. |
| 364 last_contents_.clear(); |
| 365 textfield_->SetText(ASCIIToUTF16("this is")); |
| 366 |
| 367 EXPECT_STR_EQ("this is", model_->GetText()); |
| 368 EXPECT_STR_EQ("this is", textfield_->text()); |
| 369 EXPECT_TRUE(last_contents_.empty()); |
| 370 |
| 371 textfield_->AppendText(ASCIIToUTF16(" a test")); |
| 372 EXPECT_STR_EQ("this is a test", model_->GetText()); |
| 373 EXPECT_STR_EQ("this is a test", textfield_->text()); |
| 374 EXPECT_TRUE(last_contents_.empty()); |
| 375 |
| 376 EXPECT_EQ(base::string16(), textfield_->GetSelectedText()); |
| 377 textfield_->SelectAll(false); |
| 378 EXPECT_STR_EQ("this is a test", textfield_->GetSelectedText()); |
| 379 EXPECT_TRUE(last_contents_.empty()); |
| 380 } |
| 381 |
| 382 TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCase) { |
| 383 // Check if |model_|'s text is properly lowercased for STYLE_LOWERCASE. |
| 384 InitTextfield(Textfield::STYLE_LOWERCASE); |
| 385 EXPECT_EQ(0U, textfield_->GetCursorPosition()); |
| 386 |
| 387 last_contents_.clear(); |
| 388 textfield_->SetText(ASCIIToUTF16("THIS IS")); |
| 389 EXPECT_EQ(7U, textfield_->GetCursorPosition()); |
| 390 |
| 391 EXPECT_STR_EQ("this is", model_->GetText()); |
| 392 EXPECT_STR_EQ("THIS IS", textfield_->text()); |
| 393 EXPECT_TRUE(last_contents_.empty()); |
| 394 |
| 395 textfield_->AppendText(ASCIIToUTF16(" A TEST")); |
| 396 EXPECT_EQ(7U, textfield_->GetCursorPosition()); |
| 397 EXPECT_STR_EQ("this is a test", model_->GetText()); |
| 398 EXPECT_STR_EQ("THIS IS A TEST", textfield_->text()); |
| 399 |
| 400 EXPECT_TRUE(last_contents_.empty()); |
| 401 } |
| 402 |
| 403 TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseI18n) { |
| 404 // Check if lower case conversion works for non-ASCII characters. |
| 405 InitTextfield(Textfield::STYLE_LOWERCASE); |
| 406 EXPECT_EQ(0U, textfield_->GetCursorPosition()); |
| 407 |
| 408 last_contents_.clear(); |
| 409 // Zenkaku Japanese "ABCabc" |
| 410 textfield_->SetText(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43")); |
| 411 EXPECT_EQ(6U, textfield_->GetCursorPosition()); |
| 412 // Zenkaku Japanese "abcabc" |
| 413 EXPECT_EQ(WideToUTF16(L"\xFF41\xFF42\xFF43\xFF41\xFF42\xFF43"), |
| 414 model_->GetText()); |
| 415 // Zenkaku Japanese "ABCabc" |
| 416 EXPECT_EQ(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43"), |
| 417 textfield_->text()); |
| 418 EXPECT_TRUE(last_contents_.empty()); |
| 419 |
| 420 // Zenkaku Japanese "XYZxyz" |
| 421 textfield_->AppendText(WideToUTF16(L"\xFF38\xFF39\xFF3A\xFF58\xFF59\xFF5A")); |
| 422 EXPECT_EQ(6U, textfield_->GetCursorPosition()); |
| 423 // Zenkaku Japanese "abcabcxyzxyz" |
| 424 EXPECT_EQ(WideToUTF16(L"\xFF41\xFF42\xFF43\xFF41\xFF42\xFF43" |
| 425 L"\xFF58\xFF59\xFF5A\xFF58\xFF59\xFF5A"), |
| 426 model_->GetText()); |
| 427 // Zenkaku Japanese "ABCabcXYZxyz" |
| 428 EXPECT_EQ(WideToUTF16(L"\xFF21\xFF22\xFF23\xFF41\xFF42\xFF43" |
| 429 L"\xFF38\xFF39\xFF3A\xFF58\xFF59\xFF5A"), |
| 430 textfield_->text()); |
| 431 EXPECT_TRUE(last_contents_.empty()); |
| 432 } |
| 433 |
| 434 TEST_F(NativeTextfieldViewsTest, ModelChangesTestLowerCaseWithLocale) { |
| 435 // Check if lower case conversion honors locale properly. |
| 436 std::string locale = l10n_util::GetApplicationLocale(""); |
| 437 base::i18n::SetICUDefaultLocale("tr"); |
| 438 |
| 439 InitTextfield(Textfield::STYLE_LOWERCASE); |
| 440 EXPECT_EQ(0U, textfield_->GetCursorPosition()); |
| 441 |
| 442 last_contents_.clear(); |
| 443 // Turkish 'I' should be converted to dotless 'i' (U+0131). |
| 444 textfield_->SetText(WideToUTF16(L"I")); |
| 445 EXPECT_EQ(1U, textfield_->GetCursorPosition()); |
| 446 EXPECT_EQ(WideToUTF16(L"\x0131"), model_->GetText()); |
| 447 EXPECT_EQ(WideToUTF16(L"I"), textfield_->text()); |
| 448 EXPECT_TRUE(last_contents_.empty()); |
| 449 |
| 450 base::i18n::SetICUDefaultLocale(locale); |
| 451 |
| 452 // On default (en) locale, 'I' should be converted to 'i'. |
| 453 textfield_->SetText(WideToUTF16(L"I")); |
| 454 EXPECT_EQ(1U, textfield_->GetCursorPosition()); |
| 455 EXPECT_EQ(WideToUTF16(L"i"), model_->GetText()); |
| 456 EXPECT_EQ(WideToUTF16(L"I"), textfield_->text()); |
| 457 EXPECT_TRUE(last_contents_.empty()); |
| 458 } |
| 459 |
| 460 TEST_F(NativeTextfieldViewsTest, KeyTest) { |
| 461 InitTextfield(Textfield::STYLE_DEFAULT); |
| 462 // Event flags: key, alt, shift, ctrl, caps-lock. |
| 463 SendKeyEvent(ui::VKEY_T, false, true, false, false); |
| 464 SendKeyEvent(ui::VKEY_E, false, false, false, false); |
| 465 SendKeyEvent(ui::VKEY_X, false, true, false, true); |
| 466 SendKeyEvent(ui::VKEY_T, false, false, false, true); |
| 467 SendKeyEvent(ui::VKEY_1, false, true, false, false); |
| 468 SendKeyEvent(ui::VKEY_1, false, false, false, false); |
| 469 SendKeyEvent(ui::VKEY_1, false, true, false, true); |
| 470 SendKeyEvent(ui::VKEY_1, false, false, false, true); |
| 471 EXPECT_STR_EQ("TexT!1!1", textfield_->text()); |
| 472 } |
| 473 |
| 474 TEST_F(NativeTextfieldViewsTest, ControlAndSelectTest) { |
| 475 // Insert a test string in a textfield. |
| 476 InitTextfield(Textfield::STYLE_DEFAULT); |
| 477 textfield_->SetText(ASCIIToUTF16("one two three")); |
| 478 SendKeyEvent(ui::VKEY_HOME, false /* shift */, false /* control */); |
| 479 SendKeyEvent(ui::VKEY_RIGHT, true, false); |
| 480 SendKeyEvent(ui::VKEY_RIGHT, true, false); |
| 481 SendKeyEvent(ui::VKEY_RIGHT, true, false); |
| 482 |
| 483 EXPECT_STR_EQ("one", textfield_->GetSelectedText()); |
| 484 |
| 485 // Test word select. |
| 486 SendKeyEvent(ui::VKEY_RIGHT, true, true); |
| 487 EXPECT_STR_EQ("one two", textfield_->GetSelectedText()); |
| 488 SendKeyEvent(ui::VKEY_RIGHT, true, true); |
| 489 EXPECT_STR_EQ("one two three", textfield_->GetSelectedText()); |
| 490 SendKeyEvent(ui::VKEY_LEFT, true, true); |
| 491 EXPECT_STR_EQ("one two ", textfield_->GetSelectedText()); |
| 492 SendKeyEvent(ui::VKEY_LEFT, true, true); |
| 493 EXPECT_STR_EQ("one ", textfield_->GetSelectedText()); |
| 494 |
| 495 // Replace the selected text. |
| 496 SendKeyEvent(ui::VKEY_Z, true, false); |
| 497 SendKeyEvent(ui::VKEY_E, true, false); |
| 498 SendKeyEvent(ui::VKEY_R, true, false); |
| 499 SendKeyEvent(ui::VKEY_O, true, false); |
| 500 SendKeyEvent(ui::VKEY_SPACE, false, false); |
| 501 EXPECT_STR_EQ("ZERO two three", textfield_->text()); |
| 502 |
| 503 SendKeyEvent(ui::VKEY_END, true, false); |
| 504 EXPECT_STR_EQ("two three", textfield_->GetSelectedText()); |
| 505 SendKeyEvent(ui::VKEY_HOME, true, false); |
| 506 EXPECT_STR_EQ("ZERO ", textfield_->GetSelectedText()); |
| 507 } |
| 508 |
| 509 TEST_F(NativeTextfieldViewsTest, InsertionDeletionTest) { |
| 510 // Insert a test string in a textfield. |
| 511 InitTextfield(Textfield::STYLE_DEFAULT); |
| 512 for (size_t i = 0; i < 10; i++) |
| 513 SendKeyEvent(static_cast<ui::KeyboardCode>(ui::VKEY_A + i)); |
| 514 EXPECT_STR_EQ("abcdefghij", textfield_->text()); |
| 515 |
| 516 // Test the delete and backspace keys. |
| 517 textfield_->SelectRange(gfx::Range(5)); |
| 518 for (int i = 0; i < 3; i++) |
| 519 SendKeyEvent(ui::VKEY_BACK); |
| 520 EXPECT_STR_EQ("abfghij", textfield_->text()); |
| 521 for (int i = 0; i < 3; i++) |
| 522 SendKeyEvent(ui::VKEY_DELETE); |
| 523 EXPECT_STR_EQ("abij", textfield_->text()); |
| 524 |
| 525 // Select all and replace with "k". |
| 526 textfield_->SelectAll(false); |
| 527 SendKeyEvent(ui::VKEY_K); |
| 528 EXPECT_STR_EQ("k", textfield_->text()); |
| 529 |
| 530 // Delete the previous word from cursor. |
| 531 textfield_->SetText(ASCIIToUTF16("one two three four")); |
| 532 SendKeyEvent(ui::VKEY_END); |
| 533 SendKeyEvent(ui::VKEY_BACK, false, false, true, false); |
| 534 EXPECT_STR_EQ("one two three ", textfield_->text()); |
| 535 |
| 536 // Delete text preceeding the cursor in chromeos, do nothing in windows. |
| 537 SendKeyEvent(ui::VKEY_LEFT, false, false, true, false); |
| 538 SendKeyEvent(ui::VKEY_BACK, false, true, true, false); |
| 539 #if defined(OS_WIN) |
| 540 EXPECT_STR_EQ("one two three ", textfield_->text()); |
| 541 #else |
| 542 EXPECT_STR_EQ("three ", textfield_->text()); |
| 543 #endif |
| 544 |
| 545 // Delete the next word from cursor. |
| 546 textfield_->SetText(ASCIIToUTF16("one two three four")); |
| 547 SendKeyEvent(ui::VKEY_HOME); |
| 548 SendKeyEvent(ui::VKEY_DELETE, false, false, true, false); |
| 549 EXPECT_STR_EQ(" two three four", textfield_->text()); |
| 550 |
| 551 // Delete text following the cursor in chromeos, do nothing in windows. |
| 552 SendKeyEvent(ui::VKEY_RIGHT, false, false, true, false); |
| 553 SendKeyEvent(ui::VKEY_DELETE, false, true, true, false); |
| 554 #if defined(OS_WIN) |
| 555 EXPECT_STR_EQ(" two three four", textfield_->text()); |
| 556 #else |
| 557 EXPECT_STR_EQ(" two", textfield_->text()); |
| 558 #endif |
| 559 } |
| 560 |
| 561 TEST_F(NativeTextfieldViewsTest, PasswordTest) { |
| 562 InitTextfield(Textfield::STYLE_OBSCURED); |
| 563 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, GetTextInputType()); |
| 564 EXPECT_TRUE(textfield_->enabled()); |
| 565 EXPECT_TRUE(textfield_->focusable()); |
| 566 |
| 567 last_contents_.clear(); |
| 568 textfield_->SetText(ASCIIToUTF16("password")); |
| 569 // Ensure text() and the callback returns the actual text instead of "*". |
| 570 EXPECT_STR_EQ("password", textfield_->text()); |
| 571 EXPECT_TRUE(last_contents_.empty()); |
| 572 model_->SelectAll(false); |
| 573 SetClipboardText("foo"); |
| 574 |
| 575 // Cut and copy should be disabled. |
| 576 EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_CUT)); |
| 577 textfield_view_->ExecuteCommand(IDS_APP_CUT, 0); |
| 578 SendKeyEvent(ui::VKEY_X, false, true); |
| 579 EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_COPY)); |
| 580 textfield_view_->ExecuteCommand(IDS_APP_COPY, 0); |
| 581 SendKeyEvent(ui::VKEY_C, false, true); |
| 582 SendKeyEvent(ui::VKEY_INSERT, false, true); |
| 583 EXPECT_STR_EQ("foo", base::string16(GetClipboardText())); |
| 584 EXPECT_STR_EQ("password", textfield_->text()); |
| 585 // [Shift]+[Delete] should just delete without copying text to the clipboard. |
| 586 textfield_->SelectAll(false); |
| 587 SendKeyEvent(ui::VKEY_DELETE, true, false); |
| 588 |
| 589 // Paste should work normally. |
| 590 EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_PASTE)); |
| 591 textfield_view_->ExecuteCommand(IDS_APP_PASTE, 0); |
| 592 SendKeyEvent(ui::VKEY_V, false, true); |
| 593 SendKeyEvent(ui::VKEY_INSERT, true, false); |
| 594 EXPECT_STR_EQ("foo", base::string16(GetClipboardText())); |
| 595 EXPECT_STR_EQ("foofoofoo", textfield_->text()); |
| 596 } |
| 597 |
| 598 TEST_F(NativeTextfieldViewsTest, InputTypeSetsObscured) { |
| 599 InitTextfield(Textfield::STYLE_DEFAULT); |
| 600 |
| 601 // Defaults to TEXT |
| 602 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, GetTextInputType()); |
| 603 |
| 604 // Setting to TEXT_INPUT_TYPE_PASSWORD also sets obscured state of textfield. |
| 605 textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); |
| 606 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, GetTextInputType()); |
| 607 EXPECT_TRUE(textfield_->IsObscured()); |
| 608 } |
| 609 |
| 610 TEST_F(NativeTextfieldViewsTest, ObscuredSetsInputType) { |
| 611 InitTextfield(Textfield::STYLE_DEFAULT); |
| 612 |
| 613 // Defaults to TEXT |
| 614 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, GetTextInputType()); |
| 615 |
| 616 textfield_->SetObscured(true); |
| 617 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, GetTextInputType()); |
| 618 |
| 619 textfield_->SetObscured(false); |
| 620 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, GetTextInputType()); |
| 621 } |
| 622 |
| 623 TEST_F(NativeTextfieldViewsTest, TextInputType) { |
| 624 InitTextfield(Textfield::STYLE_DEFAULT); |
| 625 |
| 626 // Defaults to TEXT |
| 627 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, GetTextInputType()); |
| 628 |
| 629 // And can be set. |
| 630 textfield_->SetTextInputType(ui::TEXT_INPUT_TYPE_URL); |
| 631 EXPECT_EQ(ui::TEXT_INPUT_TYPE_URL, GetTextInputType()); |
| 632 |
| 633 // Readonly textfields have type NONE |
| 634 textfield_->SetReadOnly(true); |
| 635 EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, GetTextInputType()); |
| 636 |
| 637 textfield_->SetReadOnly(false); |
| 638 EXPECT_EQ(ui::TEXT_INPUT_TYPE_URL, GetTextInputType()); |
| 639 |
| 640 // As do disabled textfields |
| 641 textfield_->SetEnabled(false); |
| 642 EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, GetTextInputType()); |
| 643 } |
| 644 |
| 645 TEST_F(NativeTextfieldViewsTest, OnKeyPressReturnValueTest) { |
| 646 InitTextfield(Textfield::STYLE_DEFAULT); |
| 647 |
| 648 // Character keys will be handled by input method. |
| 649 SendKeyEvent(ui::VKEY_A); |
| 650 EXPECT_TRUE(textfield_->key_received()); |
| 651 EXPECT_FALSE(textfield_->key_handled()); |
| 652 textfield_->clear(); |
| 653 |
| 654 // Home will be handled. |
| 655 SendKeyEvent(ui::VKEY_HOME); |
| 656 EXPECT_TRUE(textfield_->key_received()); |
| 657 EXPECT_TRUE(textfield_->key_handled()); |
| 658 textfield_->clear(); |
| 659 |
| 660 // F24, up/down key won't be handled. |
| 661 SendKeyEvent(ui::VKEY_F24); |
| 662 EXPECT_TRUE(textfield_->key_received()); |
| 663 EXPECT_FALSE(textfield_->key_handled()); |
| 664 textfield_->clear(); |
| 665 |
| 666 SendKeyEvent(ui::VKEY_UP); |
| 667 EXPECT_TRUE(textfield_->key_received()); |
| 668 EXPECT_FALSE(textfield_->key_handled()); |
| 669 textfield_->clear(); |
| 670 |
| 671 SendKeyEvent(ui::VKEY_DOWN); |
| 672 EXPECT_TRUE(textfield_->key_received()); |
| 673 EXPECT_FALSE(textfield_->key_handled()); |
| 674 textfield_->clear(); |
| 675 |
| 676 // Empty Textfield does not handle left/right. |
| 677 textfield_->SetText(base::string16()); |
| 678 SendKeyEvent(ui::VKEY_LEFT); |
| 679 EXPECT_TRUE(textfield_->key_received()); |
| 680 EXPECT_FALSE(textfield_->key_handled()); |
| 681 textfield_->clear(); |
| 682 |
| 683 SendKeyEvent(ui::VKEY_RIGHT); |
| 684 EXPECT_TRUE(textfield_->key_received()); |
| 685 EXPECT_FALSE(textfield_->key_handled()); |
| 686 textfield_->clear(); |
| 687 |
| 688 // Add a char. Right key should not be handled when cursor is at the end. |
| 689 SendKeyEvent(ui::VKEY_B); |
| 690 SendKeyEvent(ui::VKEY_RIGHT); |
| 691 EXPECT_TRUE(textfield_->key_received()); |
| 692 EXPECT_FALSE(textfield_->key_handled()); |
| 693 textfield_->clear(); |
| 694 |
| 695 // First left key is handled to move cursor left to the beginning. |
| 696 SendKeyEvent(ui::VKEY_LEFT); |
| 697 EXPECT_TRUE(textfield_->key_received()); |
| 698 EXPECT_TRUE(textfield_->key_handled()); |
| 699 textfield_->clear(); |
| 700 |
| 701 // Now left key should not be handled. |
| 702 SendKeyEvent(ui::VKEY_LEFT); |
| 703 EXPECT_TRUE(textfield_->key_received()); |
| 704 EXPECT_FALSE(textfield_->key_handled()); |
| 705 textfield_->clear(); |
| 706 } |
| 707 |
| 708 TEST_F(NativeTextfieldViewsTest, CursorMovement) { |
| 709 InitTextfield(Textfield::STYLE_DEFAULT); |
| 710 |
| 711 // Test with trailing whitespace. |
| 712 textfield_->SetText(ASCIIToUTF16("one two hre ")); |
| 713 |
| 714 // Send the cursor at the end. |
| 715 SendKeyEvent(ui::VKEY_END); |
| 716 |
| 717 // Ctrl+Left should move the cursor just before the last word. |
| 718 SendKeyEvent(ui::VKEY_LEFT, false, true); |
| 719 SendKeyEvent(ui::VKEY_T); |
| 720 EXPECT_STR_EQ("one two thre ", textfield_->text()); |
| 721 EXPECT_STR_EQ("one two thre ", last_contents_); |
| 722 |
| 723 // Ctrl+Right should move the cursor to the end of the last word. |
| 724 SendKeyEvent(ui::VKEY_RIGHT, false, true); |
| 725 SendKeyEvent(ui::VKEY_E); |
| 726 EXPECT_STR_EQ("one two three ", textfield_->text()); |
| 727 EXPECT_STR_EQ("one two three ", last_contents_); |
| 728 |
| 729 // Ctrl+Right again should move the cursor to the end. |
| 730 SendKeyEvent(ui::VKEY_RIGHT, false, true); |
| 731 SendKeyEvent(ui::VKEY_BACK); |
| 732 EXPECT_STR_EQ("one two three", textfield_->text()); |
| 733 EXPECT_STR_EQ("one two three", last_contents_); |
| 734 |
| 735 // Test with leading whitespace. |
| 736 textfield_->SetText(ASCIIToUTF16(" ne two")); |
| 737 |
| 738 // Send the cursor at the beginning. |
| 739 SendKeyEvent(ui::VKEY_HOME); |
| 740 |
| 741 // Ctrl+Right, then Ctrl+Left should move the cursor to the beginning of the |
| 742 // first word. |
| 743 SendKeyEvent(ui::VKEY_RIGHT, false, true); |
| 744 SendKeyEvent(ui::VKEY_LEFT, false, true); |
| 745 SendKeyEvent(ui::VKEY_O); |
| 746 EXPECT_STR_EQ(" one two", textfield_->text()); |
| 747 EXPECT_STR_EQ(" one two", last_contents_); |
| 748 |
| 749 // Ctrl+Left to move the cursor to the beginning of the first word. |
| 750 SendKeyEvent(ui::VKEY_LEFT, false, true); |
| 751 // Ctrl+Left again should move the cursor back to the very beginning. |
| 752 SendKeyEvent(ui::VKEY_LEFT, false, true); |
| 753 SendKeyEvent(ui::VKEY_DELETE); |
| 754 EXPECT_STR_EQ("one two", textfield_->text()); |
| 755 EXPECT_STR_EQ("one two", last_contents_); |
| 756 } |
| 757 |
| 758 TEST_F(NativeTextfieldViewsTest, FocusTraversalTest) { |
| 759 InitTextfields(Textfield::STYLE_DEFAULT, 3); |
| 760 textfield_->RequestFocus(); |
| 761 |
| 762 EXPECT_EQ(1, GetFocusedView()->id()); |
| 763 widget_->GetFocusManager()->AdvanceFocus(false); |
| 764 EXPECT_EQ(2, GetFocusedView()->id()); |
| 765 widget_->GetFocusManager()->AdvanceFocus(false); |
| 766 EXPECT_EQ(3, GetFocusedView()->id()); |
| 767 // Cycle back to the first textfield. |
| 768 widget_->GetFocusManager()->AdvanceFocus(false); |
| 769 EXPECT_EQ(1, GetFocusedView()->id()); |
| 770 |
| 771 widget_->GetFocusManager()->AdvanceFocus(true); |
| 772 EXPECT_EQ(3, GetFocusedView()->id()); |
| 773 widget_->GetFocusManager()->AdvanceFocus(true); |
| 774 EXPECT_EQ(2, GetFocusedView()->id()); |
| 775 widget_->GetFocusManager()->AdvanceFocus(true); |
| 776 EXPECT_EQ(1, GetFocusedView()->id()); |
| 777 // Cycle back to the last textfield. |
| 778 widget_->GetFocusManager()->AdvanceFocus(true); |
| 779 EXPECT_EQ(3, GetFocusedView()->id()); |
| 780 |
| 781 // Request focus should still work. |
| 782 textfield_->RequestFocus(); |
| 783 EXPECT_EQ(1, GetFocusedView()->id()); |
| 784 |
| 785 // Test if clicking on textfield view sets the focus to textfield_. |
| 786 widget_->GetFocusManager()->AdvanceFocus(true); |
| 787 EXPECT_EQ(3, GetFocusedView()->id()); |
| 788 ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), |
| 789 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 790 textfield_view_->OnMousePressed(click); |
| 791 EXPECT_EQ(1, GetFocusedView()->id()); |
| 792 } |
| 793 |
| 794 TEST_F(NativeTextfieldViewsTest, ContextMenuDisplayTest) { |
| 795 InitTextfield(Textfield::STYLE_DEFAULT); |
| 796 EXPECT_TRUE(textfield_->context_menu_controller()); |
| 797 textfield_->SetText(ASCIIToUTF16("hello world")); |
| 798 ui::Clipboard::GetForCurrentThread()->Clear(ui::CLIPBOARD_TYPE_COPY_PASTE); |
| 799 textfield_view_->ClearEditHistory(); |
| 800 EXPECT_TRUE(GetContextMenuModel()); |
| 801 VerifyTextfieldContextMenuContents(false, false, GetContextMenuModel()); |
| 802 |
| 803 textfield_->SelectAll(false); |
| 804 VerifyTextfieldContextMenuContents(true, false, GetContextMenuModel()); |
| 805 |
| 806 SendKeyEvent(ui::VKEY_T); |
| 807 VerifyTextfieldContextMenuContents(false, true, GetContextMenuModel()); |
| 808 |
| 809 textfield_->SelectAll(false); |
| 810 VerifyTextfieldContextMenuContents(true, true, GetContextMenuModel()); |
| 811 |
| 812 // Exercise the "paste enabled?" check in the verifier. |
| 813 SetClipboardText("Test"); |
| 814 VerifyTextfieldContextMenuContents(true, true, GetContextMenuModel()); |
| 815 } |
| 816 |
| 817 TEST_F(NativeTextfieldViewsTest, DoubleAndTripleClickTest) { |
| 818 InitTextfield(Textfield::STYLE_DEFAULT); |
| 819 textfield_->SetText(ASCIIToUTF16("hello world")); |
| 820 ui::MouseEvent click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), |
| 821 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 822 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), |
| 823 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 824 ui::MouseEvent double_click( |
| 825 ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), |
| 826 ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK, |
| 827 ui::EF_LEFT_MOUSE_BUTTON); |
| 828 |
| 829 // Test for double click. |
| 830 textfield_view_->OnMousePressed(click); |
| 831 textfield_view_->OnMouseReleased(release); |
| 832 EXPECT_TRUE(textfield_->GetSelectedText().empty()); |
| 833 textfield_view_->OnMousePressed(double_click); |
| 834 textfield_view_->OnMouseReleased(release); |
| 835 EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); |
| 836 |
| 837 // Test for triple click. |
| 838 textfield_view_->OnMousePressed(click); |
| 839 textfield_view_->OnMouseReleased(release); |
| 840 EXPECT_STR_EQ("hello world", textfield_->GetSelectedText()); |
| 841 |
| 842 // Another click should reset back to double click. |
| 843 textfield_view_->OnMousePressed(click); |
| 844 textfield_view_->OnMouseReleased(release); |
| 845 EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); |
| 846 } |
| 847 |
| 848 TEST_F(NativeTextfieldViewsTest, DragToSelect) { |
| 849 InitTextfield(Textfield::STYLE_DEFAULT); |
| 850 textfield_->SetText(ASCIIToUTF16("hello world")); |
| 851 const int kStart = GetCursorPositionX(5); |
| 852 const int kEnd = 500; |
| 853 gfx::Point start_point(kStart, 0); |
| 854 gfx::Point end_point(kEnd, 0); |
| 855 ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, start_point, start_point, |
| 856 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 857 ui::MouseEvent click_b(ui::ET_MOUSE_PRESSED, end_point, end_point, |
| 858 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 859 ui::MouseEvent drag_left(ui::ET_MOUSE_DRAGGED, gfx::Point(), gfx::Point(), |
| 860 ui::EF_LEFT_MOUSE_BUTTON, 0); |
| 861 ui::MouseEvent drag_right(ui::ET_MOUSE_DRAGGED, end_point, end_point, |
| 862 ui::EF_LEFT_MOUSE_BUTTON, 0); |
| 863 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, end_point, end_point, |
| 864 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 865 textfield_view_->OnMousePressed(click_a); |
| 866 EXPECT_TRUE(textfield_->GetSelectedText().empty()); |
| 867 // Check that dragging left selects the beginning of the string. |
| 868 textfield_view_->OnMouseDragged(drag_left); |
| 869 base::string16 text_left = textfield_->GetSelectedText(); |
| 870 EXPECT_STR_EQ("hello", text_left); |
| 871 // Check that dragging right selects the rest of the string. |
| 872 textfield_view_->OnMouseDragged(drag_right); |
| 873 base::string16 text_right = textfield_->GetSelectedText(); |
| 874 EXPECT_STR_EQ(" world", text_right); |
| 875 // Check that releasing in the same location does not alter the selection. |
| 876 textfield_view_->OnMouseReleased(release); |
| 877 EXPECT_EQ(text_right, textfield_->GetSelectedText()); |
| 878 // Check that dragging from beyond the text length works too. |
| 879 textfield_view_->OnMousePressed(click_b); |
| 880 textfield_view_->OnMouseDragged(drag_left); |
| 881 textfield_view_->OnMouseReleased(release); |
| 882 EXPECT_EQ(textfield_->text(), textfield_->GetSelectedText()); |
| 883 } |
| 884 |
| 885 #if defined(OS_WIN) |
| 886 TEST_F(NativeTextfieldViewsTest, DragAndDrop_AcceptDrop) { |
| 887 InitTextfield(Textfield::STYLE_DEFAULT); |
| 888 textfield_->SetText(ASCIIToUTF16("hello world")); |
| 889 |
| 890 ui::OSExchangeData data; |
| 891 base::string16 string(ASCIIToUTF16("string ")); |
| 892 data.SetString(string); |
| 893 int formats = 0; |
| 894 std::set<OSExchangeData::CustomFormat> custom_formats; |
| 895 |
| 896 // Ensure that disabled textfields do not accept drops. |
| 897 textfield_->SetEnabled(false); |
| 898 EXPECT_FALSE(textfield_view_->GetDropFormats(&formats, &custom_formats)); |
| 899 EXPECT_EQ(0, formats); |
| 900 EXPECT_TRUE(custom_formats.empty()); |
| 901 EXPECT_FALSE(textfield_view_->CanDrop(data)); |
| 902 textfield_->SetEnabled(true); |
| 903 |
| 904 // Ensure that read-only textfields do not accept drops. |
| 905 textfield_->SetReadOnly(true); |
| 906 EXPECT_FALSE(textfield_view_->GetDropFormats(&formats, &custom_formats)); |
| 907 EXPECT_EQ(0, formats); |
| 908 EXPECT_TRUE(custom_formats.empty()); |
| 909 EXPECT_FALSE(textfield_view_->CanDrop(data)); |
| 910 textfield_->SetReadOnly(false); |
| 911 |
| 912 // Ensure that enabled and editable textfields do accept drops. |
| 913 EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats)); |
| 914 EXPECT_EQ(ui::OSExchangeData::STRING, formats); |
| 915 EXPECT_TRUE(custom_formats.empty()); |
| 916 EXPECT_TRUE(textfield_view_->CanDrop(data)); |
| 917 gfx::Point drop_point(GetCursorPositionX(6), 0); |
| 918 ui::DropTargetEvent drop(data, drop_point, drop_point, |
| 919 ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE); |
| 920 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE, |
| 921 textfield_view_->OnDragUpdated(drop)); |
| 922 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, textfield_view_->OnPerformDrop(drop)); |
| 923 EXPECT_STR_EQ("hello string world", textfield_->text()); |
| 924 |
| 925 // Ensure that textfields do not accept non-OSExchangeData::STRING types. |
| 926 ui::OSExchangeData bad_data; |
| 927 bad_data.SetFilename(base::FilePath(FILE_PATH_LITERAL("x"))); |
| 928 #if defined(OS_WIN) |
| 929 ui::OSExchangeData::CustomFormat fmt = ui::Clipboard::GetBitmapFormatType(); |
| 930 bad_data.SetPickledData(fmt, Pickle()); |
| 931 bad_data.SetFileContents(base::FilePath(L"x"), "x"); |
| 932 bad_data.SetHtml(base::string16(ASCIIToUTF16("x")), GURL("x.org")); |
| 933 ui::OSExchangeData::DownloadFileInfo download(base::FilePath(), NULL); |
| 934 bad_data.SetDownloadFileInfo(download); |
| 935 #endif |
| 936 EXPECT_FALSE(textfield_view_->CanDrop(bad_data)); |
| 937 } |
| 938 #endif |
| 939 |
| 940 TEST_F(NativeTextfieldViewsTest, DragAndDrop_InitiateDrag) { |
| 941 InitTextfield(Textfield::STYLE_DEFAULT); |
| 942 textfield_->SetText(ASCIIToUTF16("hello string world")); |
| 943 |
| 944 // Ensure the textfield will provide selected text for drag data. |
| 945 base::string16 string; |
| 946 ui::OSExchangeData data; |
| 947 const gfx::Range kStringRange(6, 12); |
| 948 textfield_->SelectRange(kStringRange); |
| 949 const gfx::Point kStringPoint(GetCursorPositionX(9), 0); |
| 950 textfield_view_->WriteDragDataForView(NULL, kStringPoint, &data); |
| 951 EXPECT_TRUE(data.GetString(&string)); |
| 952 EXPECT_EQ(textfield_->GetSelectedText(), string); |
| 953 |
| 954 // Ensure that disabled textfields do not support drag operations. |
| 955 textfield_->SetEnabled(false); |
| 956 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, |
| 957 textfield_view_->GetDragOperationsForView(NULL, kStringPoint)); |
| 958 textfield_->SetEnabled(true); |
| 959 // Ensure that textfields without selections do not support drag operations. |
| 960 textfield_->ClearSelection(); |
| 961 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, |
| 962 textfield_view_->GetDragOperationsForView(NULL, kStringPoint)); |
| 963 textfield_->SelectRange(kStringRange); |
| 964 // Ensure that password textfields do not support drag operations. |
| 965 textfield_->SetObscured(true); |
| 966 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, |
| 967 textfield_view_->GetDragOperationsForView(NULL, kStringPoint)); |
| 968 textfield_->SetObscured(false); |
| 969 // Ensure that textfields only initiate drag operations inside the selection. |
| 970 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, kStringPoint, kStringPoint, |
| 971 ui::EF_LEFT_MOUSE_BUTTON, |
| 972 ui::EF_LEFT_MOUSE_BUTTON); |
| 973 textfield_view_->OnMousePressed(press_event); |
| 974 EXPECT_EQ(ui::DragDropTypes::DRAG_NONE, |
| 975 textfield_view_->GetDragOperationsForView(NULL, gfx::Point())); |
| 976 EXPECT_FALSE(textfield_view_->CanStartDragForView(NULL, gfx::Point(), |
| 977 gfx::Point())); |
| 978 EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, |
| 979 textfield_view_->GetDragOperationsForView(NULL, kStringPoint)); |
| 980 EXPECT_TRUE(textfield_view_->CanStartDragForView(NULL, kStringPoint, |
| 981 gfx::Point())); |
| 982 // Ensure that textfields support local moves. |
| 983 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY, |
| 984 textfield_view_->GetDragOperationsForView(textfield_view_, kStringPoint)); |
| 985 } |
| 986 |
| 987 TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheRight) { |
| 988 InitTextfield(Textfield::STYLE_DEFAULT); |
| 989 textfield_->SetText(ASCIIToUTF16("hello world")); |
| 990 |
| 991 base::string16 string; |
| 992 ui::OSExchangeData data; |
| 993 int formats = 0; |
| 994 int operations = 0; |
| 995 std::set<OSExchangeData::CustomFormat> custom_formats; |
| 996 |
| 997 // Start dragging "ello". |
| 998 textfield_->SelectRange(gfx::Range(1, 5)); |
| 999 gfx::Point point(GetCursorPositionX(3), 0); |
| 1000 ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point, |
| 1001 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 1002 textfield_view_->OnMousePressed(click_a); |
| 1003 EXPECT_TRUE(textfield_view_->CanStartDragForView(textfield_view_, |
| 1004 click_a.location(), gfx::Point())); |
| 1005 operations = textfield_view_->GetDragOperationsForView(textfield_view_, |
| 1006 click_a.location()); |
| 1007 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY, |
| 1008 operations); |
| 1009 textfield_view_->WriteDragDataForView(NULL, click_a.location(), &data); |
| 1010 EXPECT_TRUE(data.GetString(&string)); |
| 1011 EXPECT_EQ(textfield_->GetSelectedText(), string); |
| 1012 EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats)); |
| 1013 EXPECT_EQ(ui::OSExchangeData::STRING, formats); |
| 1014 EXPECT_TRUE(custom_formats.empty()); |
| 1015 |
| 1016 // Drop "ello" after "w". |
| 1017 const gfx::Point kDropPoint(GetCursorPositionX(7), 0); |
| 1018 EXPECT_TRUE(textfield_view_->CanDrop(data)); |
| 1019 ui::DropTargetEvent drop_a(data, kDropPoint, kDropPoint, operations); |
| 1020 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, |
| 1021 textfield_view_->OnDragUpdated(drop_a)); |
| 1022 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, |
| 1023 textfield_view_->OnPerformDrop(drop_a)); |
| 1024 EXPECT_STR_EQ("h welloorld", textfield_->text()); |
| 1025 textfield_view_->OnDragDone(); |
| 1026 |
| 1027 // Undo/Redo the drag&drop change. |
| 1028 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1029 EXPECT_STR_EQ("hello world", textfield_->text()); |
| 1030 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1031 EXPECT_STR_EQ("", textfield_->text()); |
| 1032 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1033 EXPECT_STR_EQ("", textfield_->text()); |
| 1034 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1035 EXPECT_STR_EQ("hello world", textfield_->text()); |
| 1036 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1037 EXPECT_STR_EQ("h welloorld", textfield_->text()); |
| 1038 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1039 EXPECT_STR_EQ("h welloorld", textfield_->text()); |
| 1040 } |
| 1041 |
| 1042 TEST_F(NativeTextfieldViewsTest, DragAndDrop_ToTheLeft) { |
| 1043 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1044 textfield_->SetText(ASCIIToUTF16("hello world")); |
| 1045 |
| 1046 base::string16 string; |
| 1047 ui::OSExchangeData data; |
| 1048 int formats = 0; |
| 1049 int operations = 0; |
| 1050 std::set<OSExchangeData::CustomFormat> custom_formats; |
| 1051 |
| 1052 // Start dragging " worl". |
| 1053 textfield_->SelectRange(gfx::Range(5, 10)); |
| 1054 gfx::Point point(GetCursorPositionX(7), 0); |
| 1055 ui::MouseEvent click_a(ui::ET_MOUSE_PRESSED, point, point, |
| 1056 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 1057 textfield_view_->OnMousePressed(click_a); |
| 1058 EXPECT_TRUE(textfield_view_->CanStartDragForView(textfield_view_, |
| 1059 click_a.location(), gfx::Point())); |
| 1060 operations = textfield_view_->GetDragOperationsForView(textfield_view_, |
| 1061 click_a.location()); |
| 1062 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE | ui::DragDropTypes::DRAG_COPY, |
| 1063 operations); |
| 1064 textfield_view_->WriteDragDataForView(NULL, click_a.location(), &data); |
| 1065 EXPECT_TRUE(data.GetString(&string)); |
| 1066 EXPECT_EQ(textfield_->GetSelectedText(), string); |
| 1067 EXPECT_TRUE(textfield_view_->GetDropFormats(&formats, &custom_formats)); |
| 1068 EXPECT_EQ(ui::OSExchangeData::STRING, formats); |
| 1069 EXPECT_TRUE(custom_formats.empty()); |
| 1070 |
| 1071 // Drop " worl" after "h". |
| 1072 EXPECT_TRUE(textfield_view_->CanDrop(data)); |
| 1073 gfx::Point drop_point(GetCursorPositionX(1), 0); |
| 1074 ui::DropTargetEvent drop_a(data, drop_point, drop_point, operations); |
| 1075 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, |
| 1076 textfield_view_->OnDragUpdated(drop_a)); |
| 1077 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, |
| 1078 textfield_view_->OnPerformDrop(drop_a)); |
| 1079 EXPECT_STR_EQ("h worlellod", textfield_->text()); |
| 1080 textfield_view_->OnDragDone(); |
| 1081 |
| 1082 // Undo/Redo the drag&drop change. |
| 1083 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1084 EXPECT_STR_EQ("hello world", textfield_->text()); |
| 1085 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1086 EXPECT_STR_EQ("", textfield_->text()); |
| 1087 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1088 EXPECT_STR_EQ("", textfield_->text()); |
| 1089 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1090 EXPECT_STR_EQ("hello world", textfield_->text()); |
| 1091 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1092 EXPECT_STR_EQ("h worlellod", textfield_->text()); |
| 1093 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1094 EXPECT_STR_EQ("h worlellod", textfield_->text()); |
| 1095 } |
| 1096 |
| 1097 TEST_F(NativeTextfieldViewsTest, DragAndDrop_Canceled) { |
| 1098 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1099 textfield_->SetText(ASCIIToUTF16("hello world")); |
| 1100 |
| 1101 // Start dragging "worl". |
| 1102 textfield_->SelectRange(gfx::Range(6, 10)); |
| 1103 gfx::Point point(GetCursorPositionX(8), 0); |
| 1104 ui::MouseEvent click(ui::ET_MOUSE_PRESSED, point, point, |
| 1105 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 1106 textfield_view_->OnMousePressed(click); |
| 1107 ui::OSExchangeData data; |
| 1108 textfield_view_->WriteDragDataForView(NULL, click.location(), &data); |
| 1109 EXPECT_TRUE(textfield_view_->CanDrop(data)); |
| 1110 // Drag the text over somewhere valid, outside the current selection. |
| 1111 gfx::Point drop_point(GetCursorPositionX(2), 0); |
| 1112 ui::DropTargetEvent drop(data, drop_point, drop_point, |
| 1113 ui::DragDropTypes::DRAG_MOVE); |
| 1114 EXPECT_EQ(ui::DragDropTypes::DRAG_MOVE, textfield_view_->OnDragUpdated(drop)); |
| 1115 // "Cancel" the drag, via move and release over the selection, and OnDragDone. |
| 1116 gfx::Point drag_point(GetCursorPositionX(9), 0); |
| 1117 ui::MouseEvent drag(ui::ET_MOUSE_DRAGGED, drag_point, drag_point, |
| 1118 ui::EF_LEFT_MOUSE_BUTTON, 0); |
| 1119 ui::MouseEvent release(ui::ET_MOUSE_RELEASED, drag_point, drag_point, |
| 1120 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 1121 textfield_view_->OnMouseDragged(drag); |
| 1122 textfield_view_->OnMouseReleased(release); |
| 1123 textfield_view_->OnDragDone(); |
| 1124 EXPECT_EQ(ASCIIToUTF16("hello world"), textfield_->text()); |
| 1125 } |
| 1126 |
| 1127 TEST_F(NativeTextfieldViewsTest, ReadOnlyTest) { |
| 1128 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1129 textfield_->SetText(ASCIIToUTF16("read only")); |
| 1130 textfield_->SetReadOnly(true); |
| 1131 EXPECT_TRUE(textfield_->enabled()); |
| 1132 EXPECT_TRUE(textfield_->focusable()); |
| 1133 |
| 1134 SendKeyEvent(ui::VKEY_HOME); |
| 1135 EXPECT_EQ(0U, textfield_->GetCursorPosition()); |
| 1136 SendKeyEvent(ui::VKEY_END); |
| 1137 EXPECT_EQ(9U, textfield_->GetCursorPosition()); |
| 1138 |
| 1139 SendKeyEvent(ui::VKEY_LEFT, false, false); |
| 1140 EXPECT_EQ(8U, textfield_->GetCursorPosition()); |
| 1141 SendKeyEvent(ui::VKEY_LEFT, false, true); |
| 1142 EXPECT_EQ(5U, textfield_->GetCursorPosition()); |
| 1143 SendKeyEvent(ui::VKEY_LEFT, true, true); |
| 1144 EXPECT_EQ(0U, textfield_->GetCursorPosition()); |
| 1145 EXPECT_STR_EQ("read ", textfield_->GetSelectedText()); |
| 1146 textfield_->SelectAll(false); |
| 1147 EXPECT_STR_EQ("read only", textfield_->GetSelectedText()); |
| 1148 |
| 1149 // Cut should be disabled. |
| 1150 SetClipboardText("Test"); |
| 1151 EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_CUT)); |
| 1152 textfield_view_->ExecuteCommand(IDS_APP_CUT, 0); |
| 1153 SendKeyEvent(ui::VKEY_X, false, true); |
| 1154 SendKeyEvent(ui::VKEY_DELETE, true, false); |
| 1155 EXPECT_STR_EQ("Test", base::string16(GetClipboardText())); |
| 1156 EXPECT_STR_EQ("read only", textfield_->text()); |
| 1157 |
| 1158 // Paste should be disabled. |
| 1159 EXPECT_FALSE(textfield_view_->IsCommandIdEnabled(IDS_APP_PASTE)); |
| 1160 textfield_view_->ExecuteCommand(IDS_APP_PASTE, 0); |
| 1161 SendKeyEvent(ui::VKEY_V, false, true); |
| 1162 SendKeyEvent(ui::VKEY_INSERT, true, false); |
| 1163 EXPECT_STR_EQ("read only", textfield_->text()); |
| 1164 |
| 1165 // Copy should work normally. |
| 1166 SetClipboardText("Test"); |
| 1167 EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_COPY)); |
| 1168 textfield_view_->ExecuteCommand(IDS_APP_COPY, 0); |
| 1169 EXPECT_STR_EQ("read only", base::string16(GetClipboardText())); |
| 1170 SetClipboardText("Test"); |
| 1171 SendKeyEvent(ui::VKEY_C, false, true); |
| 1172 EXPECT_STR_EQ("read only", base::string16(GetClipboardText())); |
| 1173 SetClipboardText("Test"); |
| 1174 SendKeyEvent(ui::VKEY_INSERT, false, true); |
| 1175 EXPECT_STR_EQ("read only", base::string16(GetClipboardText())); |
| 1176 |
| 1177 // SetText should work even in read only mode. |
| 1178 textfield_->SetText(ASCIIToUTF16(" four five six ")); |
| 1179 EXPECT_STR_EQ(" four five six ", textfield_->text()); |
| 1180 |
| 1181 textfield_->SelectAll(false); |
| 1182 EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText()); |
| 1183 |
| 1184 // Text field is unmodifiable and selection shouldn't change. |
| 1185 SendKeyEvent(ui::VKEY_DELETE); |
| 1186 EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText()); |
| 1187 SendKeyEvent(ui::VKEY_BACK); |
| 1188 EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText()); |
| 1189 SendKeyEvent(ui::VKEY_T); |
| 1190 EXPECT_STR_EQ(" four five six ", textfield_->GetSelectedText()); |
| 1191 } |
| 1192 |
| 1193 TEST_F(NativeTextfieldViewsTest, TextInputClientTest) { |
| 1194 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1195 ui::TextInputClient* client = textfield_->GetTextInputClient(); |
| 1196 EXPECT_TRUE(client); |
| 1197 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, client->GetTextInputType()); |
| 1198 |
| 1199 textfield_->SetText(ASCIIToUTF16("0123456789")); |
| 1200 gfx::Range range; |
| 1201 EXPECT_TRUE(client->GetTextRange(&range)); |
| 1202 EXPECT_EQ(0U, range.start()); |
| 1203 EXPECT_EQ(10U, range.end()); |
| 1204 |
| 1205 EXPECT_TRUE(client->SetSelectionRange(gfx::Range(1, 4))); |
| 1206 EXPECT_TRUE(client->GetSelectionRange(&range)); |
| 1207 EXPECT_EQ(gfx::Range(1, 4), range); |
| 1208 |
| 1209 // This code can't be compiled because of a bug in base::Callback. |
| 1210 #if 0 |
| 1211 GetTextHelper helper; |
| 1212 base::Callback<void(base::string16)> callback = |
| 1213 base::Bind(&GetTextHelper::set_text, base::Unretained(&helper)); |
| 1214 |
| 1215 EXPECT_TRUE(client->GetTextFromRange(range, callback)); |
| 1216 EXPECT_STR_EQ("123", helper.text()); |
| 1217 #endif |
| 1218 |
| 1219 EXPECT_TRUE(client->DeleteRange(range)); |
| 1220 EXPECT_STR_EQ("0456789", textfield_->text()); |
| 1221 |
| 1222 ui::CompositionText composition; |
| 1223 composition.text = UTF8ToUTF16("321"); |
| 1224 // Set composition through input method. |
| 1225 input_method_->Clear(); |
| 1226 input_method_->SetCompositionTextForNextKey(composition); |
| 1227 textfield_->clear(); |
| 1228 |
| 1229 on_before_user_action_ = on_after_user_action_ = 0; |
| 1230 SendKeyEvent(ui::VKEY_A); |
| 1231 EXPECT_TRUE(textfield_->key_received()); |
| 1232 EXPECT_FALSE(textfield_->key_handled()); |
| 1233 EXPECT_TRUE(client->HasCompositionText()); |
| 1234 EXPECT_TRUE(client->GetCompositionTextRange(&range)); |
| 1235 EXPECT_STR_EQ("0321456789", textfield_->text()); |
| 1236 EXPECT_EQ(gfx::Range(1, 4), range); |
| 1237 EXPECT_EQ(2, on_before_user_action_); |
| 1238 EXPECT_EQ(2, on_after_user_action_); |
| 1239 |
| 1240 input_method_->SetResultTextForNextKey(UTF8ToUTF16("123")); |
| 1241 on_before_user_action_ = on_after_user_action_ = 0; |
| 1242 textfield_->clear(); |
| 1243 SendKeyEvent(ui::VKEY_A); |
| 1244 EXPECT_TRUE(textfield_->key_received()); |
| 1245 EXPECT_FALSE(textfield_->key_handled()); |
| 1246 EXPECT_FALSE(client->HasCompositionText()); |
| 1247 EXPECT_FALSE(input_method_->cancel_composition_called()); |
| 1248 EXPECT_STR_EQ("0123456789", textfield_->text()); |
| 1249 EXPECT_EQ(2, on_before_user_action_); |
| 1250 EXPECT_EQ(2, on_after_user_action_); |
| 1251 |
| 1252 input_method_->Clear(); |
| 1253 input_method_->SetCompositionTextForNextKey(composition); |
| 1254 textfield_->clear(); |
| 1255 SendKeyEvent(ui::VKEY_A); |
| 1256 EXPECT_TRUE(client->HasCompositionText()); |
| 1257 EXPECT_STR_EQ("0123321456789", textfield_->text()); |
| 1258 |
| 1259 on_before_user_action_ = on_after_user_action_ = 0; |
| 1260 textfield_->clear(); |
| 1261 SendKeyEvent(ui::VKEY_RIGHT); |
| 1262 EXPECT_FALSE(client->HasCompositionText()); |
| 1263 EXPECT_TRUE(input_method_->cancel_composition_called()); |
| 1264 EXPECT_TRUE(textfield_->key_received()); |
| 1265 EXPECT_TRUE(textfield_->key_handled()); |
| 1266 EXPECT_STR_EQ("0123321456789", textfield_->text()); |
| 1267 EXPECT_EQ(8U, textfield_->GetCursorPosition()); |
| 1268 EXPECT_EQ(1, on_before_user_action_); |
| 1269 EXPECT_EQ(1, on_after_user_action_); |
| 1270 |
| 1271 textfield_->clear(); |
| 1272 textfield_->SetText(ASCIIToUTF16("0123456789")); |
| 1273 EXPECT_TRUE(client->SetSelectionRange(gfx::Range(5, 5))); |
| 1274 client->ExtendSelectionAndDelete(4, 2); |
| 1275 EXPECT_STR_EQ("0789", textfield_->text()); |
| 1276 |
| 1277 // On{Before,After}UserAction should be called by whatever user action |
| 1278 // triggers clearing or setting a selection if appropriate. |
| 1279 on_before_user_action_ = on_after_user_action_ = 0; |
| 1280 textfield_->clear(); |
| 1281 textfield_->ClearSelection(); |
| 1282 textfield_->SelectAll(false); |
| 1283 EXPECT_EQ(0, on_before_user_action_); |
| 1284 EXPECT_EQ(0, on_after_user_action_); |
| 1285 |
| 1286 input_method_->Clear(); |
| 1287 textfield_->SetReadOnly(true); |
| 1288 EXPECT_TRUE(input_method_->text_input_type_changed()); |
| 1289 EXPECT_FALSE(textfield_->GetTextInputClient()); |
| 1290 |
| 1291 textfield_->SetReadOnly(false); |
| 1292 input_method_->Clear(); |
| 1293 textfield_->SetObscured(true); |
| 1294 EXPECT_TRUE(input_method_->text_input_type_changed()); |
| 1295 EXPECT_TRUE(textfield_->GetTextInputClient()); |
| 1296 } |
| 1297 |
| 1298 TEST_F(NativeTextfieldViewsTest, UndoRedoTest) { |
| 1299 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1300 SendKeyEvent(ui::VKEY_A); |
| 1301 EXPECT_STR_EQ("a", textfield_->text()); |
| 1302 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1303 EXPECT_STR_EQ("", textfield_->text()); |
| 1304 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1305 EXPECT_STR_EQ("", textfield_->text()); |
| 1306 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1307 EXPECT_STR_EQ("a", textfield_->text()); |
| 1308 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1309 EXPECT_STR_EQ("a", textfield_->text()); |
| 1310 |
| 1311 // AppendText |
| 1312 textfield_->AppendText(ASCIIToUTF16("b")); |
| 1313 last_contents_.clear(); // AppendText doesn't call ContentsChanged. |
| 1314 EXPECT_STR_EQ("ab", textfield_->text()); |
| 1315 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1316 EXPECT_STR_EQ("a", textfield_->text()); |
| 1317 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1318 EXPECT_STR_EQ("ab", textfield_->text()); |
| 1319 |
| 1320 // SetText |
| 1321 SendKeyEvent(ui::VKEY_C); |
| 1322 // Undo'ing append moves the cursor to the end for now. |
| 1323 // no-op SetText won't add new edit. See TextfieldViewsModel::SetText |
| 1324 // description. |
| 1325 EXPECT_STR_EQ("abc", textfield_->text()); |
| 1326 textfield_->SetText(ASCIIToUTF16("abc")); |
| 1327 EXPECT_STR_EQ("abc", textfield_->text()); |
| 1328 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1329 EXPECT_STR_EQ("ab", textfield_->text()); |
| 1330 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1331 EXPECT_STR_EQ("abc", textfield_->text()); |
| 1332 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1333 EXPECT_STR_EQ("abc", textfield_->text()); |
| 1334 textfield_->SetText(ASCIIToUTF16("123")); |
| 1335 textfield_->SetText(ASCIIToUTF16("123")); |
| 1336 EXPECT_STR_EQ("123", textfield_->text()); |
| 1337 SendKeyEvent(ui::VKEY_END, false, false); |
| 1338 SendKeyEvent(ui::VKEY_4, false, false); |
| 1339 EXPECT_STR_EQ("1234", textfield_->text()); |
| 1340 last_contents_.clear(); |
| 1341 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1342 EXPECT_STR_EQ("123", textfield_->text()); |
| 1343 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1344 // the insert edit "c" and set edit "123" are merged to single edit, |
| 1345 // so text becomes "ab" after undo. |
| 1346 EXPECT_STR_EQ("ab", textfield_->text()); |
| 1347 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1348 EXPECT_STR_EQ("a", textfield_->text()); |
| 1349 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1350 EXPECT_STR_EQ("ab", textfield_->text()); |
| 1351 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1352 EXPECT_STR_EQ("123", textfield_->text()); |
| 1353 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1354 EXPECT_STR_EQ("1234", textfield_->text()); |
| 1355 |
| 1356 // Undoing to the same text shouldn't call ContentsChanged. |
| 1357 SendKeyEvent(ui::VKEY_A, false, true); // select all |
| 1358 SendKeyEvent(ui::VKEY_A); |
| 1359 EXPECT_STR_EQ("a", textfield_->text()); |
| 1360 SendKeyEvent(ui::VKEY_B); |
| 1361 SendKeyEvent(ui::VKEY_C); |
| 1362 EXPECT_STR_EQ("abc", textfield_->text()); |
| 1363 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1364 EXPECT_STR_EQ("1234", textfield_->text()); |
| 1365 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1366 EXPECT_STR_EQ("abc", textfield_->text()); |
| 1367 |
| 1368 // Delete/Backspace |
| 1369 SendKeyEvent(ui::VKEY_BACK); |
| 1370 EXPECT_STR_EQ("ab", textfield_->text()); |
| 1371 SendKeyEvent(ui::VKEY_HOME); |
| 1372 SendKeyEvent(ui::VKEY_DELETE); |
| 1373 EXPECT_STR_EQ("b", textfield_->text()); |
| 1374 SendKeyEvent(ui::VKEY_A, false, true); |
| 1375 SendKeyEvent(ui::VKEY_DELETE); |
| 1376 EXPECT_STR_EQ("", textfield_->text()); |
| 1377 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1378 EXPECT_STR_EQ("b", textfield_->text()); |
| 1379 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1380 EXPECT_STR_EQ("ab", textfield_->text()); |
| 1381 SendKeyEvent(ui::VKEY_Z, false, true); |
| 1382 EXPECT_STR_EQ("abc", textfield_->text()); |
| 1383 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1384 EXPECT_STR_EQ("ab", textfield_->text()); |
| 1385 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1386 EXPECT_STR_EQ("b", textfield_->text()); |
| 1387 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1388 EXPECT_STR_EQ("", textfield_->text()); |
| 1389 SendKeyEvent(ui::VKEY_Y, false, true); |
| 1390 EXPECT_STR_EQ("", textfield_->text()); |
| 1391 } |
| 1392 |
| 1393 TEST_F(NativeTextfieldViewsTest, CutCopyPaste) { |
| 1394 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1395 |
| 1396 // Ensure IDS_APP_CUT cuts. |
| 1397 textfield_->SetText(ASCIIToUTF16("123")); |
| 1398 textfield_->SelectAll(false); |
| 1399 EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_CUT)); |
| 1400 textfield_view_->ExecuteCommand(IDS_APP_CUT, 0); |
| 1401 EXPECT_STR_EQ("123", base::string16(GetClipboardText())); |
| 1402 EXPECT_STR_EQ("", textfield_->text()); |
| 1403 |
| 1404 // Ensure [Ctrl]+[x] cuts and [Ctrl]+[Alt][x] does nothing. |
| 1405 textfield_->SetText(ASCIIToUTF16("456")); |
| 1406 textfield_->SelectAll(false); |
| 1407 SendKeyEvent(ui::VKEY_X, true, false, true, false); |
| 1408 EXPECT_STR_EQ("123", base::string16(GetClipboardText())); |
| 1409 EXPECT_STR_EQ("456", textfield_->text()); |
| 1410 SendKeyEvent(ui::VKEY_X, false, true); |
| 1411 EXPECT_STR_EQ("456", base::string16(GetClipboardText())); |
| 1412 EXPECT_STR_EQ("", textfield_->text()); |
| 1413 |
| 1414 // Ensure [Shift]+[Delete] cuts. |
| 1415 textfield_->SetText(ASCIIToUTF16("123")); |
| 1416 textfield_->SelectAll(false); |
| 1417 SendKeyEvent(ui::VKEY_DELETE, true, false); |
| 1418 EXPECT_STR_EQ("123", base::string16(GetClipboardText())); |
| 1419 EXPECT_STR_EQ("", textfield_->text()); |
| 1420 |
| 1421 // Ensure IDS_APP_COPY copies. |
| 1422 textfield_->SetText(ASCIIToUTF16("789")); |
| 1423 textfield_->SelectAll(false); |
| 1424 EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_COPY)); |
| 1425 textfield_view_->ExecuteCommand(IDS_APP_COPY, 0); |
| 1426 EXPECT_STR_EQ("789", base::string16(GetClipboardText())); |
| 1427 |
| 1428 // Ensure [Ctrl]+[c] copies and [Ctrl]+[Alt][c] does nothing. |
| 1429 textfield_->SetText(ASCIIToUTF16("012")); |
| 1430 textfield_->SelectAll(false); |
| 1431 SendKeyEvent(ui::VKEY_C, true, false, true, false); |
| 1432 EXPECT_STR_EQ("789", base::string16(GetClipboardText())); |
| 1433 SendKeyEvent(ui::VKEY_C, false, true); |
| 1434 EXPECT_STR_EQ("012", base::string16(GetClipboardText())); |
| 1435 |
| 1436 // Ensure [Ctrl]+[Insert] copies. |
| 1437 textfield_->SetText(ASCIIToUTF16("345")); |
| 1438 textfield_->SelectAll(false); |
| 1439 SendKeyEvent(ui::VKEY_INSERT, false, true); |
| 1440 EXPECT_STR_EQ("345", base::string16(GetClipboardText())); |
| 1441 EXPECT_STR_EQ("345", textfield_->text()); |
| 1442 |
| 1443 // Ensure IDS_APP_PASTE, [Ctrl]+[V], and [Shift]+[Insert] pastes; |
| 1444 // also ensure that [Ctrl]+[Alt]+[V] does nothing. |
| 1445 SetClipboardText("abc"); |
| 1446 textfield_->SetText(base::string16()); |
| 1447 EXPECT_TRUE(textfield_view_->IsCommandIdEnabled(IDS_APP_PASTE)); |
| 1448 textfield_view_->ExecuteCommand(IDS_APP_PASTE, 0); |
| 1449 EXPECT_STR_EQ("abc", textfield_->text()); |
| 1450 SendKeyEvent(ui::VKEY_V, false, true); |
| 1451 EXPECT_STR_EQ("abcabc", textfield_->text()); |
| 1452 SendKeyEvent(ui::VKEY_INSERT, true, false); |
| 1453 EXPECT_STR_EQ("abcabcabc", textfield_->text()); |
| 1454 SendKeyEvent(ui::VKEY_V, true, false, true, false); |
| 1455 EXPECT_STR_EQ("abcabcabc", textfield_->text()); |
| 1456 |
| 1457 // Ensure [Ctrl]+[Shift]+[Insert] is a no-op. |
| 1458 textfield_->SelectAll(false); |
| 1459 SendKeyEvent(ui::VKEY_INSERT, true, true); |
| 1460 EXPECT_STR_EQ("abc", base::string16(GetClipboardText())); |
| 1461 EXPECT_STR_EQ("abcabcabc", textfield_->text()); |
| 1462 } |
| 1463 |
| 1464 TEST_F(NativeTextfieldViewsTest, OvertypeMode) { |
| 1465 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1466 // Overtype mode should be disabled (no-op [Insert]). |
| 1467 textfield_->SetText(ASCIIToUTF16("2")); |
| 1468 SendKeyEvent(ui::VKEY_HOME); |
| 1469 SendKeyEvent(ui::VKEY_INSERT); |
| 1470 SendKeyEvent(ui::VKEY_1, false, false); |
| 1471 EXPECT_STR_EQ("12", textfield_->text()); |
| 1472 } |
| 1473 |
| 1474 TEST_F(NativeTextfieldViewsTest, TextCursorDisplayTest) { |
| 1475 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1476 // LTR-RTL string in LTR context. |
| 1477 SendKeyEvent('a'); |
| 1478 EXPECT_STR_EQ("a", textfield_->text()); |
| 1479 int x = GetCursorBounds().x(); |
| 1480 int prev_x = x; |
| 1481 |
| 1482 SendKeyEvent('b'); |
| 1483 EXPECT_STR_EQ("ab", textfield_->text()); |
| 1484 x = GetCursorBounds().x(); |
| 1485 EXPECT_LT(prev_x, x); |
| 1486 prev_x = x; |
| 1487 |
| 1488 SendKeyEvent(0x05E1); |
| 1489 EXPECT_EQ(WideToUTF16(L"ab\x05E1"), textfield_->text()); |
| 1490 x = GetCursorBounds().x(); |
| 1491 EXPECT_EQ(prev_x, x); |
| 1492 |
| 1493 SendKeyEvent(0x05E2); |
| 1494 EXPECT_EQ(WideToUTF16(L"ab\x05E1\x5E2"), textfield_->text()); |
| 1495 x = GetCursorBounds().x(); |
| 1496 EXPECT_EQ(prev_x, x); |
| 1497 |
| 1498 // Clear text. |
| 1499 SendKeyEvent(ui::VKEY_A, false, true); |
| 1500 SendKeyEvent('\n'); |
| 1501 |
| 1502 // RTL-LTR string in LTR context. |
| 1503 SendKeyEvent(0x05E1); |
| 1504 EXPECT_EQ(WideToUTF16(L"\x05E1"), textfield_->text()); |
| 1505 x = GetCursorBounds().x(); |
| 1506 EXPECT_EQ(GetDisplayRect().x(), x); |
| 1507 prev_x = x; |
| 1508 |
| 1509 SendKeyEvent(0x05E2); |
| 1510 EXPECT_EQ(WideToUTF16(L"\x05E1\x05E2"), textfield_->text()); |
| 1511 x = GetCursorBounds().x(); |
| 1512 EXPECT_EQ(prev_x, x); |
| 1513 |
| 1514 SendKeyEvent('a'); |
| 1515 EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"a"), textfield_->text()); |
| 1516 x = GetCursorBounds().x(); |
| 1517 EXPECT_LT(prev_x, x); |
| 1518 prev_x = x; |
| 1519 |
| 1520 SendKeyEvent('b'); |
| 1521 EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"ab"), textfield_->text()); |
| 1522 x = GetCursorBounds().x(); |
| 1523 EXPECT_LT(prev_x, x); |
| 1524 } |
| 1525 |
| 1526 TEST_F(NativeTextfieldViewsTest, TextCursorDisplayInRTLTest) { |
| 1527 std::string locale = l10n_util::GetApplicationLocale(""); |
| 1528 base::i18n::SetICUDefaultLocale("he"); |
| 1529 |
| 1530 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1531 // LTR-RTL string in RTL context. |
| 1532 SendKeyEvent('a'); |
| 1533 EXPECT_STR_EQ("a", textfield_->text()); |
| 1534 int x = GetCursorBounds().x(); |
| 1535 EXPECT_EQ(GetDisplayRect().right() - 1, x); |
| 1536 int prev_x = x; |
| 1537 |
| 1538 SendKeyEvent('b'); |
| 1539 EXPECT_STR_EQ("ab", textfield_->text()); |
| 1540 x = GetCursorBounds().x(); |
| 1541 EXPECT_EQ(prev_x, x); |
| 1542 |
| 1543 SendKeyEvent(0x05E1); |
| 1544 EXPECT_EQ(WideToUTF16(L"ab\x05E1"), textfield_->text()); |
| 1545 x = GetCursorBounds().x(); |
| 1546 EXPECT_GT(prev_x, x); |
| 1547 prev_x = x; |
| 1548 |
| 1549 SendKeyEvent(0x05E2); |
| 1550 EXPECT_EQ(WideToUTF16(L"ab\x05E1\x5E2"), textfield_->text()); |
| 1551 x = GetCursorBounds().x(); |
| 1552 EXPECT_GT(prev_x, x); |
| 1553 |
| 1554 SendKeyEvent(ui::VKEY_A, false, true); |
| 1555 SendKeyEvent('\n'); |
| 1556 |
| 1557 // RTL-LTR string in RTL context. |
| 1558 SendKeyEvent(0x05E1); |
| 1559 EXPECT_EQ(WideToUTF16(L"\x05E1"), textfield_->text()); |
| 1560 x = GetCursorBounds().x(); |
| 1561 prev_x = x; |
| 1562 |
| 1563 SendKeyEvent(0x05E2); |
| 1564 EXPECT_EQ(WideToUTF16(L"\x05E1\x05E2"), textfield_->text()); |
| 1565 x = GetCursorBounds().x(); |
| 1566 EXPECT_GT(prev_x, x); |
| 1567 prev_x = x; |
| 1568 |
| 1569 SendKeyEvent('a'); |
| 1570 EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"a"), textfield_->text()); |
| 1571 x = GetCursorBounds().x(); |
| 1572 EXPECT_EQ(prev_x, x); |
| 1573 prev_x = x; |
| 1574 |
| 1575 SendKeyEvent('b'); |
| 1576 EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"ab"), textfield_->text()); |
| 1577 x = GetCursorBounds().x(); |
| 1578 EXPECT_EQ(prev_x, x); |
| 1579 |
| 1580 // Reset locale. |
| 1581 base::i18n::SetICUDefaultLocale(locale); |
| 1582 } |
| 1583 |
| 1584 TEST_F(NativeTextfieldViewsTest, HitInsideTextAreaTest) { |
| 1585 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1586 textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2")); |
| 1587 std::vector<gfx::Rect> cursor_bounds; |
| 1588 |
| 1589 // Save each cursor bound. |
| 1590 gfx::SelectionModel sel(0, gfx::CURSOR_FORWARD); |
| 1591 cursor_bounds.push_back(GetCursorBounds(sel)); |
| 1592 |
| 1593 sel = gfx::SelectionModel(1, gfx::CURSOR_BACKWARD); |
| 1594 gfx::Rect bound = GetCursorBounds(sel); |
| 1595 sel = gfx::SelectionModel(1, gfx::CURSOR_FORWARD); |
| 1596 EXPECT_EQ(bound.x(), GetCursorBounds(sel).x()); |
| 1597 cursor_bounds.push_back(bound); |
| 1598 |
| 1599 // Check that a cursor at the end of the Latin portion of the text is at the |
| 1600 // same position as a cursor placed at the end of the RTL Hebrew portion. |
| 1601 sel = gfx::SelectionModel(2, gfx::CURSOR_BACKWARD); |
| 1602 bound = GetCursorBounds(sel); |
| 1603 sel = gfx::SelectionModel(4, gfx::CURSOR_BACKWARD); |
| 1604 EXPECT_EQ(bound.x(), GetCursorBounds(sel).x()); |
| 1605 cursor_bounds.push_back(bound); |
| 1606 |
| 1607 sel = gfx::SelectionModel(3, gfx::CURSOR_BACKWARD); |
| 1608 bound = GetCursorBounds(sel); |
| 1609 sel = gfx::SelectionModel(3, gfx::CURSOR_FORWARD); |
| 1610 EXPECT_EQ(bound.x(), GetCursorBounds(sel).x()); |
| 1611 cursor_bounds.push_back(bound); |
| 1612 |
| 1613 sel = gfx::SelectionModel(2, gfx::CURSOR_FORWARD); |
| 1614 bound = GetCursorBounds(sel); |
| 1615 sel = gfx::SelectionModel(4, gfx::CURSOR_FORWARD); |
| 1616 EXPECT_EQ(bound.x(), GetCursorBounds(sel).x()); |
| 1617 cursor_bounds.push_back(bound); |
| 1618 |
| 1619 // Expected cursor position when clicking left and right of each character. |
| 1620 size_t cursor_pos_expected[] = {0, 1, 1, 2, 4, 3, 3, 2}; |
| 1621 |
| 1622 int index = 0; |
| 1623 for (int i = 0; i < static_cast<int>(cursor_bounds.size() - 1); ++i) { |
| 1624 int half_width = (cursor_bounds[i + 1].x() - cursor_bounds[i].x()) / 2; |
| 1625 MouseClick(cursor_bounds[i], half_width / 2); |
| 1626 EXPECT_EQ(cursor_pos_expected[index++], textfield_->GetCursorPosition()); |
| 1627 |
| 1628 // To avoid trigger double click. Not using sleep() since it takes longer |
| 1629 // for the test to run if using sleep(). |
| 1630 NonClientMouseClick(); |
| 1631 |
| 1632 MouseClick(cursor_bounds[i + 1], - (half_width / 2)); |
| 1633 EXPECT_EQ(cursor_pos_expected[index++], textfield_->GetCursorPosition()); |
| 1634 |
| 1635 NonClientMouseClick(); |
| 1636 } |
| 1637 } |
| 1638 |
| 1639 TEST_F(NativeTextfieldViewsTest, HitOutsideTextAreaTest) { |
| 1640 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1641 |
| 1642 // LTR-RTL string in LTR context. |
| 1643 textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2")); |
| 1644 |
| 1645 SendKeyEvent(ui::VKEY_HOME); |
| 1646 gfx::Rect bound = GetCursorBounds(); |
| 1647 MouseClick(bound, -10); |
| 1648 EXPECT_EQ(bound, GetCursorBounds()); |
| 1649 |
| 1650 SendKeyEvent(ui::VKEY_END); |
| 1651 bound = GetCursorBounds(); |
| 1652 MouseClick(bound, 10); |
| 1653 EXPECT_EQ(bound, GetCursorBounds()); |
| 1654 |
| 1655 NonClientMouseClick(); |
| 1656 |
| 1657 // RTL-LTR string in LTR context. |
| 1658 textfield_->SetText(WideToUTF16(L"\x05E1\x5E2" L"ab")); |
| 1659 |
| 1660 SendKeyEvent(ui::VKEY_HOME); |
| 1661 bound = GetCursorBounds(); |
| 1662 MouseClick(bound, 10); |
| 1663 EXPECT_EQ(bound, GetCursorBounds()); |
| 1664 |
| 1665 SendKeyEvent(ui::VKEY_END); |
| 1666 bound = GetCursorBounds(); |
| 1667 MouseClick(bound, -10); |
| 1668 EXPECT_EQ(bound, GetCursorBounds()); |
| 1669 } |
| 1670 |
| 1671 TEST_F(NativeTextfieldViewsTest, HitOutsideTextAreaInRTLTest) { |
| 1672 std::string locale = l10n_util::GetApplicationLocale(""); |
| 1673 base::i18n::SetICUDefaultLocale("he"); |
| 1674 |
| 1675 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1676 |
| 1677 // RTL-LTR string in RTL context. |
| 1678 textfield_->SetText(WideToUTF16(L"\x05E1\x5E2" L"ab")); |
| 1679 SendKeyEvent(ui::VKEY_HOME); |
| 1680 gfx::Rect bound = GetCursorBounds(); |
| 1681 MouseClick(bound, 10); |
| 1682 EXPECT_EQ(bound, GetCursorBounds()); |
| 1683 |
| 1684 SendKeyEvent(ui::VKEY_END); |
| 1685 bound = GetCursorBounds(); |
| 1686 MouseClick(bound, -10); |
| 1687 EXPECT_EQ(bound, GetCursorBounds()); |
| 1688 |
| 1689 NonClientMouseClick(); |
| 1690 |
| 1691 // LTR-RTL string in RTL context. |
| 1692 textfield_->SetText(WideToUTF16(L"ab\x05E1\x5E2")); |
| 1693 SendKeyEvent(ui::VKEY_HOME); |
| 1694 bound = GetCursorBounds(); |
| 1695 MouseClick(bound, -10); |
| 1696 EXPECT_EQ(bound, GetCursorBounds()); |
| 1697 |
| 1698 SendKeyEvent(ui::VKEY_END); |
| 1699 bound = GetCursorBounds(); |
| 1700 MouseClick(bound, 10); |
| 1701 EXPECT_EQ(bound, GetCursorBounds()); |
| 1702 |
| 1703 // Reset locale. |
| 1704 base::i18n::SetICUDefaultLocale(locale); |
| 1705 } |
| 1706 |
| 1707 TEST_F(NativeTextfieldViewsTest, OverflowTest) { |
| 1708 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1709 |
| 1710 base::string16 str; |
| 1711 for (int i = 0; i < 500; ++i) |
| 1712 SendKeyEvent('a'); |
| 1713 SendKeyEvent(kHebrewLetterSamekh); |
| 1714 EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds())); |
| 1715 |
| 1716 // Test mouse pointing. |
| 1717 MouseClick(GetCursorBounds(), -1); |
| 1718 EXPECT_EQ(500U, textfield_->GetCursorPosition()); |
| 1719 |
| 1720 // Clear text. |
| 1721 SendKeyEvent(ui::VKEY_A, false, true); |
| 1722 SendKeyEvent('\n'); |
| 1723 |
| 1724 for (int i = 0; i < 500; ++i) |
| 1725 SendKeyEvent(kHebrewLetterSamekh); |
| 1726 SendKeyEvent('a'); |
| 1727 EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds())); |
| 1728 |
| 1729 MouseClick(GetCursorBounds(), -1); |
| 1730 EXPECT_EQ(501U, textfield_->GetCursorPosition()); |
| 1731 } |
| 1732 |
| 1733 TEST_F(NativeTextfieldViewsTest, OverflowInRTLTest) { |
| 1734 std::string locale = l10n_util::GetApplicationLocale(""); |
| 1735 base::i18n::SetICUDefaultLocale("he"); |
| 1736 |
| 1737 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1738 |
| 1739 base::string16 str; |
| 1740 for (int i = 0; i < 500; ++i) |
| 1741 SendKeyEvent('a'); |
| 1742 SendKeyEvent(kHebrewLetterSamekh); |
| 1743 EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds())); |
| 1744 |
| 1745 MouseClick(GetCursorBounds(), 1); |
| 1746 EXPECT_EQ(501U, textfield_->GetCursorPosition()); |
| 1747 |
| 1748 // Clear text. |
| 1749 SendKeyEvent(ui::VKEY_A, false, true); |
| 1750 SendKeyEvent('\n'); |
| 1751 |
| 1752 for (int i = 0; i < 500; ++i) |
| 1753 SendKeyEvent(kHebrewLetterSamekh); |
| 1754 SendKeyEvent('a'); |
| 1755 EXPECT_TRUE(GetDisplayRect().Contains(GetCursorBounds())); |
| 1756 |
| 1757 MouseClick(GetCursorBounds(), 1); |
| 1758 EXPECT_EQ(500U, textfield_->GetCursorPosition()); |
| 1759 |
| 1760 // Reset locale. |
| 1761 base::i18n::SetICUDefaultLocale(locale); |
| 1762 } |
| 1763 |
| 1764 TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBoundsTest) { |
| 1765 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1766 |
| 1767 base::string16 str; |
| 1768 const uint32 char_count = 10UL; |
| 1769 ui::CompositionText composition; |
| 1770 composition.text = UTF8ToUTF16("0123456789"); |
| 1771 ui::TextInputClient* client = textfield_->GetTextInputClient(); |
| 1772 |
| 1773 // Return false if there is no composition text. |
| 1774 gfx::Rect rect; |
| 1775 EXPECT_FALSE(client->GetCompositionCharacterBounds(0, &rect)); |
| 1776 |
| 1777 // Get each character boundary by cursor. |
| 1778 gfx::Rect char_rect_in_screen_coord[char_count]; |
| 1779 gfx::Rect prev_cursor = GetCursorBounds(); |
| 1780 for (uint32 i = 0; i < char_count; ++i) { |
| 1781 composition.selection = gfx::Range(0, i+1); |
| 1782 client->SetCompositionText(composition); |
| 1783 EXPECT_TRUE(client->HasCompositionText()) << " i=" << i; |
| 1784 gfx::Rect cursor_bounds = GetCursorBounds(); |
| 1785 gfx::Point top_left(prev_cursor.x(), prev_cursor.y()); |
| 1786 gfx::Point bottom_right(cursor_bounds.x(), prev_cursor.bottom()); |
| 1787 views::View::ConvertPointToScreen(textfield_view_, &top_left); |
| 1788 views::View::ConvertPointToScreen(textfield_view_, &bottom_right); |
| 1789 char_rect_in_screen_coord[i].set_origin(top_left); |
| 1790 char_rect_in_screen_coord[i].set_width(bottom_right.x() - top_left.x()); |
| 1791 char_rect_in_screen_coord[i].set_height(bottom_right.y() - top_left.y()); |
| 1792 prev_cursor = cursor_bounds; |
| 1793 } |
| 1794 |
| 1795 for (uint32 i = 0; i < char_count; ++i) { |
| 1796 gfx::Rect actual_rect; |
| 1797 EXPECT_TRUE(client->GetCompositionCharacterBounds(i, &actual_rect)) |
| 1798 << " i=" << i; |
| 1799 EXPECT_EQ(char_rect_in_screen_coord[i], actual_rect) << " i=" << i; |
| 1800 } |
| 1801 |
| 1802 // Return false if the index is out of range. |
| 1803 EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count, &rect)); |
| 1804 EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 1, &rect)); |
| 1805 EXPECT_FALSE(client->GetCompositionCharacterBounds(char_count + 100, &rect)); |
| 1806 } |
| 1807 |
| 1808 TEST_F(NativeTextfieldViewsTest, GetCompositionCharacterBounds_ComplexText) { |
| 1809 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1810 |
| 1811 const base::char16 kUtf16Chars[] = { |
| 1812 // U+0020 SPACE |
| 1813 0x0020, |
| 1814 // U+1F408 (CAT) as surrogate pair |
| 1815 0xd83d, 0xdc08, |
| 1816 // U+5642 as Ideographic Variation Sequences |
| 1817 0x5642, 0xDB40, 0xDD00, |
| 1818 // U+260E (BLACK TELEPHONE) as Emoji Variation Sequences |
| 1819 0x260E, 0xFE0F, |
| 1820 // U+0020 SPACE |
| 1821 0x0020, |
| 1822 }; |
| 1823 const size_t kUtf16CharsCount = arraysize(kUtf16Chars); |
| 1824 |
| 1825 ui::CompositionText composition; |
| 1826 composition.text.assign(kUtf16Chars, kUtf16Chars + kUtf16CharsCount); |
| 1827 ui::TextInputClient* client = textfield_->GetTextInputClient(); |
| 1828 client->SetCompositionText(composition); |
| 1829 |
| 1830 // Make sure GetCompositionCharacterBounds never fails for index. |
| 1831 gfx::Rect rects[kUtf16CharsCount]; |
| 1832 gfx::Rect prev_cursor = GetCursorBounds(); |
| 1833 for (uint32 i = 0; i < kUtf16CharsCount; ++i) |
| 1834 EXPECT_TRUE(client->GetCompositionCharacterBounds(i, &rects[i])); |
| 1835 |
| 1836 // Here we might expect the following results but it actually depends on how |
| 1837 // Uniscribe or HarfBuzz treats them with given font. |
| 1838 // - rects[1] == rects[2] |
| 1839 // - rects[3] == rects[4] == rects[5] |
| 1840 // - rects[6] == rects[7] |
| 1841 } |
| 1842 |
| 1843 // The word we select by double clicking should remain selected regardless of |
| 1844 // where we drag the mouse afterwards without releasing the left button. |
| 1845 TEST_F(NativeTextfieldViewsTest, KeepInitiallySelectedWord) { |
| 1846 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1847 |
| 1848 textfield_->SetText(ASCIIToUTF16("abc def ghi")); |
| 1849 |
| 1850 textfield_->SelectRange(gfx::Range(5, 5)); |
| 1851 const gfx::Rect middle_cursor = GetCursorBounds(); |
| 1852 textfield_->SelectRange(gfx::Range(0, 0)); |
| 1853 const gfx::Point beginning = GetCursorBounds().origin(); |
| 1854 |
| 1855 // Double click, but do not release the left button. |
| 1856 MouseClick(middle_cursor, 0); |
| 1857 const gfx::Point middle(middle_cursor.x(), |
| 1858 middle_cursor.y() + middle_cursor.height() / 2); |
| 1859 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, middle, middle, |
| 1860 ui::EF_LEFT_MOUSE_BUTTON, |
| 1861 ui::EF_LEFT_MOUSE_BUTTON); |
| 1862 textfield_view_->OnMousePressed(press_event); |
| 1863 EXPECT_EQ(gfx::Range(4, 7), textfield_->GetSelectedRange()); |
| 1864 |
| 1865 // Drag the mouse to the beginning of the textfield. |
| 1866 ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, beginning, beginning, |
| 1867 ui::EF_LEFT_MOUSE_BUTTON, 0); |
| 1868 textfield_view_->OnMouseDragged(drag_event); |
| 1869 EXPECT_EQ(gfx::Range(7, 0), textfield_->GetSelectedRange()); |
| 1870 } |
| 1871 |
| 1872 // Touch selection and draggin currently only works for chromeos. |
| 1873 #if defined(OS_CHROMEOS) |
| 1874 TEST_F(NativeTextfieldViewsTest, TouchSelectionAndDraggingTest) { |
| 1875 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1876 textfield_->SetText(ASCIIToUTF16("hello world")); |
| 1877 EXPECT_FALSE(GetTouchSelectionController()); |
| 1878 const int eventX = GetCursorPositionX(2); |
| 1879 const int eventY = 0; |
| 1880 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing); |
| 1881 |
| 1882 // Tapping on the textfield should turn on the TouchSelectionController. |
| 1883 GestureEventForTest tap(ui::ET_GESTURE_TAP, eventX, eventY, 1.0f, 0.0f); |
| 1884 textfield_view_->OnGestureEvent(&tap); |
| 1885 EXPECT_TRUE(GetTouchSelectionController()); |
| 1886 |
| 1887 // Un-focusing the textfield should reset the TouchSelectionController |
| 1888 textfield_view_->GetFocusManager()->ClearFocus(); |
| 1889 EXPECT_FALSE(GetTouchSelectionController()); |
| 1890 |
| 1891 // With touch editing enabled, long press should not show context menu. |
| 1892 // Instead, select word and invoke TouchSelectionController. |
| 1893 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, eventX, eventY, 0.0f, |
| 1894 0.0f); |
| 1895 textfield_view_->OnGestureEvent(&tap_down); |
| 1896 GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, eventX, eventY, |
| 1897 0.0f, 0.0f); |
| 1898 textfield_view_->OnGestureEvent(&long_press); |
| 1899 EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); |
| 1900 EXPECT_TRUE(GetTouchSelectionController()); |
| 1901 |
| 1902 // Long pressing again in the selecting region should not do anything since |
| 1903 // touch drag drop is not yet enabled. |
| 1904 textfield_view_->OnGestureEvent(&tap_down); |
| 1905 textfield_view_->OnGestureEvent(&long_press); |
| 1906 EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); |
| 1907 EXPECT_TRUE(GetTouchSelectionController()); |
| 1908 EXPECT_TRUE(long_press.handled()); |
| 1909 |
| 1910 // After enabling touch drag drop, long pressing in the selected region should |
| 1911 // start a drag and remove TouchSelectionController. |
| 1912 CommandLine::ForCurrentProcess()->AppendSwitch( |
| 1913 switches::kEnableTouchDragDrop); |
| 1914 textfield_view_->OnGestureEvent(&tap_down); |
| 1915 |
| 1916 // Create a new long press event since the previous one is not marked handled. |
| 1917 GestureEventForTest long_press2(ui::ET_GESTURE_LONG_PRESS, eventX, eventY, |
| 1918 0.0f, 0.0f); |
| 1919 textfield_view_->OnGestureEvent(&long_press2); |
| 1920 EXPECT_STR_EQ("hello", textfield_->GetSelectedText()); |
| 1921 EXPECT_FALSE(GetTouchSelectionController()); |
| 1922 } |
| 1923 |
| 1924 TEST_F(NativeTextfieldViewsTest, TouchScrubbingSelection) { |
| 1925 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1926 textfield_->SetText(ASCIIToUTF16("hello world")); |
| 1927 EXPECT_FALSE(GetTouchSelectionController()); |
| 1928 |
| 1929 CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing); |
| 1930 |
| 1931 // Simulate touch-scrubbing. |
| 1932 int scrubbing_start = GetCursorPositionX(1); |
| 1933 int scrubbing_end = GetCursorPositionX(6); |
| 1934 |
| 1935 GestureEventForTest tap_down(ui::ET_GESTURE_TAP_DOWN, scrubbing_start, 0, |
| 1936 0.0f, 0.0f); |
| 1937 textfield_view_->OnGestureEvent(&tap_down); |
| 1938 |
| 1939 GestureEventForTest tap_cancel(ui::ET_GESTURE_TAP_CANCEL, scrubbing_start, 0, |
| 1940 0.0f, 0.0f); |
| 1941 textfield_view_->OnGestureEvent(&tap_cancel); |
| 1942 |
| 1943 GestureEventForTest scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, scrubbing_start, |
| 1944 0, 0.0f, 0.0f); |
| 1945 textfield_view_->OnGestureEvent(&scroll_begin); |
| 1946 |
| 1947 GestureEventForTest scroll_update(ui::ET_GESTURE_SCROLL_UPDATE, scrubbing_end, |
| 1948 0, scrubbing_end - scrubbing_start, 0.0f); |
| 1949 textfield_view_->OnGestureEvent(&scroll_update); |
| 1950 |
| 1951 GestureEventForTest scroll_end(ui::ET_GESTURE_SCROLL_END, scrubbing_end, 0, |
| 1952 0.0f, 0.0f); |
| 1953 textfield_view_->OnGestureEvent(&scroll_end); |
| 1954 |
| 1955 GestureEventForTest end(ui::ET_GESTURE_END, scrubbing_end, 0, 0.0f, 0.0f); |
| 1956 textfield_view_->OnGestureEvent(&end); |
| 1957 |
| 1958 // In the end, part of text should have been selected and handles should have |
| 1959 // appeared. |
| 1960 EXPECT_STR_EQ("ello ", textfield_->GetSelectedText()); |
| 1961 EXPECT_TRUE(GetTouchSelectionController()); |
| 1962 } |
| 1963 #endif |
| 1964 |
| 1965 // Long_Press gesture in NativeTextfieldViews can initiate a drag and drop now. |
| 1966 TEST_F(NativeTextfieldViewsTest, TestLongPressInitiatesDragDrop) { |
| 1967 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1968 textfield_->SetText(ASCIIToUTF16("Hello string world")); |
| 1969 |
| 1970 // Ensure the textfield will provide selected text for drag data. |
| 1971 textfield_->SelectRange(gfx::Range(6, 12)); |
| 1972 const gfx::Point kStringPoint(GetCursorPositionX(9), 0); |
| 1973 |
| 1974 // Enable touch-drag-drop to make long press effective. |
| 1975 CommandLine::ForCurrentProcess()->AppendSwitch( |
| 1976 switches::kEnableTouchDragDrop); |
| 1977 |
| 1978 // Create a long press event in the selected region should start a drag. |
| 1979 GestureEventForTest long_press(ui::ET_GESTURE_LONG_PRESS, kStringPoint.x(), |
| 1980 kStringPoint.y(), 0.0f, 0.0f); |
| 1981 textfield_view_->OnGestureEvent(&long_press); |
| 1982 EXPECT_TRUE(textfield_view_->CanStartDragForView(NULL, |
| 1983 kStringPoint, kStringPoint)); |
| 1984 } |
| 1985 |
| 1986 TEST_F(NativeTextfieldViewsTest, GetTextfieldBaseline_FontFallbackTest) { |
| 1987 InitTextfield(Textfield::STYLE_DEFAULT); |
| 1988 textfield_->SetText(UTF8ToUTF16("abc")); |
| 1989 const int old_baseline = textfield_->GetBaseline(); |
| 1990 |
| 1991 // Set text which may fall back to a font which has taller baseline than |
| 1992 // the default font. |
| 1993 textfield_->SetText(UTF8ToUTF16("\xE0\xB9\x91")); |
| 1994 const int new_baseline = textfield_->GetBaseline(); |
| 1995 |
| 1996 // Regardless of the text, the baseline must be the same. |
| 1997 EXPECT_EQ(new_baseline, old_baseline); |
| 1998 } |
| 1999 |
| 2000 } // namespace views |
OLD | NEW |