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