Add ICU message format support
[chromium-blink-merge.git] / content / renderer / render_view_browsertest.cc
blob772b6579dcf3b8f510e3acf5a5f8e8f012726ac8
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/basictypes.h"
6 #include "base/bind.h"
7 #include "base/callback.h"
8 #include "base/location.h"
9 #include "base/memory/shared_memory.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/time/time.h"
15 #include "base/win/windows_version.h"
16 #include "content/child/request_extra_data.h"
17 #include "content/child/service_worker/service_worker_network_provider.h"
18 #include "content/common/frame_messages.h"
19 #include "content/common/site_isolation_policy.h"
20 #include "content/common/ssl_status_serialization.h"
21 #include "content/common/view_messages.h"
22 #include "content/public/browser/browser_context.h"
23 #include "content/public/browser/native_web_keyboard_event.h"
24 #include "content/public/browser/web_ui_controller_factory.h"
25 #include "content/public/common/bindings_policy.h"
26 #include "content/public/common/content_switches.h"
27 #include "content/public/common/page_zoom.h"
28 #include "content/public/common/url_constants.h"
29 #include "content/public/common/url_utils.h"
30 #include "content/public/renderer/content_renderer_client.h"
31 #include "content/public/renderer/document_state.h"
32 #include "content/public/renderer/navigation_state.h"
33 #include "content/public/test/browser_test_utils.h"
34 #include "content/public/test/frame_load_waiter.h"
35 #include "content/public/test/render_view_test.h"
36 #include "content/public/test/test_utils.h"
37 #include "content/renderer/accessibility/renderer_accessibility.h"
38 #include "content/renderer/devtools/devtools_agent.h"
39 #include "content/renderer/history_controller.h"
40 #include "content/renderer/history_serialization.h"
41 #include "content/renderer/navigation_state_impl.h"
42 #include "content/renderer/render_process.h"
43 #include "content/renderer/render_view_impl.h"
44 #include "content/shell/browser/shell.h"
45 #include "content/shell/browser/shell_browser_context.h"
46 #include "content/test/mock_keyboard.h"
47 #include "content/test/test_render_frame.h"
48 #include "net/base/net_errors.h"
49 #include "net/cert/cert_status_flags.h"
50 #include "testing/gtest/include/gtest/gtest.h"
51 #include "third_party/WebKit/public/platform/WebData.h"
52 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
53 #include "third_party/WebKit/public/platform/WebString.h"
54 #include "third_party/WebKit/public/platform/WebURLResponse.h"
55 #include "third_party/WebKit/public/web/WebDataSource.h"
56 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
57 #include "third_party/WebKit/public/web/WebHistoryCommitType.h"
58 #include "third_party/WebKit/public/web/WebHistoryItem.h"
59 #include "third_party/WebKit/public/web/WebLocalFrame.h"
60 #include "third_party/WebKit/public/web/WebPerformance.h"
61 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
62 #include "third_party/WebKit/public/web/WebSettings.h"
63 #include "third_party/WebKit/public/web/WebView.h"
64 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
65 #include "ui/events/event.h"
66 #include "ui/events/keycodes/keyboard_codes.h"
67 #include "ui/gfx/codec/jpeg_codec.h"
68 #include "ui/gfx/range/range.h"
70 #if defined(USE_AURA) && defined(USE_X11)
71 #include <X11/Xlib.h>
72 #include "ui/events/event_constants.h"
73 #include "ui/events/keycodes/keyboard_code_conversion.h"
74 #include "ui/events/test/events_test_utils.h"
75 #include "ui/events/test/events_test_utils_x11.h"
76 #endif
78 #if defined(USE_OZONE)
79 #include "ui/events/keycodes/keyboard_code_conversion.h"
80 #endif
82 using blink::WebFrame;
83 using blink::WebInputEvent;
84 using blink::WebLocalFrame;
85 using blink::WebMouseEvent;
86 using blink::WebRuntimeFeatures;
87 using blink::WebString;
88 using blink::WebTextDirection;
89 using blink::WebURLError;
91 namespace content {
93 namespace {
95 static const int kProxyRoutingId = 13;
97 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
98 // Converts MockKeyboard::Modifiers to ui::EventFlags.
99 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers) {
100 static struct ModifierMap {
101 MockKeyboard::Modifiers src;
102 int dst;
103 } kModifierMap[] = {
104 { MockKeyboard::LEFT_SHIFT, ui::EF_SHIFT_DOWN },
105 { MockKeyboard::RIGHT_SHIFT, ui::EF_SHIFT_DOWN },
106 { MockKeyboard::LEFT_CONTROL, ui::EF_CONTROL_DOWN },
107 { MockKeyboard::RIGHT_CONTROL, ui::EF_CONTROL_DOWN },
108 { MockKeyboard::LEFT_ALT, ui::EF_ALT_DOWN },
109 { MockKeyboard::RIGHT_ALT, ui::EF_ALT_DOWN },
111 int flags = 0;
112 for (size_t i = 0; i < arraysize(kModifierMap); ++i) {
113 if (kModifierMap[i].src & modifiers) {
114 flags |= kModifierMap[i].dst;
117 return flags;
119 #endif
121 class WebUITestWebUIControllerFactory : public WebUIControllerFactory {
122 public:
123 WebUIController* CreateWebUIControllerForURL(WebUI* web_ui,
124 const GURL& url) const override {
125 return NULL;
127 WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
128 const GURL& url) const override {
129 return WebUI::kNoWebUI;
131 bool UseWebUIForURL(BrowserContext* browser_context,
132 const GURL& url) const override {
133 return HasWebUIScheme(url);
135 bool UseWebUIBindingsForURL(BrowserContext* browser_context,
136 const GURL& url) const override {
137 return HasWebUIScheme(url);
141 } // namespace
143 class RenderViewImplTest : public RenderViewTest {
144 public:
145 RenderViewImplTest() {
146 // Attach a pseudo keyboard device to this object.
147 mock_keyboard_.reset(new MockKeyboard());
150 ~RenderViewImplTest() override {}
152 void SetUp() override {
153 // Enable Blink's experimental and test only features so that test code
154 // does not have to bother enabling each feature.
155 WebRuntimeFeatures::enableExperimentalFeatures(true);
156 WebRuntimeFeatures::enableTestOnlyFeatures(true);
157 RenderViewTest::SetUp();
160 RenderViewImpl* view() {
161 return static_cast<RenderViewImpl*>(view_);
164 int view_page_id() {
165 return view()->page_id_;
168 TestRenderFrame* frame() {
169 return static_cast<TestRenderFrame*>(view()->GetMainRenderFrame());
172 // Sends IPC messages that emulates a key-press event.
173 int SendKeyEvent(MockKeyboard::Layout layout,
174 int key_code,
175 MockKeyboard::Modifiers modifiers,
176 base::string16* output) {
177 #if defined(OS_WIN)
178 // Retrieve the Unicode character for the given tuple (keyboard-layout,
179 // key-code, and modifiers).
180 // Exit when a keyboard-layout driver cannot assign a Unicode character to
181 // the tuple to prevent sending an invalid key code to the RenderView
182 // object.
183 CHECK(mock_keyboard_.get());
184 CHECK(output);
185 int length = mock_keyboard_->GetCharacters(layout, key_code, modifiers,
186 output);
187 if (length != 1)
188 return -1;
190 // Create IPC messages from Windows messages and send them to our
191 // back-end.
192 // A keyboard event of Windows consists of three Windows messages:
193 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
194 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
195 // WM_CHAR sends a composed Unicode character.
196 MSG msg1 = { NULL, WM_KEYDOWN, key_code, 0 };
197 ui::KeyEvent evt1(msg1);
198 NativeWebKeyboardEvent keydown_event(evt1);
199 SendNativeKeyEvent(keydown_event);
201 MSG msg2 = { NULL, WM_CHAR, (*output)[0], 0 };
202 ui::KeyEvent evt2(msg2);
203 NativeWebKeyboardEvent char_event(evt2);
204 SendNativeKeyEvent(char_event);
206 MSG msg3 = { NULL, WM_KEYUP, key_code, 0 };
207 ui::KeyEvent evt3(msg3);
208 NativeWebKeyboardEvent keyup_event(evt3);
209 SendNativeKeyEvent(keyup_event);
211 return length;
212 #elif defined(USE_AURA) && defined(USE_X11)
213 // We ignore |layout|, which means we are only testing the layout of the
214 // current locale. TODO(mazda): fix this to respect |layout|.
215 CHECK(output);
216 const int flags = ConvertMockKeyboardModifier(modifiers);
218 ui::ScopedXI2Event xevent;
219 xevent.InitKeyEvent(ui::ET_KEY_PRESSED,
220 static_cast<ui::KeyboardCode>(key_code),
221 flags);
222 ui::KeyEvent event1(xevent);
223 NativeWebKeyboardEvent keydown_event(event1);
224 SendNativeKeyEvent(keydown_event);
226 // X11 doesn't actually have native character events, but give the test
227 // what it wants.
228 xevent.InitKeyEvent(ui::ET_KEY_PRESSED,
229 static_cast<ui::KeyboardCode>(key_code),
230 flags);
231 ui::KeyEvent event2(xevent);
232 event2.set_character(GetCharacterFromKeyCode(event2.key_code(),
233 event2.flags()));
234 ui::KeyEventTestApi test_event2(&event2);
235 test_event2.set_is_char(true);
236 NativeWebKeyboardEvent char_event(event2);
237 SendNativeKeyEvent(char_event);
239 xevent.InitKeyEvent(ui::ET_KEY_RELEASED,
240 static_cast<ui::KeyboardCode>(key_code),
241 flags);
242 ui::KeyEvent event3(xevent);
243 NativeWebKeyboardEvent keyup_event(event3);
244 SendNativeKeyEvent(keyup_event);
246 long c = GetCharacterFromKeyCode(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 = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
272 flags);
273 output->assign(1, static_cast<base::char16>(c));
274 return 1;
275 #else
276 NOTIMPLEMENTED();
277 return L'\0';
278 #endif
281 void EnablePreferredSizeMode() {
282 view()->OnEnablePreferredSizeChangedMode();
285 const gfx::Size& GetPreferredSize() {
286 view()->CheckPreferredSize();
287 return view()->preferred_size_;
290 void SetZoomLevel(double level) {
291 view()->OnSetZoomLevelForView(false, level);
294 private:
295 scoped_ptr<MockKeyboard> mock_keyboard_;
298 class DevToolsAgentTest : public RenderViewImplTest {
299 public:
300 void Attach() {
301 std::string host_id = "host_id";
302 agent()->OnAttach(host_id);
305 void Detach() {
306 agent()->OnDetach();
309 bool IsPaused() {
310 return agent()->paused_;
313 void DispatchDevToolsMessage(const std::string& message) {
314 agent()->OnDispatchOnInspectorBackend(message);
317 void CloseWhilePaused() {
318 EXPECT_TRUE(IsPaused());
319 view()->NotifyOnClose();
322 private:
323 DevToolsAgent* agent() {
324 return frame()->devtools_agent();
328 class RenderViewImplBlinkSettingsTest : public RenderViewImplTest {
329 public:
330 void DoSetUp() {
331 RenderViewImplTest::SetUp();
334 const blink::WebSettings* settings() {
335 return view()->webview()->settings();
338 protected:
339 // Blink settings may be specified on the command line, which must
340 // be configured before RenderViewImplTest::SetUp runs. Thus we make
341 // SetUp() a no-op, and expose RenderViewImplTest::SetUp() via
342 // DoSetUp(), to allow tests to perform command line modifications
343 // before RenderViewImplTest::SetUp is run. Each test must invoke
344 // DoSetUp manually once pre-SetUp configuration is complete.
345 void SetUp() override {}
348 // Ensure that the main RenderFrame is deleted and cleared from the RenderView
349 // after closing it.
350 TEST_F(RenderViewImplTest, RenderFrameClearedAfterClose) {
351 // Create a new main frame RenderFrame so that we don't interfere with the
352 // shutdown of frame() in RenderViewTest.TearDown.
353 blink::WebURLRequest popup_request(GURL("http://foo.com"));
354 blink::WebView* new_web_view = view()->createView(
355 GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
356 blink::WebNavigationPolicyNewForegroundTab, false);
357 RenderViewImpl* new_view = RenderViewImpl::FromWebView(new_web_view);
359 // Close the view, causing the main RenderFrame to be detached and deleted.
360 new_view->Close();
361 EXPECT_FALSE(new_view->GetMainRenderFrame());
363 // Clean up after the new view so we don't leak it.
364 new_view->Release();
367 TEST_F(RenderViewImplTest, SaveImageFromDataURL) {
368 const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
369 ViewHostMsg_SaveImageFromDataURL::ID);
370 EXPECT_FALSE(msg1);
371 render_thread_->sink().ClearMessages();
373 const std::string image_data_url =
374 "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
376 view()->saveImageFromDataURL(WebString::fromUTF8(image_data_url));
377 ProcessPendingMessages();
378 const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching(
379 ViewHostMsg_SaveImageFromDataURL::ID);
380 EXPECT_TRUE(msg2);
382 ViewHostMsg_SaveImageFromDataURL::Param param1;
383 ViewHostMsg_SaveImageFromDataURL::Read(msg2, &param1);
384 EXPECT_EQ(base::get<1>(param1).length(), image_data_url.length());
385 EXPECT_EQ(base::get<1>(param1), image_data_url);
387 ProcessPendingMessages();
388 render_thread_->sink().ClearMessages();
390 const std::string large_data_url(1024 * 1024 * 10 - 1, 'd');
392 view()->saveImageFromDataURL(WebString::fromUTF8(large_data_url));
393 ProcessPendingMessages();
394 const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching(
395 ViewHostMsg_SaveImageFromDataURL::ID);
396 EXPECT_TRUE(msg3);
398 ViewHostMsg_SaveImageFromDataURL::Param param2;
399 ViewHostMsg_SaveImageFromDataURL::Read(msg3, &param2);
400 EXPECT_EQ(base::get<1>(param2).length(), large_data_url.length());
401 EXPECT_EQ(base::get<1>(param2), large_data_url);
403 ProcessPendingMessages();
404 render_thread_->sink().ClearMessages();
406 const std::string exceeded_data_url(1024 * 1024 * 10 + 1, 'd');
408 view()->saveImageFromDataURL(WebString::fromUTF8(exceeded_data_url));
409 ProcessPendingMessages();
410 const IPC::Message* msg4 = render_thread_->sink().GetFirstMessageMatching(
411 ViewHostMsg_SaveImageFromDataURL::ID);
412 EXPECT_FALSE(msg4);
415 // Test that we get form state change notifications when input fields change.
416 TEST_F(RenderViewImplTest, DISABLED_OnNavStateChanged) {
417 // Don't want any delay for form state sync changes. This will still post a
418 // message so updates will get coalesced, but as soon as we spin the message
419 // loop, it will generate an update.
420 view()->set_send_content_state_immediately(true);
422 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
424 // We should NOT have gotten a form state change notification yet.
425 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
426 ViewHostMsg_UpdateState::ID));
427 render_thread_->sink().ClearMessages();
429 // Change the value of the input. We should have gotten an update state
430 // notification. We need to spin the message loop to catch this update.
431 ExecuteJavaScriptForTests(
432 "document.getElementById('elt_text').value = 'foo';");
433 ProcessPendingMessages();
434 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
435 ViewHostMsg_UpdateState::ID));
438 TEST_F(RenderViewImplTest, OnNavigationHttpPost) {
439 // An http url will trigger a resource load so cannot be used here.
440 CommonNavigationParams common_params;
441 StartNavigationParams start_params;
442 RequestNavigationParams request_params;
443 common_params.url = GURL("data:text/html,<div>Page</div>");
444 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
445 common_params.transition = ui::PAGE_TRANSITION_TYPED;
446 request_params.page_id = -1;
448 // Set up post data.
449 const unsigned char* raw_data = reinterpret_cast<const unsigned char*>(
450 "post \0\ndata");
451 const unsigned int length = 11;
452 const std::vector<unsigned char> post_data(raw_data, raw_data + length);
453 start_params.is_post = true;
454 start_params.browser_initiated_post_data = post_data;
456 frame()->Navigate(common_params, start_params, request_params);
457 ProcessPendingMessages();
459 const IPC::Message* frame_navigate_msg =
460 render_thread_->sink().GetUniqueMessageMatching(
461 FrameHostMsg_DidCommitProvisionalLoad::ID);
462 EXPECT_TRUE(frame_navigate_msg);
464 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params;
465 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
466 &host_nav_params);
467 EXPECT_TRUE(base::get<0>(host_nav_params).is_post);
469 // Check post data sent to browser matches
470 EXPECT_TRUE(base::get<0>(host_nav_params).page_state.IsValid());
471 scoped_ptr<HistoryEntry> entry =
472 PageStateToHistoryEntry(base::get<0>(host_nav_params).page_state);
473 blink::WebHTTPBody body = entry->root().httpBody();
474 blink::WebHTTPBody::Element element;
475 bool successful = body.elementAt(0, element);
476 EXPECT_TRUE(successful);
477 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData, element.type);
478 EXPECT_EQ(length, element.data.size());
479 EXPECT_EQ(0, memcmp(raw_data, element.data.data(), length));
482 TEST_F(RenderViewImplTest, DecideNavigationPolicy) {
483 WebUITestWebUIControllerFactory factory;
484 WebUIControllerFactory::RegisterFactory(&factory);
486 DocumentState state;
487 state.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
489 // Navigations to normal HTTP URLs can be handled locally.
490 blink::WebURLRequest request(GURL("http://foo.com"));
491 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
492 policy_info.frame = GetMainFrame();
493 policy_info.extraData = &state;
494 policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
495 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
496 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
497 policy_info);
498 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
499 switches::kEnableBrowserSideNavigation)) {
500 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab, policy);
501 } else {
502 // If this is a renderer-initiated navigation that just begun, it should
503 // stop and be sent to the browser.
504 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
506 // If this a navigation that is ready to commit, it should be handled
507 // locally.
508 request.setCheckForBrowserSideNavigation(false);
509 policy = frame()->decidePolicyForNavigation(policy_info);
510 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab, policy);
513 // Verify that form posts to WebUI URLs will be sent to the browser process.
514 blink::WebURLRequest form_request(GURL("chrome://foo"));
515 blink::WebFrameClient::NavigationPolicyInfo form_policy_info(form_request);
516 form_policy_info.frame = GetMainFrame();
517 form_policy_info.extraData = &state;
518 form_policy_info.navigationType = blink::WebNavigationTypeFormSubmitted;
519 form_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
520 form_request.setHTTPMethod("POST");
521 policy = frame()->decidePolicyForNavigation(form_policy_info);
522 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
524 // Verify that popup links to WebUI URLs also are sent to browser.
525 blink::WebURLRequest popup_request(GURL("chrome://foo"));
526 blink::WebFrameClient::NavigationPolicyInfo popup_policy_info(popup_request);
527 popup_policy_info.frame = GetMainFrame();
528 popup_policy_info.extraData = &state;
529 popup_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
530 popup_policy_info.defaultPolicy = blink::WebNavigationPolicyNewForegroundTab;
531 policy = frame()->decidePolicyForNavigation(popup_policy_info);
532 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
535 TEST_F(RenderViewImplTest, DecideNavigationPolicyHandlesAllTopLevel) {
536 DocumentState state;
537 state.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
539 RendererPreferences prefs = view()->renderer_preferences();
540 prefs.browser_handles_all_top_level_requests = true;
541 view()->OnSetRendererPrefs(prefs);
543 const blink::WebNavigationType kNavTypes[] = {
544 blink::WebNavigationTypeLinkClicked,
545 blink::WebNavigationTypeFormSubmitted,
546 blink::WebNavigationTypeBackForward,
547 blink::WebNavigationTypeReload,
548 blink::WebNavigationTypeFormResubmitted,
549 blink::WebNavigationTypeOther,
552 blink::WebURLRequest request(GURL("http://foo.com"));
553 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
554 policy_info.frame = GetMainFrame();
555 policy_info.extraData = &state;
556 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
558 for (size_t i = 0; i < arraysize(kNavTypes); ++i) {
559 policy_info.navigationType = kNavTypes[i];
561 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
562 policy_info);
563 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
567 TEST_F(RenderViewImplTest, DecideNavigationPolicyForWebUI) {
568 // Enable bindings to simulate a WebUI view.
569 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI);
571 DocumentState state;
572 state.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
574 // Navigations to normal HTTP URLs will be sent to browser process.
575 blink::WebURLRequest request(GURL("http://foo.com"));
576 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
577 policy_info.frame = GetMainFrame();
578 policy_info.extraData = &state;
579 policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
580 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
582 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
583 policy_info);
584 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
586 // Navigations to WebUI URLs will also be sent to browser process.
587 blink::WebURLRequest webui_request(GURL("chrome://foo"));
588 blink::WebFrameClient::NavigationPolicyInfo webui_policy_info(webui_request);
589 webui_policy_info.frame = GetMainFrame();
590 webui_policy_info.extraData = &state;
591 webui_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
592 webui_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
593 policy = frame()->decidePolicyForNavigation(webui_policy_info);
594 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
596 // Verify that form posts to data URLs will be sent to the browser process.
597 blink::WebURLRequest data_request(GURL("data:text/html,foo"));
598 blink::WebFrameClient::NavigationPolicyInfo data_policy_info(data_request);
599 data_policy_info.frame = GetMainFrame();
600 data_policy_info.extraData = &state;
601 data_policy_info.navigationType = blink::WebNavigationTypeFormSubmitted;
602 data_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
603 data_request.setHTTPMethod("POST");
604 policy = frame()->decidePolicyForNavigation(data_policy_info);
605 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
607 // Verify that a popup that creates a view first and then navigates to a
608 // normal HTTP URL will be sent to the browser process, even though the
609 // new view does not have any enabled_bindings_.
610 blink::WebURLRequest popup_request(GURL("http://foo.com"));
611 blink::WebView* new_web_view = view()->createView(
612 GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
613 blink::WebNavigationPolicyNewForegroundTab, false);
614 RenderViewImpl* new_view = RenderViewImpl::FromWebView(new_web_view);
615 blink::WebFrameClient::NavigationPolicyInfo popup_policy_info(popup_request);
616 popup_policy_info.frame = new_web_view->mainFrame()->toWebLocalFrame();
617 popup_policy_info.extraData = &state;
618 popup_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
619 popup_policy_info.defaultPolicy = blink::WebNavigationPolicyNewForegroundTab;
620 policy = static_cast<RenderFrameImpl*>(new_view->GetMainRenderFrame())->
621 decidePolicyForNavigation(popup_policy_info);
622 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
624 // Clean up after the new view so we don't leak it.
625 new_view->Close();
626 new_view->Release();
629 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
630 // already swapped out. http://crbug.com/93427.
631 TEST_F(RenderViewImplTest, SendSwapOutACK) {
632 // This test is invalid in --site-per-process mode, as swapped-out is no
633 // longer used.
634 if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
635 return;
637 LoadHTML("<div>Page A</div>");
638 int initial_page_id = view_page_id();
640 // Increment the ref count so that we don't exit when swapping out.
641 RenderProcess::current()->AddRefProcess();
643 // Respond to a swap out request.
644 frame()->SwapOut(kProxyRoutingId, true, content::FrameReplicationState());
646 // Ensure the swap out commits synchronously.
647 EXPECT_NE(initial_page_id, view_page_id());
649 // Check for a valid OnSwapOutACK.
650 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
651 FrameHostMsg_SwapOut_ACK::ID);
652 ASSERT_TRUE(msg);
654 // It is possible to get another swap out request. Ensure that we send
655 // an ACK, even if we don't have to do anything else.
656 render_thread_->sink().ClearMessages();
657 frame()->SwapOut(kProxyRoutingId, false, content::FrameReplicationState());
658 const IPC::Message* msg2 = render_thread_->sink().GetUniqueMessageMatching(
659 FrameHostMsg_SwapOut_ACK::ID);
660 ASSERT_TRUE(msg2);
662 // If we navigate back to this RenderView, ensure we don't send a state
663 // update for the swapped out URL. (http://crbug.com/72235)
664 CommonNavigationParams common_params;
665 RequestNavigationParams request_params;
666 common_params.url = GURL("data:text/html,<div>Page B</div>");
667 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
668 common_params.transition = ui::PAGE_TRANSITION_TYPED;
669 request_params.current_history_list_length = 1;
670 request_params.current_history_list_offset = 0;
671 request_params.pending_history_list_offset = 1;
672 request_params.page_id = -1;
673 frame()->Navigate(common_params, StartNavigationParams(), request_params);
674 ProcessPendingMessages();
675 const IPC::Message* msg3 = render_thread_->sink().GetUniqueMessageMatching(
676 ViewHostMsg_UpdateState::ID);
677 EXPECT_FALSE(msg3);
680 // Ensure the RenderViewImpl reloads the previous page if a reload request
681 // arrives while it is showing swappedout://. http://crbug.com/143155.
682 TEST_F(RenderViewImplTest, ReloadWhileSwappedOut) {
683 // This test is invalid in --site-per-process mode, as swapped-out is no
684 // longer used.
685 if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
686 return;
689 // Load page A.
690 LoadHTML("<div>Page A</div>");
692 // Load page B, which will trigger an UpdateState message for page A.
693 LoadHTML("<div>Page B</div>");
695 // Check for a valid UpdateState message for page A.
696 ProcessPendingMessages();
697 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
698 ViewHostMsg_UpdateState::ID);
699 ASSERT_TRUE(msg_A);
700 ViewHostMsg_UpdateState::Param params;
701 ViewHostMsg_UpdateState::Read(msg_A, &params);
702 int page_id_A = base::get<0>(params);
703 PageState state_A = base::get<1>(params);
704 EXPECT_EQ(1, page_id_A);
705 render_thread_->sink().ClearMessages();
707 // Back to page A (page_id 1) and commit.
708 CommonNavigationParams common_params_A;
709 RequestNavigationParams request_params_A;
710 common_params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL;
711 common_params_A.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
712 request_params_A.current_history_list_length = 2;
713 request_params_A.current_history_list_offset = 1;
714 request_params_A.pending_history_list_offset = 0;
715 request_params_A.page_id = 1;
716 request_params_A.nav_entry_id = 1;
717 request_params_A.page_state = state_A;
718 frame()->Navigate(common_params_A, StartNavigationParams(), request_params_A);
719 EXPECT_EQ(1, view()->historyBackListCount());
720 EXPECT_EQ(2, view()->historyBackListCount() +
721 view()->historyForwardListCount() + 1);
722 ProcessPendingMessages();
724 // Respond to a swap out request.
725 frame()->SwapOut(kProxyRoutingId, true, content::FrameReplicationState());
727 // Check for a OnSwapOutACK.
728 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
729 FrameHostMsg_SwapOut_ACK::ID);
730 ASSERT_TRUE(msg);
731 render_thread_->sink().ClearMessages();
733 // It is possible to get a reload request at this point, containing the
734 // params.page_state of the initial page (e.g., if the new page fails the
735 // provisional load in the renderer process, after we unload the old page).
736 // Ensure the old page gets reloaded, not swappedout://.
737 CommonNavigationParams common_params;
738 RequestNavigationParams request_params;
739 common_params.url = GURL("data:text/html,<div>Page A</div>");
740 common_params.navigation_type = FrameMsg_Navigate_Type::RELOAD;
741 common_params.transition = ui::PAGE_TRANSITION_RELOAD;
742 request_params.current_history_list_length = 2;
743 request_params.current_history_list_offset = 0;
744 request_params.pending_history_list_offset = 0;
745 request_params.page_id = 1;
746 request_params.nav_entry_id = 1;
747 request_params.page_state = state_A;
748 frame()->Navigate(common_params, StartNavigationParams(), request_params);
749 ProcessPendingMessages();
751 // Verify page A committed, not swappedout://.
752 const IPC::Message* frame_navigate_msg =
753 render_thread_->sink().GetUniqueMessageMatching(
754 FrameHostMsg_DidCommitProvisionalLoad::ID);
755 EXPECT_TRUE(frame_navigate_msg);
757 // Read URL out of the parent trait of the params object.
758 FrameHostMsg_DidCommitProvisionalLoad::Param commit_load_params;
759 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
760 &commit_load_params);
761 EXPECT_NE(GURL("swappedout://"), base::get<0>(commit_load_params).url);
764 // Verify that security origins are replicated properly to RenderFrameProxies
765 // when swapping out.
766 TEST_F(RenderViewImplTest, OriginReplicationForSwapOut) {
767 // This test should only run with --site-per-process, since origin
768 // replication only happens in that mode.
769 if (!AreAllSitesIsolatedForTesting())
770 return;
772 LoadHTML(
773 "Hello <iframe src='data:text/html,frame 1'></iframe>"
774 "<iframe src='data:text/html,frame 2'></iframe>");
775 WebFrame* web_frame = frame()->GetWebFrame();
776 TestRenderFrame* child_frame = static_cast<TestRenderFrame*>(
777 RenderFrame::FromWebFrame(web_frame->firstChild()));
779 // Swap the child frame out and pass a replicated origin to be set for
780 // WebRemoteFrame.
781 content::FrameReplicationState replication_state;
782 replication_state.origin = url::Origin(GURL("http://foo.com"));
783 child_frame->SwapOut(kProxyRoutingId, true, replication_state);
785 // The child frame should now be a WebRemoteFrame.
786 EXPECT_TRUE(web_frame->firstChild()->isWebRemoteFrame());
788 // Expect the origin to be updated properly.
789 blink::WebSecurityOrigin origin = web_frame->firstChild()->securityOrigin();
790 EXPECT_EQ(origin.toString(),
791 WebString::fromUTF8(replication_state.origin.Serialize()));
793 // Now, swap out the second frame using a unique origin and verify that it is
794 // replicated correctly.
795 replication_state.origin = url::Origin();
796 TestRenderFrame* child_frame2 = static_cast<TestRenderFrame*>(
797 RenderFrame::FromWebFrame(web_frame->lastChild()));
798 child_frame2->SwapOut(kProxyRoutingId + 1, true, replication_state);
799 EXPECT_TRUE(web_frame->lastChild()->isWebRemoteFrame());
800 EXPECT_TRUE(web_frame->lastChild()->securityOrigin().isUnique());
803 // Verify that DidFlushPaint doesn't crash if called after a RenderView is
804 // swapped out. See https://crbug.com/513552.
805 TEST_F(RenderViewImplTest, PaintAfterSwapOut) {
806 // Create a new main frame RenderFrame so that we don't interfere with the
807 // shutdown of frame() in RenderViewTest.TearDown.
808 blink::WebURLRequest popup_request(GURL("http://foo.com"));
809 blink::WebView* new_web_view = view()->createView(
810 GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
811 blink::WebNavigationPolicyNewForegroundTab, false);
812 RenderViewImpl* new_view = RenderViewImpl::FromWebView(new_web_view);
814 // Respond to a swap out request.
815 TestRenderFrame* new_main_frame =
816 static_cast<TestRenderFrame*>(new_view->GetMainRenderFrame());
817 new_main_frame->SwapOut(kProxyRoutingId, true,
818 content::FrameReplicationState());
820 // Simulate getting painted after swapping out.
821 new_view->DidFlushPaint();
823 new_view->Close();
824 new_view->Release();
827 // Test that we get the correct UpdateState message when we go back twice
828 // quickly without committing. Regression test for http://crbug.com/58082.
829 // Disabled: http://crbug.com/157357 .
830 TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) {
831 // Load page A.
832 LoadHTML("<div>Page A</div>");
834 // Load page B, which will trigger an UpdateState message for page A.
835 LoadHTML("<div>Page B</div>");
837 // Check for a valid UpdateState message for page A.
838 ProcessPendingMessages();
839 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
840 ViewHostMsg_UpdateState::ID);
841 ASSERT_TRUE(msg_A);
842 ViewHostMsg_UpdateState::Param param;
843 ViewHostMsg_UpdateState::Read(msg_A, &param);
844 int page_id_A = base::get<0>(param);
845 PageState state_A = base::get<1>(param);
846 EXPECT_EQ(1, page_id_A);
847 render_thread_->sink().ClearMessages();
849 // Load page C, which will trigger an UpdateState message for page B.
850 LoadHTML("<div>Page C</div>");
852 // Check for a valid UpdateState for page B.
853 ProcessPendingMessages();
854 const IPC::Message* msg_B = render_thread_->sink().GetUniqueMessageMatching(
855 ViewHostMsg_UpdateState::ID);
856 ASSERT_TRUE(msg_B);
857 ViewHostMsg_UpdateState::Read(msg_B, &param);
858 int page_id_B = base::get<0>(param);
859 PageState state_B = base::get<1>(param);
860 EXPECT_EQ(2, page_id_B);
861 EXPECT_NE(state_A, state_B);
862 render_thread_->sink().ClearMessages();
864 // Load page D, which will trigger an UpdateState message for page C.
865 LoadHTML("<div>Page D</div>");
867 // Check for a valid UpdateState for page C.
868 ProcessPendingMessages();
869 const IPC::Message* msg_C = render_thread_->sink().GetUniqueMessageMatching(
870 ViewHostMsg_UpdateState::ID);
871 ASSERT_TRUE(msg_C);
872 ViewHostMsg_UpdateState::Read(msg_C, &param);
873 int page_id_C = base::get<0>(param);
874 PageState state_C = base::get<1>(param);
875 EXPECT_EQ(3, page_id_C);
876 EXPECT_NE(state_B, state_C);
877 render_thread_->sink().ClearMessages();
879 // Go back to C and commit, preparing for our real test.
880 CommonNavigationParams common_params_C;
881 RequestNavigationParams request_params_C;
882 common_params_C.navigation_type = FrameMsg_Navigate_Type::NORMAL;
883 common_params_C.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
884 request_params_C.current_history_list_length = 4;
885 request_params_C.current_history_list_offset = 3;
886 request_params_C.pending_history_list_offset = 2;
887 request_params_C.page_id = 3;
888 request_params_C.page_state = state_C;
889 frame()->Navigate(common_params_C, StartNavigationParams(), request_params_C);
890 ProcessPendingMessages();
891 render_thread_->sink().ClearMessages();
893 // Go back twice quickly, such that page B does not have a chance to commit.
894 // This leads to two changes to the back/forward list but only one change to
895 // the RenderView's page ID.
897 // Back to page B (page_id 2), without committing.
898 CommonNavigationParams common_params_B;
899 RequestNavigationParams request_params_B;
900 common_params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
901 common_params_B.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
902 request_params_B.current_history_list_length = 4;
903 request_params_B.current_history_list_offset = 2;
904 request_params_B.pending_history_list_offset = 1;
905 request_params_B.page_id = 2;
906 request_params_B.page_state = state_B;
907 frame()->Navigate(common_params_B, StartNavigationParams(), request_params_B);
909 // Back to page A (page_id 1) and commit.
910 CommonNavigationParams common_params;
911 RequestNavigationParams request_params;
912 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
913 common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
914 request_params.current_history_list_length = 4;
915 request_params.current_history_list_offset = 2;
916 request_params.pending_history_list_offset = 0;
917 request_params.page_id = 1;
918 request_params.page_state = state_A;
919 frame()->Navigate(common_params, StartNavigationParams(), request_params);
920 ProcessPendingMessages();
922 // Now ensure that the UpdateState message we receive is consistent
923 // and represents page C in both page_id and state.
924 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
925 ViewHostMsg_UpdateState::ID);
926 ASSERT_TRUE(msg);
927 ViewHostMsg_UpdateState::Read(msg, &param);
928 int page_id = base::get<0>(param);
929 PageState state = base::get<1>(param);
930 EXPECT_EQ(page_id_C, page_id);
931 EXPECT_NE(state_A, state);
932 EXPECT_NE(state_B, state);
933 EXPECT_EQ(state_C, state);
936 // Test that our IME backend sends a notification message when the input focus
937 // changes.
938 TEST_F(RenderViewImplTest, OnImeTypeChanged) {
939 // Load an HTML page consisting of two input fields.
940 view()->set_send_content_state_immediately(true);
941 LoadHTML("<html>"
942 "<head>"
943 "</head>"
944 "<body>"
945 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
946 "<input id=\"test2\" type=\"password\"></input>"
947 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
948 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
949 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
950 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
951 "</input>"
952 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
953 "</input>"
954 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
955 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
956 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
957 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
958 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
959 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
960 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
961 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
962 "</body>"
963 "</html>");
964 render_thread_->sink().ClearMessages();
966 struct InputModeTestCase {
967 const char* input_id;
968 ui::TextInputMode expected_mode;
970 static const InputModeTestCase kInputModeTestCases[] = {
971 {"test1", ui::TEXT_INPUT_MODE_DEFAULT},
972 {"test3", ui::TEXT_INPUT_MODE_VERBATIM},
973 {"test4", ui::TEXT_INPUT_MODE_LATIN},
974 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME},
975 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE},
976 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN},
977 {"test8", ui::TEXT_INPUT_MODE_KANA},
978 {"test9", ui::TEXT_INPUT_MODE_KATAKANA},
979 {"test10", ui::TEXT_INPUT_MODE_NUMERIC},
980 {"test11", ui::TEXT_INPUT_MODE_TEL},
981 {"test12", ui::TEXT_INPUT_MODE_EMAIL},
982 {"test13", ui::TEXT_INPUT_MODE_URL},
983 {"test14", ui::TEXT_INPUT_MODE_DEFAULT},
984 {"test15", ui::TEXT_INPUT_MODE_VERBATIM},
987 const int kRepeatCount = 10;
988 for (int i = 0; i < kRepeatCount; i++) {
989 // Move the input focus to the first <input> element, where we should
990 // activate IMEs.
991 ExecuteJavaScriptForTests("document.getElementById('test1').focus();");
992 ProcessPendingMessages();
993 render_thread_->sink().ClearMessages();
995 // Update the IME status and verify if our IME backend sends an IPC message
996 // to activate IMEs.
997 view()->UpdateTextInputState(
998 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
999 const IPC::Message* msg = render_thread_->sink().GetMessageAt(0);
1000 EXPECT_TRUE(msg != NULL);
1001 EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type());
1002 ViewHostMsg_TextInputStateChanged::Param params;
1003 ViewHostMsg_TextInputStateChanged::Read(msg, &params);
1004 ViewHostMsg_TextInputState_Params p = base::get<0>(params);
1005 ui::TextInputType type = p.type;
1006 ui::TextInputMode input_mode = p.mode;
1007 bool can_compose_inline = p.can_compose_inline;
1008 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, type);
1009 EXPECT_EQ(true, can_compose_inline);
1011 // Move the input focus to the second <input> element, where we should
1012 // de-activate IMEs.
1013 ExecuteJavaScriptForTests("document.getElementById('test2').focus();");
1014 ProcessPendingMessages();
1015 render_thread_->sink().ClearMessages();
1017 // Update the IME status and verify if our IME backend sends an IPC message
1018 // to de-activate IMEs.
1019 view()->UpdateTextInputState(
1020 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
1021 msg = render_thread_->sink().GetMessageAt(0);
1022 EXPECT_TRUE(msg != NULL);
1023 EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type());
1024 ViewHostMsg_TextInputStateChanged::Read(msg, &params);
1025 p = base::get<0>(params);
1026 type = p.type;
1027 input_mode = p.mode;
1028 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, type);
1030 for (size_t i = 0; i < arraysize(kInputModeTestCases); i++) {
1031 const InputModeTestCase* test_case = &kInputModeTestCases[i];
1032 std::string javascript =
1033 base::StringPrintf("document.getElementById('%s').focus();",
1034 test_case->input_id);
1035 // Move the input focus to the target <input> element, where we should
1036 // activate IMEs.
1037 ExecuteJavaScriptAndReturnIntValue(base::ASCIIToUTF16(javascript), NULL);
1038 ProcessPendingMessages();
1039 render_thread_->sink().ClearMessages();
1041 // Update the IME status and verify if our IME backend sends an IPC
1042 // message to activate IMEs.
1043 view()->UpdateTextInputState(
1044 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
1045 const IPC::Message* msg = render_thread_->sink().GetMessageAt(0);
1046 EXPECT_TRUE(msg != NULL);
1047 EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type());
1048 ViewHostMsg_TextInputStateChanged::Read(msg, &params);
1049 p = base::get<0>(params);
1050 type = p.type;
1051 input_mode = p.mode;
1052 EXPECT_EQ(test_case->expected_mode, input_mode);
1057 // Test that our IME backend can compose CJK words.
1058 // Our IME front-end sends many platform-independent messages to the IME backend
1059 // while it composes CJK words. This test sends the minimal messages captured
1060 // on my local environment directly to the IME backend to verify if the backend
1061 // can compose CJK words without any problems.
1062 // This test uses an array of command sets because an IME composotion does not
1063 // only depends on IME events, but also depends on window events, e.g. moving
1064 // the window focus while composing a CJK text. To handle such complicated
1065 // cases, this test should not only call IME-related functions in the
1066 // RenderWidget class, but also call some RenderWidget members, e.g.
1067 // ExecuteJavaScriptForTests(), RenderWidget::OnSetFocus(), etc.
1068 TEST_F(RenderViewImplTest, ImeComposition) {
1069 enum ImeCommand {
1070 IME_INITIALIZE,
1071 IME_SETINPUTMODE,
1072 IME_SETFOCUS,
1073 IME_SETCOMPOSITION,
1074 IME_CONFIRMCOMPOSITION,
1075 IME_CANCELCOMPOSITION
1077 struct ImeMessage {
1078 ImeCommand command;
1079 bool enable;
1080 int selection_start;
1081 int selection_end;
1082 const wchar_t* ime_string;
1083 const wchar_t* result;
1085 static const ImeMessage kImeMessages[] = {
1086 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
1087 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1088 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1089 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1090 {IME_SETCOMPOSITION, false, 1, 1, L"n", L"n"},
1091 {IME_SETCOMPOSITION, false, 2, 2, L"ni", L"ni"},
1092 {IME_SETCOMPOSITION, false, 3, 3, L"nih", L"nih"},
1093 {IME_SETCOMPOSITION, false, 4, 4, L"niha", L"niha"},
1094 {IME_SETCOMPOSITION, false, 5, 5, L"nihao", L"nihao"},
1095 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"\x4F60\x597D", L"\x4F60\x597D"},
1096 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
1097 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1098 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1099 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1100 {IME_SETCOMPOSITION, false, 0, 1, L"\xFF4B", L"\xFF4B"},
1101 {IME_SETCOMPOSITION, false, 0, 1, L"\x304B", L"\x304B"},
1102 {IME_SETCOMPOSITION, false, 0, 2, L"\x304B\xFF4E", L"\x304B\xFF4E"},
1103 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\xFF4A",
1104 L"\x304B\x3093\xFF4A"},
1105 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\x3058",
1106 L"\x304B\x3093\x3058"},
1107 {IME_SETCOMPOSITION, false, 0, 2, L"\x611F\x3058", L"\x611F\x3058"},
1108 {IME_SETCOMPOSITION, false, 0, 2, L"\x6F22\x5B57", L"\x6F22\x5B57"},
1109 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1110 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1111 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1112 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1113 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1114 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1115 {IME_SETCOMPOSITION, false, 0, 1, L"\x3147", L"\x3147"},
1116 {IME_SETCOMPOSITION, false, 0, 1, L"\xC544", L"\xC544"},
1117 {IME_SETCOMPOSITION, false, 0, 1, L"\xC548", L"\xC548"},
1118 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1119 {IME_SETCOMPOSITION, false, 0, 1, L"\x3134", L"\xC548\x3134"},
1120 {IME_SETCOMPOSITION, false, 0, 1, L"\xB140", L"\xC548\xB140"},
1121 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1122 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1123 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1124 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548\xB155"},
1127 for (size_t i = 0; i < arraysize(kImeMessages); i++) {
1128 const ImeMessage* ime_message = &kImeMessages[i];
1129 switch (ime_message->command) {
1130 case IME_INITIALIZE:
1131 // Load an HTML page consisting of a content-editable <div> element,
1132 // and move the input focus to the <div> element, where we can use
1133 // IMEs.
1134 view()->set_send_content_state_immediately(true);
1135 LoadHTML("<html>"
1136 "<head>"
1137 "</head>"
1138 "<body>"
1139 "<div id=\"test1\" contenteditable=\"true\"></div>"
1140 "</body>"
1141 "</html>");
1142 ExecuteJavaScriptForTests("document.getElementById('test1').focus();");
1143 break;
1145 case IME_SETINPUTMODE:
1146 break;
1148 case IME_SETFOCUS:
1149 // Update the window focus.
1150 view()->OnSetFocus(ime_message->enable);
1151 break;
1153 case IME_SETCOMPOSITION:
1154 view()->OnImeSetComposition(
1155 base::WideToUTF16(ime_message->ime_string),
1156 std::vector<blink::WebCompositionUnderline>(),
1157 ime_message->selection_start,
1158 ime_message->selection_end);
1159 break;
1161 case IME_CONFIRMCOMPOSITION:
1162 view()->OnImeConfirmComposition(
1163 base::WideToUTF16(ime_message->ime_string),
1164 gfx::Range::InvalidRange(),
1165 false);
1166 break;
1168 case IME_CANCELCOMPOSITION:
1169 view()->OnImeSetComposition(
1170 base::string16(),
1171 std::vector<blink::WebCompositionUnderline>(),
1172 0, 0);
1173 break;
1176 // Update the status of our IME back-end.
1177 // TODO(hbono): we should verify messages to be sent from the back-end.
1178 view()->UpdateTextInputState(
1179 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
1180 ProcessPendingMessages();
1181 render_thread_->sink().ClearMessages();
1183 if (ime_message->result) {
1184 // Retrieve the content of this page and compare it with the expected
1185 // result.
1186 const int kMaxOutputCharacters = 128;
1187 base::string16 output =
1188 GetMainFrame()->contentAsText(kMaxOutputCharacters);
1189 EXPECT_EQ(base::WideToUTF16(ime_message->result), output);
1194 // Test that the RenderView::OnSetTextDirection() function can change the text
1195 // direction of the selected input element.
1196 TEST_F(RenderViewImplTest, OnSetTextDirection) {
1197 // Load an HTML page consisting of a <textarea> element and a <div> element.
1198 // This test changes the text direction of the <textarea> element, and
1199 // writes the values of its 'dir' attribute and its 'direction' property to
1200 // verify that the text direction is changed.
1201 view()->set_send_content_state_immediately(true);
1202 LoadHTML("<html>"
1203 "<head>"
1204 "</head>"
1205 "<body>"
1206 "<textarea id=\"test\"></textarea>"
1207 "<div id=\"result\" contenteditable=\"true\"></div>"
1208 "</body>"
1209 "</html>");
1210 render_thread_->sink().ClearMessages();
1212 static const struct {
1213 WebTextDirection direction;
1214 const wchar_t* expected_result;
1215 } kTextDirection[] = {
1216 { blink::WebTextDirectionRightToLeft, L"\x000A" L"rtl,rtl" },
1217 { blink::WebTextDirectionLeftToRight, L"\x000A" L"ltr,ltr" },
1219 for (size_t i = 0; i < arraysize(kTextDirection); ++i) {
1220 // Set the text direction of the <textarea> element.
1221 ExecuteJavaScriptForTests("document.getElementById('test').focus();");
1222 view()->OnSetTextDirection(kTextDirection[i].direction);
1224 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1225 // property to the <div> element.
1226 ExecuteJavaScriptForTests(
1227 "var result = document.getElementById('result');"
1228 "var node = document.getElementById('test');"
1229 "var style = getComputedStyle(node, null);"
1230 "result.innerText ="
1231 " node.getAttribute('dir') + ',' +"
1232 " style.getPropertyValue('direction');");
1234 // Copy the document content to std::wstring and compare with the
1235 // expected result.
1236 const int kMaxOutputCharacters = 16;
1237 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
1238 EXPECT_EQ(base::WideToUTF16(kTextDirection[i].expected_result), output);
1242 // Test that we can receive correct DOM events when we send input events
1243 // through the RenderWidget::OnHandleInputEvent() function.
1244 TEST_F(RenderViewImplTest, OnHandleKeyboardEvent) {
1245 #if !defined(OS_MACOSX)
1246 // Load an HTML page consisting of one <input> element and three
1247 // contentediable <div> elements.
1248 // The <input> element is used for sending keyboard events, and the <div>
1249 // elements are used for writing DOM events in the following format:
1250 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1251 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1252 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1253 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1254 view()->set_send_content_state_immediately(true);
1255 LoadHTML("<html>"
1256 "<head>"
1257 "<title></title>"
1258 "<script type='text/javascript' language='javascript'>"
1259 "function OnKeyEvent(ev) {"
1260 " var result = document.getElementById(ev.type);"
1261 " result.innerText ="
1262 " (ev.which || ev.keyCode) + ',' +"
1263 " ev.shiftKey + ',' +"
1264 " ev.ctrlKey + ',' +"
1265 " ev.altKey;"
1266 " return true;"
1268 "</script>"
1269 "</head>"
1270 "<body>"
1271 "<input id='test' type='text'"
1272 " onkeydown='return OnKeyEvent(event);'"
1273 " onkeypress='return OnKeyEvent(event);'"
1274 " onkeyup='return OnKeyEvent(event);'>"
1275 "</input>"
1276 "<div id='keydown' contenteditable='true'>"
1277 "</div>"
1278 "<div id='keypress' contenteditable='true'>"
1279 "</div>"
1280 "<div id='keyup' contenteditable='true'>"
1281 "</div>"
1282 "</body>"
1283 "</html>");
1284 ExecuteJavaScriptForTests("document.getElementById('test').focus();");
1285 render_thread_->sink().ClearMessages();
1287 static const MockKeyboard::Layout kLayouts[] = {
1288 #if defined(OS_WIN)
1289 // Since we ignore the mock keyboard layout on Linux and instead just use
1290 // the screen's keyboard layout, these trivially pass. They are commented
1291 // out to avoid the illusion that they work.
1292 MockKeyboard::LAYOUT_ARABIC,
1293 MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1294 MockKeyboard::LAYOUT_FRENCH,
1295 MockKeyboard::LAYOUT_HEBREW,
1296 MockKeyboard::LAYOUT_RUSSIAN,
1297 #endif
1298 MockKeyboard::LAYOUT_UNITED_STATES,
1301 for (size_t i = 0; i < arraysize(kLayouts); ++i) {
1302 // For each key code, we send three keyboard events.
1303 // * we press only the key;
1304 // * we press the key and a left-shift key, and;
1305 // * we press the key and a right-alt (AltGr) key.
1306 // For each modifiers, we need a string used for formatting its expected
1307 // result. (See the above comment for its format.)
1308 static const struct {
1309 MockKeyboard::Modifiers modifiers;
1310 const char* expected_result;
1311 } kModifierData[] = {
1312 {MockKeyboard::NONE, "false,false,false"},
1313 {MockKeyboard::LEFT_SHIFT, "true,false,false"},
1314 #if defined(OS_WIN)
1315 {MockKeyboard::RIGHT_ALT, "false,false,true"},
1316 #endif
1319 MockKeyboard::Layout layout = kLayouts[i];
1320 for (size_t j = 0; j < arraysize(kModifierData); ++j) {
1321 // Virtual key codes used for this test.
1322 static const int kKeyCodes[] = {
1323 '0', '1', '2', '3', '4', '5', '6', '7',
1324 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1325 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1326 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1327 'W', 'X', 'Y', 'Z',
1328 ui::VKEY_OEM_1,
1329 ui::VKEY_OEM_PLUS,
1330 ui::VKEY_OEM_COMMA,
1331 ui::VKEY_OEM_MINUS,
1332 ui::VKEY_OEM_PERIOD,
1333 ui::VKEY_OEM_2,
1334 ui::VKEY_OEM_3,
1335 ui::VKEY_OEM_4,
1336 ui::VKEY_OEM_5,
1337 ui::VKEY_OEM_6,
1338 ui::VKEY_OEM_7,
1339 #if defined(OS_WIN)
1340 // Not sure how to handle this key on Linux.
1341 ui::VKEY_OEM_8,
1342 #endif
1345 MockKeyboard::Modifiers modifiers = kModifierData[j].modifiers;
1346 for (size_t k = 0; k < arraysize(kKeyCodes); ++k) {
1347 // Send a keyboard event to the RenderView object.
1348 // We should test a keyboard event only when the given keyboard-layout
1349 // driver is installed in a PC and the driver can assign a Unicode
1350 // charcter for the given tuple (key-code and modifiers).
1351 int key_code = kKeyCodes[k];
1352 base::string16 char_code;
1353 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1354 continue;
1356 // Create an expected result from the virtual-key code, the character
1357 // code, and the modifier-key status.
1358 // We format a string that emulates a DOM-event string produced hy
1359 // our JavaScript function. (See the above comment for the format.)
1360 static char expected_result[1024];
1361 expected_result[0] = 0;
1362 base::snprintf(&expected_result[0],
1363 sizeof(expected_result),
1364 "\n" // texts in the <input> element
1365 "%d,%s\n" // texts in the first <div> element
1366 "%d,%s\n" // texts in the second <div> element
1367 "%d,%s", // texts in the third <div> element
1368 key_code, kModifierData[j].expected_result,
1369 static_cast<int>(char_code[0]),
1370 kModifierData[j].expected_result,
1371 key_code, kModifierData[j].expected_result);
1373 // Retrieve the text in the test page and compare it with the expected
1374 // text created from a virtual-key code, a character code, and the
1375 // modifier-key status.
1376 const int kMaxOutputCharacters = 1024;
1377 std::string output = base::UTF16ToUTF8(base::StringPiece16(
1378 GetMainFrame()->contentAsText(kMaxOutputCharacters)));
1379 EXPECT_EQ(expected_result, output);
1383 #else
1384 NOTIMPLEMENTED();
1385 #endif
1388 // Test that our EditorClientImpl class can insert characters when we send
1389 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1390 // This test is for preventing regressions caused only when we use non-US
1391 // keyboards, such as Issue 10846.
1392 // see http://crbug.com/244562
1393 #if defined(OS_WIN)
1394 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1395 #else
1396 #define MAYBE_InsertCharacters InsertCharacters
1397 #endif
1398 TEST_F(RenderViewImplTest, MAYBE_InsertCharacters) {
1399 #if !defined(OS_MACOSX)
1400 static const struct {
1401 MockKeyboard::Layout layout;
1402 const wchar_t* expected_result;
1403 } kLayouts[] = {
1404 #if 0
1405 // Disabled these keyboard layouts because buildbots do not have their
1406 // keyboard-layout drivers installed.
1407 {MockKeyboard::LAYOUT_ARABIC,
1408 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1409 L"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1410 L"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1411 L"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1412 L"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1413 L"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1414 L"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1415 L"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1416 L"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1417 L"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1418 L"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1419 L"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1420 L"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1421 L"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1422 L"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1423 L"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1424 L"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1426 {MockKeyboard::LAYOUT_HEBREW,
1427 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1428 L"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1429 L"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1430 L"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1431 L"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1432 L"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1433 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1434 L"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1435 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1436 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1437 L"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1438 L"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1439 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1440 L"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1441 L"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1442 L"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1443 L"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1444 L"\x003b\x005d\x005c\x005b\x002c"
1446 #endif
1447 #if defined(OS_WIN)
1448 // On Linux, the only way to test alternate keyboard layouts is to change
1449 // the keyboard layout of the whole screen. I'm worried about the side
1450 // effects this may have on the buildbots.
1451 {MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1452 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1453 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1454 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1455 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1456 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1457 L"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1458 L"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1459 L"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1460 L"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1461 L"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1462 L"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1463 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1464 L"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1465 L"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1466 L"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1467 L"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1468 L"\x003c"
1470 {MockKeyboard::LAYOUT_FRENCH,
1471 L"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1472 L"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1473 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1474 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1475 L"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1476 L"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1477 L"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1478 L"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1479 L"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1480 L"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1481 L"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1482 L"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1483 L"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1484 L"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1485 L"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1486 L"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1487 L"\x003b\x003a\x00f9\x0029\x002a\x0021"
1489 {MockKeyboard::LAYOUT_RUSSIAN,
1490 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1491 L"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1492 L"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1493 L"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1494 L"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1495 L"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1496 L"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1497 L"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1498 L"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1499 L"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1500 L"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1501 L"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1502 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1503 L"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1504 L"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1505 L"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1506 L"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1507 L"\x0451\x0445\x005c\x044a\x044d"
1509 #endif // defined(OS_WIN)
1510 {MockKeyboard::LAYOUT_UNITED_STATES,
1511 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1512 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1513 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1514 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1515 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1516 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1517 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1518 L"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1519 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1520 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1521 L"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1522 L"\x003f\x007e\x007b\x007c\x007d\x0022"
1523 #if defined(OS_WIN)
1524 // This is ifdefed out for Linux to correspond to the fact that we don't
1525 // test alt+keystroke for now.
1526 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1527 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1528 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1529 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1530 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1531 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1532 #endif
1536 for (size_t i = 0; i < arraysize(kLayouts); ++i) {
1537 // Load an HTML page consisting of one <div> element.
1538 // This <div> element is used by the EditorClientImpl class to insert
1539 // characters received through the RenderWidget::OnHandleInputEvent()
1540 // function.
1541 view()->set_send_content_state_immediately(true);
1542 LoadHTML("<html>"
1543 "<head>"
1544 "<title></title>"
1545 "</head>"
1546 "<body>"
1547 "<div id='test' contenteditable='true'>"
1548 "</div>"
1549 "</body>"
1550 "</html>");
1551 ExecuteJavaScriptForTests("document.getElementById('test').focus();");
1552 render_thread_->sink().ClearMessages();
1554 // For each key code, we send three keyboard events.
1555 // * Pressing only the key;
1556 // * Pressing the key and a left-shift key, and;
1557 // * Pressing the key and a right-alt (AltGr) key.
1558 static const MockKeyboard::Modifiers kModifiers[] = {
1559 MockKeyboard::NONE,
1560 MockKeyboard::LEFT_SHIFT,
1561 #if defined(OS_WIN)
1562 MockKeyboard::RIGHT_ALT,
1563 #endif
1566 MockKeyboard::Layout layout = kLayouts[i].layout;
1567 for (size_t j = 0; j < arraysize(kModifiers); ++j) {
1568 // Virtual key codes used for this test.
1569 static const int kKeyCodes[] = {
1570 '0', '1', '2', '3', '4', '5', '6', '7',
1571 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1572 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1573 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1574 'W', 'X', 'Y', 'Z',
1575 ui::VKEY_OEM_1,
1576 ui::VKEY_OEM_PLUS,
1577 ui::VKEY_OEM_COMMA,
1578 ui::VKEY_OEM_MINUS,
1579 ui::VKEY_OEM_PERIOD,
1580 ui::VKEY_OEM_2,
1581 ui::VKEY_OEM_3,
1582 ui::VKEY_OEM_4,
1583 ui::VKEY_OEM_5,
1584 ui::VKEY_OEM_6,
1585 ui::VKEY_OEM_7,
1586 #if defined(OS_WIN)
1587 // Unclear how to handle this on Linux.
1588 ui::VKEY_OEM_8,
1589 #endif
1592 MockKeyboard::Modifiers modifiers = kModifiers[j];
1593 for (size_t k = 0; k < arraysize(kKeyCodes); ++k) {
1594 // Send a keyboard event to the RenderView object.
1595 // We should test a keyboard event only when the given keyboard-layout
1596 // driver is installed in a PC and the driver can assign a Unicode
1597 // charcter for the given tuple (layout, key-code, and modifiers).
1598 int key_code = kKeyCodes[k];
1599 base::string16 char_code;
1600 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1601 continue;
1605 // Retrieve the text in the test page and compare it with the expected
1606 // text created from a virtual-key code, a character code, and the
1607 // modifier-key status.
1608 const int kMaxOutputCharacters = 4096;
1609 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
1610 EXPECT_EQ(base::WideToUTF16(kLayouts[i].expected_result), output);
1612 #else
1613 NOTIMPLEMENTED();
1614 #endif
1617 // Crashy, http://crbug.com/53247.
1618 TEST_F(RenderViewImplTest, DISABLED_DidFailProvisionalLoadWithErrorForError) {
1619 GetMainFrame()->enableViewSourceMode(true);
1620 WebURLError error;
1621 error.domain = WebString::fromUTF8(net::kErrorDomain);
1622 error.reason = net::ERR_FILE_NOT_FOUND;
1623 error.unreachableURL = GURL("http://foo");
1624 WebLocalFrame* web_frame = GetMainFrame();
1626 // Start a load that will reach provisional state synchronously,
1627 // but won't complete synchronously.
1628 CommonNavigationParams common_params;
1629 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1630 common_params.url = GURL("data:text/html,test data");
1631 frame()->Navigate(common_params, StartNavigationParams(),
1632 RequestNavigationParams());
1634 // An error occurred.
1635 view()->GetMainRenderFrame()->didFailProvisionalLoad(
1636 web_frame, error, blink::WebStandardCommit);
1637 // Frame should exit view-source mode.
1638 EXPECT_FALSE(web_frame->isViewSourceModeEnabled());
1641 TEST_F(RenderViewImplTest, DidFailProvisionalLoadWithErrorForCancellation) {
1642 GetMainFrame()->enableViewSourceMode(true);
1643 WebURLError error;
1644 error.domain = WebString::fromUTF8(net::kErrorDomain);
1645 error.reason = net::ERR_ABORTED;
1646 error.unreachableURL = GURL("http://foo");
1647 WebLocalFrame* web_frame = GetMainFrame();
1649 // Start a load that will reach provisional state synchronously,
1650 // but won't complete synchronously.
1651 CommonNavigationParams common_params;
1652 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1653 common_params.url = GURL("data:text/html,test data");
1654 frame()->Navigate(common_params, StartNavigationParams(),
1655 RequestNavigationParams());
1657 // A cancellation occurred.
1658 view()->GetMainRenderFrame()->didFailProvisionalLoad(
1659 web_frame, error, blink::WebStandardCommit);
1660 // Frame should stay in view-source mode.
1661 EXPECT_TRUE(web_frame->isViewSourceModeEnabled());
1664 // Regression test for http://crbug.com/41562
1665 TEST_F(RenderViewImplTest, UpdateTargetURLWithInvalidURL) {
1666 const GURL invalid_gurl("http://");
1667 view()->setMouseOverURL(blink::WebURL(invalid_gurl));
1668 EXPECT_EQ(invalid_gurl, view()->target_url_);
1671 TEST_F(RenderViewImplTest, SetHistoryLengthAndOffset) {
1672 // No history to merge; one committed page.
1673 view()->OnSetHistoryOffsetAndLength(0, 1);
1674 EXPECT_EQ(1, view()->history_list_length_);
1675 EXPECT_EQ(0, view()->history_list_offset_);
1677 // History of length 1 to merge; one committed page.
1678 view()->OnSetHistoryOffsetAndLength(1, 2);
1679 EXPECT_EQ(2, view()->history_list_length_);
1680 EXPECT_EQ(1, view()->history_list_offset_);
1683 TEST_F(RenderViewImplTest, ContextMenu) {
1684 LoadHTML("<div>Page A</div>");
1686 // Create a right click in the center of the iframe. (I'm hoping this will
1687 // make this a bit more robust in case of some other formatting or other bug.)
1688 WebMouseEvent mouse_event;
1689 mouse_event.type = WebInputEvent::MouseDown;
1690 mouse_event.button = WebMouseEvent::ButtonRight;
1691 mouse_event.x = 250;
1692 mouse_event.y = 250;
1693 mouse_event.globalX = 250;
1694 mouse_event.globalY = 250;
1696 SendWebMouseEvent(mouse_event);
1698 // Now simulate the corresponding up event which should display the menu
1699 mouse_event.type = WebInputEvent::MouseUp;
1700 SendWebMouseEvent(mouse_event);
1702 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
1703 FrameHostMsg_ContextMenu::ID));
1706 TEST_F(RenderViewImplTest, TestBackForward) {
1707 LoadHTML("<div id=pagename>Page A</div>");
1708 PageState page_a_state =
1709 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1710 int was_page_a = -1;
1711 base::string16 check_page_a =
1712 base::ASCIIToUTF16(
1713 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1714 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1715 EXPECT_EQ(1, was_page_a);
1717 LoadHTML("<div id=pagename>Page B</div>");
1718 int was_page_b = -1;
1719 base::string16 check_page_b =
1720 base::ASCIIToUTF16(
1721 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1722 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1723 EXPECT_EQ(1, was_page_b);
1725 PageState back_state =
1726 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1728 LoadHTML("<div id=pagename>Page C</div>");
1729 int was_page_c = -1;
1730 base::string16 check_page_c =
1731 base::ASCIIToUTF16(
1732 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1733 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1734 EXPECT_EQ(1, was_page_c);
1736 PageState forward_state =
1737 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1738 GoBack(back_state);
1739 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1740 EXPECT_EQ(1, was_page_b);
1742 PageState back_state2 =
1743 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1745 GoForward(forward_state);
1746 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1747 EXPECT_EQ(1, was_page_c);
1749 GoBack(back_state2);
1750 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1751 EXPECT_EQ(1, was_page_b);
1753 forward_state =
1754 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1755 GoBack(page_a_state);
1756 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1757 EXPECT_EQ(1, was_page_a);
1759 GoForward(forward_state);
1760 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1761 EXPECT_EQ(1, was_page_b);
1764 #if defined(OS_MACOSX) || defined(USE_AURA)
1765 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_EQ(blink::WebSettings::HoverTypeNone, settings()->primaryHoverType());
2371 EXPECT_FALSE(settings()->viewportEnabled());
2374 TEST_F(RenderViewImplBlinkSettingsTest, CommandLine) {
2375 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
2376 switches::kBlinkSettings, "primaryHoverType=4,viewportEnabled=true");
2377 DoSetUp();
2378 EXPECT_EQ(blink::WebSettings::HoverTypeHover, settings()->primaryHoverType());
2379 EXPECT_TRUE(settings()->viewportEnabled());
2382 TEST_F(DevToolsAgentTest, DevToolsResumeOnClose) {
2383 Attach();
2384 EXPECT_FALSE(IsPaused());
2385 DispatchDevToolsMessage("{\"id\":1,\"method\":\"Debugger.enable\"}");
2387 // Executing javascript will pause the thread and create nested message loop.
2388 // Posting task simulates message coming from browser.
2389 base::ThreadTaskRunnerHandle::Get()->PostTask(
2390 FROM_HERE,
2391 base::Bind(&DevToolsAgentTest::CloseWhilePaused, base::Unretained(this)));
2392 ExecuteJavaScriptForTests("debugger;");
2394 // CloseWhilePaused should resume execution and continue here.
2395 EXPECT_FALSE(IsPaused());
2396 Detach();
2399 } // namespace content