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