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