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