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