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