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