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/history_item_serialization.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/render_view_impl.h"
35 #include "content/shell/browser/shell.h"
36 #include "content/shell/browser/shell_browser_context.h"
37 #include "content/test/mock_keyboard.h"
38 #include "net/base/net_errors.h"
39 #include "net/cert/cert_status_flags.h"
40 #include "testing/gtest/include/gtest/gtest.h"
41 #include "third_party/WebKit/public/platform/WebData.h"
42 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
43 #include "third_party/WebKit/public/platform/WebString.h"
44 #include "third_party/WebKit/public/platform/WebURLResponse.h"
45 #include "third_party/WebKit/public/web/WebDataSource.h"
46 #include "third_party/WebKit/public/web/WebFrame.h"
47 #include "third_party/WebKit/public/web/WebHistoryItem.h"
48 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
49 #include "third_party/WebKit/public/web/WebView.h"
50 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
51 #include "ui/events/keycodes/keyboard_codes.h"
52 #include "ui/gfx/codec/jpeg_codec.h"
53 #include "ui/gfx/range/range.h"
55 #if defined(OS_LINUX) && !defined(USE_AURA)
56 #include "ui/base/gtk/event_synthesis_gtk.h"
60 #include "ui/events/event.h"
63 #if defined(USE_AURA) && defined(USE_X11)
65 #include "ui/events/event_constants.h"
66 #include "ui/events/keycodes/keyboard_code_conversion.h"
67 #include "ui/events/test/events_test_utils_x11.h"
70 #if defined(USE_OZONE)
71 #include "ui/events/keycodes/keyboard_code_conversion.h"
74 using blink::WebFrame;
75 using blink::WebInputEvent;
76 using blink::WebMouseEvent;
77 using blink::WebRuntimeFeatures;
78 using blink::WebString;
79 using blink::WebTextDirection;
80 using blink::WebURLError;
86 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
87 // Converts MockKeyboard::Modifiers to ui::EventFlags.
88 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers) {
89 static struct ModifierMap {
90 MockKeyboard::Modifiers src;
93 { MockKeyboard::LEFT_SHIFT, ui::EF_SHIFT_DOWN },
94 { MockKeyboard::RIGHT_SHIFT, ui::EF_SHIFT_DOWN },
95 { MockKeyboard::LEFT_CONTROL, ui::EF_CONTROL_DOWN },
96 { MockKeyboard::RIGHT_CONTROL, ui::EF_CONTROL_DOWN },
97 { MockKeyboard::LEFT_ALT, ui::EF_ALT_DOWN },
98 { MockKeyboard::RIGHT_ALT, ui::EF_ALT_DOWN },
101 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kModifierMap); ++i) {
102 if (kModifierMap[i].src & modifiers) {
103 flags |= kModifierMap[i].dst;
110 class WebUITestWebUIControllerFactory : public WebUIControllerFactory {
112 virtual WebUIController* CreateWebUIControllerForURL(
113 WebUI* web_ui, const GURL& url) const OVERRIDE {
116 virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
117 const GURL& url) const OVERRIDE {
118 return WebUI::kNoWebUI;
120 virtual bool UseWebUIForURL(BrowserContext* browser_context,
121 const GURL& url) const OVERRIDE {
122 return HasWebUIScheme(url);
124 virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
125 const GURL& url) const OVERRIDE {
126 return HasWebUIScheme(url);
130 class RenderViewImplTest : public RenderViewTest {
132 RenderViewImplTest() {
133 // Attach a pseudo keyboard device to this object.
134 mock_keyboard_.reset(new MockKeyboard());
137 virtual ~RenderViewImplTest() {}
139 virtual void SetUp() OVERRIDE {
140 RenderViewTest::SetUp();
141 // Enable Blink's experimental and test only features so that test code
142 // does not have to bother enabling each feature.
143 WebRuntimeFeatures::enableExperimentalFeatures(true);
144 WebRuntimeFeatures::enableTestOnlyFeatures(true);
147 RenderViewImpl* view() {
148 return static_cast<RenderViewImpl*>(view_);
151 RenderFrameImpl* frame() {
152 return static_cast<RenderFrameImpl*>(view()->GetMainRenderFrame());
155 // Sends IPC messages that emulates a key-press event.
156 int SendKeyEvent(MockKeyboard::Layout layout,
158 MockKeyboard::Modifiers modifiers,
159 base::string16* output) {
161 // Retrieve the Unicode character for the given tuple (keyboard-layout,
162 // key-code, and modifiers).
163 // Exit when a keyboard-layout driver cannot assign a Unicode character to
164 // the tuple to prevent sending an invalid key code to the RenderView
166 CHECK(mock_keyboard_.get());
168 int length = mock_keyboard_->GetCharacters(layout, key_code, modifiers,
173 // Create IPC messages from Windows messages and send them to our
175 // A keyboard event of Windows consists of three Windows messages:
176 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
177 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
178 // WM_CHAR sends a composed Unicode character.
179 MSG msg1 = { NULL, WM_KEYDOWN, key_code, 0 };
180 #if defined(USE_AURA)
181 ui::KeyEvent evt1(msg1, false);
182 NativeWebKeyboardEvent keydown_event(&evt1);
184 NativeWebKeyboardEvent keydown_event(msg1);
186 SendNativeKeyEvent(keydown_event);
188 MSG msg2 = { NULL, WM_CHAR, (*output)[0], 0 };
189 #if defined(USE_AURA)
190 ui::KeyEvent evt2(msg2, true);
191 NativeWebKeyboardEvent char_event(&evt2);
193 NativeWebKeyboardEvent char_event(msg2);
195 SendNativeKeyEvent(char_event);
197 MSG msg3 = { NULL, WM_KEYUP, key_code, 0 };
198 #if defined(USE_AURA)
199 ui::KeyEvent evt3(msg3, false);
200 NativeWebKeyboardEvent keyup_event(&evt3);
202 NativeWebKeyboardEvent keyup_event(msg3);
204 SendNativeKeyEvent(keyup_event);
207 #elif defined(USE_AURA) && defined(USE_X11)
208 // We ignore |layout|, which means we are only testing the layout of the
209 // current locale. TODO(mazda): fix this to respect |layout|.
211 const int flags = ConvertMockKeyboardModifier(modifiers);
213 ui::ScopedXI2Event xevent;
214 xevent.InitKeyEvent(ui::ET_KEY_PRESSED,
215 static_cast<ui::KeyboardCode>(key_code),
217 ui::KeyEvent event1(xevent, false);
218 NativeWebKeyboardEvent keydown_event(&event1);
219 SendNativeKeyEvent(keydown_event);
221 xevent.InitKeyEvent(ui::ET_KEY_PRESSED,
222 static_cast<ui::KeyboardCode>(key_code),
224 ui::KeyEvent event2(xevent, true);
225 NativeWebKeyboardEvent char_event(&event2);
226 SendNativeKeyEvent(char_event);
228 xevent.InitKeyEvent(ui::ET_KEY_RELEASED,
229 static_cast<ui::KeyboardCode>(key_code),
231 ui::KeyEvent event3(xevent, false);
232 NativeWebKeyboardEvent keyup_event(&event3);
233 SendNativeKeyEvent(keyup_event);
235 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
237 output->assign(1, static_cast<base::char16>(c));
239 #elif defined(USE_OZONE)
240 const int flags = ConvertMockKeyboardModifier(modifiers);
242 // Ozone's native events are ui::Events. So first create the "native" event,
243 // then create the actual ui::KeyEvent with the native event.
244 ui::KeyEvent keydown_native_event(ui::ET_KEY_PRESSED,
245 static_cast<ui::KeyboardCode>(key_code),
248 ui::KeyEvent keydown_event(&keydown_native_event, false);
249 NativeWebKeyboardEvent keydown_web_event(&keydown_event);
250 SendNativeKeyEvent(keydown_web_event);
252 ui::KeyEvent char_native_event(ui::ET_KEY_PRESSED,
253 static_cast<ui::KeyboardCode>(key_code),
256 ui::KeyEvent char_event(&char_native_event, true);
257 NativeWebKeyboardEvent char_web_event(&char_event);
258 SendNativeKeyEvent(char_web_event);
260 ui::KeyEvent keyup_native_event(ui::ET_KEY_RELEASED,
261 static_cast<ui::KeyboardCode>(key_code),
264 ui::KeyEvent keyup_event(&keyup_native_event, false);
265 NativeWebKeyboardEvent keyup_web_event(&keyup_event);
266 SendNativeKeyEvent(keyup_web_event);
268 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
270 output->assign(1, static_cast<base::char16>(c));
272 #elif defined(TOOLKIT_GTK)
273 // We ignore |layout|, which means we are only testing the layout of the
274 // current locale. TODO(estade): fix this to respect |layout|.
275 std::vector<GdkEvent*> events;
276 ui::SynthesizeKeyPressEvents(
277 NULL, static_cast<ui::KeyboardCode>(key_code),
278 modifiers & (MockKeyboard::LEFT_CONTROL | MockKeyboard::RIGHT_CONTROL),
279 modifiers & (MockKeyboard::LEFT_SHIFT | MockKeyboard::RIGHT_SHIFT),
280 modifiers & (MockKeyboard::LEFT_ALT | MockKeyboard::RIGHT_ALT),
283 guint32 unicode_key = 0;
284 for (size_t i = 0; i < events.size(); ++i) {
285 // Only send the up/down events for key press itself (skip the up/down
286 // events for the modifier keys).
287 if ((i + 1) == (events.size() / 2) || i == (events.size() / 2)) {
288 unicode_key = gdk_keyval_to_unicode(events[i]->key.keyval);
289 NativeWebKeyboardEvent webkit_event(events[i]);
290 SendNativeKeyEvent(webkit_event);
292 // Need to add a char event after the key down.
293 if (webkit_event.type == blink::WebInputEvent::RawKeyDown) {
294 NativeWebKeyboardEvent char_event = webkit_event;
295 char_event.type = blink::WebInputEvent::Char;
296 char_event.skip_in_browser = true;
297 SendNativeKeyEvent(char_event);
300 gdk_event_free(events[i]);
303 output->assign(1, static_cast<base::char16>(unicode_key));
312 scoped_ptr<MockKeyboard> mock_keyboard_;
317 // Test that we get form state change notifications when input fields change.
318 TEST_F(RenderViewImplTest, DISABLED_OnNavStateChanged) {
319 // Don't want any delay for form state sync changes. This will still post a
320 // message so updates will get coalesced, but as soon as we spin the message
321 // loop, it will generate an update.
322 view()->set_send_content_state_immediately(true);
324 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
326 // We should NOT have gotten a form state change notification yet.
327 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
328 ViewHostMsg_UpdateState::ID));
329 render_thread_->sink().ClearMessages();
331 // Change the value of the input. We should have gotten an update state
332 // notification. We need to spin the message loop to catch this update.
333 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';");
334 ProcessPendingMessages();
335 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
336 ViewHostMsg_UpdateState::ID));
339 TEST_F(RenderViewImplTest, OnNavigationHttpPost) {
340 FrameMsg_Navigate_Params nav_params;
342 // An http url will trigger a resource load so cannot be used here.
343 nav_params.url = GURL("data:text/html,<div>Page</div>");
344 nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
345 nav_params.transition = PAGE_TRANSITION_TYPED;
346 nav_params.page_id = -1;
347 nav_params.is_post = true;
350 const unsigned char* raw_data = reinterpret_cast<const unsigned char*>(
352 const unsigned int length = 11;
353 const std::vector<unsigned char> post_data(raw_data, raw_data + length);
354 nav_params.browser_initiated_post_data = post_data;
356 frame()->OnNavigate(nav_params);
357 ProcessPendingMessages();
359 const IPC::Message* frame_navigate_msg =
360 render_thread_->sink().GetUniqueMessageMatching(
361 FrameHostMsg_DidCommitProvisionalLoad::ID);
362 EXPECT_TRUE(frame_navigate_msg);
364 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params;
365 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
367 EXPECT_TRUE(host_nav_params.a.is_post);
369 // Check post data sent to browser matches
370 EXPECT_TRUE(host_nav_params.a.page_state.IsValid());
371 const blink::WebHistoryItem item = PageStateToHistoryItem(
372 host_nav_params.a.page_state);
373 blink::WebHTTPBody body = item.httpBody();
374 blink::WebHTTPBody::Element element;
375 bool successful = body.elementAt(0, element);
376 EXPECT_TRUE(successful);
377 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData, element.type);
378 EXPECT_EQ(length, element.data.size());
379 EXPECT_EQ(0, memcmp(raw_data, element.data.data(), length));
382 TEST_F(RenderViewImplTest, DecideNavigationPolicy) {
383 WebUITestWebUIControllerFactory factory;
384 WebUIControllerFactory::RegisterFactory(&factory);
387 state.set_navigation_state(NavigationState::CreateContentInitiated());
389 // Navigations to normal HTTP URLs can be handled locally.
390 blink::WebURLRequest request(GURL("http://foo.com"));
391 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
395 blink::WebNavigationTypeLinkClicked,
396 blink::WebNavigationPolicyCurrentTab,
398 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab, policy);
400 // Verify that form posts to WebUI URLs will be sent to the browser process.
401 blink::WebURLRequest form_request(GURL("chrome://foo"));
402 form_request.setHTTPMethod("POST");
403 policy = frame()->decidePolicyForNavigation(
407 blink::WebNavigationTypeFormSubmitted,
408 blink::WebNavigationPolicyCurrentTab,
410 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
412 // Verify that popup links to WebUI URLs also are sent to browser.
413 blink::WebURLRequest popup_request(GURL("chrome://foo"));
414 policy = frame()->decidePolicyForNavigation(
418 blink::WebNavigationTypeLinkClicked,
419 blink::WebNavigationPolicyNewForegroundTab,
421 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
424 TEST_F(RenderViewImplTest, DecideNavigationPolicyHandlesAllTopLevel) {
426 state.set_navigation_state(NavigationState::CreateContentInitiated());
428 RendererPreferences prefs = view()->renderer_preferences();
429 prefs.browser_handles_all_top_level_requests = true;
430 view()->OnSetRendererPrefs(prefs);
432 const blink::WebNavigationType kNavTypes[] = {
433 blink::WebNavigationTypeLinkClicked,
434 blink::WebNavigationTypeFormSubmitted,
435 blink::WebNavigationTypeBackForward,
436 blink::WebNavigationTypeReload,
437 blink::WebNavigationTypeFormResubmitted,
438 blink::WebNavigationTypeOther,
441 blink::WebURLRequest request(GURL("http://foo.com"));
442 for (size_t i = 0; i < arraysize(kNavTypes); ++i) {
443 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
448 blink::WebNavigationPolicyCurrentTab,
450 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
454 TEST_F(RenderViewImplTest, DecideNavigationPolicyForWebUI) {
455 // Enable bindings to simulate a WebUI view.
456 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI);
459 state.set_navigation_state(NavigationState::CreateContentInitiated());
461 // Navigations to normal HTTP URLs will be sent to browser process.
462 blink::WebURLRequest request(GURL("http://foo.com"));
463 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
467 blink::WebNavigationTypeLinkClicked,
468 blink::WebNavigationPolicyCurrentTab,
470 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
472 // Navigations to WebUI URLs will also be sent to browser process.
473 blink::WebURLRequest webui_request(GURL("chrome://foo"));
474 policy = frame()->decidePolicyForNavigation(
478 blink::WebNavigationTypeLinkClicked,
479 blink::WebNavigationPolicyCurrentTab,
481 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
483 // Verify that form posts to data URLs will be sent to the browser process.
484 blink::WebURLRequest data_request(GURL("data:text/html,foo"));
485 data_request.setHTTPMethod("POST");
486 policy = frame()->decidePolicyForNavigation(
490 blink::WebNavigationTypeFormSubmitted,
491 blink::WebNavigationPolicyCurrentTab,
493 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
495 // Verify that a popup that creates a view first and then navigates to a
496 // normal HTTP URL will be sent to the browser process, even though the
497 // new view does not have any enabled_bindings_.
498 blink::WebURLRequest popup_request(GURL("http://foo.com"));
499 blink::WebView* new_web_view = view()->createView(
500 GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
501 blink::WebNavigationPolicyNewForegroundTab, false);
502 RenderViewImpl* new_view = RenderViewImpl::FromWebView(new_web_view);
503 policy = static_cast<RenderFrameImpl*>(new_view->GetMainRenderFrame())->
504 decidePolicyForNavigation(
505 new_web_view->mainFrame(),
508 blink::WebNavigationTypeLinkClicked,
509 blink::WebNavigationPolicyNewForegroundTab,
511 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
513 // Clean up after the new view so we don't leak it.
518 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
519 // already swapped out. http://crbug.com/93427.
520 TEST_F(RenderViewImplTest, SendSwapOutACK) {
521 LoadHTML("<div>Page A</div>");
522 int initial_page_id = view()->GetPageId();
524 // Respond to a swap out request.
525 view()->main_render_frame()->OnSwapOut();
527 // Ensure the swap out commits synchronously.
528 EXPECT_NE(initial_page_id, view()->GetPageId());
530 // Check for a valid OnSwapOutACK.
531 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
532 FrameHostMsg_SwapOut_ACK::ID);
535 // It is possible to get another swap out request. Ensure that we send
536 // an ACK, even if we don't have to do anything else.
537 render_thread_->sink().ClearMessages();
538 view()->main_render_frame()->OnSwapOut();
539 const IPC::Message* msg2 = render_thread_->sink().GetUniqueMessageMatching(
540 FrameHostMsg_SwapOut_ACK::ID);
543 // If we navigate back to this RenderView, ensure we don't send a state
544 // update for the swapped out URL. (http://crbug.com/72235)
545 FrameMsg_Navigate_Params nav_params;
546 nav_params.url = GURL("data:text/html,<div>Page B</div>");
547 nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
548 nav_params.transition = PAGE_TRANSITION_TYPED;
549 nav_params.current_history_list_length = 1;
550 nav_params.current_history_list_offset = 0;
551 nav_params.pending_history_list_offset = 1;
552 nav_params.page_id = -1;
553 frame()->OnNavigate(nav_params);
554 ProcessPendingMessages();
555 const IPC::Message* msg3 = render_thread_->sink().GetUniqueMessageMatching(
556 ViewHostMsg_UpdateState::ID);
560 // Ensure the RenderViewImpl reloads the previous page if a reload request
561 // arrives while it is showing swappedout://. http://crbug.com/143155.
562 TEST_F(RenderViewImplTest, ReloadWhileSwappedOut) {
564 LoadHTML("<div>Page A</div>");
566 // Load page B, which will trigger an UpdateState message for page A.
567 LoadHTML("<div>Page B</div>");
569 // Check for a valid UpdateState message for page A.
570 ProcessPendingMessages();
571 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
572 ViewHostMsg_UpdateState::ID);
576 ViewHostMsg_UpdateState::Read(msg_A, &page_id_A, &state_A);
577 EXPECT_EQ(1, page_id_A);
578 render_thread_->sink().ClearMessages();
580 // Back to page A (page_id 1) and commit.
581 FrameMsg_Navigate_Params params_A;
582 params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL;
583 params_A.transition = PAGE_TRANSITION_FORWARD_BACK;
584 params_A.current_history_list_length = 2;
585 params_A.current_history_list_offset = 1;
586 params_A.pending_history_list_offset = 0;
587 params_A.page_id = 1;
588 params_A.page_state = state_A;
589 frame()->OnNavigate(params_A);
590 ProcessPendingMessages();
592 // Respond to a swap out request.
593 view()->main_render_frame()->OnSwapOut();
595 // Check for a OnSwapOutACK.
596 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
597 FrameHostMsg_SwapOut_ACK::ID);
599 render_thread_->sink().ClearMessages();
601 // It is possible to get a reload request at this point, containing the
602 // params.page_state of the initial page (e.g., if the new page fails the
603 // provisional load in the renderer process, after we unload the old page).
604 // Ensure the old page gets reloaded, not swappedout://.
605 FrameMsg_Navigate_Params nav_params;
606 nav_params.url = GURL("data:text/html,<div>Page A</div>");
607 nav_params.navigation_type = FrameMsg_Navigate_Type::RELOAD;
608 nav_params.transition = PAGE_TRANSITION_RELOAD;
609 nav_params.current_history_list_length = 2;
610 nav_params.current_history_list_offset = 0;
611 nav_params.pending_history_list_offset = 0;
612 nav_params.page_id = 1;
613 nav_params.page_state = state_A;
614 frame()->OnNavigate(nav_params);
615 ProcessPendingMessages();
617 // Verify page A committed, not swappedout://.
618 const IPC::Message* frame_navigate_msg =
619 render_thread_->sink().GetUniqueMessageMatching(
620 FrameHostMsg_DidCommitProvisionalLoad::ID);
621 EXPECT_TRUE(frame_navigate_msg);
623 // Read URL out of the parent trait of the params object.
624 FrameHostMsg_DidCommitProvisionalLoad::Param commit_params;
625 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
627 EXPECT_NE(GURL("swappedout://"), commit_params.a.url);
631 // Test that we get the correct UpdateState message when we go back twice
632 // quickly without committing. Regression test for http://crbug.com/58082.
633 // Disabled: http://crbug.com/157357 .
634 TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) {
636 LoadHTML("<div>Page A</div>");
638 // Load page B, which will trigger an UpdateState message for page A.
639 LoadHTML("<div>Page B</div>");
641 // Check for a valid UpdateState message for page A.
642 ProcessPendingMessages();
643 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
644 ViewHostMsg_UpdateState::ID);
648 ViewHostMsg_UpdateState::Read(msg_A, &page_id_A, &state_A);
649 EXPECT_EQ(1, page_id_A);
650 render_thread_->sink().ClearMessages();
652 // Load page C, which will trigger an UpdateState message for page B.
653 LoadHTML("<div>Page C</div>");
655 // Check for a valid UpdateState for page B.
656 ProcessPendingMessages();
657 const IPC::Message* msg_B = render_thread_->sink().GetUniqueMessageMatching(
658 ViewHostMsg_UpdateState::ID);
662 ViewHostMsg_UpdateState::Read(msg_B, &page_id_B, &state_B);
663 EXPECT_EQ(2, page_id_B);
664 EXPECT_NE(state_A, state_B);
665 render_thread_->sink().ClearMessages();
667 // Load page D, which will trigger an UpdateState message for page C.
668 LoadHTML("<div>Page D</div>");
670 // Check for a valid UpdateState for page C.
671 ProcessPendingMessages();
672 const IPC::Message* msg_C = render_thread_->sink().GetUniqueMessageMatching(
673 ViewHostMsg_UpdateState::ID);
677 ViewHostMsg_UpdateState::Read(msg_C, &page_id_C, &state_C);
678 EXPECT_EQ(3, page_id_C);
679 EXPECT_NE(state_B, state_C);
680 render_thread_->sink().ClearMessages();
682 // Go back to C and commit, preparing for our real test.
683 FrameMsg_Navigate_Params params_C;
684 params_C.navigation_type = FrameMsg_Navigate_Type::NORMAL;
685 params_C.transition = PAGE_TRANSITION_FORWARD_BACK;
686 params_C.current_history_list_length = 4;
687 params_C.current_history_list_offset = 3;
688 params_C.pending_history_list_offset = 2;
689 params_C.page_id = 3;
690 params_C.page_state = state_C;
691 frame()->OnNavigate(params_C);
692 ProcessPendingMessages();
693 render_thread_->sink().ClearMessages();
695 // Go back twice quickly, such that page B does not have a chance to commit.
696 // This leads to two changes to the back/forward list but only one change to
697 // the RenderView's page ID.
699 // Back to page B (page_id 2), without committing.
700 FrameMsg_Navigate_Params params_B;
701 params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
702 params_B.transition = PAGE_TRANSITION_FORWARD_BACK;
703 params_B.current_history_list_length = 4;
704 params_B.current_history_list_offset = 2;
705 params_B.pending_history_list_offset = 1;
706 params_B.page_id = 2;
707 params_B.page_state = state_B;
708 frame()->OnNavigate(params_B);
710 // Back to page A (page_id 1) and commit.
711 FrameMsg_Navigate_Params params;
712 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
713 params.transition = PAGE_TRANSITION_FORWARD_BACK;
714 params_B.current_history_list_length = 4;
715 params_B.current_history_list_offset = 2;
716 params_B.pending_history_list_offset = 0;
718 params.page_state = state_A;
719 frame()->OnNavigate(params);
720 ProcessPendingMessages();
722 // Now ensure that the UpdateState message we receive is consistent
723 // and represents page C in both page_id and state.
724 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
725 ViewHostMsg_UpdateState::ID);
729 ViewHostMsg_UpdateState::Read(msg, &page_id, &state);
730 EXPECT_EQ(page_id_C, page_id);
731 EXPECT_NE(state_A, state);
732 EXPECT_NE(state_B, state);
733 EXPECT_EQ(state_C, state);
736 // Test that the history_page_ids_ list can reveal when a stale back/forward
737 // navigation arrives from the browser and can be ignored. See
738 // http://crbug.com/86758.
739 TEST_F(RenderViewImplTest, StaleNavigationsIgnored) {
741 LoadHTML("<div>Page A</div>");
742 EXPECT_EQ(1, view()->history_list_length_);
743 EXPECT_EQ(0, view()->history_list_offset_);
744 EXPECT_EQ(1, view()->history_page_ids_[0]);
746 // Load page B, which will trigger an UpdateState message for page A.
747 LoadHTML("<div>Page B</div>");
748 EXPECT_EQ(2, view()->history_list_length_);
749 EXPECT_EQ(1, view()->history_list_offset_);
750 EXPECT_EQ(2, view()->history_page_ids_[1]);
752 // Check for a valid UpdateState message for page A.
753 ProcessPendingMessages();
754 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
755 ViewHostMsg_UpdateState::ID);
759 ViewHostMsg_UpdateState::Read(msg_A, &page_id_A, &state_A);
760 EXPECT_EQ(1, page_id_A);
761 render_thread_->sink().ClearMessages();
763 // Back to page A (page_id 1) and commit.
764 FrameMsg_Navigate_Params params_A;
765 params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL;
766 params_A.transition = PAGE_TRANSITION_FORWARD_BACK;
767 params_A.current_history_list_length = 2;
768 params_A.current_history_list_offset = 1;
769 params_A.pending_history_list_offset = 0;
770 params_A.page_id = 1;
771 params_A.page_state = state_A;
772 frame()->OnNavigate(params_A);
773 ProcessPendingMessages();
775 // A new navigation commits, clearing the forward history.
776 LoadHTML("<div>Page C</div>");
777 EXPECT_EQ(2, view()->history_list_length_);
778 EXPECT_EQ(1, view()->history_list_offset_);
779 EXPECT_EQ(3, view()->history_page_ids_[1]);
781 // The browser then sends a stale navigation to B, which should be ignored.
782 FrameMsg_Navigate_Params params_B;
783 params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
784 params_B.transition = PAGE_TRANSITION_FORWARD_BACK;
785 params_B.current_history_list_length = 2;
786 params_B.current_history_list_offset = 0;
787 params_B.pending_history_list_offset = 1;
788 params_B.page_id = 2;
789 params_B.page_state = state_A; // Doesn't matter, just has to be present.
790 frame()->OnNavigate(params_B);
792 // State should be unchanged.
793 EXPECT_EQ(2, view()->history_list_length_);
794 EXPECT_EQ(1, view()->history_list_offset_);
795 EXPECT_EQ(3, view()->history_page_ids_[1]);
798 // Test that we do not ignore navigations after the entry limit is reached,
799 // in which case the browser starts dropping entries from the front. In this
800 // case, we'll see a page_id mismatch but the RenderView's id will be older,
801 // not newer, than params.page_id. Use this as a cue that we should update the
802 // state and not treat it like a navigation to a cropped forward history item.
803 // See http://crbug.com/89798.
804 TEST_F(RenderViewImplTest, DontIgnoreBackAfterNavEntryLimit) {
806 LoadHTML("<div>Page A</div>");
807 EXPECT_EQ(1, view()->history_list_length_);
808 EXPECT_EQ(0, view()->history_list_offset_);
809 EXPECT_EQ(1, view()->history_page_ids_[0]);
811 // Load page B, which will trigger an UpdateState message for page A.
812 LoadHTML("<div>Page B</div>");
813 EXPECT_EQ(2, view()->history_list_length_);
814 EXPECT_EQ(1, view()->history_list_offset_);
815 EXPECT_EQ(2, view()->history_page_ids_[1]);
817 // Check for a valid UpdateState message for page A.
818 ProcessPendingMessages();
819 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
820 ViewHostMsg_UpdateState::ID);
824 ViewHostMsg_UpdateState::Read(msg_A, &page_id_A, &state_A);
825 EXPECT_EQ(1, page_id_A);
826 render_thread_->sink().ClearMessages();
828 // Load page C, which will trigger an UpdateState message for page B.
829 LoadHTML("<div>Page C</div>");
830 EXPECT_EQ(3, view()->history_list_length_);
831 EXPECT_EQ(2, view()->history_list_offset_);
832 EXPECT_EQ(3, view()->history_page_ids_[2]);
834 // Check for a valid UpdateState message for page B.
835 ProcessPendingMessages();
836 const IPC::Message* msg_B = render_thread_->sink().GetUniqueMessageMatching(
837 ViewHostMsg_UpdateState::ID);
841 ViewHostMsg_UpdateState::Read(msg_B, &page_id_B, &state_B);
842 EXPECT_EQ(2, page_id_B);
843 render_thread_->sink().ClearMessages();
845 // Suppose the browser has limited the number of NavigationEntries to 2.
846 // It has now dropped the first entry, but the renderer isn't notified.
847 // Ensure that going back to page B (page_id 2) at offset 0 is successful.
848 FrameMsg_Navigate_Params params_B;
849 params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
850 params_B.transition = PAGE_TRANSITION_FORWARD_BACK;
851 params_B.current_history_list_length = 2;
852 params_B.current_history_list_offset = 1;
853 params_B.pending_history_list_offset = 0;
854 params_B.page_id = 2;
855 params_B.page_state = state_B;
856 frame()->OnNavigate(params_B);
857 ProcessPendingMessages();
859 EXPECT_EQ(2, view()->history_list_length_);
860 EXPECT_EQ(0, view()->history_list_offset_);
861 EXPECT_EQ(2, view()->history_page_ids_[0]);
864 // Test that our IME backend sends a notification message when the input focus
866 TEST_F(RenderViewImplTest, OnImeTypeChanged) {
867 // Enable our IME backend code.
868 view()->OnSetInputMethodActive(true);
870 // Load an HTML page consisting of two input fields.
871 view()->set_send_content_state_immediately(true);
876 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
877 "<input id=\"test2\" type=\"password\"></input>"
878 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
879 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
880 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
881 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
883 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
885 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
886 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
887 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
888 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
889 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
890 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
891 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
892 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
895 render_thread_->sink().ClearMessages();
897 struct InputModeTestCase {
898 const char* input_id;
899 ui::TextInputMode expected_mode;
901 static const InputModeTestCase kInputModeTestCases[] = {
902 {"test1", ui::TEXT_INPUT_MODE_DEFAULT},
903 {"test3", ui::TEXT_INPUT_MODE_VERBATIM},
904 {"test4", ui::TEXT_INPUT_MODE_LATIN},
905 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME},
906 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE},
907 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN},
908 {"test8", ui::TEXT_INPUT_MODE_KANA},
909 {"test9", ui::TEXT_INPUT_MODE_KATAKANA},
910 {"test10", ui::TEXT_INPUT_MODE_NUMERIC},
911 {"test11", ui::TEXT_INPUT_MODE_TEL},
912 {"test12", ui::TEXT_INPUT_MODE_EMAIL},
913 {"test13", ui::TEXT_INPUT_MODE_URL},
914 {"test14", ui::TEXT_INPUT_MODE_DEFAULT},
915 {"test15", ui::TEXT_INPUT_MODE_VERBATIM},
918 const int kRepeatCount = 10;
919 for (int i = 0; i < kRepeatCount; i++) {
920 // Move the input focus to the first <input> element, where we should
922 ExecuteJavaScript("document.getElementById('test1').focus();");
923 ProcessPendingMessages();
924 render_thread_->sink().ClearMessages();
926 // Update the IME status and verify if our IME backend sends an IPC message
928 view()->UpdateTextInputType();
929 const IPC::Message* msg = render_thread_->sink().GetMessageAt(0);
930 EXPECT_TRUE(msg != NULL);
931 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
932 ui::TextInputType type;
933 bool can_compose_inline = false;
934 ui::TextInputMode input_mode = ui::TEXT_INPUT_MODE_DEFAULT;
935 ViewHostMsg_TextInputTypeChanged::Read(msg,
938 &can_compose_inline);
939 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, type);
940 EXPECT_EQ(true, can_compose_inline);
942 // Move the input focus to the second <input> element, where we should
944 ExecuteJavaScript("document.getElementById('test2').focus();");
945 ProcessPendingMessages();
946 render_thread_->sink().ClearMessages();
948 // Update the IME status and verify if our IME backend sends an IPC message
949 // to de-activate IMEs.
950 view()->UpdateTextInputType();
951 msg = render_thread_->sink().GetMessageAt(0);
952 EXPECT_TRUE(msg != NULL);
953 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
954 ViewHostMsg_TextInputTypeChanged::Read(msg,
957 &can_compose_inline);
958 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, type);
960 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kInputModeTestCases); i++) {
961 const InputModeTestCase* test_case = &kInputModeTestCases[i];
962 std::string javascript =
963 base::StringPrintf("document.getElementById('%s').focus();",
964 test_case->input_id);
965 // Move the input focus to the target <input> element, where we should
967 ExecuteJavaScriptAndReturnIntValue(base::ASCIIToUTF16(javascript), NULL);
968 ProcessPendingMessages();
969 render_thread_->sink().ClearMessages();
971 // Update the IME status and verify if our IME backend sends an IPC
972 // message to activate IMEs.
973 view()->UpdateTextInputType();
974 const IPC::Message* msg = render_thread_->sink().GetMessageAt(0);
975 EXPECT_TRUE(msg != NULL);
976 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
977 ViewHostMsg_TextInputTypeChanged::Read(msg,
980 &can_compose_inline);
981 EXPECT_EQ(test_case->expected_mode, input_mode);
986 // Test that our IME backend can compose CJK words.
987 // Our IME front-end sends many platform-independent messages to the IME backend
988 // while it composes CJK words. This test sends the minimal messages captured
989 // on my local environment directly to the IME backend to verify if the backend
990 // can compose CJK words without any problems.
991 // This test uses an array of command sets because an IME composotion does not
992 // only depends on IME events, but also depends on window events, e.g. moving
993 // the window focus while composing a CJK text. To handle such complicated
994 // cases, this test should not only call IME-related functions in the
995 // RenderWidget class, but also call some RenderWidget members, e.g.
996 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc.
997 TEST_F(RenderViewImplTest, ImeComposition) {
1003 IME_CONFIRMCOMPOSITION,
1004 IME_CANCELCOMPOSITION
1009 int selection_start;
1011 const wchar_t* ime_string;
1012 const wchar_t* result;
1014 static const ImeMessage kImeMessages[] = {
1015 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
1016 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1017 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1018 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1019 {IME_SETCOMPOSITION, false, 1, 1, L"n", L"n"},
1020 {IME_SETCOMPOSITION, false, 2, 2, L"ni", L"ni"},
1021 {IME_SETCOMPOSITION, false, 3, 3, L"nih", L"nih"},
1022 {IME_SETCOMPOSITION, false, 4, 4, L"niha", L"niha"},
1023 {IME_SETCOMPOSITION, false, 5, 5, L"nihao", L"nihao"},
1024 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"\x4F60\x597D", L"\x4F60\x597D"},
1025 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
1026 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1027 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1028 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1029 {IME_SETCOMPOSITION, false, 0, 1, L"\xFF4B", L"\xFF4B"},
1030 {IME_SETCOMPOSITION, false, 0, 1, L"\x304B", L"\x304B"},
1031 {IME_SETCOMPOSITION, false, 0, 2, L"\x304B\xFF4E", L"\x304B\xFF4E"},
1032 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\xFF4A",
1033 L"\x304B\x3093\xFF4A"},
1034 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\x3058",
1035 L"\x304B\x3093\x3058"},
1036 {IME_SETCOMPOSITION, false, 0, 2, L"\x611F\x3058", L"\x611F\x3058"},
1037 {IME_SETCOMPOSITION, false, 0, 2, L"\x6F22\x5B57", L"\x6F22\x5B57"},
1038 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1039 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1040 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1041 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1042 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1043 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1044 {IME_SETCOMPOSITION, false, 0, 1, L"\x3147", L"\x3147"},
1045 {IME_SETCOMPOSITION, false, 0, 1, L"\xC544", L"\xC544"},
1046 {IME_SETCOMPOSITION, false, 0, 1, L"\xC548", L"\xC548"},
1047 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1048 {IME_SETCOMPOSITION, false, 0, 1, L"\x3134", L"\xC548\x3134"},
1049 {IME_SETCOMPOSITION, false, 0, 1, L"\xB140", L"\xC548\xB140"},
1050 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1051 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1052 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1053 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548\xB155"},
1056 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kImeMessages); i++) {
1057 const ImeMessage* ime_message = &kImeMessages[i];
1058 switch (ime_message->command) {
1059 case IME_INITIALIZE:
1060 // Load an HTML page consisting of a content-editable <div> element,
1061 // and move the input focus to the <div> element, where we can use
1063 view()->OnSetInputMethodActive(ime_message->enable);
1064 view()->set_send_content_state_immediately(true);
1069 "<div id=\"test1\" contenteditable=\"true\"></div>"
1072 ExecuteJavaScript("document.getElementById('test1').focus();");
1075 case IME_SETINPUTMODE:
1076 // Activate (or deactivate) our IME back-end.
1077 view()->OnSetInputMethodActive(ime_message->enable);
1081 // Update the window focus.
1082 view()->OnSetFocus(ime_message->enable);
1085 case IME_SETCOMPOSITION:
1086 view()->OnImeSetComposition(
1087 base::WideToUTF16Hack(ime_message->ime_string),
1088 std::vector<blink::WebCompositionUnderline>(),
1089 ime_message->selection_start,
1090 ime_message->selection_end);
1093 case IME_CONFIRMCOMPOSITION:
1094 view()->OnImeConfirmComposition(
1095 base::WideToUTF16Hack(ime_message->ime_string),
1096 gfx::Range::InvalidRange(),
1100 case IME_CANCELCOMPOSITION:
1101 view()->OnImeSetComposition(
1103 std::vector<blink::WebCompositionUnderline>(),
1108 // Update the status of our IME back-end.
1109 // TODO(hbono): we should verify messages to be sent from the back-end.
1110 view()->UpdateTextInputType();
1111 ProcessPendingMessages();
1112 render_thread_->sink().ClearMessages();
1114 if (ime_message->result) {
1115 // Retrieve the content of this page and compare it with the expected
1117 const int kMaxOutputCharacters = 128;
1118 std::wstring output = base::UTF16ToWideHack(
1119 GetMainFrame()->contentAsText(kMaxOutputCharacters));
1120 EXPECT_EQ(output, ime_message->result);
1125 // Test that the RenderView::OnSetTextDirection() function can change the text
1126 // direction of the selected input element.
1127 TEST_F(RenderViewImplTest, OnSetTextDirection) {
1128 // Load an HTML page consisting of a <textarea> element and a <div> element.
1129 // This test changes the text direction of the <textarea> element, and
1130 // writes the values of its 'dir' attribute and its 'direction' property to
1131 // verify that the text direction is changed.
1132 view()->set_send_content_state_immediately(true);
1137 "<textarea id=\"test\"></textarea>"
1138 "<div id=\"result\" contenteditable=\"true\"></div>"
1141 render_thread_->sink().ClearMessages();
1143 static const struct {
1144 WebTextDirection direction;
1145 const wchar_t* expected_result;
1146 } kTextDirection[] = {
1147 { blink::WebTextDirectionRightToLeft, L"\x000A" L"rtl,rtl" },
1148 { blink::WebTextDirectionLeftToRight, L"\x000A" L"ltr,ltr" },
1150 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTextDirection); ++i) {
1151 // Set the text direction of the <textarea> element.
1152 ExecuteJavaScript("document.getElementById('test').focus();");
1153 view()->OnSetTextDirection(kTextDirection[i].direction);
1155 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1156 // property to the <div> element.
1157 ExecuteJavaScript("var result = document.getElementById('result');"
1158 "var node = document.getElementById('test');"
1159 "var style = getComputedStyle(node, null);"
1160 "result.innerText ="
1161 " node.getAttribute('dir') + ',' +"
1162 " style.getPropertyValue('direction');");
1164 // Copy the document content to std::wstring and compare with the
1166 const int kMaxOutputCharacters = 16;
1167 std::wstring output = base::UTF16ToWideHack(
1168 GetMainFrame()->contentAsText(kMaxOutputCharacters));
1169 EXPECT_EQ(output, kTextDirection[i].expected_result);
1173 // see http://crbug.com/238750
1175 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent
1177 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent
1180 // Test that we can receive correct DOM events when we send input events
1181 // through the RenderWidget::OnHandleInputEvent() function.
1182 TEST_F(RenderViewImplTest, MAYBE_OnHandleKeyboardEvent) {
1183 #if !defined(OS_MACOSX)
1184 // Load an HTML page consisting of one <input> element and three
1185 // contentediable <div> elements.
1186 // The <input> element is used for sending keyboard events, and the <div>
1187 // elements are used for writing DOM events in the following format:
1188 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1189 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1190 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1191 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1192 view()->set_send_content_state_immediately(true);
1196 "<script type='text/javascript' language='javascript'>"
1197 "function OnKeyEvent(ev) {"
1198 " var result = document.getElementById(ev.type);"
1199 " result.innerText ="
1200 " (ev.which || ev.keyCode) + ',' +"
1201 " ev.shiftKey + ',' +"
1202 " ev.ctrlKey + ',' +"
1209 "<input id='test' type='text'"
1210 " onkeydown='return OnKeyEvent(event);'"
1211 " onkeypress='return OnKeyEvent(event);'"
1212 " onkeyup='return OnKeyEvent(event);'>"
1214 "<div id='keydown' contenteditable='true'>"
1216 "<div id='keypress' contenteditable='true'>"
1218 "<div id='keyup' contenteditable='true'>"
1222 ExecuteJavaScript("document.getElementById('test').focus();");
1223 render_thread_->sink().ClearMessages();
1225 static const MockKeyboard::Layout kLayouts[] = {
1227 // Since we ignore the mock keyboard layout on Linux and instead just use
1228 // the screen's keyboard layout, these trivially pass. They are commented
1229 // out to avoid the illusion that they work.
1230 MockKeyboard::LAYOUT_ARABIC,
1231 MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1232 MockKeyboard::LAYOUT_FRENCH,
1233 MockKeyboard::LAYOUT_HEBREW,
1234 MockKeyboard::LAYOUT_RUSSIAN,
1236 MockKeyboard::LAYOUT_UNITED_STATES,
1239 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLayouts); ++i) {
1240 // For each key code, we send three keyboard events.
1241 // * we press only the key;
1242 // * we press the key and a left-shift key, and;
1243 // * we press the key and a right-alt (AltGr) key.
1244 // For each modifiers, we need a string used for formatting its expected
1245 // result. (See the above comment for its format.)
1246 static const struct {
1247 MockKeyboard::Modifiers modifiers;
1248 const char* expected_result;
1249 } kModifierData[] = {
1250 {MockKeyboard::NONE, "false,false,false"},
1251 {MockKeyboard::LEFT_SHIFT, "true,false,false"},
1253 {MockKeyboard::RIGHT_ALT, "false,false,true"},
1257 MockKeyboard::Layout layout = kLayouts[i];
1258 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kModifierData); ++j) {
1259 // Virtual key codes used for this test.
1260 static const int kKeyCodes[] = {
1261 '0', '1', '2', '3', '4', '5', '6', '7',
1262 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1263 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1264 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1270 ui::VKEY_OEM_PERIOD,
1278 // Not sure how to handle this key on Linux.
1283 MockKeyboard::Modifiers modifiers = kModifierData[j].modifiers;
1284 for (size_t k = 0; k < ARRAYSIZE_UNSAFE(kKeyCodes); ++k) {
1285 // Send a keyboard event to the RenderView object.
1286 // We should test a keyboard event only when the given keyboard-layout
1287 // driver is installed in a PC and the driver can assign a Unicode
1288 // charcter for the given tuple (key-code and modifiers).
1289 int key_code = kKeyCodes[k];
1290 base::string16 char_code;
1291 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1294 // Create an expected result from the virtual-key code, the character
1295 // code, and the modifier-key status.
1296 // We format a string that emulates a DOM-event string produced hy
1297 // our JavaScript function. (See the above comment for the format.)
1298 static char expected_result[1024];
1299 expected_result[0] = 0;
1300 base::snprintf(&expected_result[0],
1301 sizeof(expected_result),
1302 "\n" // texts in the <input> element
1303 "%d,%s\n" // texts in the first <div> element
1304 "%d,%s\n" // texts in the second <div> element
1305 "%d,%s", // texts in the third <div> element
1306 key_code, kModifierData[j].expected_result,
1307 static_cast<int>(char_code[0]),
1308 kModifierData[j].expected_result,
1309 key_code, kModifierData[j].expected_result);
1311 // Retrieve the text in the test page and compare it with the expected
1312 // text created from a virtual-key code, a character code, and the
1313 // modifier-key status.
1314 const int kMaxOutputCharacters = 1024;
1315 std::string output = base::UTF16ToUTF8(
1316 GetMainFrame()->contentAsText(kMaxOutputCharacters));
1317 EXPECT_EQ(expected_result, output);
1326 // Test that our EditorClientImpl class can insert characters when we send
1327 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1328 // This test is for preventing regressions caused only when we use non-US
1329 // keyboards, such as Issue 10846.
1330 // see http://crbug.com/244562
1332 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1334 #define MAYBE_InsertCharacters InsertCharacters
1336 TEST_F(RenderViewImplTest, MAYBE_InsertCharacters) {
1337 #if !defined(OS_MACOSX)
1338 static const struct {
1339 MockKeyboard::Layout layout;
1340 const wchar_t* expected_result;
1343 // Disabled these keyboard layouts because buildbots do not have their
1344 // keyboard-layout drivers installed.
1345 {MockKeyboard::LAYOUT_ARABIC,
1346 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1347 L"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1348 L"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1349 L"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1350 L"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1351 L"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1352 L"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1353 L"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1354 L"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1355 L"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1356 L"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1357 L"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1358 L"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1359 L"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1360 L"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1361 L"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1362 L"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1364 {MockKeyboard::LAYOUT_HEBREW,
1365 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1366 L"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1367 L"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1368 L"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1369 L"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1370 L"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1371 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1372 L"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1373 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1374 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1375 L"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1376 L"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1377 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1378 L"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1379 L"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1380 L"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1381 L"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1382 L"\x003b\x005d\x005c\x005b\x002c"
1386 // On Linux, the only way to test alternate keyboard layouts is to change
1387 // the keyboard layout of the whole screen. I'm worried about the side
1388 // effects this may have on the buildbots.
1389 {MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1390 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1391 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1392 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1393 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1394 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1395 L"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1396 L"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1397 L"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1398 L"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1399 L"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1400 L"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1401 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1402 L"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1403 L"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1404 L"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1405 L"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1408 {MockKeyboard::LAYOUT_FRENCH,
1409 L"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1410 L"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1411 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1412 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1413 L"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1414 L"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1415 L"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1416 L"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1417 L"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1418 L"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1419 L"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1420 L"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1421 L"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1422 L"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1423 L"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1424 L"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1425 L"\x003b\x003a\x00f9\x0029\x002a\x0021"
1427 {MockKeyboard::LAYOUT_RUSSIAN,
1428 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1429 L"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1430 L"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1431 L"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1432 L"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1433 L"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1434 L"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1435 L"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1436 L"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1437 L"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1438 L"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1439 L"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1440 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1441 L"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1442 L"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1443 L"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1444 L"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1445 L"\x0451\x0445\x005c\x044a\x044d"
1447 #endif // defined(OS_WIN)
1448 {MockKeyboard::LAYOUT_UNITED_STATES,
1449 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1450 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1451 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1452 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1453 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1454 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1455 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1456 L"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1457 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1458 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1459 L"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1460 L"\x003f\x007e\x007b\x007c\x007d\x0022"
1462 // This is ifdefed out for Linux to correspond to the fact that we don't
1463 // test alt+keystroke for now.
1464 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1465 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1466 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1467 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1468 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1469 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1474 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLayouts); ++i) {
1475 // Load an HTML page consisting of one <div> element.
1476 // This <div> element is used by the EditorClientImpl class to insert
1477 // characters received through the RenderWidget::OnHandleInputEvent()
1479 view()->set_send_content_state_immediately(true);
1485 "<div id='test' contenteditable='true'>"
1489 ExecuteJavaScript("document.getElementById('test').focus();");
1490 render_thread_->sink().ClearMessages();
1492 // For each key code, we send three keyboard events.
1493 // * Pressing only the key;
1494 // * Pressing the key and a left-shift key, and;
1495 // * Pressing the key and a right-alt (AltGr) key.
1496 static const MockKeyboard::Modifiers kModifiers[] = {
1498 MockKeyboard::LEFT_SHIFT,
1500 MockKeyboard::RIGHT_ALT,
1504 MockKeyboard::Layout layout = kLayouts[i].layout;
1505 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kModifiers); ++j) {
1506 // Virtual key codes used for this test.
1507 static const int kKeyCodes[] = {
1508 '0', '1', '2', '3', '4', '5', '6', '7',
1509 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1510 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1511 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1517 ui::VKEY_OEM_PERIOD,
1525 // Unclear how to handle this on Linux.
1530 MockKeyboard::Modifiers modifiers = kModifiers[j];
1531 for (size_t k = 0; k < ARRAYSIZE_UNSAFE(kKeyCodes); ++k) {
1532 // Send a keyboard event to the RenderView object.
1533 // We should test a keyboard event only when the given keyboard-layout
1534 // driver is installed in a PC and the driver can assign a Unicode
1535 // charcter for the given tuple (layout, key-code, and modifiers).
1536 int key_code = kKeyCodes[k];
1537 base::string16 char_code;
1538 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1543 // Retrieve the text in the test page and compare it with the expected
1544 // text created from a virtual-key code, a character code, and the
1545 // modifier-key status.
1546 const int kMaxOutputCharacters = 4096;
1547 std::wstring output = base::UTF16ToWideHack(
1548 GetMainFrame()->contentAsText(kMaxOutputCharacters));
1549 EXPECT_EQ(kLayouts[i].expected_result, output);
1556 // Crashy, http://crbug.com/53247.
1557 TEST_F(RenderViewImplTest, DISABLED_DidFailProvisionalLoadWithErrorForError) {
1558 GetMainFrame()->enableViewSourceMode(true);
1560 error.domain = WebString::fromUTF8(net::kErrorDomain);
1561 error.reason = net::ERR_FILE_NOT_FOUND;
1562 error.unreachableURL = GURL("http://foo");
1563 WebFrame* web_frame = GetMainFrame();
1565 // Start a load that will reach provisional state synchronously,
1566 // but won't complete synchronously.
1567 FrameMsg_Navigate_Params params;
1568 params.page_id = -1;
1569 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1570 params.url = GURL("data:text/html,test data");
1571 frame()->OnNavigate(params);
1573 // An error occurred.
1574 view()->main_render_frame()->didFailProvisionalLoad(web_frame, error);
1575 // Frame should exit view-source mode.
1576 EXPECT_FALSE(web_frame->isViewSourceModeEnabled());
1579 TEST_F(RenderViewImplTest, DidFailProvisionalLoadWithErrorForCancellation) {
1580 GetMainFrame()->enableViewSourceMode(true);
1582 error.domain = WebString::fromUTF8(net::kErrorDomain);
1583 error.reason = net::ERR_ABORTED;
1584 error.unreachableURL = GURL("http://foo");
1585 WebFrame* web_frame = GetMainFrame();
1587 // Start a load that will reach provisional state synchronously,
1588 // but won't complete synchronously.
1589 FrameMsg_Navigate_Params params;
1590 params.page_id = -1;
1591 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1592 params.url = GURL("data:text/html,test data");
1593 frame()->OnNavigate(params);
1595 // A cancellation occurred.
1596 view()->main_render_frame()->didFailProvisionalLoad(web_frame, error);
1597 // Frame should stay in view-source mode.
1598 EXPECT_TRUE(web_frame->isViewSourceModeEnabled());
1601 // Regression test for http://crbug.com/41562
1602 TEST_F(RenderViewImplTest, UpdateTargetURLWithInvalidURL) {
1603 const GURL invalid_gurl("http://");
1604 view()->setMouseOverURL(blink::WebURL(invalid_gurl));
1605 EXPECT_EQ(invalid_gurl, view()->target_url_);
1608 TEST_F(RenderViewImplTest, SetHistoryLengthAndPrune) {
1609 int expected_page_id = -1;
1611 // No history to merge and no committed pages.
1612 view()->OnSetHistoryLengthAndPrune(0, -1);
1613 EXPECT_EQ(0, view()->history_list_length_);
1614 EXPECT_EQ(-1, view()->history_list_offset_);
1616 // History to merge and no committed pages.
1617 view()->OnSetHistoryLengthAndPrune(2, -1);
1618 EXPECT_EQ(2, view()->history_list_length_);
1619 EXPECT_EQ(1, view()->history_list_offset_);
1620 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1621 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1624 // No history to merge and a committed page to be kept.
1625 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1626 expected_page_id = view()->page_id_;
1627 view()->OnSetHistoryLengthAndPrune(0, expected_page_id);
1628 EXPECT_EQ(1, view()->history_list_length_);
1629 EXPECT_EQ(0, view()->history_list_offset_);
1630 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1633 // No history to merge and a committed page to be pruned.
1634 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1635 expected_page_id = view()->page_id_;
1636 view()->OnSetHistoryLengthAndPrune(0, expected_page_id + 1);
1637 EXPECT_EQ(0, view()->history_list_length_);
1638 EXPECT_EQ(-1, view()->history_list_offset_);
1641 // No history to merge and a committed page that the browser was unaware of.
1642 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1643 expected_page_id = view()->page_id_;
1644 view()->OnSetHistoryLengthAndPrune(0, -1);
1645 EXPECT_EQ(1, view()->history_list_length_);
1646 EXPECT_EQ(0, view()->history_list_offset_);
1647 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1650 // History to merge and a committed page to be kept.
1651 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1652 expected_page_id = view()->page_id_;
1653 view()->OnSetHistoryLengthAndPrune(2, expected_page_id);
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 // History to merge and a committed page to be pruned.
1662 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1663 expected_page_id = view()->page_id_;
1664 view()->OnSetHistoryLengthAndPrune(2, expected_page_id + 1);
1665 EXPECT_EQ(2, view()->history_list_length_);
1666 EXPECT_EQ(1, view()->history_list_offset_);
1667 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1668 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1671 // History to merge and a committed page that the browser was unaware of.
1672 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1673 expected_page_id = view()->page_id_;
1674 view()->OnSetHistoryLengthAndPrune(2, -1);
1675 EXPECT_EQ(3, view()->history_list_length_);
1676 EXPECT_EQ(2, view()->history_list_offset_);
1677 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1678 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1679 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1682 int expected_page_id_2 = -1;
1684 // No history to merge and two committed pages, both to be kept.
1685 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1686 expected_page_id = view()->page_id_;
1687 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
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);
1691 EXPECT_EQ(2, view()->history_list_length_);
1692 EXPECT_EQ(1, view()->history_list_offset_);
1693 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1694 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[1]);
1697 // No history to merge and two committed pages, and only the second is kept.
1698 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1699 expected_page_id = view()->page_id_;
1700 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1701 expected_page_id_2 = view()->page_id_;
1702 EXPECT_GT(expected_page_id_2, expected_page_id);
1703 view()->OnSetHistoryLengthAndPrune(0, expected_page_id_2);
1704 EXPECT_EQ(1, view()->history_list_length_);
1705 EXPECT_EQ(0, view()->history_list_offset_);
1706 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[0]);
1709 // No history to merge and two committed pages, both of which the browser was
1711 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1712 expected_page_id = view()->page_id_;
1713 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1714 expected_page_id_2 = view()->page_id_;
1715 EXPECT_GT(expected_page_id_2, expected_page_id);
1716 view()->OnSetHistoryLengthAndPrune(0, -1);
1717 EXPECT_EQ(2, view()->history_list_length_);
1718 EXPECT_EQ(1, view()->history_list_offset_);
1719 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1720 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[1]);
1723 // History to merge and two committed pages, both to be kept.
1724 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1725 expected_page_id = view()->page_id_;
1726 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1727 expected_page_id_2 = view()->page_id_;
1728 EXPECT_GT(expected_page_id_2, expected_page_id);
1729 view()->OnSetHistoryLengthAndPrune(2, expected_page_id);
1730 EXPECT_EQ(4, view()->history_list_length_);
1731 EXPECT_EQ(3, view()->history_list_offset_);
1732 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1733 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1734 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1735 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[3]);
1738 // History to merge and two committed pages, and only the second is kept.
1739 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1740 expected_page_id = view()->page_id_;
1741 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1742 expected_page_id_2 = view()->page_id_;
1743 EXPECT_GT(expected_page_id_2, expected_page_id);
1744 view()->OnSetHistoryLengthAndPrune(2, expected_page_id_2);
1745 EXPECT_EQ(3, view()->history_list_length_);
1746 EXPECT_EQ(2, view()->history_list_offset_);
1747 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1748 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1749 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[2]);
1752 // History to merge and two committed pages, both of which the browser was
1754 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1755 expected_page_id = view()->page_id_;
1756 frame()->didCommitProvisionalLoad(GetMainFrame(), true);
1757 expected_page_id_2 = view()->page_id_;
1758 EXPECT_GT(expected_page_id_2, expected_page_id);
1759 view()->OnSetHistoryLengthAndPrune(2, -1);
1760 EXPECT_EQ(4, view()->history_list_length_);
1761 EXPECT_EQ(3, view()->history_list_offset_);
1762 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1763 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1764 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1765 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[3]);
1768 TEST_F(RenderViewImplTest, ContextMenu) {
1769 LoadHTML("<div>Page A</div>");
1771 // Create a right click in the center of the iframe. (I'm hoping this will
1772 // make this a bit more robust in case of some other formatting or other bug.)
1773 WebMouseEvent mouse_event;
1774 mouse_event.type = WebInputEvent::MouseDown;
1775 mouse_event.button = WebMouseEvent::ButtonRight;
1776 mouse_event.x = 250;
1777 mouse_event.y = 250;
1778 mouse_event.globalX = 250;
1779 mouse_event.globalY = 250;
1781 SendWebMouseEvent(mouse_event);
1783 // Now simulate the corresponding up event which should display the menu
1784 mouse_event.type = WebInputEvent::MouseUp;
1785 SendWebMouseEvent(mouse_event);
1787 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
1788 FrameHostMsg_ContextMenu::ID));
1791 TEST_F(RenderViewImplTest, TestBackForward) {
1792 LoadHTML("<div id=pagename>Page A</div>");
1793 blink::WebHistoryItem page_a_item = GetMainFrame()->currentHistoryItem();
1794 int was_page_a = -1;
1795 base::string16 check_page_a =
1797 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1798 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1799 EXPECT_EQ(1, was_page_a);
1801 LoadHTML("<div id=pagename>Page B</div>");
1802 int was_page_b = -1;
1803 base::string16 check_page_b =
1805 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1806 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1807 EXPECT_EQ(1, was_page_b);
1809 LoadHTML("<div id=pagename>Page C</div>");
1810 int was_page_c = -1;
1811 base::string16 check_page_c =
1813 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1814 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1815 EXPECT_EQ(1, was_page_b);
1817 blink::WebHistoryItem forward_item = GetMainFrame()->currentHistoryItem();
1818 GoBack(GetMainFrame()->previousHistoryItem());
1819 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1820 EXPECT_EQ(1, was_page_b);
1822 GoForward(forward_item);
1823 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1824 EXPECT_EQ(1, was_page_c);
1826 GoBack(GetMainFrame()->previousHistoryItem());
1827 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1828 EXPECT_EQ(1, was_page_b);
1830 forward_item = GetMainFrame()->currentHistoryItem();
1831 GoBack(page_a_item);
1832 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1833 EXPECT_EQ(1, was_page_a);
1835 GoForward(forward_item);
1836 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1837 EXPECT_EQ(1, was_page_b);
1840 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
1841 TEST_F(RenderViewImplTest, GetCompositionCharacterBoundsTest) {
1844 // http://crbug.com/304193
1845 if (base::win::GetVersion() < base::win::VERSION_VISTA)
1849 LoadHTML("<textarea id=\"test\"></textarea>");
1850 ExecuteJavaScript("document.getElementById('test').focus();");
1852 const base::string16 empty_string;
1853 const std::vector<blink::WebCompositionUnderline> empty_underline;
1854 std::vector<gfx::Rect> bounds;
1855 view()->OnSetFocus(true);
1856 view()->OnSetInputMethodActive(true);
1858 // ASCII composition
1859 const base::string16 ascii_composition = base::UTF8ToUTF16("aiueo");
1860 view()->OnImeSetComposition(ascii_composition, empty_underline, 0, 0);
1861 view()->GetCompositionCharacterBounds(&bounds);
1862 ASSERT_EQ(ascii_composition.size(), bounds.size());
1863 for (size_t i = 0; i < bounds.size(); ++i)
1864 EXPECT_LT(0, bounds[i].width());
1865 view()->OnImeConfirmComposition(
1866 empty_string, gfx::Range::InvalidRange(), false);
1868 // Non surrogate pair unicode character.
1869 const base::string16 unicode_composition = base::UTF8ToUTF16(
1870 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1871 view()->OnImeSetComposition(unicode_composition, empty_underline, 0, 0);
1872 view()->GetCompositionCharacterBounds(&bounds);
1873 ASSERT_EQ(unicode_composition.size(), bounds.size());
1874 for (size_t i = 0; i < bounds.size(); ++i)
1875 EXPECT_LT(0, bounds[i].width());
1876 view()->OnImeConfirmComposition(
1877 empty_string, gfx::Range::InvalidRange(), false);
1879 // Surrogate pair character.
1880 const base::string16 surrogate_pair_char =
1881 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1882 view()->OnImeSetComposition(surrogate_pair_char,
1886 view()->GetCompositionCharacterBounds(&bounds);
1887 ASSERT_EQ(surrogate_pair_char.size(), bounds.size());
1888 EXPECT_LT(0, bounds[0].width());
1889 EXPECT_EQ(0, bounds[1].width());
1890 view()->OnImeConfirmComposition(
1891 empty_string, gfx::Range::InvalidRange(), false);
1894 const base::string16 surrogate_pair_mixed_composition =
1895 surrogate_pair_char + base::UTF8ToUTF16("\xE3\x81\x82") +
1896 surrogate_pair_char + base::UTF8ToUTF16("b") + surrogate_pair_char;
1897 const size_t utf16_length = 8UL;
1898 const bool is_surrogate_pair_empty_rect[8] = {
1899 false, true, false, false, true, false, false, true };
1900 view()->OnImeSetComposition(surrogate_pair_mixed_composition,
1904 view()->GetCompositionCharacterBounds(&bounds);
1905 ASSERT_EQ(utf16_length, bounds.size());
1906 for (size_t i = 0; i < utf16_length; ++i) {
1907 if (is_surrogate_pair_empty_rect[i]) {
1908 EXPECT_EQ(0, bounds[i].width());
1910 EXPECT_LT(0, bounds[i].width());
1913 view()->OnImeConfirmComposition(
1914 empty_string, gfx::Range::InvalidRange(), false);
1918 TEST_F(RenderViewImplTest, ZoomLimit) {
1919 const double kMinZoomLevel = ZoomFactorToZoomLevel(kMinimumZoomFactor);
1920 const double kMaxZoomLevel = ZoomFactorToZoomLevel(kMaximumZoomFactor);
1922 FrameMsg_Navigate_Params params;
1923 params.page_id = -1;
1924 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1926 // Verifies navigation to a URL with preset zoom level indeed sets the level.
1927 // Regression test for http://crbug.com/139559, where the level was not
1928 // properly set when it is out of the default zoom limits of WebView.
1929 params.url = GURL("data:text/html,min_zoomlimit_test");
1930 view()->OnSetZoomLevelForLoadingURL(params.url, kMinZoomLevel);
1931 frame()->OnNavigate(params);
1932 ProcessPendingMessages();
1933 EXPECT_DOUBLE_EQ(kMinZoomLevel, view()->GetWebView()->zoomLevel());
1935 // It should work even when the zoom limit is temporarily changed in the page.
1936 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
1937 ZoomFactorToZoomLevel(1.0));
1938 params.url = GURL("data:text/html,max_zoomlimit_test");
1939 view()->OnSetZoomLevelForLoadingURL(params.url, kMaxZoomLevel);
1940 frame()->OnNavigate(params);
1941 ProcessPendingMessages();
1942 EXPECT_DOUBLE_EQ(kMaxZoomLevel, view()->GetWebView()->zoomLevel());
1945 TEST_F(RenderViewImplTest, SetEditableSelectionAndComposition) {
1946 // Load an HTML page consisting of an input field.
1951 "<input id=\"test1\" value=\"some test text hello\"></input>"
1954 ExecuteJavaScript("document.getElementById('test1').focus();");
1955 frame()->OnSetEditableSelectionOffsets(4, 8);
1956 const std::vector<blink::WebCompositionUnderline> empty_underline;
1957 frame()->OnSetCompositionFromExistingText(7, 10, empty_underline);
1958 blink::WebTextInputInfo info = view()->webview()->textInputInfo();
1959 EXPECT_EQ(4, info.selectionStart);
1960 EXPECT_EQ(8, info.selectionEnd);
1961 EXPECT_EQ(7, info.compositionStart);
1962 EXPECT_EQ(10, info.compositionEnd);
1963 frame()->OnUnselect();
1964 info = view()->webview()->textInputInfo();
1965 EXPECT_EQ(0, info.selectionStart);
1966 EXPECT_EQ(0, info.selectionEnd);
1970 TEST_F(RenderViewImplTest, OnExtendSelectionAndDelete) {
1971 // Load an HTML page consisting of an input field.
1976 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
1979 ExecuteJavaScript("document.getElementById('test1').focus();");
1980 frame()->OnSetEditableSelectionOffsets(10, 10);
1981 frame()->OnExtendSelectionAndDelete(3, 4);
1982 blink::WebTextInputInfo info = view()->webview()->textInputInfo();
1983 EXPECT_EQ("abcdefgopqrstuvwxyz", info.value);
1984 EXPECT_EQ(7, info.selectionStart);
1985 EXPECT_EQ(7, info.selectionEnd);
1986 frame()->OnSetEditableSelectionOffsets(4, 8);
1987 frame()->OnExtendSelectionAndDelete(2, 5);
1988 info = view()->webview()->textInputInfo();
1989 EXPECT_EQ("abuvwxyz", info.value);
1990 EXPECT_EQ(2, info.selectionStart);
1991 EXPECT_EQ(2, info.selectionEnd);
1994 // Test that the navigating specific frames works correctly.
1995 TEST_F(RenderViewImplTest, NavigateFrame) {
1997 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
1999 // Navigate the frame only.
2000 FrameMsg_Navigate_Params nav_params;
2001 nav_params.url = GURL("data:text/html,world");
2002 nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2003 nav_params.transition = PAGE_TRANSITION_TYPED;
2004 nav_params.current_history_list_length = 1;
2005 nav_params.current_history_list_offset = 0;
2006 nav_params.pending_history_list_offset = 1;
2007 nav_params.page_id = -1;
2008 nav_params.frame_to_navigate = "frame";
2009 frame()->OnNavigate(nav_params);
2010 ProcessPendingMessages();
2012 // Copy the document content to std::wstring and compare with the
2014 const int kMaxOutputCharacters = 256;
2015 std::wstring output = base::UTF16ToWideHack(
2016 GetMainFrame()->contentAsText(kMaxOutputCharacters));
2017 EXPECT_EQ(output, L"hello \n\nworld");
2020 // This test ensures that a RenderFrame object is created for the top level
2021 // frame in the RenderView.
2022 TEST_F(RenderViewImplTest, BasicRenderFrame) {
2023 EXPECT_TRUE(view()->main_render_frame_.get());
2026 TEST_F(RenderViewImplTest, GetSSLStatusOfFrame) {
2027 LoadHTML("<!DOCTYPE html><html><body></body></html>");
2029 WebFrame* frame = GetMainFrame();
2030 SSLStatus ssl_status = view()->GetSSLStatusOfFrame(frame);
2031 EXPECT_FALSE(net::IsCertStatusError(ssl_status.cert_status));
2033 const_cast<blink::WebURLResponse&>(frame->dataSource()->response()).
2035 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS, 0, 0,
2036 SignedCertificateTimestampIDStatusList()));
2037 ssl_status = view()->GetSSLStatusOfFrame(frame);
2038 EXPECT_TRUE(net::IsCertStatusError(ssl_status.cert_status));
2041 TEST_F(RenderViewImplTest, MessageOrderInDidChangeSelection) {
2042 view()->OnSetInputMethodActive(true);
2043 view()->set_send_content_state_immediately(true);
2044 LoadHTML("<textarea id=\"test\"></textarea>");
2046 view()->handling_input_event_ = true;
2047 ExecuteJavaScript("document.getElementById('test').focus();");
2049 bool is_input_type_called = false;
2050 bool is_selection_called = false;
2051 size_t last_input_type = 0;
2052 size_t last_selection = 0;
2054 for (size_t i = 0; i < render_thread_->sink().message_count(); ++i) {
2055 const uint32 type = render_thread_->sink().GetMessageAt(i)->type();
2056 if (type == ViewHostMsg_TextInputTypeChanged::ID) {
2057 is_input_type_called = true;
2058 last_input_type = i;
2059 } else if (type == ViewHostMsg_SelectionChanged::ID) {
2060 is_selection_called = true;
2065 EXPECT_TRUE(is_input_type_called);
2066 EXPECT_TRUE(is_selection_called);
2068 // InputTypeChange shold be called earlier than SelectionChanged.
2069 EXPECT_LT(last_input_type, last_selection);
2072 class SuppressErrorPageTest : public RenderViewTest {
2074 virtual ContentRendererClient* CreateContentRendererClient() OVERRIDE {
2075 return new TestContentRendererClient;
2078 RenderViewImpl* view() {
2079 return static_cast<RenderViewImpl*>(view_);
2082 RenderFrameImpl* frame() {
2083 return static_cast<RenderFrameImpl*>(view()->GetMainRenderFrame());
2087 class TestContentRendererClient : public ContentRendererClient {
2089 virtual bool ShouldSuppressErrorPage(RenderFrame* render_frame,
2090 const GURL& url) OVERRIDE {
2091 return url == GURL("http://example.com/suppress");
2094 virtual void GetNavigationErrorStrings(
2095 content::RenderView* render_view,
2096 blink::WebFrame* frame,
2097 const blink::WebURLRequest& failed_request,
2098 const blink::WebURLError& error,
2099 std::string* error_html,
2100 base::string16* error_description) OVERRIDE {
2102 *error_html = "A suffusion of yellow.";
2107 #if defined(OS_ANDROID)
2108 // Crashing on Android: http://crbug.com/311341
2109 #define MAYBE_Suppresses DISABLED_Suppresses
2111 #define MAYBE_Suppresses Suppresses
2114 TEST_F(SuppressErrorPageTest, MAYBE_Suppresses) {
2116 error.domain = WebString::fromUTF8(net::kErrorDomain);
2117 error.reason = net::ERR_FILE_NOT_FOUND;
2118 error.unreachableURL = GURL("http://example.com/suppress");
2119 WebFrame* web_frame = GetMainFrame();
2121 // Start a load that will reach provisional state synchronously,
2122 // but won't complete synchronously.
2123 FrameMsg_Navigate_Params params;
2124 params.page_id = -1;
2125 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2126 params.url = GURL("data:text/html,test data");
2127 frame()->OnNavigate(params);
2129 // An error occurred.
2130 view()->main_render_frame()->didFailProvisionalLoad(web_frame, error);
2131 const int kMaxOutputCharacters = 22;
2133 base::UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters)));
2136 #if defined(OS_ANDROID)
2137 // Crashing on Android: http://crbug.com/311341
2138 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2140 #define MAYBE_DoesNotSuppress DoesNotSuppress
2143 TEST_F(SuppressErrorPageTest, MAYBE_DoesNotSuppress) {
2145 error.domain = WebString::fromUTF8(net::kErrorDomain);
2146 error.reason = net::ERR_FILE_NOT_FOUND;
2147 error.unreachableURL = GURL("http://example.com/dont-suppress");
2148 WebFrame* web_frame = GetMainFrame();
2150 // Start a load that will reach provisional state synchronously,
2151 // but won't complete synchronously.
2152 FrameMsg_Navigate_Params params;
2153 params.page_id = -1;
2154 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2155 params.url = GURL("data:text/html,test data");
2156 frame()->OnNavigate(params);
2158 // An error occurred.
2159 view()->main_render_frame()->didFailProvisionalLoad(web_frame, error);
2160 ProcessPendingMessages();
2161 const int kMaxOutputCharacters = 22;
2162 EXPECT_EQ("A suffusion of yellow.",
2163 base::UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters)));
2166 // Tests if IME API's candidatewindow* events sent from browser are handled
2168 TEST_F(RenderViewImplTest, SendCandidateWindowEvents) {
2169 // Sends an HTML with an <input> element and scripts to the renderer.
2170 // The script handles all 3 of candidatewindow* events for an
2171 // InputMethodContext object and once it received 'show', 'update', 'hide'
2172 // should appear in the result div.
2173 LoadHTML("<input id='test'>"
2174 "<div id='result'>Result: </div>"
2176 "window.onload = function() {"
2177 " var result = document.getElementById('result');"
2178 " var test = document.getElementById('test');"
2180 " var context = test.inputMethodContext;"
2182 " context.oncandidatewindowshow = function() {"
2183 " result.innerText += 'show'; };"
2184 " context.oncandidatewindowupdate = function(){"
2185 " result.innerText += 'update'; };"
2186 " context.oncandidatewindowhide = function(){"
2187 " result.innerText += 'hide'; };"
2192 // Fire candidatewindow events.
2193 view()->OnCandidateWindowShown();
2194 view()->OnCandidateWindowUpdated();
2195 view()->OnCandidateWindowHidden();
2197 // Retrieve the content and check if it is expected.
2198 const int kMaxOutputCharacters = 50;
2199 std::string output = base::UTF16ToUTF8(
2200 GetMainFrame()->contentAsText(kMaxOutputCharacters));
2201 EXPECT_EQ(output, "\nResult:showupdatehide");
2204 // Ensure the render view sends favicon url update events correctly.
2205 TEST_F(RenderViewImplTest, SendFaviconURLUpdateEvent) {
2206 // An event should be sent when a favicon url exists.
2209 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2212 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
2213 ViewHostMsg_UpdateFaviconURL::ID));
2214 render_thread_->sink().ClearMessages();
2216 // An event should not be sent if no favicon url exists. This is an assumption
2217 // made by some of Chrome's favicon handling.
2222 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
2223 ViewHostMsg_UpdateFaviconURL::ID));
2226 // Test progress tracker messages.
2227 TEST_F(RenderViewImplTest, SendProgressCompletionUpdates) {
2228 std::string data_url_string = "data:text/html,<body>placeholder</body>";
2229 GURL url(data_url_string);
2230 GetMainFrame()->loadRequest(blink::WebURLRequest(url));
2232 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
2233 FrameHostMsg_DidStartLoading::ID));
2235 // The load started, we should receive a start notification and a progress
2236 // update with the minimum progress.
2237 const IPC::Message* message = render_thread_->sink().GetFirstMessageMatching(
2238 ViewHostMsg_DidChangeLoadProgress::ID);
2239 EXPECT_TRUE(message);
2240 Tuple1<double> progress_value;
2241 ViewHostMsg_DidChangeLoadProgress::Read(message, &progress_value);
2242 EXPECT_EQ(0.1, progress_value.a);
2243 render_thread_->sink().ClearMessages();
2245 ProcessPendingMessages();
2247 // The data url has loaded, so we should see a progress change to 1.0 (done)
2248 // and a stop notification.
2249 message = render_thread_->sink().GetFirstMessageMatching(
2250 ViewHostMsg_DidChangeLoadProgress::ID);
2251 EXPECT_TRUE(message);
2252 ViewHostMsg_DidChangeLoadProgress::Read(message, &progress_value);
2253 EXPECT_EQ(1.0, progress_value.a);
2255 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
2256 FrameHostMsg_DidStopLoading::ID));
2257 render_thread_->sink().ClearMessages();
2260 TEST_F(RenderViewImplTest, FocusElementCallsFocusedNodeChanged) {
2261 LoadHTML("<input id='test1' value='hello1'></input>"
2262 "<input id='test2' value='hello2'></input>");
2264 ExecuteJavaScript("document.getElementById('test1').focus();");
2265 const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
2266 ViewHostMsg_FocusedNodeChanged::ID);
2269 ViewHostMsg_FocusedNodeChanged::Param params;
2270 ViewHostMsg_FocusedNodeChanged::Read(msg1, ¶ms);
2271 EXPECT_TRUE(params.a);
2272 render_thread_->sink().ClearMessages();
2274 ExecuteJavaScript("document.getElementById('test2').focus();");
2275 const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching(
2276 ViewHostMsg_FocusedNodeChanged::ID);
2278 ViewHostMsg_FocusedNodeChanged::Read(msg2, ¶ms);
2279 EXPECT_TRUE(params.a);
2280 render_thread_->sink().ClearMessages();
2282 view()->webview()->clearFocusedElement();
2283 const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching(
2284 ViewHostMsg_FocusedNodeChanged::ID);
2286 ViewHostMsg_FocusedNodeChanged::Read(msg3, ¶ms);
2287 EXPECT_FALSE(params.a);
2288 render_thread_->sink().ClearMessages();
2291 TEST_F(RenderViewImplTest, ServiceWorkerNetworkProviderSetup) {
2292 ServiceWorkerNetworkProvider* provider = NULL;
2293 RequestExtraData* extra_data = NULL;
2295 // Make sure each new document has a new provider and
2296 // that the main request is tagged with the provider's id.
2297 LoadHTML("<b>A Document</b>");
2298 ASSERT_TRUE(GetMainFrame()->dataSource());
2299 provider = ServiceWorkerNetworkProvider::FromDocumentState(
2300 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2301 ASSERT_TRUE(provider);
2302 extra_data = static_cast<RequestExtraData*>(
2303 GetMainFrame()->dataSource()->request().extraData());
2304 ASSERT_TRUE(extra_data);
2305 EXPECT_EQ(extra_data->service_worker_provider_id(),
2306 provider->provider_id());
2307 int provider1_id = provider->provider_id();
2309 LoadHTML("<b>New Document B Goes Here</b>");
2310 ASSERT_TRUE(GetMainFrame()->dataSource());
2311 provider = ServiceWorkerNetworkProvider::FromDocumentState(
2312 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2313 ASSERT_TRUE(provider);
2314 EXPECT_NE(provider1_id, provider->provider_id());
2315 extra_data = static_cast<RequestExtraData*>(
2316 GetMainFrame()->dataSource()->request().extraData());
2317 ASSERT_TRUE(extra_data);
2318 EXPECT_EQ(extra_data->service_worker_provider_id(),
2319 provider->provider_id());
2321 // See that subresource requests are also tagged with the provider's id.
2322 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2323 blink::WebURLRequest request(GURL("http://foo.com"));
2324 request.setTargetType(blink::WebURLRequest::TargetIsSubresource);
2325 blink::WebURLResponse redirect_response;
2326 frame()->willSendRequest(GetMainFrame(), 0, request, redirect_response);
2327 extra_data = static_cast<RequestExtraData*>(request.extraData());
2328 ASSERT_TRUE(extra_data);
2329 EXPECT_EQ(extra_data->service_worker_provider_id(),
2330 provider->provider_id());
2333 TEST_F(RenderViewImplTest, OnSetAccessibilityMode) {
2334 ASSERT_EQ(AccessibilityModeOff, view()->accessibility_mode());
2335 ASSERT_EQ((RendererAccessibility*) NULL, view()->renderer_accessibility());
2337 view()->OnSetAccessibilityMode(AccessibilityModeTreeOnly);
2338 ASSERT_EQ(AccessibilityModeTreeOnly, view()->accessibility_mode());
2339 ASSERT_NE((RendererAccessibility*) NULL, view()->renderer_accessibility());
2340 ASSERT_EQ(RendererAccessibilityTypeComplete,
2341 view()->renderer_accessibility()->GetType());
2343 view()->OnSetAccessibilityMode(AccessibilityModeOff);
2344 ASSERT_EQ(AccessibilityModeOff, view()->accessibility_mode());
2345 ASSERT_EQ((RendererAccessibility*) NULL, view()->renderer_accessibility());
2347 view()->OnSetAccessibilityMode(AccessibilityModeComplete);
2348 ASSERT_EQ(AccessibilityModeComplete, view()->accessibility_mode());
2349 ASSERT_NE((RendererAccessibility*) NULL, view()->renderer_accessibility());
2350 ASSERT_EQ(RendererAccessibilityTypeComplete,
2351 view()->renderer_accessibility()->GetType());
2353 view()->OnSetAccessibilityMode(AccessibilityModeEditableTextOnly);
2354 ASSERT_EQ(AccessibilityModeEditableTextOnly, view()->accessibility_mode());
2355 ASSERT_NE((RendererAccessibility*) NULL, view()->renderer_accessibility());
2356 ASSERT_EQ(RendererAccessibilityTypeFocusOnly,
2357 view()->renderer_accessibility()->GetType());
2360 } // namespace content