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