Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / renderer / render_view_browsertest.cc
bloba5b060ba6d72365bc2183c9ab0d49973070e0909
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"
6 #include "base/bind.h"
7 #include "base/callback.h"
8 #include "base/location.h"
9 #include "base/memory/shared_memory.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/time/time.h"
15 #include "base/win/windows_version.h"
16 #include "content/child/request_extra_data.h"
17 #include "content/child/service_worker/service_worker_network_provider.h"
18 #include "content/common/frame_messages.h"
19 #include "content/common/ssl_status_serialization.h"
20 #include "content/common/view_messages.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/native_web_keyboard_event.h"
23 #include "content/public/browser/web_ui_controller_factory.h"
24 #include "content/public/common/bindings_policy.h"
25 #include "content/public/common/content_switches.h"
26 #include "content/public/common/page_zoom.h"
27 #include "content/public/common/url_constants.h"
28 #include "content/public/common/url_utils.h"
29 #include "content/public/renderer/content_renderer_client.h"
30 #include "content/public/renderer/document_state.h"
31 #include "content/public/renderer/navigation_state.h"
32 #include "content/public/test/browser_test_utils.h"
33 #include "content/public/test/frame_load_waiter.h"
34 #include "content/public/test/render_view_test.h"
35 #include "content/public/test/test_utils.h"
36 #include "content/renderer/accessibility/renderer_accessibility.h"
37 #include "content/renderer/devtools/devtools_agent.h"
38 #include "content/renderer/history_controller.h"
39 #include "content/renderer/history_serialization.h"
40 #include "content/renderer/navigation_state_impl.h"
41 #include "content/renderer/render_process.h"
42 #include "content/renderer/render_view_impl.h"
43 #include "content/shell/browser/shell.h"
44 #include "content/shell/browser/shell_browser_context.h"
45 #include "content/test/mock_keyboard.h"
46 #include "content/test/test_render_frame.h"
47 #include "net/base/net_errors.h"
48 #include "net/cert/cert_status_flags.h"
49 #include "testing/gtest/include/gtest/gtest.h"
50 #include "third_party/WebKit/public/platform/WebData.h"
51 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
52 #include "third_party/WebKit/public/platform/WebString.h"
53 #include "third_party/WebKit/public/platform/WebURLResponse.h"
54 #include "third_party/WebKit/public/web/WebDataSource.h"
55 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
56 #include "third_party/WebKit/public/web/WebHistoryCommitType.h"
57 #include "third_party/WebKit/public/web/WebHistoryItem.h"
58 #include "third_party/WebKit/public/web/WebLocalFrame.h"
59 #include "third_party/WebKit/public/web/WebPerformance.h"
60 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
61 #include "third_party/WebKit/public/web/WebSettings.h"
62 #include "third_party/WebKit/public/web/WebView.h"
63 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
64 #include "ui/events/event.h"
65 #include "ui/events/keycodes/keyboard_codes.h"
66 #include "ui/gfx/codec/jpeg_codec.h"
67 #include "ui/gfx/range/range.h"
69 #if defined(USE_AURA) && defined(USE_X11)
70 #include <X11/Xlib.h>
71 #include "ui/events/event_constants.h"
72 #include "ui/events/keycodes/keyboard_code_conversion.h"
73 #include "ui/events/test/events_test_utils.h"
74 #include "ui/events/test/events_test_utils_x11.h"
75 #endif
77 #if defined(USE_OZONE)
78 #include "ui/events/keycodes/keyboard_code_conversion.h"
79 #endif
81 using blink::WebFrame;
82 using blink::WebInputEvent;
83 using blink::WebLocalFrame;
84 using blink::WebMouseEvent;
85 using blink::WebRuntimeFeatures;
86 using blink::WebString;
87 using blink::WebTextDirection;
88 using blink::WebURLError;
90 namespace content {
92 namespace {
94 static const int kProxyRoutingId = 13;
96 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
97 // Converts MockKeyboard::Modifiers to ui::EventFlags.
98 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers) {
99 static struct ModifierMap {
100 MockKeyboard::Modifiers src;
101 int dst;
102 } kModifierMap[] = {
103 { MockKeyboard::LEFT_SHIFT, ui::EF_SHIFT_DOWN },
104 { MockKeyboard::RIGHT_SHIFT, ui::EF_SHIFT_DOWN },
105 { MockKeyboard::LEFT_CONTROL, ui::EF_CONTROL_DOWN },
106 { MockKeyboard::RIGHT_CONTROL, ui::EF_CONTROL_DOWN },
107 { MockKeyboard::LEFT_ALT, ui::EF_ALT_DOWN },
108 { MockKeyboard::RIGHT_ALT, ui::EF_ALT_DOWN },
110 int flags = 0;
111 for (size_t i = 0; i < arraysize(kModifierMap); ++i) {
112 if (kModifierMap[i].src & modifiers) {
113 flags |= kModifierMap[i].dst;
116 return flags;
118 #endif
120 class WebUITestWebUIControllerFactory : public WebUIControllerFactory {
121 public:
122 WebUIController* CreateWebUIControllerForURL(WebUI* web_ui,
123 const GURL& url) const override {
124 return NULL;
126 WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
127 const GURL& url) const override {
128 return WebUI::kNoWebUI;
130 bool UseWebUIForURL(BrowserContext* browser_context,
131 const GURL& url) const override {
132 return HasWebUIScheme(url);
134 bool UseWebUIBindingsForURL(BrowserContext* browser_context,
135 const GURL& url) const override {
136 return HasWebUIScheme(url);
140 } // namespace
142 class RenderViewImplTest : public RenderViewTest {
143 public:
144 RenderViewImplTest() {
145 // Attach a pseudo keyboard device to this object.
146 mock_keyboard_.reset(new MockKeyboard());
149 ~RenderViewImplTest() override {}
151 void SetUp() override {
152 // Enable Blink's experimental and test only features so that test code
153 // does not have to bother enabling each feature.
154 WebRuntimeFeatures::enableExperimentalFeatures(true);
155 WebRuntimeFeatures::enableTestOnlyFeatures(true);
156 RenderViewTest::SetUp();
159 RenderViewImpl* view() {
160 return static_cast<RenderViewImpl*>(view_);
163 int view_page_id() {
164 return view()->page_id_;
167 TestRenderFrame* frame() {
168 return static_cast<TestRenderFrame*>(view()->GetMainRenderFrame());
171 // Sends IPC messages that emulates a key-press event.
172 int SendKeyEvent(MockKeyboard::Layout layout,
173 int key_code,
174 MockKeyboard::Modifiers modifiers,
175 base::string16* output) {
176 #if defined(OS_WIN)
177 // Retrieve the Unicode character for the given tuple (keyboard-layout,
178 // key-code, and modifiers).
179 // Exit when a keyboard-layout driver cannot assign a Unicode character to
180 // the tuple to prevent sending an invalid key code to the RenderView
181 // object.
182 CHECK(mock_keyboard_.get());
183 CHECK(output);
184 int length = mock_keyboard_->GetCharacters(layout, key_code, modifiers,
185 output);
186 if (length != 1)
187 return -1;
189 // Create IPC messages from Windows messages and send them to our
190 // back-end.
191 // A keyboard event of Windows consists of three Windows messages:
192 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
193 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
194 // WM_CHAR sends a composed Unicode character.
195 MSG msg1 = { NULL, WM_KEYDOWN, key_code, 0 };
196 ui::KeyEvent evt1(msg1);
197 NativeWebKeyboardEvent keydown_event(evt1);
198 SendNativeKeyEvent(keydown_event);
200 MSG msg2 = { NULL, WM_CHAR, (*output)[0], 0 };
201 ui::KeyEvent evt2(msg2);
202 NativeWebKeyboardEvent char_event(evt2);
203 SendNativeKeyEvent(char_event);
205 MSG msg3 = { NULL, WM_KEYUP, key_code, 0 };
206 ui::KeyEvent evt3(msg3);
207 NativeWebKeyboardEvent keyup_event(evt3);
208 SendNativeKeyEvent(keyup_event);
210 return length;
211 #elif defined(USE_AURA) && defined(USE_X11)
212 // We ignore |layout|, which means we are only testing the layout of the
213 // current locale. TODO(mazda): fix this to respect |layout|.
214 CHECK(output);
215 const int flags = ConvertMockKeyboardModifier(modifiers);
217 ui::ScopedXI2Event xevent;
218 xevent.InitKeyEvent(ui::ET_KEY_PRESSED,
219 static_cast<ui::KeyboardCode>(key_code),
220 flags);
221 ui::KeyEvent event1(xevent);
222 NativeWebKeyboardEvent keydown_event(event1);
223 SendNativeKeyEvent(keydown_event);
225 // X11 doesn't actually have native character events, but give the test
226 // what it wants.
227 xevent.InitKeyEvent(ui::ET_KEY_PRESSED,
228 static_cast<ui::KeyboardCode>(key_code),
229 flags);
230 ui::KeyEvent event2(xevent);
231 event2.set_character(GetCharacterFromKeyCode(event2.key_code(),
232 event2.flags()));
233 ui::KeyEventTestApi test_event2(&event2);
234 test_event2.set_is_char(true);
235 NativeWebKeyboardEvent char_event(event2);
236 SendNativeKeyEvent(char_event);
238 xevent.InitKeyEvent(ui::ET_KEY_RELEASED,
239 static_cast<ui::KeyboardCode>(key_code),
240 flags);
241 ui::KeyEvent event3(xevent);
242 NativeWebKeyboardEvent keyup_event(event3);
243 SendNativeKeyEvent(keyup_event);
245 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
246 flags);
247 output->assign(1, static_cast<base::char16>(c));
248 return 1;
249 #elif defined(USE_OZONE)
250 const int flags = ConvertMockKeyboardModifier(modifiers);
252 ui::KeyEvent keydown_event(ui::ET_KEY_PRESSED,
253 static_cast<ui::KeyboardCode>(key_code),
254 flags);
255 NativeWebKeyboardEvent keydown_web_event(keydown_event);
256 SendNativeKeyEvent(keydown_web_event);
258 ui::KeyEvent char_event(keydown_event.GetCharacter(),
259 static_cast<ui::KeyboardCode>(key_code),
260 flags);
261 NativeWebKeyboardEvent char_web_event(char_event);
262 SendNativeKeyEvent(char_web_event);
264 ui::KeyEvent keyup_event(ui::ET_KEY_RELEASED,
265 static_cast<ui::KeyboardCode>(key_code),
266 flags);
267 NativeWebKeyboardEvent keyup_web_event(keyup_event);
268 SendNativeKeyEvent(keyup_web_event);
270 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
271 flags);
272 output->assign(1, static_cast<base::char16>(c));
273 return 1;
274 #else
275 NOTIMPLEMENTED();
276 return L'\0';
277 #endif
280 void EnablePreferredSizeMode() {
281 view()->OnEnablePreferredSizeChangedMode();
284 const gfx::Size& GetPreferredSize() {
285 view()->CheckPreferredSize();
286 return view()->preferred_size_;
289 void SetZoomLevel(double level) {
290 view()->OnSetZoomLevelForView(false, level);
293 private:
294 scoped_ptr<MockKeyboard> mock_keyboard_;
297 class DevToolsAgentTest : public RenderViewImplTest {
298 public:
299 void Attach() {
300 std::string host_id = "host_id";
301 agent()->OnAttach(host_id);
304 void Detach() {
305 agent()->OnDetach();
308 bool IsPaused() {
309 return agent()->paused_;
312 void DispatchDevToolsMessage(const std::string& message) {
313 agent()->OnDispatchOnInspectorBackend(message);
316 void CloseWhilePaused() {
317 EXPECT_TRUE(IsPaused());
318 view()->NotifyOnClose();
321 private:
322 DevToolsAgent* agent() {
323 return frame()->devtools_agent();
327 class RenderViewImplBlinkSettingsTest : public RenderViewImplTest {
328 public:
329 void DoSetUp() {
330 RenderViewImplTest::SetUp();
333 const blink::WebSettings* settings() {
334 return view()->webview()->settings();
337 protected:
338 // Blink settings may be specified on the command line, which must
339 // be configured before RenderViewImplTest::SetUp runs. Thus we make
340 // SetUp() a no-op, and expose RenderViewImplTest::SetUp() via
341 // DoSetUp(), to allow tests to perform command line modifications
342 // before RenderViewImplTest::SetUp is run. Each test must invoke
343 // DoSetUp manually once pre-SetUp configuration is complete.
344 void SetUp() override {}
347 // Ensure that the main RenderFrame is deleted and cleared from the RenderView
348 // after closing it.
349 TEST_F(RenderViewImplTest, RenderFrameClearedAfterClose) {
350 // Create a new main frame RenderFrame so that we don't interfere with the
351 // shutdown of frame() in RenderViewTest.TearDown.
352 blink::WebURLRequest popup_request(GURL("http://foo.com"));
353 blink::WebView* new_web_view = view()->createView(
354 GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
355 blink::WebNavigationPolicyNewForegroundTab, false);
356 RenderViewImpl* new_view = RenderViewImpl::FromWebView(new_web_view);
358 // Close the view, causing the main RenderFrame to be detached and deleted.
359 new_view->Close();
360 EXPECT_FALSE(new_view->GetMainRenderFrame());
362 // Clean up after the new view so we don't leak it.
363 new_view->Release();
366 TEST_F(RenderViewImplTest, SaveImageFromDataURL) {
367 const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
368 ViewHostMsg_SaveImageFromDataURL::ID);
369 EXPECT_FALSE(msg1);
370 render_thread_->sink().ClearMessages();
372 const std::string image_data_url =
373 "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
375 view()->saveImageFromDataURL(WebString::fromUTF8(image_data_url));
376 ProcessPendingMessages();
377 const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching(
378 ViewHostMsg_SaveImageFromDataURL::ID);
379 EXPECT_TRUE(msg2);
381 ViewHostMsg_SaveImageFromDataURL::Param param1;
382 ViewHostMsg_SaveImageFromDataURL::Read(msg2, &param1);
383 EXPECT_EQ(base::get<1>(param1).length(), image_data_url.length());
384 EXPECT_EQ(base::get<1>(param1), image_data_url);
386 ProcessPendingMessages();
387 render_thread_->sink().ClearMessages();
389 const std::string large_data_url(1024 * 1024 * 10 - 1, 'd');
391 view()->saveImageFromDataURL(WebString::fromUTF8(large_data_url));
392 ProcessPendingMessages();
393 const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching(
394 ViewHostMsg_SaveImageFromDataURL::ID);
395 EXPECT_TRUE(msg3);
397 ViewHostMsg_SaveImageFromDataURL::Param param2;
398 ViewHostMsg_SaveImageFromDataURL::Read(msg3, &param2);
399 EXPECT_EQ(base::get<1>(param2).length(), large_data_url.length());
400 EXPECT_EQ(base::get<1>(param2), large_data_url);
402 ProcessPendingMessages();
403 render_thread_->sink().ClearMessages();
405 const std::string exceeded_data_url(1024 * 1024 * 10 + 1, 'd');
407 view()->saveImageFromDataURL(WebString::fromUTF8(exceeded_data_url));
408 ProcessPendingMessages();
409 const IPC::Message* msg4 = render_thread_->sink().GetFirstMessageMatching(
410 ViewHostMsg_SaveImageFromDataURL::ID);
411 EXPECT_FALSE(msg4);
414 // Test that we get form state change notifications when input fields change.
415 TEST_F(RenderViewImplTest, DISABLED_OnNavStateChanged) {
416 // Don't want any delay for form state sync changes. This will still post a
417 // message so updates will get coalesced, but as soon as we spin the message
418 // loop, it will generate an update.
419 view()->set_send_content_state_immediately(true);
421 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
423 // We should NOT have gotten a form state change notification yet.
424 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
425 ViewHostMsg_UpdateState::ID));
426 render_thread_->sink().ClearMessages();
428 // Change the value of the input. We should have gotten an update state
429 // notification. We need to spin the message loop to catch this update.
430 ExecuteJavaScriptForTests(
431 "document.getElementById('elt_text').value = 'foo';");
432 ProcessPendingMessages();
433 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
434 ViewHostMsg_UpdateState::ID));
437 TEST_F(RenderViewImplTest, OnNavigationHttpPost) {
438 // An http url will trigger a resource load so cannot be used here.
439 CommonNavigationParams common_params;
440 StartNavigationParams start_params;
441 RequestNavigationParams request_params;
442 common_params.url = GURL("data:text/html,<div>Page</div>");
443 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
444 common_params.transition = ui::PAGE_TRANSITION_TYPED;
445 request_params.page_id = -1;
447 // Set up post data.
448 const unsigned char* raw_data = reinterpret_cast<const unsigned char*>(
449 "post \0\ndata");
450 const unsigned int length = 11;
451 const std::vector<unsigned char> post_data(raw_data, raw_data + length);
452 start_params.is_post = true;
453 start_params.browser_initiated_post_data = post_data;
455 frame()->Navigate(common_params, start_params, request_params);
456 ProcessPendingMessages();
458 const IPC::Message* frame_navigate_msg =
459 render_thread_->sink().GetUniqueMessageMatching(
460 FrameHostMsg_DidCommitProvisionalLoad::ID);
461 EXPECT_TRUE(frame_navigate_msg);
463 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params;
464 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
465 &host_nav_params);
466 EXPECT_TRUE(base::get<0>(host_nav_params).is_post);
468 // Check post data sent to browser matches
469 EXPECT_TRUE(base::get<0>(host_nav_params).page_state.IsValid());
470 scoped_ptr<HistoryEntry> entry =
471 PageStateToHistoryEntry(base::get<0>(host_nav_params).page_state);
472 blink::WebHTTPBody body = entry->root().httpBody();
473 blink::WebHTTPBody::Element element;
474 bool successful = body.elementAt(0, element);
475 EXPECT_TRUE(successful);
476 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData, element.type);
477 EXPECT_EQ(length, element.data.size());
478 EXPECT_EQ(0, memcmp(raw_data, element.data.data(), length));
481 TEST_F(RenderViewImplTest, DecideNavigationPolicy) {
482 WebUITestWebUIControllerFactory factory;
483 WebUIControllerFactory::RegisterFactory(&factory);
485 DocumentState state;
486 state.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
488 // Navigations to normal HTTP URLs can be handled locally.
489 blink::WebURLRequest request(GURL("http://foo.com"));
490 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
491 policy_info.frame = GetMainFrame();
492 policy_info.extraData = &state;
493 policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
494 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
495 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
496 policy_info);
497 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
498 switches::kEnableBrowserSideNavigation)) {
499 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab, policy);
500 } else {
501 // If this is a renderer-initiated navigation that just begun, it should
502 // stop and be sent to the browser.
503 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
505 // If this a navigation that is ready to commit, it should be handled
506 // locally.
507 request.setCheckForBrowserSideNavigation(false);
508 policy = frame()->decidePolicyForNavigation(policy_info);
509 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab, policy);
512 // Verify that form posts to WebUI URLs will be sent to the browser process.
513 blink::WebURLRequest form_request(GURL("chrome://foo"));
514 blink::WebFrameClient::NavigationPolicyInfo form_policy_info(form_request);
515 form_policy_info.frame = GetMainFrame();
516 form_policy_info.extraData = &state;
517 form_policy_info.navigationType = blink::WebNavigationTypeFormSubmitted;
518 form_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
519 form_request.setHTTPMethod("POST");
520 policy = frame()->decidePolicyForNavigation(form_policy_info);
521 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
523 // Verify that popup links to WebUI URLs also are sent to browser.
524 blink::WebURLRequest popup_request(GURL("chrome://foo"));
525 blink::WebFrameClient::NavigationPolicyInfo popup_policy_info(popup_request);
526 popup_policy_info.frame = GetMainFrame();
527 popup_policy_info.extraData = &state;
528 popup_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
529 popup_policy_info.defaultPolicy = blink::WebNavigationPolicyNewForegroundTab;
530 policy = frame()->decidePolicyForNavigation(popup_policy_info);
531 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
534 TEST_F(RenderViewImplTest, DecideNavigationPolicyHandlesAllTopLevel) {
535 DocumentState state;
536 state.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
538 RendererPreferences prefs = view()->renderer_preferences();
539 prefs.browser_handles_all_top_level_requests = true;
540 view()->OnSetRendererPrefs(prefs);
542 const blink::WebNavigationType kNavTypes[] = {
543 blink::WebNavigationTypeLinkClicked,
544 blink::WebNavigationTypeFormSubmitted,
545 blink::WebNavigationTypeBackForward,
546 blink::WebNavigationTypeReload,
547 blink::WebNavigationTypeFormResubmitted,
548 blink::WebNavigationTypeOther,
551 blink::WebURLRequest request(GURL("http://foo.com"));
552 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
553 policy_info.frame = GetMainFrame();
554 policy_info.extraData = &state;
555 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
557 for (size_t i = 0; i < arraysize(kNavTypes); ++i) {
558 policy_info.navigationType = kNavTypes[i];
560 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
561 policy_info);
562 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
566 TEST_F(RenderViewImplTest, DecideNavigationPolicyForWebUI) {
567 // Enable bindings to simulate a WebUI view.
568 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI);
570 DocumentState state;
571 state.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
573 // Navigations to normal HTTP URLs will be sent to browser process.
574 blink::WebURLRequest request(GURL("http://foo.com"));
575 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
576 policy_info.frame = GetMainFrame();
577 policy_info.extraData = &state;
578 policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
579 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
581 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
582 policy_info);
583 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
585 // Navigations to WebUI URLs will also be sent to browser process.
586 blink::WebURLRequest webui_request(GURL("chrome://foo"));
587 blink::WebFrameClient::NavigationPolicyInfo webui_policy_info(webui_request);
588 webui_policy_info.frame = GetMainFrame();
589 webui_policy_info.extraData = &state;
590 webui_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
591 webui_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
592 policy = frame()->decidePolicyForNavigation(webui_policy_info);
593 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
595 // Verify that form posts to data URLs will be sent to the browser process.
596 blink::WebURLRequest data_request(GURL("data:text/html,foo"));
597 blink::WebFrameClient::NavigationPolicyInfo data_policy_info(data_request);
598 data_policy_info.frame = GetMainFrame();
599 data_policy_info.extraData = &state;
600 data_policy_info.navigationType = blink::WebNavigationTypeFormSubmitted;
601 data_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
602 data_request.setHTTPMethod("POST");
603 policy = frame()->decidePolicyForNavigation(data_policy_info);
604 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
606 // Verify that a popup that creates a view first and then navigates to a
607 // normal HTTP URL will be sent to the browser process, even though the
608 // new view does not have any enabled_bindings_.
609 blink::WebURLRequest popup_request(GURL("http://foo.com"));
610 blink::WebView* new_web_view = view()->createView(
611 GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
612 blink::WebNavigationPolicyNewForegroundTab, false);
613 RenderViewImpl* new_view = RenderViewImpl::FromWebView(new_web_view);
614 blink::WebFrameClient::NavigationPolicyInfo popup_policy_info(popup_request);
615 popup_policy_info.frame = new_web_view->mainFrame()->toWebLocalFrame();
616 popup_policy_info.extraData = &state;
617 popup_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
618 popup_policy_info.defaultPolicy = blink::WebNavigationPolicyNewForegroundTab;
619 policy = static_cast<RenderFrameImpl*>(new_view->GetMainRenderFrame())->
620 decidePolicyForNavigation(popup_policy_info);
621 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
623 // Clean up after the new view so we don't leak it.
624 new_view->Close();
625 new_view->Release();
628 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
629 // already swapped out. http://crbug.com/93427.
630 TEST_F(RenderViewImplTest, SendSwapOutACK) {
631 // This test is invalid in --site-per-process mode, as swapped-out is no
632 // longer used.
633 if (RenderFrameProxy::IsSwappedOutStateForbidden()) {
634 return;
636 LoadHTML("<div>Page A</div>");
637 int initial_page_id = view_page_id();
639 // Increment the ref count so that we don't exit when swapping out.
640 RenderProcess::current()->AddRefProcess();
642 // Respond to a swap out request.
643 frame()->SwapOut(kProxyRoutingId, true, content::FrameReplicationState());
645 // Ensure the swap out commits synchronously.
646 EXPECT_NE(initial_page_id, view_page_id());
648 // Check for a valid OnSwapOutACK.
649 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
650 FrameHostMsg_SwapOut_ACK::ID);
651 ASSERT_TRUE(msg);
653 // It is possible to get another swap out request. Ensure that we send
654 // an ACK, even if we don't have to do anything else.
655 render_thread_->sink().ClearMessages();
656 frame()->SwapOut(kProxyRoutingId, false, content::FrameReplicationState());
657 const IPC::Message* msg2 = render_thread_->sink().GetUniqueMessageMatching(
658 FrameHostMsg_SwapOut_ACK::ID);
659 ASSERT_TRUE(msg2);
661 // If we navigate back to this RenderView, ensure we don't send a state
662 // update for the swapped out URL. (http://crbug.com/72235)
663 CommonNavigationParams common_params;
664 RequestNavigationParams request_params;
665 common_params.url = GURL("data:text/html,<div>Page B</div>");
666 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
667 common_params.transition = ui::PAGE_TRANSITION_TYPED;
668 request_params.current_history_list_length = 1;
669 request_params.current_history_list_offset = 0;
670 request_params.pending_history_list_offset = 1;
671 request_params.page_id = -1;
672 frame()->Navigate(common_params, StartNavigationParams(), request_params);
673 ProcessPendingMessages();
674 const IPC::Message* msg3 = render_thread_->sink().GetUniqueMessageMatching(
675 ViewHostMsg_UpdateState::ID);
676 EXPECT_FALSE(msg3);
679 // Ensure the RenderViewImpl reloads the previous page if a reload request
680 // arrives while it is showing swappedout://. http://crbug.com/143155.
681 TEST_F(RenderViewImplTest, ReloadWhileSwappedOut) {
682 // This test is invalid in --site-per-process mode, as swapped-out is no
683 // longer used.
684 if (RenderFrameProxy::IsSwappedOutStateForbidden()) {
685 return;
688 // Load page A.
689 LoadHTML("<div>Page A</div>");
691 // Load page B, which will trigger an UpdateState message for page A.
692 LoadHTML("<div>Page B</div>");
694 // Check for a valid UpdateState message for page A.
695 ProcessPendingMessages();
696 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
697 ViewHostMsg_UpdateState::ID);
698 ASSERT_TRUE(msg_A);
699 ViewHostMsg_UpdateState::Param params;
700 ViewHostMsg_UpdateState::Read(msg_A, &params);
701 int page_id_A = base::get<0>(params);
702 PageState state_A = base::get<1>(params);
703 EXPECT_EQ(1, page_id_A);
704 render_thread_->sink().ClearMessages();
706 // Back to page A (page_id 1) and commit.
707 CommonNavigationParams common_params_A;
708 RequestNavigationParams request_params_A;
709 common_params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL;
710 common_params_A.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
711 request_params_A.current_history_list_length = 2;
712 request_params_A.current_history_list_offset = 1;
713 request_params_A.pending_history_list_offset = 0;
714 request_params_A.page_id = 1;
715 request_params_A.nav_entry_id = 1;
716 request_params_A.page_state = state_A;
717 frame()->Navigate(common_params_A, StartNavigationParams(), request_params_A);
718 EXPECT_EQ(1, view()->historyBackListCount());
719 EXPECT_EQ(2, view()->historyBackListCount() +
720 view()->historyForwardListCount() + 1);
721 ProcessPendingMessages();
723 // Respond to a swap out request.
724 frame()->SwapOut(kProxyRoutingId, true, content::FrameReplicationState());
726 // Check for a OnSwapOutACK.
727 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
728 FrameHostMsg_SwapOut_ACK::ID);
729 ASSERT_TRUE(msg);
730 render_thread_->sink().ClearMessages();
732 // It is possible to get a reload request at this point, containing the
733 // params.page_state of the initial page (e.g., if the new page fails the
734 // provisional load in the renderer process, after we unload the old page).
735 // Ensure the old page gets reloaded, not swappedout://.
736 CommonNavigationParams common_params;
737 RequestNavigationParams request_params;
738 common_params.url = GURL("data:text/html,<div>Page A</div>");
739 common_params.navigation_type = FrameMsg_Navigate_Type::RELOAD;
740 common_params.transition = ui::PAGE_TRANSITION_RELOAD;
741 request_params.current_history_list_length = 2;
742 request_params.current_history_list_offset = 0;
743 request_params.pending_history_list_offset = 0;
744 request_params.page_id = 1;
745 request_params.nav_entry_id = 1;
746 request_params.page_state = state_A;
747 frame()->Navigate(common_params, StartNavigationParams(), request_params);
748 ProcessPendingMessages();
750 // Verify page A committed, not swappedout://.
751 const IPC::Message* frame_navigate_msg =
752 render_thread_->sink().GetUniqueMessageMatching(
753 FrameHostMsg_DidCommitProvisionalLoad::ID);
754 EXPECT_TRUE(frame_navigate_msg);
756 // Read URL out of the parent trait of the params object.
757 FrameHostMsg_DidCommitProvisionalLoad::Param commit_load_params;
758 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
759 &commit_load_params);
760 EXPECT_NE(GURL("swappedout://"), base::get<0>(commit_load_params).url);
763 // Verify that security origins are replicated properly to RenderFrameProxies
764 // when swapping out.
765 TEST_F(RenderViewImplTest, OriginReplicationForSwapOut) {
766 // This test should only run with --site-per-process, since origin
767 // replication only happens in that mode.
768 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
769 switches::kSitePerProcess))
770 return;
772 LoadHTML(
773 "Hello <iframe src='data:text/html,frame 1'></iframe>"
774 "<iframe src='data:text/html,frame 2'></iframe>");
775 WebFrame* web_frame = frame()->GetWebFrame();
776 TestRenderFrame* child_frame = static_cast<TestRenderFrame*>(
777 RenderFrame::FromWebFrame(web_frame->firstChild()));
779 // Swap the child frame out and pass a replicated origin to be set for
780 // WebRemoteFrame.
781 content::FrameReplicationState replication_state;
782 replication_state.origin = url::Origin(GURL("http://foo.com"));
783 child_frame->SwapOut(kProxyRoutingId, true, replication_state);
785 // The child frame should now be a WebRemoteFrame.
786 EXPECT_TRUE(web_frame->firstChild()->isWebRemoteFrame());
788 // Expect the origin to be updated properly.
789 blink::WebSecurityOrigin origin = web_frame->firstChild()->securityOrigin();
790 EXPECT_EQ(origin.toString(),
791 WebString::fromUTF8(replication_state.origin.Serialize()));
793 // Now, swap out the second frame using a unique origin and verify that it is
794 // replicated correctly.
795 replication_state.origin = url::Origin();
796 TestRenderFrame* child_frame2 = static_cast<TestRenderFrame*>(
797 RenderFrame::FromWebFrame(web_frame->lastChild()));
798 child_frame2->SwapOut(kProxyRoutingId + 1, true, replication_state);
799 EXPECT_TRUE(web_frame->lastChild()->isWebRemoteFrame());
800 EXPECT_TRUE(web_frame->lastChild()->securityOrigin().isUnique());
803 // Test that we get the correct UpdateState message when we go back twice
804 // quickly without committing. Regression test for http://crbug.com/58082.
805 // Disabled: http://crbug.com/157357 .
806 TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) {
807 // Load page A.
808 LoadHTML("<div>Page A</div>");
810 // Load page B, which will trigger an UpdateState message for page A.
811 LoadHTML("<div>Page B</div>");
813 // Check for a valid UpdateState message for page A.
814 ProcessPendingMessages();
815 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
816 ViewHostMsg_UpdateState::ID);
817 ASSERT_TRUE(msg_A);
818 ViewHostMsg_UpdateState::Param param;
819 ViewHostMsg_UpdateState::Read(msg_A, &param);
820 int page_id_A = base::get<0>(param);
821 PageState state_A = base::get<1>(param);
822 EXPECT_EQ(1, page_id_A);
823 render_thread_->sink().ClearMessages();
825 // Load page C, which will trigger an UpdateState message for page B.
826 LoadHTML("<div>Page C</div>");
828 // Check for a valid UpdateState for page B.
829 ProcessPendingMessages();
830 const IPC::Message* msg_B = render_thread_->sink().GetUniqueMessageMatching(
831 ViewHostMsg_UpdateState::ID);
832 ASSERT_TRUE(msg_B);
833 ViewHostMsg_UpdateState::Read(msg_B, &param);
834 int page_id_B = base::get<0>(param);
835 PageState state_B = base::get<1>(param);
836 EXPECT_EQ(2, page_id_B);
837 EXPECT_NE(state_A, state_B);
838 render_thread_->sink().ClearMessages();
840 // Load page D, which will trigger an UpdateState message for page C.
841 LoadHTML("<div>Page D</div>");
843 // Check for a valid UpdateState for page C.
844 ProcessPendingMessages();
845 const IPC::Message* msg_C = render_thread_->sink().GetUniqueMessageMatching(
846 ViewHostMsg_UpdateState::ID);
847 ASSERT_TRUE(msg_C);
848 ViewHostMsg_UpdateState::Read(msg_C, &param);
849 int page_id_C = base::get<0>(param);
850 PageState state_C = base::get<1>(param);
851 EXPECT_EQ(3, page_id_C);
852 EXPECT_NE(state_B, state_C);
853 render_thread_->sink().ClearMessages();
855 // Go back to C and commit, preparing for our real test.
856 CommonNavigationParams common_params_C;
857 RequestNavigationParams request_params_C;
858 common_params_C.navigation_type = FrameMsg_Navigate_Type::NORMAL;
859 common_params_C.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
860 request_params_C.current_history_list_length = 4;
861 request_params_C.current_history_list_offset = 3;
862 request_params_C.pending_history_list_offset = 2;
863 request_params_C.page_id = 3;
864 request_params_C.page_state = state_C;
865 frame()->Navigate(common_params_C, StartNavigationParams(), request_params_C);
866 ProcessPendingMessages();
867 render_thread_->sink().ClearMessages();
869 // Go back twice quickly, such that page B does not have a chance to commit.
870 // This leads to two changes to the back/forward list but only one change to
871 // the RenderView's page ID.
873 // Back to page B (page_id 2), without committing.
874 CommonNavigationParams common_params_B;
875 RequestNavigationParams request_params_B;
876 common_params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
877 common_params_B.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
878 request_params_B.current_history_list_length = 4;
879 request_params_B.current_history_list_offset = 2;
880 request_params_B.pending_history_list_offset = 1;
881 request_params_B.page_id = 2;
882 request_params_B.page_state = state_B;
883 frame()->Navigate(common_params_B, StartNavigationParams(), request_params_B);
885 // Back to page A (page_id 1) and commit.
886 CommonNavigationParams common_params;
887 RequestNavigationParams request_params;
888 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
889 common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
890 request_params.current_history_list_length = 4;
891 request_params.current_history_list_offset = 2;
892 request_params.pending_history_list_offset = 0;
893 request_params.page_id = 1;
894 request_params.page_state = state_A;
895 frame()->Navigate(common_params, StartNavigationParams(), request_params);
896 ProcessPendingMessages();
898 // Now ensure that the UpdateState message we receive is consistent
899 // and represents page C in both page_id and state.
900 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
901 ViewHostMsg_UpdateState::ID);
902 ASSERT_TRUE(msg);
903 ViewHostMsg_UpdateState::Read(msg, &param);
904 int page_id = base::get<0>(param);
905 PageState state = base::get<1>(param);
906 EXPECT_EQ(page_id_C, page_id);
907 EXPECT_NE(state_A, state);
908 EXPECT_NE(state_B, state);
909 EXPECT_EQ(state_C, state);
912 // Test that our IME backend sends a notification message when the input focus
913 // changes.
914 TEST_F(RenderViewImplTest, OnImeTypeChanged) {
915 // Load an HTML page consisting of two input fields.
916 view()->set_send_content_state_immediately(true);
917 LoadHTML("<html>"
918 "<head>"
919 "</head>"
920 "<body>"
921 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
922 "<input id=\"test2\" type=\"password\"></input>"
923 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
924 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
925 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
926 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
927 "</input>"
928 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
929 "</input>"
930 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
931 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
932 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
933 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
934 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
935 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
936 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
937 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
938 "</body>"
939 "</html>");
940 render_thread_->sink().ClearMessages();
942 struct InputModeTestCase {
943 const char* input_id;
944 ui::TextInputMode expected_mode;
946 static const InputModeTestCase kInputModeTestCases[] = {
947 {"test1", ui::TEXT_INPUT_MODE_DEFAULT},
948 {"test3", ui::TEXT_INPUT_MODE_VERBATIM},
949 {"test4", ui::TEXT_INPUT_MODE_LATIN},
950 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME},
951 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE},
952 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN},
953 {"test8", ui::TEXT_INPUT_MODE_KANA},
954 {"test9", ui::TEXT_INPUT_MODE_KATAKANA},
955 {"test10", ui::TEXT_INPUT_MODE_NUMERIC},
956 {"test11", ui::TEXT_INPUT_MODE_TEL},
957 {"test12", ui::TEXT_INPUT_MODE_EMAIL},
958 {"test13", ui::TEXT_INPUT_MODE_URL},
959 {"test14", ui::TEXT_INPUT_MODE_DEFAULT},
960 {"test15", ui::TEXT_INPUT_MODE_VERBATIM},
963 const int kRepeatCount = 10;
964 for (int i = 0; i < kRepeatCount; i++) {
965 // Move the input focus to the first <input> element, where we should
966 // activate IMEs.
967 ExecuteJavaScriptForTests("document.getElementById('test1').focus();");
968 ProcessPendingMessages();
969 render_thread_->sink().ClearMessages();
971 // Update the IME status and verify if our IME backend sends an IPC message
972 // to activate IMEs.
973 view()->UpdateTextInputType();
974 const IPC::Message* msg = render_thread_->sink().GetMessageAt(0);
975 EXPECT_TRUE(msg != NULL);
976 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
977 ViewHostMsg_TextInputTypeChanged::Param params;
978 ViewHostMsg_TextInputTypeChanged::Read(msg, &params);
979 ui::TextInputType type = base::get<0>(params);
980 ui::TextInputMode input_mode = base::get<1>(params);
981 bool can_compose_inline = base::get<2>(params);
982 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, type);
983 EXPECT_EQ(true, can_compose_inline);
985 // Move the input focus to the second <input> element, where we should
986 // de-activate IMEs.
987 ExecuteJavaScriptForTests("document.getElementById('test2').focus();");
988 ProcessPendingMessages();
989 render_thread_->sink().ClearMessages();
991 // Update the IME status and verify if our IME backend sends an IPC message
992 // to de-activate IMEs.
993 view()->UpdateTextInputType();
994 msg = render_thread_->sink().GetMessageAt(0);
995 EXPECT_TRUE(msg != NULL);
996 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
997 ViewHostMsg_TextInputTypeChanged::Read(msg, & params);
998 type = base::get<0>(params);
999 input_mode = base::get<1>(params);
1000 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, type);
1002 for (size_t i = 0; i < arraysize(kInputModeTestCases); i++) {
1003 const InputModeTestCase* test_case = &kInputModeTestCases[i];
1004 std::string javascript =
1005 base::StringPrintf("document.getElementById('%s').focus();",
1006 test_case->input_id);
1007 // Move the input focus to the target <input> element, where we should
1008 // activate IMEs.
1009 ExecuteJavaScriptAndReturnIntValue(base::ASCIIToUTF16(javascript), NULL);
1010 ProcessPendingMessages();
1011 render_thread_->sink().ClearMessages();
1013 // Update the IME status and verify if our IME backend sends an IPC
1014 // message to activate IMEs.
1015 view()->UpdateTextInputType();
1016 const IPC::Message* msg = render_thread_->sink().GetMessageAt(0);
1017 EXPECT_TRUE(msg != NULL);
1018 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
1019 ViewHostMsg_TextInputTypeChanged::Read(msg, & params);
1020 type = base::get<0>(params);
1021 input_mode = base::get<1>(params);
1022 EXPECT_EQ(test_case->expected_mode, input_mode);
1027 // Test that our IME backend can compose CJK words.
1028 // Our IME front-end sends many platform-independent messages to the IME backend
1029 // while it composes CJK words. This test sends the minimal messages captured
1030 // on my local environment directly to the IME backend to verify if the backend
1031 // can compose CJK words without any problems.
1032 // This test uses an array of command sets because an IME composotion does not
1033 // only depends on IME events, but also depends on window events, e.g. moving
1034 // the window focus while composing a CJK text. To handle such complicated
1035 // cases, this test should not only call IME-related functions in the
1036 // RenderWidget class, but also call some RenderWidget members, e.g.
1037 // ExecuteJavaScriptForTests(), RenderWidget::OnSetFocus(), etc.
1038 TEST_F(RenderViewImplTest, ImeComposition) {
1039 enum ImeCommand {
1040 IME_INITIALIZE,
1041 IME_SETINPUTMODE,
1042 IME_SETFOCUS,
1043 IME_SETCOMPOSITION,
1044 IME_CONFIRMCOMPOSITION,
1045 IME_CANCELCOMPOSITION
1047 struct ImeMessage {
1048 ImeCommand command;
1049 bool enable;
1050 int selection_start;
1051 int selection_end;
1052 const wchar_t* ime_string;
1053 const wchar_t* result;
1055 static const ImeMessage kImeMessages[] = {
1056 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
1057 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1058 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1059 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1060 {IME_SETCOMPOSITION, false, 1, 1, L"n", L"n"},
1061 {IME_SETCOMPOSITION, false, 2, 2, L"ni", L"ni"},
1062 {IME_SETCOMPOSITION, false, 3, 3, L"nih", L"nih"},
1063 {IME_SETCOMPOSITION, false, 4, 4, L"niha", L"niha"},
1064 {IME_SETCOMPOSITION, false, 5, 5, L"nihao", L"nihao"},
1065 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"\x4F60\x597D", L"\x4F60\x597D"},
1066 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
1067 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1068 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1069 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1070 {IME_SETCOMPOSITION, false, 0, 1, L"\xFF4B", L"\xFF4B"},
1071 {IME_SETCOMPOSITION, false, 0, 1, L"\x304B", L"\x304B"},
1072 {IME_SETCOMPOSITION, false, 0, 2, L"\x304B\xFF4E", L"\x304B\xFF4E"},
1073 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\xFF4A",
1074 L"\x304B\x3093\xFF4A"},
1075 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\x3058",
1076 L"\x304B\x3093\x3058"},
1077 {IME_SETCOMPOSITION, false, 0, 2, L"\x611F\x3058", L"\x611F\x3058"},
1078 {IME_SETCOMPOSITION, false, 0, 2, L"\x6F22\x5B57", L"\x6F22\x5B57"},
1079 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1080 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1081 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1082 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1083 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1084 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1085 {IME_SETCOMPOSITION, false, 0, 1, L"\x3147", L"\x3147"},
1086 {IME_SETCOMPOSITION, false, 0, 1, L"\xC544", L"\xC544"},
1087 {IME_SETCOMPOSITION, false, 0, 1, L"\xC548", L"\xC548"},
1088 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1089 {IME_SETCOMPOSITION, false, 0, 1, L"\x3134", L"\xC548\x3134"},
1090 {IME_SETCOMPOSITION, false, 0, 1, L"\xB140", L"\xC548\xB140"},
1091 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1092 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1093 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1094 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548\xB155"},
1097 for (size_t i = 0; i < arraysize(kImeMessages); i++) {
1098 const ImeMessage* ime_message = &kImeMessages[i];
1099 switch (ime_message->command) {
1100 case IME_INITIALIZE:
1101 // Load an HTML page consisting of a content-editable <div> element,
1102 // and move the input focus to the <div> element, where we can use
1103 // IMEs.
1104 view()->set_send_content_state_immediately(true);
1105 LoadHTML("<html>"
1106 "<head>"
1107 "</head>"
1108 "<body>"
1109 "<div id=\"test1\" contenteditable=\"true\"></div>"
1110 "</body>"
1111 "</html>");
1112 ExecuteJavaScriptForTests("document.getElementById('test1').focus();");
1113 break;
1115 case IME_SETINPUTMODE:
1116 break;
1118 case IME_SETFOCUS:
1119 // Update the window focus.
1120 view()->OnSetFocus(ime_message->enable);
1121 break;
1123 case IME_SETCOMPOSITION:
1124 view()->OnImeSetComposition(
1125 base::WideToUTF16(ime_message->ime_string),
1126 std::vector<blink::WebCompositionUnderline>(),
1127 ime_message->selection_start,
1128 ime_message->selection_end);
1129 break;
1131 case IME_CONFIRMCOMPOSITION:
1132 view()->OnImeConfirmComposition(
1133 base::WideToUTF16(ime_message->ime_string),
1134 gfx::Range::InvalidRange(),
1135 false);
1136 break;
1138 case IME_CANCELCOMPOSITION:
1139 view()->OnImeSetComposition(
1140 base::string16(),
1141 std::vector<blink::WebCompositionUnderline>(),
1142 0, 0);
1143 break;
1146 // Update the status of our IME back-end.
1147 // TODO(hbono): we should verify messages to be sent from the back-end.
1148 view()->UpdateTextInputType();
1149 ProcessPendingMessages();
1150 render_thread_->sink().ClearMessages();
1152 if (ime_message->result) {
1153 // Retrieve the content of this page and compare it with the expected
1154 // result.
1155 const int kMaxOutputCharacters = 128;
1156 base::string16 output =
1157 GetMainFrame()->contentAsText(kMaxOutputCharacters);
1158 EXPECT_EQ(base::WideToUTF16(ime_message->result), output);
1163 // Test that the RenderView::OnSetTextDirection() function can change the text
1164 // direction of the selected input element.
1165 TEST_F(RenderViewImplTest, OnSetTextDirection) {
1166 // Load an HTML page consisting of a <textarea> element and a <div> element.
1167 // This test changes the text direction of the <textarea> element, and
1168 // writes the values of its 'dir' attribute and its 'direction' property to
1169 // verify that the text direction is changed.
1170 view()->set_send_content_state_immediately(true);
1171 LoadHTML("<html>"
1172 "<head>"
1173 "</head>"
1174 "<body>"
1175 "<textarea id=\"test\"></textarea>"
1176 "<div id=\"result\" contenteditable=\"true\"></div>"
1177 "</body>"
1178 "</html>");
1179 render_thread_->sink().ClearMessages();
1181 static const struct {
1182 WebTextDirection direction;
1183 const wchar_t* expected_result;
1184 } kTextDirection[] = {
1185 { blink::WebTextDirectionRightToLeft, L"\x000A" L"rtl,rtl" },
1186 { blink::WebTextDirectionLeftToRight, L"\x000A" L"ltr,ltr" },
1188 for (size_t i = 0; i < arraysize(kTextDirection); ++i) {
1189 // Set the text direction of the <textarea> element.
1190 ExecuteJavaScriptForTests("document.getElementById('test').focus();");
1191 view()->OnSetTextDirection(kTextDirection[i].direction);
1193 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1194 // property to the <div> element.
1195 ExecuteJavaScriptForTests(
1196 "var result = document.getElementById('result');"
1197 "var node = document.getElementById('test');"
1198 "var style = getComputedStyle(node, null);"
1199 "result.innerText ="
1200 " node.getAttribute('dir') + ',' +"
1201 " style.getPropertyValue('direction');");
1203 // Copy the document content to std::wstring and compare with the
1204 // expected result.
1205 const int kMaxOutputCharacters = 16;
1206 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
1207 EXPECT_EQ(base::WideToUTF16(kTextDirection[i].expected_result), output);
1211 // Test that we can receive correct DOM events when we send input events
1212 // through the RenderWidget::OnHandleInputEvent() function.
1213 TEST_F(RenderViewImplTest, OnHandleKeyboardEvent) {
1214 #if !defined(OS_MACOSX)
1215 // Load an HTML page consisting of one <input> element and three
1216 // contentediable <div> elements.
1217 // The <input> element is used for sending keyboard events, and the <div>
1218 // elements are used for writing DOM events in the following format:
1219 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1220 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1221 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1222 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1223 view()->set_send_content_state_immediately(true);
1224 LoadHTML("<html>"
1225 "<head>"
1226 "<title></title>"
1227 "<script type='text/javascript' language='javascript'>"
1228 "function OnKeyEvent(ev) {"
1229 " var result = document.getElementById(ev.type);"
1230 " result.innerText ="
1231 " (ev.which || ev.keyCode) + ',' +"
1232 " ev.shiftKey + ',' +"
1233 " ev.ctrlKey + ',' +"
1234 " ev.altKey;"
1235 " return true;"
1237 "</script>"
1238 "</head>"
1239 "<body>"
1240 "<input id='test' type='text'"
1241 " onkeydown='return OnKeyEvent(event);'"
1242 " onkeypress='return OnKeyEvent(event);'"
1243 " onkeyup='return OnKeyEvent(event);'>"
1244 "</input>"
1245 "<div id='keydown' contenteditable='true'>"
1246 "</div>"
1247 "<div id='keypress' contenteditable='true'>"
1248 "</div>"
1249 "<div id='keyup' contenteditable='true'>"
1250 "</div>"
1251 "</body>"
1252 "</html>");
1253 ExecuteJavaScriptForTests("document.getElementById('test').focus();");
1254 render_thread_->sink().ClearMessages();
1256 static const MockKeyboard::Layout kLayouts[] = {
1257 #if defined(OS_WIN)
1258 // Since we ignore the mock keyboard layout on Linux and instead just use
1259 // the screen's keyboard layout, these trivially pass. They are commented
1260 // out to avoid the illusion that they work.
1261 MockKeyboard::LAYOUT_ARABIC,
1262 MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1263 MockKeyboard::LAYOUT_FRENCH,
1264 MockKeyboard::LAYOUT_HEBREW,
1265 MockKeyboard::LAYOUT_RUSSIAN,
1266 #endif
1267 MockKeyboard::LAYOUT_UNITED_STATES,
1270 for (size_t i = 0; i < arraysize(kLayouts); ++i) {
1271 // For each key code, we send three keyboard events.
1272 // * we press only the key;
1273 // * we press the key and a left-shift key, and;
1274 // * we press the key and a right-alt (AltGr) key.
1275 // For each modifiers, we need a string used for formatting its expected
1276 // result. (See the above comment for its format.)
1277 static const struct {
1278 MockKeyboard::Modifiers modifiers;
1279 const char* expected_result;
1280 } kModifierData[] = {
1281 {MockKeyboard::NONE, "false,false,false"},
1282 {MockKeyboard::LEFT_SHIFT, "true,false,false"},
1283 #if defined(OS_WIN)
1284 {MockKeyboard::RIGHT_ALT, "false,false,true"},
1285 #endif
1288 MockKeyboard::Layout layout = kLayouts[i];
1289 for (size_t j = 0; j < arraysize(kModifierData); ++j) {
1290 // Virtual key codes used for this test.
1291 static const int kKeyCodes[] = {
1292 '0', '1', '2', '3', '4', '5', '6', '7',
1293 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1294 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1295 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1296 'W', 'X', 'Y', 'Z',
1297 ui::VKEY_OEM_1,
1298 ui::VKEY_OEM_PLUS,
1299 ui::VKEY_OEM_COMMA,
1300 ui::VKEY_OEM_MINUS,
1301 ui::VKEY_OEM_PERIOD,
1302 ui::VKEY_OEM_2,
1303 ui::VKEY_OEM_3,
1304 ui::VKEY_OEM_4,
1305 ui::VKEY_OEM_5,
1306 ui::VKEY_OEM_6,
1307 ui::VKEY_OEM_7,
1308 #if defined(OS_WIN)
1309 // Not sure how to handle this key on Linux.
1310 ui::VKEY_OEM_8,
1311 #endif
1314 MockKeyboard::Modifiers modifiers = kModifierData[j].modifiers;
1315 for (size_t k = 0; k < arraysize(kKeyCodes); ++k) {
1316 // Send a keyboard event to the RenderView object.
1317 // We should test a keyboard event only when the given keyboard-layout
1318 // driver is installed in a PC and the driver can assign a Unicode
1319 // charcter for the given tuple (key-code and modifiers).
1320 int key_code = kKeyCodes[k];
1321 base::string16 char_code;
1322 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1323 continue;
1325 // Create an expected result from the virtual-key code, the character
1326 // code, and the modifier-key status.
1327 // We format a string that emulates a DOM-event string produced hy
1328 // our JavaScript function. (See the above comment for the format.)
1329 static char expected_result[1024];
1330 expected_result[0] = 0;
1331 base::snprintf(&expected_result[0],
1332 sizeof(expected_result),
1333 "\n" // texts in the <input> element
1334 "%d,%s\n" // texts in the first <div> element
1335 "%d,%s\n" // texts in the second <div> element
1336 "%d,%s", // texts in the third <div> element
1337 key_code, kModifierData[j].expected_result,
1338 static_cast<int>(char_code[0]),
1339 kModifierData[j].expected_result,
1340 key_code, kModifierData[j].expected_result);
1342 // Retrieve the text in the test page and compare it with the expected
1343 // text created from a virtual-key code, a character code, and the
1344 // modifier-key status.
1345 const int kMaxOutputCharacters = 1024;
1346 std::string output = base::UTF16ToUTF8(base::StringPiece16(
1347 GetMainFrame()->contentAsText(kMaxOutputCharacters)));
1348 EXPECT_EQ(expected_result, output);
1352 #else
1353 NOTIMPLEMENTED();
1354 #endif
1357 // Test that our EditorClientImpl class can insert characters when we send
1358 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1359 // This test is for preventing regressions caused only when we use non-US
1360 // keyboards, such as Issue 10846.
1361 // see http://crbug.com/244562
1362 #if defined(OS_WIN)
1363 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1364 #else
1365 #define MAYBE_InsertCharacters InsertCharacters
1366 #endif
1367 TEST_F(RenderViewImplTest, MAYBE_InsertCharacters) {
1368 #if !defined(OS_MACOSX)
1369 static const struct {
1370 MockKeyboard::Layout layout;
1371 const wchar_t* expected_result;
1372 } kLayouts[] = {
1373 #if 0
1374 // Disabled these keyboard layouts because buildbots do not have their
1375 // keyboard-layout drivers installed.
1376 {MockKeyboard::LAYOUT_ARABIC,
1377 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1378 L"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1379 L"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1380 L"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1381 L"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1382 L"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1383 L"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1384 L"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1385 L"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1386 L"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1387 L"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1388 L"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1389 L"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1390 L"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1391 L"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1392 L"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1393 L"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1395 {MockKeyboard::LAYOUT_HEBREW,
1396 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1397 L"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1398 L"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1399 L"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1400 L"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1401 L"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1402 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1403 L"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1404 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1405 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1406 L"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1407 L"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1408 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1409 L"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1410 L"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1411 L"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1412 L"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1413 L"\x003b\x005d\x005c\x005b\x002c"
1415 #endif
1416 #if defined(OS_WIN)
1417 // On Linux, the only way to test alternate keyboard layouts is to change
1418 // the keyboard layout of the whole screen. I'm worried about the side
1419 // effects this may have on the buildbots.
1420 {MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1421 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1422 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1423 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1424 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1425 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1426 L"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1427 L"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1428 L"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1429 L"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1430 L"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1431 L"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1432 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1433 L"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1434 L"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1435 L"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1436 L"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1437 L"\x003c"
1439 {MockKeyboard::LAYOUT_FRENCH,
1440 L"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1441 L"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1442 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1443 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1444 L"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1445 L"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1446 L"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1447 L"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1448 L"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1449 L"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1450 L"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1451 L"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1452 L"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1453 L"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1454 L"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1455 L"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1456 L"\x003b\x003a\x00f9\x0029\x002a\x0021"
1458 {MockKeyboard::LAYOUT_RUSSIAN,
1459 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1460 L"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1461 L"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1462 L"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1463 L"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1464 L"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1465 L"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1466 L"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1467 L"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1468 L"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1469 L"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1470 L"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1471 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1472 L"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1473 L"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1474 L"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1475 L"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1476 L"\x0451\x0445\x005c\x044a\x044d"
1478 #endif // defined(OS_WIN)
1479 {MockKeyboard::LAYOUT_UNITED_STATES,
1480 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1481 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1482 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1483 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1484 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1485 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1486 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1487 L"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1488 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1489 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1490 L"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1491 L"\x003f\x007e\x007b\x007c\x007d\x0022"
1492 #if defined(OS_WIN)
1493 // This is ifdefed out for Linux to correspond to the fact that we don't
1494 // test alt+keystroke for now.
1495 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1496 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1497 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1498 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1499 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1500 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1501 #endif
1505 for (size_t i = 0; i < arraysize(kLayouts); ++i) {
1506 // Load an HTML page consisting of one <div> element.
1507 // This <div> element is used by the EditorClientImpl class to insert
1508 // characters received through the RenderWidget::OnHandleInputEvent()
1509 // function.
1510 view()->set_send_content_state_immediately(true);
1511 LoadHTML("<html>"
1512 "<head>"
1513 "<title></title>"
1514 "</head>"
1515 "<body>"
1516 "<div id='test' contenteditable='true'>"
1517 "</div>"
1518 "</body>"
1519 "</html>");
1520 ExecuteJavaScriptForTests("document.getElementById('test').focus();");
1521 render_thread_->sink().ClearMessages();
1523 // For each key code, we send three keyboard events.
1524 // * Pressing only the key;
1525 // * Pressing the key and a left-shift key, and;
1526 // * Pressing the key and a right-alt (AltGr) key.
1527 static const MockKeyboard::Modifiers kModifiers[] = {
1528 MockKeyboard::NONE,
1529 MockKeyboard::LEFT_SHIFT,
1530 #if defined(OS_WIN)
1531 MockKeyboard::RIGHT_ALT,
1532 #endif
1535 MockKeyboard::Layout layout = kLayouts[i].layout;
1536 for (size_t j = 0; j < arraysize(kModifiers); ++j) {
1537 // Virtual key codes used for this test.
1538 static const int kKeyCodes[] = {
1539 '0', '1', '2', '3', '4', '5', '6', '7',
1540 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1541 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1542 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1543 'W', 'X', 'Y', 'Z',
1544 ui::VKEY_OEM_1,
1545 ui::VKEY_OEM_PLUS,
1546 ui::VKEY_OEM_COMMA,
1547 ui::VKEY_OEM_MINUS,
1548 ui::VKEY_OEM_PERIOD,
1549 ui::VKEY_OEM_2,
1550 ui::VKEY_OEM_3,
1551 ui::VKEY_OEM_4,
1552 ui::VKEY_OEM_5,
1553 ui::VKEY_OEM_6,
1554 ui::VKEY_OEM_7,
1555 #if defined(OS_WIN)
1556 // Unclear how to handle this on Linux.
1557 ui::VKEY_OEM_8,
1558 #endif
1561 MockKeyboard::Modifiers modifiers = kModifiers[j];
1562 for (size_t k = 0; k < arraysize(kKeyCodes); ++k) {
1563 // Send a keyboard event to the RenderView object.
1564 // We should test a keyboard event only when the given keyboard-layout
1565 // driver is installed in a PC and the driver can assign a Unicode
1566 // charcter for the given tuple (layout, key-code, and modifiers).
1567 int key_code = kKeyCodes[k];
1568 base::string16 char_code;
1569 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1570 continue;
1574 // Retrieve the text in the test page and compare it with the expected
1575 // text created from a virtual-key code, a character code, and the
1576 // modifier-key status.
1577 const int kMaxOutputCharacters = 4096;
1578 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
1579 EXPECT_EQ(base::WideToUTF16(kLayouts[i].expected_result), output);
1581 #else
1582 NOTIMPLEMENTED();
1583 #endif
1586 // Crashy, http://crbug.com/53247.
1587 TEST_F(RenderViewImplTest, DISABLED_DidFailProvisionalLoadWithErrorForError) {
1588 GetMainFrame()->enableViewSourceMode(true);
1589 WebURLError error;
1590 error.domain = WebString::fromUTF8(net::kErrorDomain);
1591 error.reason = net::ERR_FILE_NOT_FOUND;
1592 error.unreachableURL = GURL("http://foo");
1593 WebLocalFrame* web_frame = GetMainFrame();
1595 // Start a load that will reach provisional state synchronously,
1596 // but won't complete synchronously.
1597 CommonNavigationParams common_params;
1598 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1599 common_params.url = GURL("data:text/html,test data");
1600 frame()->Navigate(common_params, StartNavigationParams(),
1601 RequestNavigationParams());
1603 // An error occurred.
1604 view()->GetMainRenderFrame()->didFailProvisionalLoad(
1605 web_frame, error, blink::WebStandardCommit);
1606 // Frame should exit view-source mode.
1607 EXPECT_FALSE(web_frame->isViewSourceModeEnabled());
1610 TEST_F(RenderViewImplTest, DidFailProvisionalLoadWithErrorForCancellation) {
1611 GetMainFrame()->enableViewSourceMode(true);
1612 WebURLError error;
1613 error.domain = WebString::fromUTF8(net::kErrorDomain);
1614 error.reason = net::ERR_ABORTED;
1615 error.unreachableURL = GURL("http://foo");
1616 WebLocalFrame* web_frame = GetMainFrame();
1618 // Start a load that will reach provisional state synchronously,
1619 // but won't complete synchronously.
1620 CommonNavigationParams common_params;
1621 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1622 common_params.url = GURL("data:text/html,test data");
1623 frame()->Navigate(common_params, StartNavigationParams(),
1624 RequestNavigationParams());
1626 // A cancellation occurred.
1627 view()->GetMainRenderFrame()->didFailProvisionalLoad(
1628 web_frame, error, blink::WebStandardCommit);
1629 // Frame should stay in view-source mode.
1630 EXPECT_TRUE(web_frame->isViewSourceModeEnabled());
1633 // Regression test for http://crbug.com/41562
1634 TEST_F(RenderViewImplTest, UpdateTargetURLWithInvalidURL) {
1635 const GURL invalid_gurl("http://");
1636 view()->setMouseOverURL(blink::WebURL(invalid_gurl));
1637 EXPECT_EQ(invalid_gurl, view()->target_url_);
1640 TEST_F(RenderViewImplTest, SetHistoryLengthAndOffset) {
1641 // No history to merge; one committed page.
1642 view()->OnSetHistoryOffsetAndLength(0, 1);
1643 EXPECT_EQ(1, view()->history_list_length_);
1644 EXPECT_EQ(0, view()->history_list_offset_);
1646 // History of length 1 to merge; one committed page.
1647 view()->OnSetHistoryOffsetAndLength(1, 2);
1648 EXPECT_EQ(2, view()->history_list_length_);
1649 EXPECT_EQ(1, view()->history_list_offset_);
1652 TEST_F(RenderViewImplTest, ContextMenu) {
1653 LoadHTML("<div>Page A</div>");
1655 // Create a right click in the center of the iframe. (I'm hoping this will
1656 // make this a bit more robust in case of some other formatting or other bug.)
1657 WebMouseEvent mouse_event;
1658 mouse_event.type = WebInputEvent::MouseDown;
1659 mouse_event.button = WebMouseEvent::ButtonRight;
1660 mouse_event.x = 250;
1661 mouse_event.y = 250;
1662 mouse_event.globalX = 250;
1663 mouse_event.globalY = 250;
1665 SendWebMouseEvent(mouse_event);
1667 // Now simulate the corresponding up event which should display the menu
1668 mouse_event.type = WebInputEvent::MouseUp;
1669 SendWebMouseEvent(mouse_event);
1671 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
1672 FrameHostMsg_ContextMenu::ID));
1675 TEST_F(RenderViewImplTest, TestBackForward) {
1676 LoadHTML("<div id=pagename>Page A</div>");
1677 PageState page_a_state =
1678 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1679 int was_page_a = -1;
1680 base::string16 check_page_a =
1681 base::ASCIIToUTF16(
1682 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1683 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1684 EXPECT_EQ(1, was_page_a);
1686 LoadHTML("<div id=pagename>Page B</div>");
1687 int was_page_b = -1;
1688 base::string16 check_page_b =
1689 base::ASCIIToUTF16(
1690 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1691 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1692 EXPECT_EQ(1, was_page_b);
1694 PageState back_state =
1695 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1697 LoadHTML("<div id=pagename>Page C</div>");
1698 int was_page_c = -1;
1699 base::string16 check_page_c =
1700 base::ASCIIToUTF16(
1701 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1702 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1703 EXPECT_EQ(1, was_page_c);
1705 PageState forward_state =
1706 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1707 GoBack(back_state);
1708 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1709 EXPECT_EQ(1, was_page_b);
1711 PageState back_state2 =
1712 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1714 GoForward(forward_state);
1715 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1716 EXPECT_EQ(1, was_page_c);
1718 GoBack(back_state2);
1719 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1720 EXPECT_EQ(1, was_page_b);
1722 forward_state =
1723 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1724 GoBack(page_a_state);
1725 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1726 EXPECT_EQ(1, was_page_a);
1728 GoForward(forward_state);
1729 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1730 EXPECT_EQ(1, was_page_b);
1733 #if defined(OS_MACOSX) || defined(USE_AURA)
1734 TEST_F(RenderViewImplTest, GetCompositionCharacterBoundsTest) {
1736 #if defined(OS_WIN)
1737 // http://crbug.com/304193
1738 if (base::win::GetVersion() < base::win::VERSION_VISTA)
1739 return;
1740 // http://crbug.com/508747
1741 if (base::win::GetVersion() >= base::win::VERSION_WIN10)
1742 return;
1743 #endif
1745 LoadHTML("<textarea id=\"test\"></textarea>");
1746 ExecuteJavaScriptForTests("document.getElementById('test').focus();");
1748 const base::string16 empty_string;
1749 const std::vector<blink::WebCompositionUnderline> empty_underline;
1750 std::vector<gfx::Rect> bounds;
1751 view()->OnSetFocus(true);
1753 // ASCII composition
1754 const base::string16 ascii_composition = base::UTF8ToUTF16("aiueo");
1755 view()->OnImeSetComposition(ascii_composition, empty_underline, 0, 0);
1756 view()->GetCompositionCharacterBounds(&bounds);
1757 ASSERT_EQ(ascii_composition.size(), bounds.size());
1758 for (size_t i = 0; i < bounds.size(); ++i)
1759 EXPECT_LT(0, bounds[i].width());
1760 view()->OnImeConfirmComposition(
1761 empty_string, gfx::Range::InvalidRange(), false);
1763 // Non surrogate pair unicode character.
1764 const base::string16 unicode_composition = base::UTF8ToUTF16(
1765 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1766 view()->OnImeSetComposition(unicode_composition, empty_underline, 0, 0);
1767 view()->GetCompositionCharacterBounds(&bounds);
1768 ASSERT_EQ(unicode_composition.size(), bounds.size());
1769 for (size_t i = 0; i < bounds.size(); ++i)
1770 EXPECT_LT(0, bounds[i].width());
1771 view()->OnImeConfirmComposition(
1772 empty_string, gfx::Range::InvalidRange(), false);
1774 // Surrogate pair character.
1775 const base::string16 surrogate_pair_char =
1776 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1777 view()->OnImeSetComposition(surrogate_pair_char,
1778 empty_underline,
1781 view()->GetCompositionCharacterBounds(&bounds);
1782 ASSERT_EQ(surrogate_pair_char.size(), bounds.size());
1783 EXPECT_LT(0, bounds[0].width());
1784 EXPECT_EQ(0, bounds[1].width());
1785 view()->OnImeConfirmComposition(
1786 empty_string, gfx::Range::InvalidRange(), false);
1788 // Mixed string.
1789 const base::string16 surrogate_pair_mixed_composition =
1790 surrogate_pair_char + base::UTF8ToUTF16("\xE3\x81\x82") +
1791 surrogate_pair_char + base::UTF8ToUTF16("b") + surrogate_pair_char;
1792 const size_t utf16_length = 8UL;
1793 const bool is_surrogate_pair_empty_rect[8] = {
1794 false, true, false, false, true, false, false, true };
1795 view()->OnImeSetComposition(surrogate_pair_mixed_composition,
1796 empty_underline,
1799 view()->GetCompositionCharacterBounds(&bounds);
1800 ASSERT_EQ(utf16_length, bounds.size());
1801 for (size_t i = 0; i < utf16_length; ++i) {
1802 if (is_surrogate_pair_empty_rect[i]) {
1803 EXPECT_EQ(0, bounds[i].width());
1804 } else {
1805 EXPECT_LT(0, bounds[i].width());
1808 view()->OnImeConfirmComposition(
1809 empty_string, gfx::Range::InvalidRange(), false);
1811 #endif
1813 TEST_F(RenderViewImplTest, ZoomLimit) {
1814 const double kMinZoomLevel = ZoomFactorToZoomLevel(kMinimumZoomFactor);
1815 const double kMaxZoomLevel = ZoomFactorToZoomLevel(kMaximumZoomFactor);
1817 // Verifies navigation to a URL with preset zoom level indeed sets the level.
1818 // Regression test for http://crbug.com/139559, where the level was not
1819 // properly set when it is out of the default zoom limits of WebView.
1820 CommonNavigationParams common_params;
1821 common_params.url = GURL("data:text/html,min_zoomlimit_test");
1822 view()->OnSetZoomLevelForLoadingURL(common_params.url, kMinZoomLevel);
1823 frame()->Navigate(common_params, StartNavigationParams(),
1824 RequestNavigationParams());
1825 ProcessPendingMessages();
1826 EXPECT_DOUBLE_EQ(kMinZoomLevel, view()->GetWebView()->zoomLevel());
1828 // It should work even when the zoom limit is temporarily changed in the page.
1829 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
1830 ZoomFactorToZoomLevel(1.0));
1831 common_params.url = GURL("data:text/html,max_zoomlimit_test");
1832 view()->OnSetZoomLevelForLoadingURL(common_params.url, kMaxZoomLevel);
1833 frame()->Navigate(common_params, StartNavigationParams(),
1834 RequestNavigationParams());
1835 ProcessPendingMessages();
1836 EXPECT_DOUBLE_EQ(kMaxZoomLevel, view()->GetWebView()->zoomLevel());
1839 TEST_F(RenderViewImplTest, SetEditableSelectionAndComposition) {
1840 // Load an HTML page consisting of an input field.
1841 LoadHTML("<html>"
1842 "<head>"
1843 "</head>"
1844 "<body>"
1845 "<input id=\"test1\" value=\"some test text hello\"></input>"
1846 "</body>"
1847 "</html>");
1848 ExecuteJavaScriptForTests("document.getElementById('test1').focus();");
1849 frame()->SetEditableSelectionOffsets(4, 8);
1850 const std::vector<blink::WebCompositionUnderline> empty_underline;
1851 frame()->SetCompositionFromExistingText(7, 10, empty_underline);
1852 blink::WebTextInputInfo info = view()->webview()->textInputInfo();
1853 EXPECT_EQ(4, info.selectionStart);
1854 EXPECT_EQ(8, info.selectionEnd);
1855 EXPECT_EQ(7, info.compositionStart);
1856 EXPECT_EQ(10, info.compositionEnd);
1857 frame()->Unselect();
1858 info = view()->webview()->textInputInfo();
1859 EXPECT_EQ(0, info.selectionStart);
1860 EXPECT_EQ(0, info.selectionEnd);
1864 TEST_F(RenderViewImplTest, OnExtendSelectionAndDelete) {
1865 // Load an HTML page consisting of an input field.
1866 LoadHTML("<html>"
1867 "<head>"
1868 "</head>"
1869 "<body>"
1870 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
1871 "</body>"
1872 "</html>");
1873 ExecuteJavaScriptForTests("document.getElementById('test1').focus();");
1874 frame()->SetEditableSelectionOffsets(10, 10);
1875 frame()->ExtendSelectionAndDelete(3, 4);
1876 blink::WebTextInputInfo info = view()->webview()->textInputInfo();
1877 EXPECT_EQ("abcdefgopqrstuvwxyz", info.value);
1878 EXPECT_EQ(7, info.selectionStart);
1879 EXPECT_EQ(7, info.selectionEnd);
1880 frame()->SetEditableSelectionOffsets(4, 8);
1881 frame()->ExtendSelectionAndDelete(2, 5);
1882 info = view()->webview()->textInputInfo();
1883 EXPECT_EQ("abuvwxyz", info.value);
1884 EXPECT_EQ(2, info.selectionStart);
1885 EXPECT_EQ(2, info.selectionEnd);
1888 // Test that the navigating specific frames works correctly.
1889 TEST_F(RenderViewImplTest, NavigateSubframe) {
1890 // Load page A.
1891 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
1893 // Navigate the frame only.
1894 CommonNavigationParams common_params;
1895 RequestNavigationParams request_params;
1896 common_params.url = GURL("data:text/html,world");
1897 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1898 common_params.transition = ui::PAGE_TRANSITION_TYPED;
1899 request_params.current_history_list_length = 1;
1900 request_params.current_history_list_offset = 0;
1901 request_params.pending_history_list_offset = 1;
1902 request_params.page_id = -1;
1903 request_params.browser_navigation_start =
1904 base::TimeTicks::FromInternalValue(1);
1906 TestRenderFrame* subframe =
1907 static_cast<TestRenderFrame*>(RenderFrameImpl::FromWebFrame(
1908 view()->webview()->findFrameByName("frame")));
1909 subframe->Navigate(common_params, StartNavigationParams(), request_params);
1910 FrameLoadWaiter(subframe).Wait();
1912 // Copy the document content to std::wstring and compare with the
1913 // expected result.
1914 const int kMaxOutputCharacters = 256;
1915 std::string output = base::UTF16ToUTF8(base::StringPiece16(
1916 GetMainFrame()->contentAsText(kMaxOutputCharacters)));
1917 EXPECT_EQ(output, "hello \n\nworld");
1920 // This test ensures that a RenderFrame object is created for the top level
1921 // frame in the RenderView.
1922 TEST_F(RenderViewImplTest, BasicRenderFrame) {
1923 EXPECT_TRUE(view()->main_render_frame_);
1926 TEST_F(RenderViewImplTest, GetSSLStatusOfFrame) {
1927 LoadHTML("<!DOCTYPE html><html><body></body></html>");
1929 WebLocalFrame* frame = GetMainFrame();
1930 SSLStatus ssl_status = view()->GetSSLStatusOfFrame(frame);
1931 EXPECT_FALSE(net::IsCertStatusError(ssl_status.cert_status));
1933 const_cast<blink::WebURLResponse&>(frame->dataSource()->response()).
1934 setSecurityInfo(
1935 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS, 0, 0,
1936 SignedCertificateTimestampIDStatusList()));
1937 ssl_status = view()->GetSSLStatusOfFrame(frame);
1938 EXPECT_TRUE(net::IsCertStatusError(ssl_status.cert_status));
1941 TEST_F(RenderViewImplTest, MessageOrderInDidChangeSelection) {
1942 view()->set_send_content_state_immediately(true);
1943 LoadHTML("<textarea id=\"test\"></textarea>");
1945 view()->handling_input_event_ = true;
1946 ExecuteJavaScriptForTests("document.getElementById('test').focus();");
1948 bool is_input_type_called = false;
1949 bool is_selection_called = false;
1950 size_t last_input_type = 0;
1951 size_t last_selection = 0;
1953 for (size_t i = 0; i < render_thread_->sink().message_count(); ++i) {
1954 const uint32 type = render_thread_->sink().GetMessageAt(i)->type();
1955 if (type == ViewHostMsg_TextInputTypeChanged::ID) {
1956 is_input_type_called = true;
1957 last_input_type = i;
1958 } else if (type == ViewHostMsg_SelectionChanged::ID) {
1959 is_selection_called = true;
1960 last_selection = i;
1964 EXPECT_TRUE(is_input_type_called);
1965 EXPECT_TRUE(is_selection_called);
1967 // InputTypeChange shold be called earlier than SelectionChanged.
1968 EXPECT_LT(last_input_type, last_selection);
1971 class RendererErrorPageTest : public RenderViewImplTest {
1972 public:
1973 ContentRendererClient* CreateContentRendererClient() override {
1974 return new TestContentRendererClient;
1977 RenderViewImpl* view() {
1978 return static_cast<RenderViewImpl*>(view_);
1981 RenderFrameImpl* frame() {
1982 return static_cast<RenderFrameImpl*>(view()->GetMainRenderFrame());
1985 private:
1986 class TestContentRendererClient : public ContentRendererClient {
1987 public:
1988 bool ShouldSuppressErrorPage(RenderFrame* render_frame,
1989 const GURL& url) override {
1990 return url == GURL("http://example.com/suppress");
1993 void GetNavigationErrorStrings(content::RenderView* render_view,
1994 blink::WebFrame* frame,
1995 const blink::WebURLRequest& failed_request,
1996 const blink::WebURLError& error,
1997 std::string* error_html,
1998 base::string16* error_description) override {
1999 if (error_html)
2000 *error_html = "A suffusion of yellow.";
2003 bool HasErrorPage(int http_status_code,
2004 std::string* error_domain) override {
2005 return true;
2010 #if defined(OS_ANDROID)
2011 // Crashing on Android: http://crbug.com/311341
2012 #define MAYBE_Suppresses DISABLED_Suppresses
2013 #else
2014 #define MAYBE_Suppresses Suppresses
2015 #endif
2017 TEST_F(RendererErrorPageTest, MAYBE_Suppresses) {
2018 WebURLError error;
2019 error.domain = WebString::fromUTF8(net::kErrorDomain);
2020 error.reason = net::ERR_FILE_NOT_FOUND;
2021 error.unreachableURL = GURL("http://example.com/suppress");
2022 WebLocalFrame* web_frame = GetMainFrame();
2024 // Start a load that will reach provisional state synchronously,
2025 // but won't complete synchronously.
2026 CommonNavigationParams common_params;
2027 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2028 common_params.url = GURL("data:text/html,test data");
2029 TestRenderFrame* main_frame = static_cast<TestRenderFrame*>(frame());
2030 main_frame->Navigate(common_params, StartNavigationParams(),
2031 RequestNavigationParams());
2033 // An error occurred.
2034 main_frame->didFailProvisionalLoad(web_frame, error,
2035 blink::WebStandardCommit);
2036 const int kMaxOutputCharacters = 22;
2037 EXPECT_EQ("", base::UTF16ToASCII(
2038 base::StringPiece16(web_frame->contentAsText(kMaxOutputCharacters))));
2041 #if defined(OS_ANDROID)
2042 // Crashing on Android: http://crbug.com/311341
2043 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2044 #else
2045 #define MAYBE_DoesNotSuppress DoesNotSuppress
2046 #endif
2048 TEST_F(RendererErrorPageTest, MAYBE_DoesNotSuppress) {
2049 WebURLError error;
2050 error.domain = WebString::fromUTF8(net::kErrorDomain);
2051 error.reason = net::ERR_FILE_NOT_FOUND;
2052 error.unreachableURL = GURL("http://example.com/dont-suppress");
2053 WebLocalFrame* web_frame = GetMainFrame();
2055 // Start a load that will reach provisional state synchronously,
2056 // but won't complete synchronously.
2057 CommonNavigationParams common_params;
2058 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2059 common_params.url = GURL("data:text/html,test data");
2060 TestRenderFrame* main_frame = static_cast<TestRenderFrame*>(frame());
2061 main_frame->Navigate(common_params, StartNavigationParams(),
2062 RequestNavigationParams());
2064 // An error occurred.
2065 main_frame->didFailProvisionalLoad(web_frame, error,
2066 blink::WebStandardCommit);
2068 // The error page itself is loaded asynchronously.
2069 FrameLoadWaiter(main_frame).Wait();
2070 const int kMaxOutputCharacters = 22;
2071 EXPECT_EQ("A suffusion of yellow.",
2072 base::UTF16ToASCII(base::StringPiece16(
2073 web_frame->contentAsText(kMaxOutputCharacters))));
2076 #if defined(OS_ANDROID)
2077 // Crashing on Android: http://crbug.com/311341
2078 #define MAYBE_HttpStatusCodeErrorWithEmptyBody \
2079 DISABLED_HttpStatusCodeErrorWithEmptyBody
2080 #else
2081 #define MAYBE_HttpStatusCodeErrorWithEmptyBody HttpStatusCodeErrorWithEmptyBody
2082 #endif
2083 TEST_F(RendererErrorPageTest, MAYBE_HttpStatusCodeErrorWithEmptyBody) {
2084 blink::WebURLResponse response;
2085 response.initialize();
2086 response.setHTTPStatusCode(503);
2087 WebLocalFrame* web_frame = GetMainFrame();
2089 // Start a load that will reach provisional state synchronously,
2090 // but won't complete synchronously.
2091 CommonNavigationParams common_params;
2092 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2093 common_params.url = GURL("data:text/html,test data");
2094 TestRenderFrame* main_frame = static_cast<TestRenderFrame*>(frame());
2095 main_frame->Navigate(common_params, StartNavigationParams(),
2096 RequestNavigationParams());
2098 // Emulate a 4xx/5xx main resource response with an empty body.
2099 main_frame->didReceiveResponse(web_frame, 1, response);
2100 main_frame->didFinishDocumentLoad(web_frame, true);
2102 // The error page itself is loaded asynchronously.
2103 FrameLoadWaiter(main_frame).Wait();
2104 const int kMaxOutputCharacters = 22;
2105 EXPECT_EQ("A suffusion of yellow.",
2106 base::UTF16ToASCII(base::StringPiece16(
2107 web_frame->contentAsText(kMaxOutputCharacters))));
2110 // Ensure the render view sends favicon url update events correctly.
2111 TEST_F(RenderViewImplTest, SendFaviconURLUpdateEvent) {
2112 // An event should be sent when a favicon url exists.
2113 LoadHTML("<html>"
2114 "<head>"
2115 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2116 "</head>"
2117 "</html>");
2118 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
2119 ViewHostMsg_UpdateFaviconURL::ID));
2120 render_thread_->sink().ClearMessages();
2122 // An event should not be sent if no favicon url exists. This is an assumption
2123 // made by some of Chrome's favicon handling.
2124 LoadHTML("<html>"
2125 "<head>"
2126 "</head>"
2127 "</html>");
2128 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
2129 ViewHostMsg_UpdateFaviconURL::ID));
2132 TEST_F(RenderViewImplTest, FocusElementCallsFocusedNodeChanged) {
2133 LoadHTML("<input id='test1' value='hello1'></input>"
2134 "<input id='test2' value='hello2'></input>");
2136 ExecuteJavaScriptForTests("document.getElementById('test1').focus();");
2137 const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
2138 ViewHostMsg_FocusedNodeChanged::ID);
2139 EXPECT_TRUE(msg1);
2141 ViewHostMsg_FocusedNodeChanged::Param params;
2142 ViewHostMsg_FocusedNodeChanged::Read(msg1, &params);
2143 EXPECT_TRUE(base::get<0>(params));
2144 render_thread_->sink().ClearMessages();
2146 ExecuteJavaScriptForTests("document.getElementById('test2').focus();");
2147 const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching(
2148 ViewHostMsg_FocusedNodeChanged::ID);
2149 EXPECT_TRUE(msg2);
2150 ViewHostMsg_FocusedNodeChanged::Read(msg2, &params);
2151 EXPECT_TRUE(base::get<0>(params));
2152 render_thread_->sink().ClearMessages();
2154 view()->webview()->clearFocusedElement();
2155 const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching(
2156 ViewHostMsg_FocusedNodeChanged::ID);
2157 EXPECT_TRUE(msg3);
2158 ViewHostMsg_FocusedNodeChanged::Read(msg3, &params);
2159 EXPECT_FALSE(base::get<0>(params));
2160 render_thread_->sink().ClearMessages();
2163 TEST_F(RenderViewImplTest, ServiceWorkerNetworkProviderSetup) {
2164 ServiceWorkerNetworkProvider* provider = NULL;
2165 RequestExtraData* extra_data = NULL;
2167 // Make sure each new document has a new provider and
2168 // that the main request is tagged with the provider's id.
2169 LoadHTML("<b>A Document</b>");
2170 ASSERT_TRUE(GetMainFrame()->dataSource());
2171 provider = ServiceWorkerNetworkProvider::FromDocumentState(
2172 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2173 ASSERT_TRUE(provider);
2174 extra_data = static_cast<RequestExtraData*>(
2175 GetMainFrame()->dataSource()->request().extraData());
2176 ASSERT_TRUE(extra_data);
2177 EXPECT_EQ(extra_data->service_worker_provider_id(),
2178 provider->provider_id());
2179 int provider1_id = provider->provider_id();
2181 LoadHTML("<b>New Document B Goes Here</b>");
2182 ASSERT_TRUE(GetMainFrame()->dataSource());
2183 provider = ServiceWorkerNetworkProvider::FromDocumentState(
2184 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2185 ASSERT_TRUE(provider);
2186 EXPECT_NE(provider1_id, provider->provider_id());
2187 extra_data = static_cast<RequestExtraData*>(
2188 GetMainFrame()->dataSource()->request().extraData());
2189 ASSERT_TRUE(extra_data);
2190 EXPECT_EQ(extra_data->service_worker_provider_id(),
2191 provider->provider_id());
2193 // See that subresource requests are also tagged with the provider's id.
2194 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2195 blink::WebURLRequest request(GURL("http://foo.com"));
2196 request.setRequestContext(blink::WebURLRequest::RequestContextSubresource);
2197 blink::WebURLResponse redirect_response;
2198 frame()->willSendRequest(GetMainFrame(), 0, request, redirect_response);
2199 extra_data = static_cast<RequestExtraData*>(request.extraData());
2200 ASSERT_TRUE(extra_data);
2201 EXPECT_EQ(extra_data->service_worker_provider_id(),
2202 provider->provider_id());
2205 TEST_F(RenderViewImplTest, OnSetAccessibilityMode) {
2206 ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
2207 ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2209 frame()->SetAccessibilityMode(AccessibilityModeTreeOnly);
2210 ASSERT_EQ(AccessibilityModeTreeOnly, frame()->accessibility_mode());
2211 ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2213 frame()->SetAccessibilityMode(AccessibilityModeOff);
2214 ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
2215 ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2217 frame()->SetAccessibilityMode(AccessibilityModeComplete);
2218 ASSERT_EQ(AccessibilityModeComplete, frame()->accessibility_mode());
2219 ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2222 TEST_F(RenderViewImplTest, ScreenMetricsEmulation) {
2223 LoadHTML("<body style='min-height:1000px;'></body>");
2225 blink::WebDeviceEmulationParams params;
2226 base::string16 get_width = base::ASCIIToUTF16("Number(window.innerWidth)");
2227 base::string16 get_height = base::ASCIIToUTF16("Number(window.innerHeight)");
2228 int width, height;
2230 params.viewSize.width = 327;
2231 params.viewSize.height = 415;
2232 view()->OnEnableDeviceEmulation(params);
2233 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width));
2234 EXPECT_EQ(params.viewSize.width, width);
2235 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height));
2236 EXPECT_EQ(params.viewSize.height, height);
2238 params.viewSize.width = 1005;
2239 params.viewSize.height = 1102;
2240 view()->OnEnableDeviceEmulation(params);
2241 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width));
2242 EXPECT_EQ(params.viewSize.width, width);
2243 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height));
2244 EXPECT_EQ(params.viewSize.height, height);
2246 view()->OnDisableDeviceEmulation();
2248 view()->OnEnableDeviceEmulation(params);
2249 // Don't disable here to test that emulation is being shutdown properly.
2252 // Sanity checks for the Navigation Timing API |navigationStart| override. We
2253 // are asserting only most basic constraints, as TimeTicks (passed as the
2254 // override) are not comparable with the wall time (returned by the Blink API).
2255 TEST_F(RenderViewImplTest, NavigationStartOverride) {
2256 // Verify that a navigation that claims to have started at the earliest
2257 // possible TimeTicks is indeed reported as one that started before
2258 // OnNavigate() is called.
2259 base::Time before_navigation = base::Time::Now();
2260 CommonNavigationParams early_common_params;
2261 StartNavigationParams early_start_params;
2262 RequestNavigationParams early_request_params;
2263 early_common_params.url = GURL("data:text/html,<div>Page</div>");
2264 early_common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2265 early_common_params.transition = ui::PAGE_TRANSITION_TYPED;
2266 early_start_params.is_post = true;
2267 early_request_params.browser_navigation_start =
2268 base::TimeTicks::FromInternalValue(1);
2270 frame()->Navigate(early_common_params, early_start_params,
2271 early_request_params);
2272 ProcessPendingMessages();
2274 base::Time early_nav_reported_start =
2275 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2276 EXPECT_LT(early_nav_reported_start, before_navigation);
2278 // Verify that a navigation that claims to have started in the future - 42
2279 // days from now is *not* reported as one that starts in the future; as we
2280 // sanitize the override allowing a maximum of ::Now().
2281 CommonNavigationParams late_common_params;
2282 RequestNavigationParams late_request_params;
2283 StartNavigationParams late_start_params;
2284 late_common_params.url = GURL("data:text/html,<div>Another page</div>");
2285 late_common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2286 late_common_params.transition = ui::PAGE_TRANSITION_TYPED;
2287 late_start_params.is_post = true;
2288 late_request_params.browser_navigation_start =
2289 base::TimeTicks::Now() + base::TimeDelta::FromDays(42);
2291 frame()->Navigate(late_common_params, late_start_params, late_request_params);
2292 ProcessPendingMessages();
2293 base::Time after_navigation =
2294 base::Time::Now() + base::TimeDelta::FromDays(1);
2296 base::Time late_nav_reported_start =
2297 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2298 EXPECT_LE(late_nav_reported_start, after_navigation);
2301 TEST_F(RenderViewImplTest, PreferredSizeZoomed) {
2302 LoadHTML("<body style='margin:0;'><div style='display:inline-block; "
2303 "width:400px; height:400px;'/></body>");
2304 view()->webview()->mainFrame()->setCanHaveScrollbars(false);
2305 EnablePreferredSizeMode();
2307 gfx::Size size = GetPreferredSize();
2308 EXPECT_EQ(gfx::Size(400, 400), size);
2310 SetZoomLevel(ZoomFactorToZoomLevel(2.0));
2311 size = GetPreferredSize();
2312 EXPECT_EQ(gfx::Size(800, 800), size);
2315 // Ensure the RenderViewImpl history list is properly updated when starting a
2316 // new browser-initiated navigation.
2317 TEST_F(RenderViewImplTest, HistoryIsProperlyUpdatedOnNavigation) {
2318 EXPECT_EQ(0, view()->historyBackListCount());
2319 EXPECT_EQ(0, view()->historyBackListCount() +
2320 view()->historyForwardListCount() + 1);
2322 // Receive a Navigate message with history parameters.
2323 RequestNavigationParams request_params;
2324 request_params.current_history_list_length = 2;
2325 request_params.current_history_list_offset = 1;
2326 request_params.pending_history_list_offset = 2;
2327 request_params.page_id = -1;
2328 frame()->Navigate(CommonNavigationParams(), StartNavigationParams(),
2329 request_params);
2331 // The history list in RenderView should have been updated.
2332 EXPECT_EQ(1, view()->historyBackListCount());
2333 EXPECT_EQ(2, view()->historyBackListCount() +
2334 view()->historyForwardListCount() + 1);
2337 TEST_F(RenderViewImplBlinkSettingsTest, Default) {
2338 DoSetUp();
2339 EXPECT_EQ(blink::WebSettings::HoverTypeNone, settings()->primaryHoverType());
2340 EXPECT_FALSE(settings()->viewportEnabled());
2343 TEST_F(RenderViewImplBlinkSettingsTest, CommandLine) {
2344 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
2345 switches::kBlinkSettings, "primaryHoverType=4,viewportEnabled=true");
2346 DoSetUp();
2347 EXPECT_EQ(blink::WebSettings::HoverTypeHover, settings()->primaryHoverType());
2348 EXPECT_TRUE(settings()->viewportEnabled());
2351 TEST_F(DevToolsAgentTest, DevToolsResumeOnClose) {
2352 Attach();
2353 EXPECT_FALSE(IsPaused());
2354 DispatchDevToolsMessage("{\"id\":1,\"method\":\"Debugger.enable\"}");
2356 // Executing javascript will pause the thread and create nested message loop.
2357 // Posting task simulates message coming from browser.
2358 base::ThreadTaskRunnerHandle::Get()->PostTask(
2359 FROM_HERE,
2360 base::Bind(&DevToolsAgentTest::CloseWhilePaused, base::Unretained(this)));
2361 ExecuteJavaScriptForTests("debugger;");
2363 // CloseWhilePaused should resume execution and continue here.
2364 EXPECT_FALSE(IsPaused());
2365 Detach();
2368 } // namespace content