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