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 "base/basictypes.h" 6 #include "base/bind.h" 7 #include "base/callback.h" 8 #include "base/memory/shared_memory.h" 9 #include "base/strings/string_util.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "base/win/windows_version.h" 12 #include "content/child/request_extra_data.h" 13 #include "content/child/service_worker/service_worker_network_provider.h" 14 #include "content/common/frame_messages.h" 15 #include "content/common/ssl_status_serialization.h" 16 #include "content/common/view_messages.h" 17 #include "content/public/browser/browser_context.h" 18 #include "content/public/browser/native_web_keyboard_event.h" 19 #include "content/public/browser/web_ui_controller_factory.h" 20 #include "content/public/common/bindings_policy.h" 21 #include "content/public/common/page_zoom.h" 22 #include "content/public/common/url_constants.h" 23 #include "content/public/common/url_utils.h" 24 #include "content/public/renderer/content_renderer_client.h" 25 #include "content/public/renderer/document_state.h" 26 #include "content/public/renderer/navigation_state.h" 27 #include "content/public/test/browser_test_utils.h" 28 #include "content/public/test/render_view_test.h" 29 #include "content/public/test/test_utils.h" 30 #include "content/renderer/accessibility/renderer_accessibility.h" 31 #include "content/renderer/accessibility/renderer_accessibility_complete.h" 32 #include "content/renderer/accessibility/renderer_accessibility_focus_only.h" 33 #include "content/renderer/history_controller.h" 34 #include "content/renderer/history_serialization.h" 35 #include "content/renderer/render_view_impl.h" 36 #include "content/shell/browser/shell.h" 37 #include "content/shell/browser/shell_browser_context.h" 38 #include "content/test/frame_load_waiter.h" 39 #include "content/test/mock_keyboard.h" 40 #include "net/base/net_errors.h" 41 #include "net/cert/cert_status_flags.h" 42 #include "testing/gtest/include/gtest/gtest.h" 43 #include "third_party/WebKit/public/platform/WebData.h" 44 #include "third_party/WebKit/public/platform/WebHTTPBody.h" 45 #include "third_party/WebKit/public/platform/WebString.h" 46 #include "third_party/WebKit/public/platform/WebURLResponse.h" 47 #include "third_party/WebKit/public/web/WebDataSource.h" 48 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h" 49 #include "third_party/WebKit/public/web/WebHistoryItem.h" 50 #include "third_party/WebKit/public/web/WebLocalFrame.h" 51 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h" 52 #include "third_party/WebKit/public/web/WebView.h" 53 #include "third_party/WebKit/public/web/WebWindowFeatures.h" 54 #include "ui/events/keycodes/keyboard_codes.h" 55 #include "ui/gfx/codec/jpeg_codec.h" 56 #include "ui/gfx/range/range.h" 57 58 #if defined(USE_AURA) 59 #include "ui/events/event.h" 60 #endif 61 62 #if defined(USE_AURA) && defined(USE_X11) 63 #include <X11/Xlib.h> 64 #include "ui/events/event_constants.h" 65 #include "ui/events/keycodes/keyboard_code_conversion.h" 66 #include "ui/events/test/events_test_utils_x11.h" 67 #endif 68 69 #if defined(USE_OZONE) 70 #include "ui/events/keycodes/keyboard_code_conversion.h" 71 #endif 72 73 using blink::WebFrame; 74 using blink::WebInputEvent; 75 using blink::WebLocalFrame; 76 using blink::WebMouseEvent; 77 using blink::WebRuntimeFeatures; 78 using blink::WebString; 79 using blink::WebTextDirection; 80 using blink::WebURLError; 81 82 namespace content { 83 84 namespace { 85 86 static const int kProxyRoutingId = 13; 87 88 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE) 89 // Converts MockKeyboard::Modifiers to ui::EventFlags. 90 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers) { 91 static struct ModifierMap { 92 MockKeyboard::Modifiers src; 93 int dst; 94 } kModifierMap[] = { 95 { MockKeyboard::LEFT_SHIFT, ui::EF_SHIFT_DOWN }, 96 { MockKeyboard::RIGHT_SHIFT, ui::EF_SHIFT_DOWN }, 97 { MockKeyboard::LEFT_CONTROL, ui::EF_CONTROL_DOWN }, 98 { MockKeyboard::RIGHT_CONTROL, ui::EF_CONTROL_DOWN }, 99 { MockKeyboard::LEFT_ALT, ui::EF_ALT_DOWN }, 100 { MockKeyboard::RIGHT_ALT, ui::EF_ALT_DOWN }, 101 }; 102 int flags = 0; 103 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kModifierMap); ++i) { 104 if (kModifierMap[i].src & modifiers) { 105 flags |= kModifierMap[i].dst; 106 } 107 } 108 return flags; 109 } 110 #endif 111 112 class WebUITestWebUIControllerFactory : public WebUIControllerFactory { 113 public: 114 virtual WebUIController* CreateWebUIControllerForURL( 115 WebUI* web_ui, const GURL& url) const OVERRIDE { 116 return NULL; 117 } 118 virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context, 119 const GURL& url) const OVERRIDE { 120 return WebUI::kNoWebUI; 121 } 122 virtual bool UseWebUIForURL(BrowserContext* browser_context, 123 const GURL& url) const OVERRIDE { 124 return HasWebUIScheme(url); 125 } 126 virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context, 127 const GURL& url) const OVERRIDE { 128 return HasWebUIScheme(url); 129 } 130 }; 131 132 class RenderViewImplTest : public RenderViewTest { 133 public: 134 RenderViewImplTest() { 135 // Attach a pseudo keyboard device to this object. 136 mock_keyboard_.reset(new MockKeyboard()); 137 } 138 139 virtual ~RenderViewImplTest() {} 140 141 virtual void SetUp() OVERRIDE { 142 RenderViewTest::SetUp(); 143 // Enable Blink's experimental and test only features so that test code 144 // does not have to bother enabling each feature. 145 WebRuntimeFeatures::enableExperimentalFeatures(true); 146 WebRuntimeFeatures::enableTestOnlyFeatures(true); 147 } 148 149 RenderViewImpl* view() { 150 return static_cast<RenderViewImpl*>(view_); 151 } 152 153 RenderFrameImpl* frame() { 154 return static_cast<RenderFrameImpl*>(view()->GetMainRenderFrame()); 155 } 156 157 // Sends IPC messages that emulates a key-press event. 158 int SendKeyEvent(MockKeyboard::Layout layout, 159 int key_code, 160 MockKeyboard::Modifiers modifiers, 161 base::string16* output) { 162 #if defined(OS_WIN) 163 // Retrieve the Unicode character for the given tuple (keyboard-layout, 164 // key-code, and modifiers). 165 // Exit when a keyboard-layout driver cannot assign a Unicode character to 166 // the tuple to prevent sending an invalid key code to the RenderView 167 // object. 168 CHECK(mock_keyboard_.get()); 169 CHECK(output); 170 int length = mock_keyboard_->GetCharacters(layout, key_code, modifiers, 171 output); 172 if (length != 1) 173 return -1; 174 175 // Create IPC messages from Windows messages and send them to our 176 // back-end. 177 // A keyboard event of Windows consists of three Windows messages: 178 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP. 179 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand, 180 // WM_CHAR sends a composed Unicode character. 181 MSG msg1 = { NULL, WM_KEYDOWN, key_code, 0 }; 182 #if defined(USE_AURA) 183 ui::KeyEvent evt1(msg1, false); 184 NativeWebKeyboardEvent keydown_event(&evt1); 185 #else 186 NativeWebKeyboardEvent keydown_event(msg1); 187 #endif 188 SendNativeKeyEvent(keydown_event); 189 190 MSG msg2 = { NULL, WM_CHAR, (*output)[0], 0 }; 191 #if defined(USE_AURA) 192 ui::KeyEvent evt2(msg2, true); 193 NativeWebKeyboardEvent char_event(&evt2); 194 #else 195 NativeWebKeyboardEvent char_event(msg2); 196 #endif 197 SendNativeKeyEvent(char_event); 198 199 MSG msg3 = { NULL, WM_KEYUP, key_code, 0 }; 200 #if defined(USE_AURA) 201 ui::KeyEvent evt3(msg3, false); 202 NativeWebKeyboardEvent keyup_event(&evt3); 203 #else 204 NativeWebKeyboardEvent keyup_event(msg3); 205 #endif 206 SendNativeKeyEvent(keyup_event); 207 208 return length; 209 #elif defined(USE_AURA) && defined(USE_X11) 210 // We ignore |layout|, which means we are only testing the layout of the 211 // current locale. TODO(mazda): fix this to respect |layout|. 212 CHECK(output); 213 const int flags = ConvertMockKeyboardModifier(modifiers); 214 215 ui::ScopedXI2Event xevent; 216 xevent.InitKeyEvent(ui::ET_KEY_PRESSED, 217 static_cast<ui::KeyboardCode>(key_code), 218 flags); 219 ui::KeyEvent event1(xevent, false); 220 NativeWebKeyboardEvent keydown_event(&event1); 221 SendNativeKeyEvent(keydown_event); 222 223 xevent.InitKeyEvent(ui::ET_KEY_PRESSED, 224 static_cast<ui::KeyboardCode>(key_code), 225 flags); 226 ui::KeyEvent event2(xevent, true); 227 NativeWebKeyboardEvent char_event(&event2); 228 SendNativeKeyEvent(char_event); 229 230 xevent.InitKeyEvent(ui::ET_KEY_RELEASED, 231 static_cast<ui::KeyboardCode>(key_code), 232 flags); 233 ui::KeyEvent event3(xevent, false); 234 NativeWebKeyboardEvent keyup_event(&event3); 235 SendNativeKeyEvent(keyup_event); 236 237 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code), 238 flags); 239 output->assign(1, static_cast<base::char16>(c)); 240 return 1; 241 #elif defined(USE_OZONE) 242 const int flags = ConvertMockKeyboardModifier(modifiers); 243 244 // Ozone's native events are ui::Events. So first create the "native" event, 245 // then create the actual ui::KeyEvent with the native event. 246 ui::KeyEvent keydown_native_event(ui::ET_KEY_PRESSED, 247 static_cast<ui::KeyboardCode>(key_code), 248 flags, 249 true); 250 ui::KeyEvent keydown_event(&keydown_native_event, false); 251 NativeWebKeyboardEvent keydown_web_event(&keydown_event); 252 SendNativeKeyEvent(keydown_web_event); 253 254 ui::KeyEvent char_native_event(ui::ET_KEY_PRESSED, 255 static_cast<ui::KeyboardCode>(key_code), 256 flags, 257 true); 258 ui::KeyEvent char_event(&char_native_event, true); 259 NativeWebKeyboardEvent char_web_event(&char_event); 260 SendNativeKeyEvent(char_web_event); 261 262 ui::KeyEvent keyup_native_event(ui::ET_KEY_RELEASED, 263 static_cast<ui::KeyboardCode>(key_code), 264 flags, 265 true); 266 ui::KeyEvent keyup_event(&keyup_native_event, false); 267 NativeWebKeyboardEvent keyup_web_event(&keyup_event); 268 SendNativeKeyEvent(keyup_web_event); 269 270 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code), 271 flags); 272 output->assign(1, static_cast<base::char16>(c)); 273 return 1; 274 #else 275 NOTIMPLEMENTED(); 276 return L'\0'; 277 #endif 278 } 279 280 private: 281 scoped_ptr<MockKeyboard> mock_keyboard_; 282 }; 283 284 } // namespace 285 286 // Test that we get form state change notifications when input fields change. 287 TEST_F(RenderViewImplTest, DISABLED_OnNavStateChanged) { 288 // Don't want any delay for form state sync changes. This will still post a 289 // message so updates will get coalesced, but as soon as we spin the message 290 // loop, it will generate an update. 291 view()->set_send_content_state_immediately(true); 292 293 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>"); 294 295 // We should NOT have gotten a form state change notification yet. 296 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching( 297 ViewHostMsg_UpdateState::ID)); 298 render_thread_->sink().ClearMessages(); 299 300 // Change the value of the input. We should have gotten an update state 301 // notification. We need to spin the message loop to catch this update. 302 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';"); 303 ProcessPendingMessages(); 304 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching( 305 ViewHostMsg_UpdateState::ID)); 306 } 307 308 TEST_F(RenderViewImplTest, OnNavigationHttpPost) { 309 FrameMsg_Navigate_Params nav_params; 310 311 // An http url will trigger a resource load so cannot be used here. 312 nav_params.url = GURL("data:text/html,<div>Page</div>"); 313 nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL; 314 nav_params.transition = PAGE_TRANSITION_TYPED; 315 nav_params.page_id = -1; 316 nav_params.is_post = true; 317 318 // Set up post data. 319 const unsigned char* raw_data = reinterpret_cast<const unsigned char*>( 320 "post \0\ndata"); 321 const unsigned int length = 11; 322 const std::vector<unsigned char> post_data(raw_data, raw_data + length); 323 nav_params.browser_initiated_post_data = post_data; 324 325 frame()->OnNavigate(nav_params); 326 ProcessPendingMessages(); 327 328 const IPC::Message* frame_navigate_msg = 329 render_thread_->sink().GetUniqueMessageMatching( 330 FrameHostMsg_DidCommitProvisionalLoad::ID); 331 EXPECT_TRUE(frame_navigate_msg); 332 333 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params; 334 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg, 335 &host_nav_params); 336 EXPECT_TRUE(host_nav_params.a.is_post); 337 338 // Check post data sent to browser matches 339 EXPECT_TRUE(host_nav_params.a.page_state.IsValid()); 340 scoped_ptr<HistoryEntry> entry = 341 PageStateToHistoryEntry(host_nav_params.a.page_state); 342 blink::WebHTTPBody body = entry->root().httpBody(); 343 blink::WebHTTPBody::Element element; 344 bool successful = body.elementAt(0, element); 345 EXPECT_TRUE(successful); 346 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData, element.type); 347 EXPECT_EQ(length, element.data.size()); 348 EXPECT_EQ(0, memcmp(raw_data, element.data.data(), length)); 349 } 350 351 TEST_F(RenderViewImplTest, DecideNavigationPolicy) { 352 WebUITestWebUIControllerFactory factory; 353 WebUIControllerFactory::RegisterFactory(&factory); 354 355 DocumentState state; 356 state.set_navigation_state(NavigationState::CreateContentInitiated()); 357 358 // Navigations to normal HTTP URLs can be handled locally. 359 blink::WebURLRequest request(GURL("http://foo.com")); 360 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation( 361 GetMainFrame(), 362 &state, 363 request, 364 blink::WebNavigationTypeLinkClicked, 365 blink::WebNavigationPolicyCurrentTab, 366 false); 367 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab, policy); 368 369 // Verify that form posts to WebUI URLs will be sent to the browser process. 370 blink::WebURLRequest form_request(GURL("chrome://foo")); 371 form_request.setHTTPMethod("POST"); 372 policy = frame()->decidePolicyForNavigation( 373 GetMainFrame(), 374 &state, 375 form_request, 376 blink::WebNavigationTypeFormSubmitted, 377 blink::WebNavigationPolicyCurrentTab, 378 false); 379 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy); 380 381 // Verify that popup links to WebUI URLs also are sent to browser. 382 blink::WebURLRequest popup_request(GURL("chrome://foo")); 383 policy = frame()->decidePolicyForNavigation( 384 GetMainFrame(), 385 &state, 386 popup_request, 387 blink::WebNavigationTypeLinkClicked, 388 blink::WebNavigationPolicyNewForegroundTab, 389 false); 390 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy); 391 } 392 393 TEST_F(RenderViewImplTest, DecideNavigationPolicyHandlesAllTopLevel) { 394 DocumentState state; 395 state.set_navigation_state(NavigationState::CreateContentInitiated()); 396 397 RendererPreferences prefs = view()->renderer_preferences(); 398 prefs.browser_handles_all_top_level_requests = true; 399 view()->OnSetRendererPrefs(prefs); 400 401 const blink::WebNavigationType kNavTypes[] = { 402 blink::WebNavigationTypeLinkClicked, 403 blink::WebNavigationTypeFormSubmitted, 404 blink::WebNavigationTypeBackForward, 405 blink::WebNavigationTypeReload, 406 blink::WebNavigationTypeFormResubmitted, 407 blink::WebNavigationTypeOther, 408 }; 409 410 blink::WebURLRequest request(GURL("http://foo.com")); 411 for (size_t i = 0; i < arraysize(kNavTypes); ++i) { 412 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation( 413 GetMainFrame(), 414 &state, 415 request, 416 kNavTypes[i], 417 blink::WebNavigationPolicyCurrentTab, 418 false); 419 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy); 420 } 421 } 422 423 TEST_F(RenderViewImplTest, DecideNavigationPolicyForWebUI) { 424 // Enable bindings to simulate a WebUI view. 425 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI); 426 427 DocumentState state; 428 state.set_navigation_state(NavigationState::CreateContentInitiated()); 429 430 // Navigations to normal HTTP URLs will be sent to browser process. 431 blink::WebURLRequest request(GURL("http://foo.com")); 432 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation( 433 GetMainFrame(), 434 &state, 435 request, 436 blink::WebNavigationTypeLinkClicked, 437 blink::WebNavigationPolicyCurrentTab, 438 false); 439 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy); 440 441 // Navigations to WebUI URLs will also be sent to browser process. 442 blink::WebURLRequest webui_request(GURL("chrome://foo")); 443 policy = frame()->decidePolicyForNavigation( 444 GetMainFrame(), 445 &state, 446 webui_request, 447 blink::WebNavigationTypeLinkClicked, 448 blink::WebNavigationPolicyCurrentTab, 449 false); 450 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy); 451 452 // Verify that form posts to data URLs will be sent to the browser process. 453 blink::WebURLRequest data_request(GURL("data:text/html,foo")); 454 data_request.setHTTPMethod("POST"); 455 policy = frame()->decidePolicyForNavigation( 456 GetMainFrame(), 457 &state, 458 data_request, 459 blink::WebNavigationTypeFormSubmitted, 460 blink::WebNavigationPolicyCurrentTab, 461 false); 462 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy); 463 464 // Verify that a popup that creates a view first and then navigates to a 465 // normal HTTP URL will be sent to the browser process, even though the 466 // new view does not have any enabled_bindings_. 467 blink::WebURLRequest popup_request(GURL("http://foo.com")); 468 blink::WebView* new_web_view = view()->createView( 469 GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo", 470 blink::WebNavigationPolicyNewForegroundTab, false); 471 RenderViewImpl* new_view = RenderViewImpl::FromWebView(new_web_view); 472 policy = static_cast<RenderFrameImpl*>(new_view->GetMainRenderFrame())-> 473 decidePolicyForNavigation( 474 new_web_view->mainFrame()->toWebLocalFrame(), 475 &state, 476 popup_request, 477 blink::WebNavigationTypeLinkClicked, 478 blink::WebNavigationPolicyNewForegroundTab, 479 false); 480 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy); 481 482 // Clean up after the new view so we don't leak it. 483 new_view->Close(); 484 new_view->Release(); 485 } 486 487 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is 488 // already swapped out. http://crbug.com/93427. 489 TEST_F(RenderViewImplTest, SendSwapOutACK) { 490 LoadHTML("<div>Page A</div>"); 491 int initial_page_id = view()->GetPageId(); 492 493 // Respond to a swap out request. 494 view()->main_render_frame()->OnSwapOut(kProxyRoutingId); 495 496 // Ensure the swap out commits synchronously. 497 EXPECT_NE(initial_page_id, view()->GetPageId()); 498 499 // Check for a valid OnSwapOutACK. 500 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching( 501 FrameHostMsg_SwapOut_ACK::ID); 502 ASSERT_TRUE(msg); 503 504 // It is possible to get another swap out request. Ensure that we send 505 // an ACK, even if we don't have to do anything else. 506 render_thread_->sink().ClearMessages(); 507 view()->main_render_frame()->OnSwapOut(kProxyRoutingId); 508 const IPC::Message* msg2 = render_thread_->sink().GetUniqueMessageMatching( 509 FrameHostMsg_SwapOut_ACK::ID); 510 ASSERT_TRUE(msg2); 511 512 // If we navigate back to this RenderView, ensure we don't send a state 513 // update for the swapped out URL. (http://crbug.com/72235) 514 FrameMsg_Navigate_Params nav_params; 515 nav_params.url = GURL("data:text/html,<div>Page B</div>"); 516 nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL; 517 nav_params.transition = PAGE_TRANSITION_TYPED; 518 nav_params.current_history_list_length = 1; 519 nav_params.current_history_list_offset = 0; 520 nav_params.pending_history_list_offset = 1; 521 nav_params.page_id = -1; 522 frame()->OnNavigate(nav_params); 523 ProcessPendingMessages(); 524 const IPC::Message* msg3 = render_thread_->sink().GetUniqueMessageMatching( 525 ViewHostMsg_UpdateState::ID); 526 EXPECT_FALSE(msg3); 527 } 528 529 // Ensure the RenderViewImpl reloads the previous page if a reload request 530 // arrives while it is showing swappedout://. http://crbug.com/143155. 531 TEST_F(RenderViewImplTest, ReloadWhileSwappedOut) { 532 // Load page A. 533 LoadHTML("<div>Page A</div>"); 534 535 // Load page B, which will trigger an UpdateState message for page A. 536 LoadHTML("<div>Page B</div>"); 537 538 // Check for a valid UpdateState message for page A. 539 ProcessPendingMessages(); 540 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching( 541 ViewHostMsg_UpdateState::ID); 542 ASSERT_TRUE(msg_A); 543 ViewHostMsg_UpdateState::Param params; 544 ViewHostMsg_UpdateState::Read(msg_A, ¶ms); 545 int page_id_A = params.a; 546 PageState state_A = params.b; 547 EXPECT_EQ(1, page_id_A); 548 render_thread_->sink().ClearMessages(); 549 550 // Back to page A (page_id 1) and commit. 551 FrameMsg_Navigate_Params params_A; 552 params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL; 553 params_A.transition = PAGE_TRANSITION_FORWARD_BACK; 554 params_A.current_history_list_length = 2; 555 params_A.current_history_list_offset = 1; 556 params_A.pending_history_list_offset = 0; 557 params_A.page_id = 1; 558 params_A.page_state = state_A; 559 frame()->OnNavigate(params_A); 560 ProcessPendingMessages(); 561 562 // Respond to a swap out request. 563 view()->main_render_frame()->OnSwapOut(kProxyRoutingId); 564 565 // Check for a OnSwapOutACK. 566 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching( 567 FrameHostMsg_SwapOut_ACK::ID); 568 ASSERT_TRUE(msg); 569 render_thread_->sink().ClearMessages(); 570 571 // It is possible to get a reload request at this point, containing the 572 // params.page_state of the initial page (e.g., if the new page fails the 573 // provisional load in the renderer process, after we unload the old page). 574 // Ensure the old page gets reloaded, not swappedout://. 575 FrameMsg_Navigate_Params nav_params; 576 nav_params.url = GURL("data:text/html,<div>Page A</div>"); 577 nav_params.navigation_type = FrameMsg_Navigate_Type::RELOAD; 578 nav_params.transition = PAGE_TRANSITION_RELOAD; 579 nav_params.current_history_list_length = 2; 580 nav_params.current_history_list_offset = 0; 581 nav_params.pending_history_list_offset = 0; 582 nav_params.page_id = 1; 583 nav_params.page_state = state_A; 584 frame()->OnNavigate(nav_params); 585 ProcessPendingMessages(); 586 587 // Verify page A committed, not swappedout://. 588 const IPC::Message* frame_navigate_msg = 589 render_thread_->sink().GetUniqueMessageMatching( 590 FrameHostMsg_DidCommitProvisionalLoad::ID); 591 EXPECT_TRUE(frame_navigate_msg); 592 593 // Read URL out of the parent trait of the params object. 594 FrameHostMsg_DidCommitProvisionalLoad::Param commit_params; 595 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg, 596 &commit_params); 597 EXPECT_NE(GURL("swappedout://"), commit_params.a.url); 598 } 599 600 601 // Test that we get the correct UpdateState message when we go back twice 602 // quickly without committing. Regression test for http://crbug.com/58082. 603 // Disabled: http://crbug.com/157357 . 604 TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) { 605 // Load page A. 606 LoadHTML("<div>Page A</div>"); 607 608 // Load page B, which will trigger an UpdateState message for page A. 609 LoadHTML("<div>Page B</div>"); 610 611 // Check for a valid UpdateState message for page A. 612 ProcessPendingMessages(); 613 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching( 614 ViewHostMsg_UpdateState::ID); 615 ASSERT_TRUE(msg_A); 616 ViewHostMsg_UpdateState::Param param; 617 ViewHostMsg_UpdateState::Read(msg_A, ¶m); 618 int page_id_A = param.a; 619 PageState state_A = param.b; 620 EXPECT_EQ(1, page_id_A); 621 render_thread_->sink().ClearMessages(); 622 623 // Load page C, which will trigger an UpdateState message for page B. 624 LoadHTML("<div>Page C</div>"); 625 626 // Check for a valid UpdateState for page B. 627 ProcessPendingMessages(); 628 const IPC::Message* msg_B = render_thread_->sink().GetUniqueMessageMatching( 629 ViewHostMsg_UpdateState::ID); 630 ASSERT_TRUE(msg_B); 631 ViewHostMsg_UpdateState::Read(msg_B, ¶m); 632 int page_id_B = param.a; 633 PageState state_B = param.b; 634 EXPECT_EQ(2, page_id_B); 635 EXPECT_NE(state_A, state_B); 636 render_thread_->sink().ClearMessages(); 637 638 // Load page D, which will trigger an UpdateState message for page C. 639 LoadHTML("<div>Page D</div>"); 640 641 // Check for a valid UpdateState for page C. 642 ProcessPendingMessages(); 643 const IPC::Message* msg_C = render_thread_->sink().GetUniqueMessageMatching( 644 ViewHostMsg_UpdateState::ID); 645 ASSERT_TRUE(msg_C); 646 ViewHostMsg_UpdateState::Read(msg_C, ¶m); 647 int page_id_C = param.a; 648 PageState state_C = param.b; 649 EXPECT_EQ(3, page_id_C); 650 EXPECT_NE(state_B, state_C); 651 render_thread_->sink().ClearMessages(); 652 653 // Go back to C and commit, preparing for our real test. 654 FrameMsg_Navigate_Params params_C; 655 params_C.navigation_type = FrameMsg_Navigate_Type::NORMAL; 656 params_C.transition = PAGE_TRANSITION_FORWARD_BACK; 657 params_C.current_history_list_length = 4; 658 params_C.current_history_list_offset = 3; 659 params_C.pending_history_list_offset = 2; 660 params_C.page_id = 3; 661 params_C.page_state = state_C; 662 frame()->OnNavigate(params_C); 663 ProcessPendingMessages(); 664 render_thread_->sink().ClearMessages(); 665 666 // Go back twice quickly, such that page B does not have a chance to commit. 667 // This leads to two changes to the back/forward list but only one change to 668 // the RenderView's page ID. 669 670 // Back to page B (page_id 2), without committing. 671 FrameMsg_Navigate_Params params_B; 672 params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL; 673 params_B.transition = PAGE_TRANSITION_FORWARD_BACK; 674 params_B.current_history_list_length = 4; 675 params_B.current_history_list_offset = 2; 676 params_B.pending_history_list_offset = 1; 677 params_B.page_id = 2; 678 params_B.page_state = state_B; 679 frame()->OnNavigate(params_B); 680 681 // Back to page A (page_id 1) and commit. 682 FrameMsg_Navigate_Params params; 683 params.navigation_type = FrameMsg_Navigate_Type::NORMAL; 684 params.transition = PAGE_TRANSITION_FORWARD_BACK; 685 params_B.current_history_list_length = 4; 686 params_B.current_history_list_offset = 2; 687 params_B.pending_history_list_offset = 0; 688 params.page_id = 1; 689 params.page_state = state_A; 690 frame()->OnNavigate(params); 691 ProcessPendingMessages(); 692 693 // Now ensure that the UpdateState message we receive is consistent 694 // and represents page C in both page_id and state. 695 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching( 696 ViewHostMsg_UpdateState::ID); 697 ASSERT_TRUE(msg); 698 ViewHostMsg_UpdateState::Read(msg, ¶m); 699 int page_id = param.a; 700 PageState state = param.b; 701 EXPECT_EQ(page_id_C, page_id); 702 EXPECT_NE(state_A, state); 703 EXPECT_NE(state_B, state); 704 EXPECT_EQ(state_C, state); 705 } 706 707 // Test that the history_page_ids_ list can reveal when a stale back/forward 708 // navigation arrives from the browser and can be ignored. See 709 // http://crbug.com/86758. 710 TEST_F(RenderViewImplTest, StaleNavigationsIgnored) { 711 // Load page A. 712 LoadHTML("<div>Page A</div>"); 713 EXPECT_EQ(1, view()->history_list_length_); 714 EXPECT_EQ(0, view()->history_list_offset_); 715 EXPECT_EQ(1, view()->history_page_ids_[0]); 716 717 // Load page B, which will trigger an UpdateState message for page A. 718 LoadHTML("<div>Page B</div>"); 719 EXPECT_EQ(2, view()->history_list_length_); 720 EXPECT_EQ(1, view()->history_list_offset_); 721 EXPECT_EQ(2, view()->history_page_ids_[1]); 722 723 // Check for a valid UpdateState message for page A. 724 ProcessPendingMessages(); 725 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching( 726 ViewHostMsg_UpdateState::ID); 727 ASSERT_TRUE(msg_A); 728 ViewHostMsg_UpdateState::Param param; 729 ViewHostMsg_UpdateState::Read(msg_A, ¶m); 730 int page_id_A = param.a; 731 PageState state_A = param.b; 732 EXPECT_EQ(1, page_id_A); 733 render_thread_->sink().ClearMessages(); 734 735 // Back to page A (page_id 1) and commit. 736 FrameMsg_Navigate_Params params_A; 737 params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL; 738 params_A.transition = PAGE_TRANSITION_FORWARD_BACK; 739 params_A.current_history_list_length = 2; 740 params_A.current_history_list_offset = 1; 741 params_A.pending_history_list_offset = 0; 742 params_A.page_id = 1; 743 params_A.page_state = state_A; 744 frame()->OnNavigate(params_A); 745 ProcessPendingMessages(); 746 747 // A new navigation commits, clearing the forward history. 748 LoadHTML("<div>Page C</div>"); 749 EXPECT_EQ(2, view()->history_list_length_); 750 EXPECT_EQ(1, view()->history_list_offset_); 751 EXPECT_EQ(3, view()->history_page_ids_[1]); 752 753 // The browser then sends a stale navigation to B, which should be ignored. 754 FrameMsg_Navigate_Params params_B; 755 params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL; 756 params_B.transition = PAGE_TRANSITION_FORWARD_BACK; 757 params_B.current_history_list_length = 2; 758 params_B.current_history_list_offset = 0; 759 params_B.pending_history_list_offset = 1; 760 params_B.page_id = 2; 761 params_B.page_state = state_A; // Doesn't matter, just has to be present. 762 frame()->OnNavigate(params_B); 763 764 // State should be unchanged. 765 EXPECT_EQ(2, view()->history_list_length_); 766 EXPECT_EQ(1, view()->history_list_offset_); 767 EXPECT_EQ(3, view()->history_page_ids_[1]); 768 } 769 770 // Test that we do not ignore navigations after the entry limit is reached, 771 // in which case the browser starts dropping entries from the front. In this 772 // case, we'll see a page_id mismatch but the RenderView's id will be older, 773 // not newer, than params.page_id. Use this as a cue that we should update the 774 // state and not treat it like a navigation to a cropped forward history item. 775 // See http://crbug.com/89798. 776 TEST_F(RenderViewImplTest, DontIgnoreBackAfterNavEntryLimit) { 777 // Load page A. 778 LoadHTML("<div>Page A</div>"); 779 EXPECT_EQ(1, view()->history_list_length_); 780 EXPECT_EQ(0, view()->history_list_offset_); 781 EXPECT_EQ(1, view()->history_page_ids_[0]); 782 783 // Load page B, which will trigger an UpdateState message for page A. 784 LoadHTML("<div>Page B</div>"); 785 EXPECT_EQ(2, view()->history_list_length_); 786 EXPECT_EQ(1, view()->history_list_offset_); 787 EXPECT_EQ(2, view()->history_page_ids_[1]); 788 789 // Check for a valid UpdateState message for page A. 790 ProcessPendingMessages(); 791 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching( 792 ViewHostMsg_UpdateState::ID); 793 ASSERT_TRUE(msg_A); 794 ViewHostMsg_UpdateState::Param param; 795 ViewHostMsg_UpdateState::Read(msg_A, ¶m); 796 int page_id_A = param.a; 797 PageState state_A = param.b; 798 EXPECT_EQ(1, page_id_A); 799 render_thread_->sink().ClearMessages(); 800 801 // Load page C, which will trigger an UpdateState message for page B. 802 LoadHTML("<div>Page C</div>"); 803 EXPECT_EQ(3, view()->history_list_length_); 804 EXPECT_EQ(2, view()->history_list_offset_); 805 EXPECT_EQ(3, view()->history_page_ids_[2]); 806 807 // Check for a valid UpdateState message for page B. 808 ProcessPendingMessages(); 809 const IPC::Message* msg_B = render_thread_->sink().GetUniqueMessageMatching( 810 ViewHostMsg_UpdateState::ID); 811 ASSERT_TRUE(msg_B); 812 ViewHostMsg_UpdateState::Read(msg_B, ¶m); 813 int page_id_B = param.a; 814 PageState state_B = param.b; 815 EXPECT_EQ(2, page_id_B); 816 render_thread_->sink().ClearMessages(); 817 818 // Suppose the browser has limited the number of NavigationEntries to 2. 819 // It has now dropped the first entry, but the renderer isn't notified. 820 // Ensure that going back to page B (page_id 2) at offset 0 is successful. 821 FrameMsg_Navigate_Params params_B; 822 params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL; 823 params_B.transition = PAGE_TRANSITION_FORWARD_BACK; 824 params_B.current_history_list_length = 2; 825 params_B.current_history_list_offset = 1; 826 params_B.pending_history_list_offset = 0; 827 params_B.page_id = 2; 828 params_B.page_state = state_B; 829 frame()->OnNavigate(params_B); 830 ProcessPendingMessages(); 831 832 EXPECT_EQ(2, view()->history_list_length_); 833 EXPECT_EQ(0, view()->history_list_offset_); 834 EXPECT_EQ(2, view()->history_page_ids_[0]); 835 } 836 837 // Test that our IME backend sends a notification message when the input focus 838 // changes. 839 TEST_F(RenderViewImplTest, OnImeTypeChanged) { 840 // Enable our IME backend code. 841 view()->OnSetInputMethodActive(true); 842 843 // Load an HTML page consisting of two input fields. 844 view()->set_send_content_state_immediately(true); 845 LoadHTML("<html>" 846 "<head>" 847 "</head>" 848 "<body>" 849 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>" 850 "<input id=\"test2\" type=\"password\"></input>" 851 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>" 852 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>" 853 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>" 854 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">" 855 "</input>" 856 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">" 857 "</input>" 858 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>" 859 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>" 860 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>" 861 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>" 862 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>" 863 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>" 864 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>" 865 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>" 866 "</body>" 867 "</html>"); 868 render_thread_->sink().ClearMessages(); 869 870 struct InputModeTestCase { 871 const char* input_id; 872 ui::TextInputMode expected_mode; 873 }; 874 static const InputModeTestCase kInputModeTestCases[] = { 875 {"test1", ui::TEXT_INPUT_MODE_DEFAULT}, 876 {"test3", ui::TEXT_INPUT_MODE_VERBATIM}, 877 {"test4", ui::TEXT_INPUT_MODE_LATIN}, 878 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME}, 879 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE}, 880 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN}, 881 {"test8", ui::TEXT_INPUT_MODE_KANA}, 882 {"test9", ui::TEXT_INPUT_MODE_KATAKANA}, 883 {"test10", ui::TEXT_INPUT_MODE_NUMERIC}, 884 {"test11", ui::TEXT_INPUT_MODE_TEL}, 885 {"test12", ui::TEXT_INPUT_MODE_EMAIL}, 886 {"test13", ui::TEXT_INPUT_MODE_URL}, 887 {"test14", ui::TEXT_INPUT_MODE_DEFAULT}, 888 {"test15", ui::TEXT_INPUT_MODE_VERBATIM}, 889 }; 890 891 const int kRepeatCount = 10; 892 for (int i = 0; i < kRepeatCount; i++) { 893 // Move the input focus to the first <input> element, where we should 894 // activate IMEs. 895 ExecuteJavaScript("document.getElementById('test1').focus();"); 896 ProcessPendingMessages(); 897 render_thread_->sink().ClearMessages(); 898 899 // Update the IME status and verify if our IME backend sends an IPC message 900 // to activate IMEs. 901 view()->UpdateTextInputState( 902 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME); 903 const IPC::Message* msg = render_thread_->sink().GetMessageAt(0); 904 EXPECT_TRUE(msg != NULL); 905 EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type()); 906 ViewHostMsg_TextInputStateChanged::Param params; 907 ViewHostMsg_TextInputStateChanged::Read(msg, ¶ms); 908 ViewHostMsg_TextInputState_Params p = params.a; 909 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, p.type); 910 EXPECT_EQ(true, p.can_compose_inline); 911 912 // Move the input focus to the second <input> element, where we should 913 // de-activate IMEs. 914 ExecuteJavaScript("document.getElementById('test2').focus();"); 915 ProcessPendingMessages(); 916 render_thread_->sink().ClearMessages(); 917 918 // Update the IME status and verify if our IME backend sends an IPC message 919 // to de-activate IMEs. 920 view()->UpdateTextInputState( 921 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME); 922 msg = render_thread_->sink().GetMessageAt(0); 923 EXPECT_TRUE(msg != NULL); 924 EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type()); 925 ViewHostMsg_TextInputStateChanged::Read(msg, ¶ms); 926 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, params.a.type); 927 928 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kInputModeTestCases); j++) { 929 const InputModeTestCase* test_case = &kInputModeTestCases[j]; 930 std::string javascript = 931 base::StringPrintf("document.getElementById('%s').focus();", 932 test_case->input_id); 933 // Move the input focus to the target <input> element, where we should 934 // activate IMEs. 935 ExecuteJavaScript(javascript.c_str()); 936 ProcessPendingMessages(); 937 render_thread_->sink().ClearMessages(); 938 939 // Update the IME status and verify if our IME backend sends an IPC 940 // message to activate IMEs. 941 view()->UpdateTextInputState( 942 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME); 943 msg = render_thread_->sink().GetMessageAt(0); 944 EXPECT_TRUE(msg != NULL); 945 EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type()); 946 ViewHostMsg_TextInputStateChanged::Read(msg, ¶ms); 947 EXPECT_EQ(test_case->expected_mode, params.a.mode); 948 } 949 } 950 } 951 952 // Test that our IME backend can compose CJK words. 953 // Our IME front-end sends many platform-independent messages to the IME backend 954 // while it composes CJK words. This test sends the minimal messages captured 955 // on my local environment directly to the IME backend to verify if the backend 956 // can compose CJK words without any problems. 957 // This test uses an array of command sets because an IME composotion does not 958 // only depends on IME events, but also depends on window events, e.g. moving 959 // the window focus while composing a CJK text. To handle such complicated 960 // cases, this test should not only call IME-related functions in the 961 // RenderWidget class, but also call some RenderWidget members, e.g. 962 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc. 963 TEST_F(RenderViewImplTest, ImeComposition) { 964 enum ImeCommand { 965 IME_INITIALIZE, 966 IME_SETINPUTMODE, 967 IME_SETFOCUS, 968 IME_SETCOMPOSITION, 969 IME_CONFIRMCOMPOSITION, 970 IME_CANCELCOMPOSITION 971 }; 972 struct ImeMessage { 973 ImeCommand command; 974 bool enable; 975 int selection_start; 976 int selection_end; 977 const wchar_t* ime_string; 978 const wchar_t* result; 979 }; 980 static const ImeMessage kImeMessages[] = { 981 // Scenario 1: input a Chinese word with Microsoft IME (on Vista). 982 {IME_INITIALIZE, true, 0, 0, NULL, NULL}, 983 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL}, 984 {IME_SETFOCUS, true, 0, 0, NULL, NULL}, 985 {IME_SETCOMPOSITION, false, 1, 1, L"n", L"n"}, 986 {IME_SETCOMPOSITION, false, 2, 2, L"ni", L"ni"}, 987 {IME_SETCOMPOSITION, false, 3, 3, L"nih", L"nih"}, 988 {IME_SETCOMPOSITION, false, 4, 4, L"niha", L"niha"}, 989 {IME_SETCOMPOSITION, false, 5, 5, L"nihao", L"nihao"}, 990 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"\x4F60\x597D", L"\x4F60\x597D"}, 991 // Scenario 2: input a Japanese word with Microsoft IME (on Vista). 992 {IME_INITIALIZE, true, 0, 0, NULL, NULL}, 993 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL}, 994 {IME_SETFOCUS, true, 0, 0, NULL, NULL}, 995 {IME_SETCOMPOSITION, false, 0, 1, L"\xFF4B", L"\xFF4B"}, 996 {IME_SETCOMPOSITION, false, 0, 1, L"\x304B", L"\x304B"}, 997 {IME_SETCOMPOSITION, false, 0, 2, L"\x304B\xFF4E", L"\x304B\xFF4E"}, 998 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\xFF4A", 999 L"\x304B\x3093\xFF4A"}, 1000 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\x3058", 1001 L"\x304B\x3093\x3058"}, 1002 {IME_SETCOMPOSITION, false, 0, 2, L"\x611F\x3058", L"\x611F\x3058"}, 1003 {IME_SETCOMPOSITION, false, 0, 2, L"\x6F22\x5B57", L"\x6F22\x5B57"}, 1004 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"}, 1005 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"}, 1006 // Scenario 3: input a Korean word with Microsot IME (on Vista). 1007 {IME_INITIALIZE, true, 0, 0, NULL, NULL}, 1008 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL}, 1009 {IME_SETFOCUS, true, 0, 0, NULL, NULL}, 1010 {IME_SETCOMPOSITION, false, 0, 1, L"\x3147", L"\x3147"}, 1011 {IME_SETCOMPOSITION, false, 0, 1, L"\xC544", L"\xC544"}, 1012 {IME_SETCOMPOSITION, false, 0, 1, L"\xC548", L"\xC548"}, 1013 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548"}, 1014 {IME_SETCOMPOSITION, false, 0, 1, L"\x3134", L"\xC548\x3134"}, 1015 {IME_SETCOMPOSITION, false, 0, 1, L"\xB140", L"\xC548\xB140"}, 1016 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"}, 1017 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\xC548"}, 1018 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"}, 1019 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548\xB155"}, 1020 }; 1021 1022 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kImeMessages); i++) { 1023 const ImeMessage* ime_message = &kImeMessages[i]; 1024 switch (ime_message->command) { 1025 case IME_INITIALIZE: 1026 // Load an HTML page consisting of a content-editable <div> element, 1027 // and move the input focus to the <div> element, where we can use 1028 // IMEs. 1029 view()->OnSetInputMethodActive(ime_message->enable); 1030 view()->set_send_content_state_immediately(true); 1031 LoadHTML("<html>" 1032 "<head>" 1033 "</head>" 1034 "<body>" 1035 "<div id=\"test1\" contenteditable=\"true\"></div>" 1036 "</body>" 1037 "</html>"); 1038 ExecuteJavaScript("document.getElementById('test1').focus();"); 1039 break; 1040 1041 case IME_SETINPUTMODE: 1042 // Activate (or deactivate) our IME back-end. 1043 view()->OnSetInputMethodActive(ime_message->enable); 1044 break; 1045 1046 case IME_SETFOCUS: 1047 // Update the window focus. 1048 view()->OnSetFocus(ime_message->enable); 1049 break; 1050 1051 case IME_SETCOMPOSITION: 1052 view()->OnImeSetComposition( 1053 base::WideToUTF16(ime_message->ime_string), 1054 std::vector<blink::WebCompositionUnderline>(), 1055 ime_message->selection_start, 1056 ime_message->selection_end); 1057 break; 1058 1059 case IME_CONFIRMCOMPOSITION: 1060 view()->OnImeConfirmComposition( 1061 base::WideToUTF16(ime_message->ime_string), 1062 gfx::Range::InvalidRange(), 1063 false); 1064 break; 1065 1066 case IME_CANCELCOMPOSITION: 1067 view()->OnImeSetComposition( 1068 base::string16(), 1069 std::vector<blink::WebCompositionUnderline>(), 1070 0, 0); 1071 break; 1072 } 1073 1074 // Update the status of our IME back-end. 1075 // TODO(hbono): we should verify messages to be sent from the back-end. 1076 view()->UpdateTextInputState( 1077 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME); 1078 ProcessPendingMessages(); 1079 render_thread_->sink().ClearMessages(); 1080 1081 if (ime_message->result) { 1082 // Retrieve the content of this page and compare it with the expected 1083 // result. 1084 const int kMaxOutputCharacters = 128; 1085 base::string16 output = 1086 GetMainFrame()->contentAsText(kMaxOutputCharacters); 1087 EXPECT_EQ(base::WideToUTF16(ime_message->result), output); 1088 } 1089 } 1090 } 1091 1092 // Test that the RenderView::OnSetTextDirection() function can change the text 1093 // direction of the selected input element. 1094 TEST_F(RenderViewImplTest, OnSetTextDirection) { 1095 // Load an HTML page consisting of a <textarea> element and a <div> element. 1096 // This test changes the text direction of the <textarea> element, and 1097 // writes the values of its 'dir' attribute and its 'direction' property to 1098 // verify that the text direction is changed. 1099 view()->set_send_content_state_immediately(true); 1100 LoadHTML("<html>" 1101 "<head>" 1102 "</head>" 1103 "<body>" 1104 "<textarea id=\"test\"></textarea>" 1105 "<div id=\"result\" contenteditable=\"true\"></div>" 1106 "</body>" 1107 "</html>"); 1108 render_thread_->sink().ClearMessages(); 1109 1110 static const struct { 1111 WebTextDirection direction; 1112 const wchar_t* expected_result; 1113 } kTextDirection[] = { 1114 { blink::WebTextDirectionRightToLeft, L"\x000A" L"rtl,rtl" }, 1115 { blink::WebTextDirectionLeftToRight, L"\x000A" L"ltr,ltr" }, 1116 }; 1117 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTextDirection); ++i) { 1118 // Set the text direction of the <textarea> element. 1119 ExecuteJavaScript("document.getElementById('test').focus();"); 1120 view()->OnSetTextDirection(kTextDirection[i].direction); 1121 1122 // Write the values of its DOM 'dir' attribute and its CSS 'direction' 1123 // property to the <div> element. 1124 ExecuteJavaScript("var result = document.getElementById('result');" 1125 "var node = document.getElementById('test');" 1126 "var style = getComputedStyle(node, null);" 1127 "result.innerText =" 1128 " node.getAttribute('dir') + ',' +" 1129 " style.getPropertyValue('direction');"); 1130 1131 // Copy the document content to std::wstring and compare with the 1132 // expected result. 1133 const int kMaxOutputCharacters = 16; 1134 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters); 1135 EXPECT_EQ(base::WideToUTF16(kTextDirection[i].expected_result), output); 1136 } 1137 } 1138 1139 // see http://crbug.com/238750 1140 #if defined(OS_WIN) 1141 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent 1142 #else 1143 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent 1144 #endif 1145 1146 // Test that we can receive correct DOM events when we send input events 1147 // through the RenderWidget::OnHandleInputEvent() function. 1148 TEST_F(RenderViewImplTest, MAYBE_OnHandleKeyboardEvent) { 1149 #if !defined(OS_MACOSX) 1150 // Load an HTML page consisting of one <input> element and three 1151 // contentediable <div> elements. 1152 // The <input> element is used for sending keyboard events, and the <div> 1153 // elements are used for writing DOM events in the following format: 1154 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>". 1155 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to 1156 // true when pressing an alt key, i.e. the |ev.metaKey| value is not 1157 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed. 1158 view()->set_send_content_state_immediately(true); 1159 LoadHTML("<html>" 1160 "<head>" 1161 "<title></title>" 1162 "<script type='text/javascript' language='javascript'>" 1163 "function OnKeyEvent(ev) {" 1164 " var result = document.getElementById(ev.type);" 1165 " result.innerText =" 1166 " (ev.which || ev.keyCode) + ',' +" 1167 " ev.shiftKey + ',' +" 1168 " ev.ctrlKey + ',' +" 1169 " ev.altKey;" 1170 " return true;" 1171 "}" 1172 "</script>" 1173 "</head>" 1174 "<body>" 1175 "<input id='test' type='text'" 1176 " onkeydown='return OnKeyEvent(event);'" 1177 " onkeypress='return OnKeyEvent(event);'" 1178 " onkeyup='return OnKeyEvent(event);'>" 1179 "</input>" 1180 "<div id='keydown' contenteditable='true'>" 1181 "</div>" 1182 "<div id='keypress' contenteditable='true'>" 1183 "</div>" 1184 "<div id='keyup' contenteditable='true'>" 1185 "</div>" 1186 "</body>" 1187 "</html>"); 1188 ExecuteJavaScript("document.getElementById('test').focus();"); 1189 render_thread_->sink().ClearMessages(); 1190 1191 static const MockKeyboard::Layout kLayouts[] = { 1192 #if defined(OS_WIN) 1193 // Since we ignore the mock keyboard layout on Linux and instead just use 1194 // the screen's keyboard layout, these trivially pass. They are commented 1195 // out to avoid the illusion that they work. 1196 MockKeyboard::LAYOUT_ARABIC, 1197 MockKeyboard::LAYOUT_CANADIAN_FRENCH, 1198 MockKeyboard::LAYOUT_FRENCH, 1199 MockKeyboard::LAYOUT_HEBREW, 1200 MockKeyboard::LAYOUT_RUSSIAN, 1201 #endif 1202 MockKeyboard::LAYOUT_UNITED_STATES, 1203 }; 1204 1205 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLayouts); ++i) { 1206 // For each key code, we send three keyboard events. 1207 // * we press only the key; 1208 // * we press the key and a left-shift key, and; 1209 // * we press the key and a right-alt (AltGr) key. 1210 // For each modifiers, we need a string used for formatting its expected 1211 // result. (See the above comment for its format.) 1212 static const struct { 1213 MockKeyboard::Modifiers modifiers; 1214 const char* expected_result; 1215 } kModifierData[] = { 1216 {MockKeyboard::NONE, "false,false,false"}, 1217 {MockKeyboard::LEFT_SHIFT, "true,false,false"}, 1218 #if defined(OS_WIN) 1219 {MockKeyboard::RIGHT_ALT, "false,false,true"}, 1220 #endif 1221 }; 1222 1223 MockKeyboard::Layout layout = kLayouts[i]; 1224 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kModifierData); ++j) { 1225 // Virtual key codes used for this test. 1226 static const int kKeyCodes[] = { 1227 '0', '1', '2', '3', '4', '5', '6', '7', 1228 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 1229 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 1230 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 1231 'W', 'X', 'Y', 'Z', 1232 ui::VKEY_OEM_1, 1233 ui::VKEY_OEM_PLUS, 1234 ui::VKEY_OEM_COMMA, 1235 ui::VKEY_OEM_MINUS, 1236 ui::VKEY_OEM_PERIOD, 1237 ui::VKEY_OEM_2, 1238 ui::VKEY_OEM_3, 1239 ui::VKEY_OEM_4, 1240 ui::VKEY_OEM_5, 1241 ui::VKEY_OEM_6, 1242 ui::VKEY_OEM_7, 1243 #if defined(OS_WIN) 1244 // Not sure how to handle this key on Linux. 1245 ui::VKEY_OEM_8, 1246 #endif 1247 }; 1248 1249 MockKeyboard::Modifiers modifiers = kModifierData[j].modifiers; 1250 for (size_t k = 0; k < ARRAYSIZE_UNSAFE(kKeyCodes); ++k) { 1251 // Send a keyboard event to the RenderView object. 1252 // We should test a keyboard event only when the given keyboard-layout 1253 // driver is installed in a PC and the driver can assign a Unicode 1254 // charcter for the given tuple (key-code and modifiers). 1255 int key_code = kKeyCodes[k]; 1256 base::string16 char_code; 1257 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0) 1258 continue; 1259 1260 // Create an expected result from the virtual-key code, the character 1261 // code, and the modifier-key status. 1262 // We format a string that emulates a DOM-event string produced hy 1263 // our JavaScript function. (See the above comment for the format.) 1264 static char expected_result[1024]; 1265 expected_result[0] = 0; 1266 base::snprintf(&expected_result[0], 1267 sizeof(expected_result), 1268 "\n" // texts in the <input> element 1269 "%d,%s\n" // texts in the first <div> element 1270 "%d,%s\n" // texts in the second <div> element 1271 "%d,%s", // texts in the third <div> element 1272 key_code, kModifierData[j].expected_result, 1273 static_cast<int>(char_code[0]), 1274 kModifierData[j].expected_result, 1275 key_code, kModifierData[j].expected_result); 1276 1277 // Retrieve the text in the test page and compare it with the expected 1278 // text created from a virtual-key code, a character code, and the 1279 // modifier-key status. 1280 const int kMaxOutputCharacters = 1024; 1281 std::string output = base::UTF16ToUTF8( 1282 GetMainFrame()->contentAsText(kMaxOutputCharacters)); 1283 EXPECT_EQ(expected_result, output); 1284 } 1285 } 1286 } 1287 #else 1288 NOTIMPLEMENTED(); 1289 #endif 1290 } 1291 1292 // Test that our EditorClientImpl class can insert characters when we send 1293 // keyboard events through the RenderWidget::OnHandleInputEvent() function. 1294 // This test is for preventing regressions caused only when we use non-US 1295 // keyboards, such as Issue 10846. 1296 // see http://crbug.com/244562 1297 #if defined(OS_WIN) 1298 #define MAYBE_InsertCharacters DISABLED_InsertCharacters 1299 #else 1300 #define MAYBE_InsertCharacters InsertCharacters 1301 #endif 1302 TEST_F(RenderViewImplTest, MAYBE_InsertCharacters) { 1303 #if !defined(OS_MACOSX) 1304 static const struct { 1305 MockKeyboard::Layout layout; 1306 const wchar_t* expected_result; 1307 } kLayouts[] = { 1308 #if 0 1309 // Disabled these keyboard layouts because buildbots do not have their 1310 // keyboard-layout drivers installed. 1311 {MockKeyboard::LAYOUT_ARABIC, 1312 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037" 1313 L"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644" 1314 L"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e" 1315 L"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635" 1316 L"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632" 1317 L"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021" 1318 L"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029" 1319 L"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640" 1320 L"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c" 1321 L"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a" 1322 L"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c" 1323 L"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035" 1324 L"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b" 1325 L"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629" 1326 L"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639" 1327 L"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648" 1328 L"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637" 1329 }, 1330 {MockKeyboard::LAYOUT_HEBREW, 1331 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037" 1332 L"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db" 1333 L"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de" 1334 L"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4" 1335 L"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d" 1336 L"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028" 1337 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a" 1338 L"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047" 1339 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f" 1340 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057" 1341 L"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c" 1342 L"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031" 1343 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039" 1344 L"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9" 1345 L"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4" 1346 L"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1" 1347 L"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e" 1348 L"\x003b\x005d\x005c\x005b\x002c" 1349 }, 1350 #endif 1351 #if defined(OS_WIN) 1352 // On Linux, the only way to test alternate keyboard layouts is to change 1353 // the keyboard layout of the whole screen. I'm worried about the side 1354 // effects this may have on the buildbots. 1355 {MockKeyboard::LAYOUT_CANADIAN_FRENCH, 1356 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037" 1357 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066" 1358 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e" 1359 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076" 1360 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d" 1361 L"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024" 1362 L"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043" 1363 L"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b" 1364 L"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053" 1365 L"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a" 1366 L"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031" 1367 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039" 1368 L"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068" 1369 L"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070" 1370 L"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078" 1371 L"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9" 1372 L"\x003c" 1373 }, 1374 {MockKeyboard::LAYOUT_FRENCH, 1375 L"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8" 1376 L"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066" 1377 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e" 1378 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076" 1379 L"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b" 1380 L"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032" 1381 L"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041" 1382 L"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049" 1383 L"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051" 1384 L"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059" 1385 L"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0" 1386 L"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d" 1387 L"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065" 1388 L"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d" 1389 L"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075" 1390 L"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c" 1391 L"\x003b\x003a\x00f9\x0029\x002a\x0021" 1392 }, 1393 {MockKeyboard::LAYOUT_RUSSIAN, 1394 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037" 1395 L"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430" 1396 L"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442" 1397 L"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c" 1398 L"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d" 1399 L"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029" 1400 L"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a" 1401 L"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f" 1402 L"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429" 1403 L"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426" 1404 L"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e" 1405 L"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031" 1406 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039" 1407 L"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440" 1408 L"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437" 1409 L"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447" 1410 L"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e" 1411 L"\x0451\x0445\x005c\x044a\x044d" 1412 }, 1413 #endif // defined(OS_WIN) 1414 {MockKeyboard::LAYOUT_UNITED_STATES, 1415 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037" 1416 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066" 1417 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e" 1418 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076" 1419 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d" 1420 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029" 1421 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a" 1422 L"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047" 1423 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f" 1424 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057" 1425 L"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e" 1426 L"\x003f\x007e\x007b\x007c\x007d\x0022" 1427 #if defined(OS_WIN) 1428 // This is ifdefed out for Linux to correspond to the fact that we don't 1429 // test alt+keystroke for now. 1430 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037" 1431 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066" 1432 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e" 1433 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076" 1434 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d" 1435 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027" 1436 #endif 1437 }, 1438 }; 1439 1440 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLayouts); ++i) { 1441 // Load an HTML page consisting of one <div> element. 1442 // This <div> element is used by the EditorClientImpl class to insert 1443 // characters received through the RenderWidget::OnHandleInputEvent() 1444 // function. 1445 view()->set_send_content_state_immediately(true); 1446 LoadHTML("<html>" 1447 "<head>" 1448 "<title></title>" 1449 "</head>" 1450 "<body>" 1451 "<div id='test' contenteditable='true'>" 1452 "</div>" 1453 "</body>" 1454 "</html>"); 1455 ExecuteJavaScript("document.getElementById('test').focus();"); 1456 render_thread_->sink().ClearMessages(); 1457 1458 // For each key code, we send three keyboard events. 1459 // * Pressing only the key; 1460 // * Pressing the key and a left-shift key, and; 1461 // * Pressing the key and a right-alt (AltGr) key. 1462 static const MockKeyboard::Modifiers kModifiers[] = { 1463 MockKeyboard::NONE, 1464 MockKeyboard::LEFT_SHIFT, 1465 #if defined(OS_WIN) 1466 MockKeyboard::RIGHT_ALT, 1467 #endif 1468 }; 1469 1470 MockKeyboard::Layout layout = kLayouts[i].layout; 1471 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kModifiers); ++j) { 1472 // Virtual key codes used for this test. 1473 static const int kKeyCodes[] = { 1474 '0', '1', '2', '3', '4', '5', '6', '7', 1475 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 1476 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 1477 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 1478 'W', 'X', 'Y', 'Z', 1479 ui::VKEY_OEM_1, 1480 ui::VKEY_OEM_PLUS, 1481 ui::VKEY_OEM_COMMA, 1482 ui::VKEY_OEM_MINUS, 1483 ui::VKEY_OEM_PERIOD, 1484 ui::VKEY_OEM_2, 1485 ui::VKEY_OEM_3, 1486 ui::VKEY_OEM_4, 1487 ui::VKEY_OEM_5, 1488 ui::VKEY_OEM_6, 1489 ui::VKEY_OEM_7, 1490 #if defined(OS_WIN) 1491 // Unclear how to handle this on Linux. 1492 ui::VKEY_OEM_8, 1493 #endif 1494 }; 1495 1496 MockKeyboard::Modifiers modifiers = kModifiers[j]; 1497 for (size_t k = 0; k < ARRAYSIZE_UNSAFE(kKeyCodes); ++k) { 1498 // Send a keyboard event to the RenderView object. 1499 // We should test a keyboard event only when the given keyboard-layout 1500 // driver is installed in a PC and the driver can assign a Unicode 1501 // charcter for the given tuple (layout, key-code, and modifiers). 1502 int key_code = kKeyCodes[k]; 1503 base::string16 char_code; 1504 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0) 1505 continue; 1506 } 1507 } 1508 1509 // Retrieve the text in the test page and compare it with the expected 1510 // text created from a virtual-key code, a character code, and the 1511 // modifier-key status. 1512 const int kMaxOutputCharacters = 4096; 1513 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters); 1514 EXPECT_EQ(base::WideToUTF16(kLayouts[i].expected_result), output); 1515 } 1516 #else 1517 NOTIMPLEMENTED(); 1518 #endif 1519 } 1520 1521 // Crashy, http://crbug.com/53247. 1522 TEST_F(RenderViewImplTest, DISABLED_DidFailProvisionalLoadWithErrorForError) { 1523 GetMainFrame()->enableViewSourceMode(true); 1524 WebURLError error; 1525 error.domain = WebString::fromUTF8(net::kErrorDomain); 1526 error.reason = net::ERR_FILE_NOT_FOUND; 1527 error.unreachableURL = GURL("http://foo"); 1528 WebLocalFrame* web_frame = GetMainFrame(); 1529 1530 // Start a load that will reach provisional state synchronously, 1531 // but won't complete synchronously. 1532 FrameMsg_Navigate_Params params; 1533 params.page_id = -1; 1534 params.navigation_type = FrameMsg_Navigate_Type::NORMAL; 1535 params.url = GURL("data:text/html,test data"); 1536 frame()->OnNavigate(params); 1537 1538 // An error occurred. 1539 view()->main_render_frame()->didFailProvisionalLoad(web_frame, error); 1540 // Frame should exit view-source mode. 1541 EXPECT_FALSE(web_frame->isViewSourceModeEnabled()); 1542 } 1543 1544 TEST_F(RenderViewImplTest, DidFailProvisionalLoadWithErrorForCancellation) { 1545 GetMainFrame()->enableViewSourceMode(true); 1546 WebURLError error; 1547 error.domain = WebString::fromUTF8(net::kErrorDomain); 1548 error.reason = net::ERR_ABORTED; 1549 error.unreachableURL = GURL("http://foo"); 1550 WebLocalFrame* web_frame = GetMainFrame(); 1551 1552 // Start a load that will reach provisional state synchronously, 1553 // but won't complete synchronously. 1554 FrameMsg_Navigate_Params params; 1555 params.page_id = -1; 1556 params.navigation_type = FrameMsg_Navigate_Type::NORMAL; 1557 params.url = GURL("data:text/html,test data"); 1558 frame()->OnNavigate(params); 1559 1560 // A cancellation occurred. 1561 view()->main_render_frame()->didFailProvisionalLoad(web_frame, error); 1562 // Frame should stay in view-source mode. 1563 EXPECT_TRUE(web_frame->isViewSourceModeEnabled()); 1564 } 1565 1566 // Regression test for http://crbug.com/41562 1567 TEST_F(RenderViewImplTest, UpdateTargetURLWithInvalidURL) { 1568 const GURL invalid_gurl("http://"); 1569 view()->setMouseOverURL(blink::WebURL(invalid_gurl)); 1570 EXPECT_EQ(invalid_gurl, view()->target_url_); 1571 } 1572 1573 TEST_F(RenderViewImplTest, SetHistoryLengthAndPrune) { 1574 int expected_page_id = -1; 1575 1576 // No history to merge and no committed pages. 1577 view()->OnSetHistoryLengthAndPrune(0, -1); 1578 EXPECT_EQ(0, view()->history_list_length_); 1579 EXPECT_EQ(-1, view()->history_list_offset_); 1580 1581 // History to merge and no committed pages. 1582 view()->OnSetHistoryLengthAndPrune(2, -1); 1583 EXPECT_EQ(2, view()->history_list_length_); 1584 EXPECT_EQ(1, view()->history_list_offset_); 1585 EXPECT_EQ(-1, view()->history_page_ids_[0]); 1586 EXPECT_EQ(-1, view()->history_page_ids_[1]); 1587 ClearHistory(); 1588 1589 blink::WebHistoryItem item; 1590 item.initialize(); 1591 1592 // No history to merge and a committed page to be kept. 1593 frame()->didCommitProvisionalLoad(GetMainFrame(), 1594 item, 1595 blink::WebStandardCommit); 1596 expected_page_id = view()->page_id_; 1597 view()->OnSetHistoryLengthAndPrune(0, expected_page_id); 1598 EXPECT_EQ(1, view()->history_list_length_); 1599 EXPECT_EQ(0, view()->history_list_offset_); 1600 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]); 1601 ClearHistory(); 1602 1603 // No history to merge and a committed page to be pruned. 1604 frame()->didCommitProvisionalLoad(GetMainFrame(), 1605 item, 1606 blink::WebStandardCommit); 1607 expected_page_id = view()->page_id_; 1608 view()->OnSetHistoryLengthAndPrune(0, expected_page_id + 1); 1609 EXPECT_EQ(0, view()->history_list_length_); 1610 EXPECT_EQ(-1, view()->history_list_offset_); 1611 ClearHistory(); 1612 1613 // No history to merge and a committed page that the browser was unaware of. 1614 frame()->didCommitProvisionalLoad(GetMainFrame(), 1615 item, 1616 blink::WebStandardCommit); 1617 expected_page_id = view()->page_id_; 1618 view()->OnSetHistoryLengthAndPrune(0, -1); 1619 EXPECT_EQ(1, view()->history_list_length_); 1620 EXPECT_EQ(0, view()->history_list_offset_); 1621 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]); 1622 ClearHistory(); 1623 1624 // History to merge and a committed page to be kept. 1625 frame()->didCommitProvisionalLoad(GetMainFrame(), 1626 item, 1627 blink::WebStandardCommit); 1628 expected_page_id = view()->page_id_; 1629 view()->OnSetHistoryLengthAndPrune(2, expected_page_id); 1630 EXPECT_EQ(3, view()->history_list_length_); 1631 EXPECT_EQ(2, view()->history_list_offset_); 1632 EXPECT_EQ(-1, view()->history_page_ids_[0]); 1633 EXPECT_EQ(-1, view()->history_page_ids_[1]); 1634 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]); 1635 ClearHistory(); 1636 1637 // History to merge and a committed page to be pruned. 1638 frame()->didCommitProvisionalLoad(GetMainFrame(), 1639 item, 1640 blink::WebStandardCommit); 1641 expected_page_id = view()->page_id_; 1642 view()->OnSetHistoryLengthAndPrune(2, expected_page_id + 1); 1643 EXPECT_EQ(2, view()->history_list_length_); 1644 EXPECT_EQ(1, view()->history_list_offset_); 1645 EXPECT_EQ(-1, view()->history_page_ids_[0]); 1646 EXPECT_EQ(-1, view()->history_page_ids_[1]); 1647 ClearHistory(); 1648 1649 // History to merge and a committed page that the browser was unaware of. 1650 frame()->didCommitProvisionalLoad(GetMainFrame(), 1651 item, 1652 blink::WebStandardCommit); 1653 expected_page_id = view()->page_id_; 1654 view()->OnSetHistoryLengthAndPrune(2, -1); 1655 EXPECT_EQ(3, view()->history_list_length_); 1656 EXPECT_EQ(2, view()->history_list_offset_); 1657 EXPECT_EQ(-1, view()->history_page_ids_[0]); 1658 EXPECT_EQ(-1, view()->history_page_ids_[1]); 1659 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]); 1660 ClearHistory(); 1661 1662 int expected_page_id_2 = -1; 1663 1664 // No history to merge and two committed pages, both to be kept. 1665 frame()->didCommitProvisionalLoad(GetMainFrame(), 1666 item, 1667 blink::WebStandardCommit); 1668 expected_page_id = view()->page_id_; 1669 frame()->didCommitProvisionalLoad(GetMainFrame(), 1670 item, 1671 blink::WebStandardCommit); 1672 expected_page_id_2 = view()->page_id_; 1673 EXPECT_GT(expected_page_id_2, expected_page_id); 1674 view()->OnSetHistoryLengthAndPrune(0, expected_page_id); 1675 EXPECT_EQ(2, view()->history_list_length_); 1676 EXPECT_EQ(1, view()->history_list_offset_); 1677 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]); 1678 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[1]); 1679 ClearHistory(); 1680 1681 // No history to merge and two committed pages, and only the second is kept. 1682 frame()->didCommitProvisionalLoad(GetMainFrame(), 1683 item, 1684 blink::WebStandardCommit); 1685 expected_page_id = view()->page_id_; 1686 frame()->didCommitProvisionalLoad(GetMainFrame(), 1687 item, 1688 blink::WebStandardCommit); 1689 expected_page_id_2 = view()->page_id_; 1690 EXPECT_GT(expected_page_id_2, expected_page_id); 1691 view()->OnSetHistoryLengthAndPrune(0, expected_page_id_2); 1692 EXPECT_EQ(1, view()->history_list_length_); 1693 EXPECT_EQ(0, view()->history_list_offset_); 1694 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[0]); 1695 ClearHistory(); 1696 1697 // No history to merge and two committed pages, both of which the browser was 1698 // unaware of. 1699 frame()->didCommitProvisionalLoad(GetMainFrame(), 1700 item, 1701 blink::WebStandardCommit); 1702 expected_page_id = view()->page_id_; 1703 frame()->didCommitProvisionalLoad(GetMainFrame(), 1704 item, 1705 blink::WebStandardCommit); 1706 expected_page_id_2 = view()->page_id_; 1707 EXPECT_GT(expected_page_id_2, expected_page_id); 1708 view()->OnSetHistoryLengthAndPrune(0, -1); 1709 EXPECT_EQ(2, view()->history_list_length_); 1710 EXPECT_EQ(1, view()->history_list_offset_); 1711 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]); 1712 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[1]); 1713 ClearHistory(); 1714 1715 // History to merge and two committed pages, both to be kept. 1716 frame()->didCommitProvisionalLoad(GetMainFrame(), 1717 item, 1718 blink::WebStandardCommit); 1719 expected_page_id = view()->page_id_; 1720 frame()->didCommitProvisionalLoad(GetMainFrame(), 1721 item, 1722 blink::WebStandardCommit); 1723 expected_page_id_2 = view()->page_id_; 1724 EXPECT_GT(expected_page_id_2, expected_page_id); 1725 view()->OnSetHistoryLengthAndPrune(2, expected_page_id); 1726 EXPECT_EQ(4, view()->history_list_length_); 1727 EXPECT_EQ(3, view()->history_list_offset_); 1728 EXPECT_EQ(-1, view()->history_page_ids_[0]); 1729 EXPECT_EQ(-1, view()->history_page_ids_[1]); 1730 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]); 1731 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[3]); 1732 ClearHistory(); 1733 1734 // History to merge and two committed pages, and only the second is kept. 1735 frame()->didCommitProvisionalLoad(GetMainFrame(), 1736 item, 1737 blink::WebStandardCommit); 1738 expected_page_id = view()->page_id_; 1739 frame()->didCommitProvisionalLoad(GetMainFrame(), 1740 item, 1741 blink::WebStandardCommit); 1742 expected_page_id_2 = view()->page_id_; 1743 EXPECT_GT(expected_page_id_2, expected_page_id); 1744 view()->OnSetHistoryLengthAndPrune(2, expected_page_id_2); 1745 EXPECT_EQ(3, view()->history_list_length_); 1746 EXPECT_EQ(2, view()->history_list_offset_); 1747 EXPECT_EQ(-1, view()->history_page_ids_[0]); 1748 EXPECT_EQ(-1, view()->history_page_ids_[1]); 1749 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[2]); 1750 ClearHistory(); 1751 1752 // History to merge and two committed pages, both of which the browser was 1753 // unaware of. 1754 frame()->didCommitProvisionalLoad(GetMainFrame(), 1755 item, 1756 blink::WebStandardCommit); 1757 expected_page_id = view()->page_id_; 1758 frame()->didCommitProvisionalLoad(GetMainFrame(), 1759 item, 1760 blink::WebStandardCommit); 1761 expected_page_id_2 = view()->page_id_; 1762 EXPECT_GT(expected_page_id_2, expected_page_id); 1763 view()->OnSetHistoryLengthAndPrune(2, -1); 1764 EXPECT_EQ(4, view()->history_list_length_); 1765 EXPECT_EQ(3, view()->history_list_offset_); 1766 EXPECT_EQ(-1, view()->history_page_ids_[0]); 1767 EXPECT_EQ(-1, view()->history_page_ids_[1]); 1768 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]); 1769 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[3]); 1770 } 1771 1772 TEST_F(RenderViewImplTest, ContextMenu) { 1773 LoadHTML("<div>Page A</div>"); 1774 1775 // Create a right click in the center of the iframe. (I'm hoping this will 1776 // make this a bit more robust in case of some other formatting or other bug.) 1777 WebMouseEvent mouse_event; 1778 mouse_event.type = WebInputEvent::MouseDown; 1779 mouse_event.button = WebMouseEvent::ButtonRight; 1780 mouse_event.x = 250; 1781 mouse_event.y = 250; 1782 mouse_event.globalX = 250; 1783 mouse_event.globalY = 250; 1784 1785 SendWebMouseEvent(mouse_event); 1786 1787 // Now simulate the corresponding up event which should display the menu 1788 mouse_event.type = WebInputEvent::MouseUp; 1789 SendWebMouseEvent(mouse_event); 1790 1791 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching( 1792 FrameHostMsg_ContextMenu::ID)); 1793 } 1794 1795 TEST_F(RenderViewImplTest, TestBackForward) { 1796 LoadHTML("<div id=pagename>Page A</div>"); 1797 PageState page_a_state = 1798 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry()); 1799 int was_page_a = -1; 1800 base::string16 check_page_a = 1801 base::ASCIIToUTF16( 1802 "Number(document.getElementById('pagename').innerHTML == 'Page A')"); 1803 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a)); 1804 EXPECT_EQ(1, was_page_a); 1805 1806 LoadHTML("<div id=pagename>Page B</div>"); 1807 int was_page_b = -1; 1808 base::string16 check_page_b = 1809 base::ASCIIToUTF16( 1810 "Number(document.getElementById('pagename').innerHTML == 'Page B')"); 1811 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b)); 1812 EXPECT_EQ(1, was_page_b); 1813 1814 PageState back_state = 1815 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry()); 1816 1817 LoadHTML("<div id=pagename>Page C</div>"); 1818 int was_page_c = -1; 1819 base::string16 check_page_c = 1820 base::ASCIIToUTF16( 1821 "Number(document.getElementById('pagename').innerHTML == 'Page C')"); 1822 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c)); 1823 EXPECT_EQ(1, was_page_b); 1824 1825 PageState forward_state = 1826 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry()); 1827 GoBack(back_state); 1828 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b)); 1829 EXPECT_EQ(1, was_page_b); 1830 1831 PageState back_state2 = 1832 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry()); 1833 1834 GoForward(forward_state); 1835 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c)); 1836 EXPECT_EQ(1, was_page_c); 1837 1838 GoBack(back_state2); 1839 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b)); 1840 EXPECT_EQ(1, was_page_b); 1841 1842 forward_state = 1843 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry()); 1844 GoBack(page_a_state); 1845 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a)); 1846 EXPECT_EQ(1, was_page_a); 1847 1848 GoForward(forward_state); 1849 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b)); 1850 EXPECT_EQ(1, was_page_b); 1851 } 1852 1853 #if defined(OS_MACOSX) || defined(USE_AURA) 1854 TEST_F(RenderViewImplTest, GetCompositionCharacterBoundsTest) { 1855 1856 #if defined(OS_WIN) 1857 // http://crbug.com/304193 1858 if (base::win::GetVersion() < base::win::VERSION_VISTA) 1859 return; 1860 #endif 1861 1862 LoadHTML("<textarea id=\"test\"></textarea>"); 1863 ExecuteJavaScript("document.getElementById('test').focus();"); 1864 1865 const base::string16 empty_string; 1866 const std::vector<blink::WebCompositionUnderline> empty_underline; 1867 std::vector<gfx::Rect> bounds; 1868 view()->OnSetFocus(true); 1869 view()->OnSetInputMethodActive(true); 1870 1871 // ASCII composition 1872 const base::string16 ascii_composition = base::UTF8ToUTF16("aiueo"); 1873 view()->OnImeSetComposition(ascii_composition, empty_underline, 0, 0); 1874 view()->GetCompositionCharacterBounds(&bounds); 1875 ASSERT_EQ(ascii_composition.size(), bounds.size()); 1876 for (size_t i = 0; i < bounds.size(); ++i) 1877 EXPECT_LT(0, bounds[i].width()); 1878 view()->OnImeConfirmComposition( 1879 empty_string, gfx::Range::InvalidRange(), false); 1880 1881 // Non surrogate pair unicode character. 1882 const base::string16 unicode_composition = base::UTF8ToUTF16( 1883 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A"); 1884 view()->OnImeSetComposition(unicode_composition, empty_underline, 0, 0); 1885 view()->GetCompositionCharacterBounds(&bounds); 1886 ASSERT_EQ(unicode_composition.size(), bounds.size()); 1887 for (size_t i = 0; i < bounds.size(); ++i) 1888 EXPECT_LT(0, bounds[i].width()); 1889 view()->OnImeConfirmComposition( 1890 empty_string, gfx::Range::InvalidRange(), false); 1891 1892 // Surrogate pair character. 1893 const base::string16 surrogate_pair_char = 1894 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F"); 1895 view()->OnImeSetComposition(surrogate_pair_char, 1896 empty_underline, 1897 0, 1898 0); 1899 view()->GetCompositionCharacterBounds(&bounds); 1900 ASSERT_EQ(surrogate_pair_char.size(), bounds.size()); 1901 EXPECT_LT(0, bounds[0].width()); 1902 EXPECT_EQ(0, bounds[1].width()); 1903 view()->OnImeConfirmComposition( 1904 empty_string, gfx::Range::InvalidRange(), false); 1905 1906 // Mixed string. 1907 const base::string16 surrogate_pair_mixed_composition = 1908 surrogate_pair_char + base::UTF8ToUTF16("\xE3\x81\x82") + 1909 surrogate_pair_char + base::UTF8ToUTF16("b") + surrogate_pair_char; 1910 const size_t utf16_length = 8UL; 1911 const bool is_surrogate_pair_empty_rect[8] = { 1912 false, true, false, false, true, false, false, true }; 1913 view()->OnImeSetComposition(surrogate_pair_mixed_composition, 1914 empty_underline, 1915 0, 1916 0); 1917 view()->GetCompositionCharacterBounds(&bounds); 1918 ASSERT_EQ(utf16_length, bounds.size()); 1919 for (size_t i = 0; i < utf16_length; ++i) { 1920 if (is_surrogate_pair_empty_rect[i]) { 1921 EXPECT_EQ(0, bounds[i].width()); 1922 } else { 1923 EXPECT_LT(0, bounds[i].width()); 1924 } 1925 } 1926 view()->OnImeConfirmComposition( 1927 empty_string, gfx::Range::InvalidRange(), false); 1928 } 1929 #endif 1930 1931 TEST_F(RenderViewImplTest, ZoomLimit) { 1932 const double kMinZoomLevel = ZoomFactorToZoomLevel(kMinimumZoomFactor); 1933 const double kMaxZoomLevel = ZoomFactorToZoomLevel(kMaximumZoomFactor); 1934 1935 FrameMsg_Navigate_Params params; 1936 params.page_id = -1; 1937 params.navigation_type = FrameMsg_Navigate_Type::NORMAL; 1938 1939 // Verifies navigation to a URL with preset zoom level indeed sets the level. 1940 // Regression test for http://crbug.com/139559, where the level was not 1941 // properly set when it is out of the default zoom limits of WebView. 1942 params.url = GURL("data:text/html,min_zoomlimit_test"); 1943 view()->OnSetZoomLevelForLoadingURL(params.url, kMinZoomLevel); 1944 frame()->OnNavigate(params); 1945 ProcessPendingMessages(); 1946 EXPECT_DOUBLE_EQ(kMinZoomLevel, view()->GetWebView()->zoomLevel()); 1947 1948 // It should work even when the zoom limit is temporarily changed in the page. 1949 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0), 1950 ZoomFactorToZoomLevel(1.0)); 1951 params.url = GURL("data:text/html,max_zoomlimit_test"); 1952 view()->OnSetZoomLevelForLoadingURL(params.url, kMaxZoomLevel); 1953 frame()->OnNavigate(params); 1954 ProcessPendingMessages(); 1955 EXPECT_DOUBLE_EQ(kMaxZoomLevel, view()->GetWebView()->zoomLevel()); 1956 } 1957 1958 TEST_F(RenderViewImplTest, SetEditableSelectionAndComposition) { 1959 // Load an HTML page consisting of an input field. 1960 LoadHTML("<html>" 1961 "<head>" 1962 "</head>" 1963 "<body>" 1964 "<input id=\"test1\" value=\"some test text hello\"></input>" 1965 "</body>" 1966 "</html>"); 1967 ExecuteJavaScript("document.getElementById('test1').focus();"); 1968 frame()->OnSetEditableSelectionOffsets(4, 8); 1969 const std::vector<blink::WebCompositionUnderline> empty_underline; 1970 frame()->OnSetCompositionFromExistingText(7, 10, empty_underline); 1971 blink::WebTextInputInfo info = view()->webview()->textInputInfo(); 1972 EXPECT_EQ(4, info.selectionStart); 1973 EXPECT_EQ(8, info.selectionEnd); 1974 EXPECT_EQ(7, info.compositionStart); 1975 EXPECT_EQ(10, info.compositionEnd); 1976 frame()->OnUnselect(); 1977 info = view()->webview()->textInputInfo(); 1978 EXPECT_EQ(0, info.selectionStart); 1979 EXPECT_EQ(0, info.selectionEnd); 1980 } 1981 1982 1983 TEST_F(RenderViewImplTest, OnExtendSelectionAndDelete) { 1984 // Load an HTML page consisting of an input field. 1985 LoadHTML("<html>" 1986 "<head>" 1987 "</head>" 1988 "<body>" 1989 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>" 1990 "</body>" 1991 "</html>"); 1992 ExecuteJavaScript("document.getElementById('test1').focus();"); 1993 frame()->OnSetEditableSelectionOffsets(10, 10); 1994 frame()->OnExtendSelectionAndDelete(3, 4); 1995 blink::WebTextInputInfo info = view()->webview()->textInputInfo(); 1996 EXPECT_EQ("abcdefgopqrstuvwxyz", info.value); 1997 EXPECT_EQ(7, info.selectionStart); 1998 EXPECT_EQ(7, info.selectionEnd); 1999 frame()->OnSetEditableSelectionOffsets(4, 8); 2000 frame()->OnExtendSelectionAndDelete(2, 5); 2001 info = view()->webview()->textInputInfo(); 2002 EXPECT_EQ("abuvwxyz", info.value); 2003 EXPECT_EQ(2, info.selectionStart); 2004 EXPECT_EQ(2, info.selectionEnd); 2005 } 2006 2007 // Test that the navigating specific frames works correctly. 2008 TEST_F(RenderViewImplTest, NavigateFrame) { 2009 // Load page A. 2010 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>"); 2011 2012 // Navigate the frame only. 2013 FrameMsg_Navigate_Params nav_params; 2014 nav_params.url = GURL("data:text/html,world"); 2015 nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL; 2016 nav_params.transition = PAGE_TRANSITION_TYPED; 2017 nav_params.current_history_list_length = 1; 2018 nav_params.current_history_list_offset = 0; 2019 nav_params.pending_history_list_offset = 1; 2020 nav_params.page_id = -1; 2021 nav_params.frame_to_navigate = "frame"; 2022 frame()->OnNavigate(nav_params); 2023 FrameLoadWaiter( 2024 RenderFrame::FromWebFrame(frame()->GetWebFrame()->firstChild())).Wait(); 2025 2026 // Copy the document content to std::wstring and compare with the 2027 // expected result. 2028 const int kMaxOutputCharacters = 256; 2029 std::string output = base::UTF16ToUTF8( 2030 GetMainFrame()->contentAsText(kMaxOutputCharacters)); 2031 EXPECT_EQ(output, "hello \n\nworld"); 2032 } 2033 2034 // This test ensures that a RenderFrame object is created for the top level 2035 // frame in the RenderView. 2036 TEST_F(RenderViewImplTest, BasicRenderFrame) { 2037 EXPECT_TRUE(view()->main_render_frame_.get()); 2038 } 2039 2040 TEST_F(RenderViewImplTest, GetSSLStatusOfFrame) { 2041 LoadHTML("<!DOCTYPE html><html><body></body></html>"); 2042 2043 WebLocalFrame* frame = GetMainFrame(); 2044 SSLStatus ssl_status = view()->GetSSLStatusOfFrame(frame); 2045 EXPECT_FALSE(net::IsCertStatusError(ssl_status.cert_status)); 2046 2047 const_cast<blink::WebURLResponse&>(frame->dataSource()->response()). 2048 setSecurityInfo( 2049 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS, 0, 0, 2050 SignedCertificateTimestampIDStatusList())); 2051 ssl_status = view()->GetSSLStatusOfFrame(frame); 2052 EXPECT_TRUE(net::IsCertStatusError(ssl_status.cert_status)); 2053 } 2054 2055 TEST_F(RenderViewImplTest, MessageOrderInDidChangeSelection) { 2056 view()->OnSetInputMethodActive(true); 2057 view()->set_send_content_state_immediately(true); 2058 LoadHTML("<textarea id=\"test\"></textarea>"); 2059 2060 view()->handling_input_event_ = true; 2061 ExecuteJavaScript("document.getElementById('test').focus();"); 2062 2063 bool is_input_type_called = false; 2064 bool is_selection_called = false; 2065 size_t last_input_type = 0; 2066 size_t last_selection = 0; 2067 2068 for (size_t i = 0; i < render_thread_->sink().message_count(); ++i) { 2069 const uint32 type = render_thread_->sink().GetMessageAt(i)->type(); 2070 if (type == ViewHostMsg_TextInputStateChanged::ID) { 2071 is_input_type_called = true; 2072 last_input_type = i; 2073 } else if (type == ViewHostMsg_SelectionChanged::ID) { 2074 is_selection_called = true; 2075 last_selection = i; 2076 } 2077 } 2078 2079 EXPECT_TRUE(is_input_type_called); 2080 EXPECT_TRUE(is_selection_called); 2081 2082 // InputTypeChange shold be called earlier than SelectionChanged. 2083 EXPECT_LT(last_input_type, last_selection); 2084 } 2085 2086 class SuppressErrorPageTest : public RenderViewTest { 2087 public: 2088 virtual ContentRendererClient* CreateContentRendererClient() OVERRIDE { 2089 return new TestContentRendererClient; 2090 } 2091 2092 RenderViewImpl* view() { 2093 return static_cast<RenderViewImpl*>(view_); 2094 } 2095 2096 RenderFrameImpl* frame() { 2097 return static_cast<RenderFrameImpl*>(view()->GetMainRenderFrame()); 2098 } 2099 2100 private: 2101 class TestContentRendererClient : public ContentRendererClient { 2102 public: 2103 virtual bool ShouldSuppressErrorPage(RenderFrame* render_frame, 2104 const GURL& url) OVERRIDE { 2105 return url == GURL("http://example.com/suppress"); 2106 } 2107 2108 virtual void GetNavigationErrorStrings( 2109 content::RenderView* render_view, 2110 blink::WebFrame* frame, 2111 const blink::WebURLRequest& failed_request, 2112 const blink::WebURLError& error, 2113 std::string* error_html, 2114 base::string16* error_description) OVERRIDE { 2115 if (error_html) 2116 *error_html = "A suffusion of yellow."; 2117 } 2118 }; 2119 }; 2120 2121 #if defined(OS_ANDROID) 2122 // Crashing on Android: http://crbug.com/311341 2123 #define MAYBE_Suppresses DISABLED_Suppresses 2124 #else 2125 #define MAYBE_Suppresses Suppresses 2126 #endif 2127 2128 TEST_F(SuppressErrorPageTest, MAYBE_Suppresses) { 2129 WebURLError error; 2130 error.domain = WebString::fromUTF8(net::kErrorDomain); 2131 error.reason = net::ERR_FILE_NOT_FOUND; 2132 error.unreachableURL = GURL("http://example.com/suppress"); 2133 WebLocalFrame* web_frame = GetMainFrame(); 2134 2135 // Start a load that will reach provisional state synchronously, 2136 // but won't complete synchronously. 2137 FrameMsg_Navigate_Params params; 2138 params.page_id = -1; 2139 params.navigation_type = FrameMsg_Navigate_Type::NORMAL; 2140 params.url = GURL("data:text/html,test data"); 2141 frame()->OnNavigate(params); 2142 2143 // An error occurred. 2144 view()->main_render_frame()->didFailProvisionalLoad(web_frame, error); 2145 const int kMaxOutputCharacters = 22; 2146 EXPECT_EQ("", 2147 base::UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters))); 2148 } 2149 2150 #if defined(OS_ANDROID) 2151 // Crashing on Android: http://crbug.com/311341 2152 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress 2153 #else 2154 #define MAYBE_DoesNotSuppress DoesNotSuppress 2155 #endif 2156 2157 TEST_F(SuppressErrorPageTest, MAYBE_DoesNotSuppress) { 2158 WebURLError error; 2159 error.domain = WebString::fromUTF8(net::kErrorDomain); 2160 error.reason = net::ERR_FILE_NOT_FOUND; 2161 error.unreachableURL = GURL("http://example.com/dont-suppress"); 2162 WebLocalFrame* web_frame = GetMainFrame(); 2163 2164 // Start a load that will reach provisional state synchronously, 2165 // but won't complete synchronously. 2166 FrameMsg_Navigate_Params params; 2167 params.page_id = -1; 2168 params.navigation_type = FrameMsg_Navigate_Type::NORMAL; 2169 params.url = GURL("data:text/html,test data"); 2170 frame()->OnNavigate(params); 2171 2172 // An error occurred. 2173 view()->main_render_frame()->didFailProvisionalLoad(web_frame, error); 2174 // The error page itself is loaded asynchronously. 2175 FrameLoadWaiter(frame()).Wait(); 2176 const int kMaxOutputCharacters = 22; 2177 EXPECT_EQ("A suffusion of yellow.", 2178 base::UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters))); 2179 } 2180 2181 // Tests if IME API's candidatewindow* events sent from browser are handled 2182 // in renderer. 2183 TEST_F(RenderViewImplTest, SendCandidateWindowEvents) { 2184 // Sends an HTML with an <input> element and scripts to the renderer. 2185 // The script handles all 3 of candidatewindow* events for an 2186 // InputMethodContext object and once it received 'show', 'update', 'hide' 2187 // should appear in the result div. 2188 LoadHTML("<input id='test'>" 2189 "<div id='result'>Result: </div>" 2190 "<script>" 2191 "window.onload = function() {" 2192 " var result = document.getElementById('result');" 2193 " var test = document.getElementById('test');" 2194 " test.focus();" 2195 " var context = test.inputMethodContext;" 2196 " if (context) {" 2197 " context.oncandidatewindowshow = function() {" 2198 " result.innerText += 'show'; };" 2199 " context.oncandidatewindowupdate = function(){" 2200 " result.innerText += 'update'; };" 2201 " context.oncandidatewindowhide = function(){" 2202 " result.innerText += 'hide'; };" 2203 " }" 2204 "};" 2205 "</script>"); 2206 2207 // Fire candidatewindow events. 2208 view()->OnCandidateWindowShown(); 2209 view()->OnCandidateWindowUpdated(); 2210 view()->OnCandidateWindowHidden(); 2211 2212 // Retrieve the content and check if it is expected. 2213 const int kMaxOutputCharacters = 50; 2214 std::string output = base::UTF16ToUTF8( 2215 GetMainFrame()->contentAsText(kMaxOutputCharacters)); 2216 EXPECT_EQ(output, "\nResult:showupdatehide"); 2217 } 2218 2219 // Ensure the render view sends favicon url update events correctly. 2220 TEST_F(RenderViewImplTest, SendFaviconURLUpdateEvent) { 2221 // An event should be sent when a favicon url exists. 2222 LoadHTML("<html>" 2223 "<head>" 2224 "<link rel='icon' href='http://www.google.com/favicon.ico'>" 2225 "</head>" 2226 "</html>"); 2227 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching( 2228 ViewHostMsg_UpdateFaviconURL::ID)); 2229 render_thread_->sink().ClearMessages(); 2230 2231 // An event should not be sent if no favicon url exists. This is an assumption 2232 // made by some of Chrome's favicon handling. 2233 LoadHTML("<html>" 2234 "<head>" 2235 "</head>" 2236 "</html>"); 2237 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching( 2238 ViewHostMsg_UpdateFaviconURL::ID)); 2239 } 2240 2241 TEST_F(RenderViewImplTest, FocusElementCallsFocusedNodeChanged) { 2242 LoadHTML("<input id='test1' value='hello1'></input>" 2243 "<input id='test2' value='hello2'></input>"); 2244 2245 ExecuteJavaScript("document.getElementById('test1').focus();"); 2246 const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching( 2247 ViewHostMsg_FocusedNodeChanged::ID); 2248 EXPECT_TRUE(msg1); 2249 2250 ViewHostMsg_FocusedNodeChanged::Param params; 2251 ViewHostMsg_FocusedNodeChanged::Read(msg1, ¶ms); 2252 EXPECT_TRUE(params.a); 2253 render_thread_->sink().ClearMessages(); 2254 2255 ExecuteJavaScript("document.getElementById('test2').focus();"); 2256 const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching( 2257 ViewHostMsg_FocusedNodeChanged::ID); 2258 EXPECT_TRUE(msg2); 2259 ViewHostMsg_FocusedNodeChanged::Read(msg2, ¶ms); 2260 EXPECT_TRUE(params.a); 2261 render_thread_->sink().ClearMessages(); 2262 2263 view()->webview()->clearFocusedElement(); 2264 const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching( 2265 ViewHostMsg_FocusedNodeChanged::ID); 2266 EXPECT_TRUE(msg3); 2267 ViewHostMsg_FocusedNodeChanged::Read(msg3, ¶ms); 2268 EXPECT_FALSE(params.a); 2269 render_thread_->sink().ClearMessages(); 2270 } 2271 2272 TEST_F(RenderViewImplTest, ServiceWorkerNetworkProviderSetup) { 2273 ServiceWorkerNetworkProvider* provider = NULL; 2274 RequestExtraData* extra_data = NULL; 2275 2276 // Make sure each new document has a new provider and 2277 // that the main request is tagged with the provider's id. 2278 LoadHTML("<b>A Document</b>"); 2279 ASSERT_TRUE(GetMainFrame()->dataSource()); 2280 provider = ServiceWorkerNetworkProvider::FromDocumentState( 2281 DocumentState::FromDataSource(GetMainFrame()->dataSource())); 2282 ASSERT_TRUE(provider); 2283 extra_data = static_cast<RequestExtraData*>( 2284 GetMainFrame()->dataSource()->request().extraData()); 2285 ASSERT_TRUE(extra_data); 2286 EXPECT_EQ(extra_data->service_worker_provider_id(), 2287 provider->provider_id()); 2288 int provider1_id = provider->provider_id(); 2289 2290 LoadHTML("<b>New Document B Goes Here</b>"); 2291 ASSERT_TRUE(GetMainFrame()->dataSource()); 2292 provider = ServiceWorkerNetworkProvider::FromDocumentState( 2293 DocumentState::FromDataSource(GetMainFrame()->dataSource())); 2294 ASSERT_TRUE(provider); 2295 EXPECT_NE(provider1_id, provider->provider_id()); 2296 extra_data = static_cast<RequestExtraData*>( 2297 GetMainFrame()->dataSource()->request().extraData()); 2298 ASSERT_TRUE(extra_data); 2299 EXPECT_EQ(extra_data->service_worker_provider_id(), 2300 provider->provider_id()); 2301 2302 // See that subresource requests are also tagged with the provider's id. 2303 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame())); 2304 blink::WebURLRequest request(GURL("http://foo.com")); 2305 request.setTargetType(blink::WebURLRequest::TargetIsSubresource); 2306 blink::WebURLResponse redirect_response; 2307 frame()->willSendRequest(GetMainFrame(), 0, request, redirect_response); 2308 extra_data = static_cast<RequestExtraData*>(request.extraData()); 2309 ASSERT_TRUE(extra_data); 2310 EXPECT_EQ(extra_data->service_worker_provider_id(), 2311 provider->provider_id()); 2312 } 2313 2314 TEST_F(RenderViewImplTest, OnSetAccessibilityMode) { 2315 ASSERT_EQ(AccessibilityModeOff, view()->accessibility_mode()); 2316 ASSERT_EQ((RendererAccessibility*) NULL, view()->renderer_accessibility()); 2317 2318 view()->OnSetAccessibilityMode(AccessibilityModeTreeOnly); 2319 ASSERT_EQ(AccessibilityModeTreeOnly, view()->accessibility_mode()); 2320 ASSERT_NE((RendererAccessibility*) NULL, view()->renderer_accessibility()); 2321 ASSERT_EQ(RendererAccessibilityTypeComplete, 2322 view()->renderer_accessibility()->GetType()); 2323 2324 view()->OnSetAccessibilityMode(AccessibilityModeOff); 2325 ASSERT_EQ(AccessibilityModeOff, view()->accessibility_mode()); 2326 ASSERT_EQ((RendererAccessibility*) NULL, view()->renderer_accessibility()); 2327 2328 view()->OnSetAccessibilityMode(AccessibilityModeComplete); 2329 ASSERT_EQ(AccessibilityModeComplete, view()->accessibility_mode()); 2330 ASSERT_NE((RendererAccessibility*) NULL, view()->renderer_accessibility()); 2331 ASSERT_EQ(RendererAccessibilityTypeComplete, 2332 view()->renderer_accessibility()->GetType()); 2333 2334 view()->OnSetAccessibilityMode(AccessibilityModeEditableTextOnly); 2335 ASSERT_EQ(AccessibilityModeEditableTextOnly, view()->accessibility_mode()); 2336 ASSERT_NE((RendererAccessibility*) NULL, view()->renderer_accessibility()); 2337 ASSERT_EQ(RendererAccessibilityTypeFocusOnly, 2338 view()->renderer_accessibility()->GetType()); 2339 } 2340 2341 TEST_F(RenderViewImplTest, ScreenMetricsEmulation) { 2342 LoadHTML("<body style='min-height:1000px;'></body>"); 2343 2344 blink::WebDeviceEmulationParams params; 2345 base::string16 get_width = base::ASCIIToUTF16("Number(window.innerWidth)"); 2346 base::string16 get_height = base::ASCIIToUTF16("Number(window.innerHeight)"); 2347 int width, height; 2348 2349 params.viewSize.width = 327; 2350 params.viewSize.height = 415; 2351 view()->EnableScreenMetricsEmulation(params); 2352 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width)); 2353 EXPECT_EQ(params.viewSize.width, width); 2354 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height)); 2355 EXPECT_EQ(params.viewSize.height, height); 2356 2357 params.viewSize.width = 1005; 2358 params.viewSize.height = 1102; 2359 view()->EnableScreenMetricsEmulation(params); 2360 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width)); 2361 EXPECT_EQ(params.viewSize.width, width); 2362 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height)); 2363 EXPECT_EQ(params.viewSize.height, height); 2364 2365 view()->DisableScreenMetricsEmulation(); 2366 2367 view()->EnableScreenMetricsEmulation(params); 2368 // Don't disable here to test that emulation is being shutdown properly. 2369 } 2370 2371 } // namespace content 2372