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/ssl_status_serialization.h"
20 #include "content/common/view_messages.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/native_web_keyboard_event.h"
23 #include "content/public/browser/web_ui_controller_factory.h"
24 #include "content/public/common/bindings_policy.h"
25 #include "content/public/common/content_switches.h"
26 #include "content/public/common/page_zoom.h"
27 #include "content/public/common/url_constants.h"
28 #include "content/public/common/url_utils.h"
29 #include "content/public/renderer/content_renderer_client.h"
30 #include "content/public/renderer/document_state.h"
31 #include "content/public/renderer/navigation_state.h"
32 #include "content/public/test/browser_test_utils.h"
33 #include "content/public/test/frame_load_waiter.h"
34 #include "content/public/test/render_view_test.h"
35 #include "content/public/test/test_utils.h"
36 #include "content/renderer/accessibility/renderer_accessibility.h"
37 #include "content/renderer/devtools/devtools_agent.h"
38 #include "content/renderer/history_controller.h"
39 #include "content/renderer/history_serialization.h"
40 #include "content/renderer/navigation_state_impl.h"
41 #include "content/renderer/render_process.h"
42 #include "content/renderer/render_view_impl.h"
43 #include "content/shell/browser/shell.h"
44 #include "content/shell/browser/shell_browser_context.h"
45 #include "content/test/mock_keyboard.h"
46 #include "content/test/test_render_frame.h"
47 #include "net/base/net_errors.h"
48 #include "net/cert/cert_status_flags.h"
49 #include "testing/gtest/include/gtest/gtest.h"
50 #include "third_party/WebKit/public/platform/WebData.h"
51 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
52 #include "third_party/WebKit/public/platform/WebString.h"
53 #include "third_party/WebKit/public/platform/WebURLResponse.h"
54 #include "third_party/WebKit/public/web/WebDataSource.h"
55 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
56 #include "third_party/WebKit/public/web/WebHistoryCommitType.h"
57 #include "third_party/WebKit/public/web/WebHistoryItem.h"
58 #include "third_party/WebKit/public/web/WebLocalFrame.h"
59 #include "third_party/WebKit/public/web/WebPerformance.h"
60 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
61 #include "third_party/WebKit/public/web/WebSettings.h"
62 #include "third_party/WebKit/public/web/WebView.h"
63 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
64 #include "ui/events/event.h"
65 #include "ui/events/keycodes/keyboard_codes.h"
66 #include "ui/gfx/codec/jpeg_codec.h"
67 #include "ui/gfx/range/range.h"
69 #if defined(USE_AURA) && defined(USE_X11)
71 #include "ui/events/event_constants.h"
72 #include "ui/events/keycodes/keyboard_code_conversion.h"
73 #include "ui/events/test/events_test_utils.h"
74 #include "ui/events/test/events_test_utils_x11.h"
77 #if defined(USE_OZONE)
78 #include "ui/events/keycodes/keyboard_code_conversion.h"
81 using blink::WebFrame
;
82 using blink::WebInputEvent
;
83 using blink::WebLocalFrame
;
84 using blink::WebMouseEvent
;
85 using blink::WebRuntimeFeatures
;
86 using blink::WebString
;
87 using blink::WebTextDirection
;
88 using blink::WebURLError
;
94 static const int kProxyRoutingId
= 13;
96 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
97 // Converts MockKeyboard::Modifiers to ui::EventFlags.
98 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers
) {
99 static struct ModifierMap
{
100 MockKeyboard::Modifiers src
;
103 { MockKeyboard::LEFT_SHIFT
, ui::EF_SHIFT_DOWN
},
104 { MockKeyboard::RIGHT_SHIFT
, ui::EF_SHIFT_DOWN
},
105 { MockKeyboard::LEFT_CONTROL
, ui::EF_CONTROL_DOWN
},
106 { MockKeyboard::RIGHT_CONTROL
, ui::EF_CONTROL_DOWN
},
107 { MockKeyboard::LEFT_ALT
, ui::EF_ALT_DOWN
},
108 { MockKeyboard::RIGHT_ALT
, ui::EF_ALT_DOWN
},
111 for (size_t i
= 0; i
< arraysize(kModifierMap
); ++i
) {
112 if (kModifierMap
[i
].src
& modifiers
) {
113 flags
|= kModifierMap
[i
].dst
;
120 class WebUITestWebUIControllerFactory
: public WebUIControllerFactory
{
122 WebUIController
* CreateWebUIControllerForURL(WebUI
* web_ui
,
123 const GURL
& url
) const override
{
126 WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
127 const GURL
& url
) const override
{
128 return WebUI::kNoWebUI
;
130 bool UseWebUIForURL(BrowserContext
* browser_context
,
131 const GURL
& url
) const override
{
132 return HasWebUIScheme(url
);
134 bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
135 const GURL
& url
) const override
{
136 return HasWebUIScheme(url
);
142 class RenderViewImplTest
: public RenderViewTest
{
144 RenderViewImplTest() {
145 // Attach a pseudo keyboard device to this object.
146 mock_keyboard_
.reset(new MockKeyboard());
149 ~RenderViewImplTest() override
{}
151 void SetUp() override
{
152 // Enable Blink's experimental and test only features so that test code
153 // does not have to bother enabling each feature.
154 WebRuntimeFeatures::enableExperimentalFeatures(true);
155 WebRuntimeFeatures::enableTestOnlyFeatures(true);
156 RenderViewTest::SetUp();
159 RenderViewImpl
* view() {
160 return static_cast<RenderViewImpl
*>(view_
);
164 return view()->page_id_
;
167 TestRenderFrame
* frame() {
168 return static_cast<TestRenderFrame
*>(view()->GetMainRenderFrame());
171 // Sends IPC messages that emulates a key-press event.
172 int SendKeyEvent(MockKeyboard::Layout layout
,
174 MockKeyboard::Modifiers modifiers
,
175 base::string16
* output
) {
177 // Retrieve the Unicode character for the given tuple (keyboard-layout,
178 // key-code, and modifiers).
179 // Exit when a keyboard-layout driver cannot assign a Unicode character to
180 // the tuple to prevent sending an invalid key code to the RenderView
182 CHECK(mock_keyboard_
.get());
184 int length
= mock_keyboard_
->GetCharacters(layout
, key_code
, modifiers
,
189 // Create IPC messages from Windows messages and send them to our
191 // A keyboard event of Windows consists of three Windows messages:
192 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
193 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
194 // WM_CHAR sends a composed Unicode character.
195 MSG msg1
= { NULL
, WM_KEYDOWN
, key_code
, 0 };
196 ui::KeyEvent
evt1(msg1
);
197 NativeWebKeyboardEvent
keydown_event(evt1
);
198 SendNativeKeyEvent(keydown_event
);
200 MSG msg2
= { NULL
, WM_CHAR
, (*output
)[0], 0 };
201 ui::KeyEvent
evt2(msg2
);
202 NativeWebKeyboardEvent
char_event(evt2
);
203 SendNativeKeyEvent(char_event
);
205 MSG msg3
= { NULL
, WM_KEYUP
, key_code
, 0 };
206 ui::KeyEvent
evt3(msg3
);
207 NativeWebKeyboardEvent
keyup_event(evt3
);
208 SendNativeKeyEvent(keyup_event
);
211 #elif defined(USE_AURA) && defined(USE_X11)
212 // We ignore |layout|, which means we are only testing the layout of the
213 // current locale. TODO(mazda): fix this to respect |layout|.
215 const int flags
= ConvertMockKeyboardModifier(modifiers
);
217 ui::ScopedXI2Event xevent
;
218 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
219 static_cast<ui::KeyboardCode
>(key_code
),
221 ui::KeyEvent
event1(xevent
);
222 NativeWebKeyboardEvent
keydown_event(event1
);
223 SendNativeKeyEvent(keydown_event
);
225 // X11 doesn't actually have native character events, but give the test
227 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
228 static_cast<ui::KeyboardCode
>(key_code
),
230 ui::KeyEvent
event2(xevent
);
231 event2
.set_character(GetCharacterFromKeyCode(event2
.key_code(),
233 ui::KeyEventTestApi
test_event2(&event2
);
234 test_event2
.set_is_char(true);
235 NativeWebKeyboardEvent
char_event(event2
);
236 SendNativeKeyEvent(char_event
);
238 xevent
.InitKeyEvent(ui::ET_KEY_RELEASED
,
239 static_cast<ui::KeyboardCode
>(key_code
),
241 ui::KeyEvent
event3(xevent
);
242 NativeWebKeyboardEvent
keyup_event(event3
);
243 SendNativeKeyEvent(keyup_event
);
245 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
247 output
->assign(1, static_cast<base::char16
>(c
));
249 #elif defined(USE_OZONE)
250 const int flags
= ConvertMockKeyboardModifier(modifiers
);
252 ui::KeyEvent
keydown_event(ui::ET_KEY_PRESSED
,
253 static_cast<ui::KeyboardCode
>(key_code
),
255 NativeWebKeyboardEvent
keydown_web_event(keydown_event
);
256 SendNativeKeyEvent(keydown_web_event
);
258 ui::KeyEvent
char_event(keydown_event
.GetCharacter(),
259 static_cast<ui::KeyboardCode
>(key_code
),
261 NativeWebKeyboardEvent
char_web_event(char_event
);
262 SendNativeKeyEvent(char_web_event
);
264 ui::KeyEvent
keyup_event(ui::ET_KEY_RELEASED
,
265 static_cast<ui::KeyboardCode
>(key_code
),
267 NativeWebKeyboardEvent
keyup_web_event(keyup_event
);
268 SendNativeKeyEvent(keyup_web_event
);
270 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
272 output
->assign(1, static_cast<base::char16
>(c
));
280 void EnablePreferredSizeMode() {
281 view()->OnEnablePreferredSizeChangedMode();
284 const gfx::Size
& GetPreferredSize() {
285 view()->CheckPreferredSize();
286 return view()->preferred_size_
;
289 void SetZoomLevel(double level
) {
290 view()->OnSetZoomLevelForView(false, level
);
294 scoped_ptr
<MockKeyboard
> mock_keyboard_
;
297 class DevToolsAgentTest
: public RenderViewImplTest
{
300 std::string host_id
= "host_id";
301 agent()->OnAttach(host_id
);
309 return agent()->paused_
;
312 void DispatchDevToolsMessage(const std::string
& message
) {
313 agent()->OnDispatchOnInspectorBackend(message
);
316 void CloseWhilePaused() {
317 EXPECT_TRUE(IsPaused());
318 view()->NotifyOnClose();
322 DevToolsAgent
* agent() {
323 return frame()->devtools_agent();
327 class RenderViewImplBlinkSettingsTest
: public RenderViewImplTest
{
330 RenderViewImplTest::SetUp();
333 const blink::WebSettings
* settings() {
334 return view()->webview()->settings();
338 // Blink settings may be specified on the command line, which must
339 // be configured before RenderViewImplTest::SetUp runs. Thus we make
340 // SetUp() a no-op, and expose RenderViewImplTest::SetUp() via
341 // DoSetUp(), to allow tests to perform command line modifications
342 // before RenderViewImplTest::SetUp is run. Each test must invoke
343 // DoSetUp manually once pre-SetUp configuration is complete.
344 void SetUp() override
{}
347 // Ensure that the main RenderFrame is deleted and cleared from the RenderView
349 TEST_F(RenderViewImplTest
, RenderFrameClearedAfterClose
) {
350 // Create a new main frame RenderFrame so that we don't interfere with the
351 // shutdown of frame() in RenderViewTest.TearDown.
352 blink::WebURLRequest
popup_request(GURL("http://foo.com"));
353 blink::WebView
* new_web_view
= view()->createView(
354 GetMainFrame(), popup_request
, blink::WebWindowFeatures(), "foo",
355 blink::WebNavigationPolicyNewForegroundTab
, false);
356 RenderViewImpl
* new_view
= RenderViewImpl::FromWebView(new_web_view
);
358 // Close the view, causing the main RenderFrame to be detached and deleted.
360 EXPECT_FALSE(new_view
->GetMainRenderFrame());
362 // Clean up after the new view so we don't leak it.
366 TEST_F(RenderViewImplTest
, SaveImageFromDataURL
) {
367 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
368 ViewHostMsg_SaveImageFromDataURL::ID
);
370 render_thread_
->sink().ClearMessages();
372 const std::string image_data_url
=
373 "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
375 view()->saveImageFromDataURL(WebString::fromUTF8(image_data_url
));
376 ProcessPendingMessages();
377 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
378 ViewHostMsg_SaveImageFromDataURL::ID
);
381 ViewHostMsg_SaveImageFromDataURL::Param param1
;
382 ViewHostMsg_SaveImageFromDataURL::Read(msg2
, ¶m1
);
383 EXPECT_EQ(base::get
<1>(param1
).length(), image_data_url
.length());
384 EXPECT_EQ(base::get
<1>(param1
), image_data_url
);
386 ProcessPendingMessages();
387 render_thread_
->sink().ClearMessages();
389 const std::string
large_data_url(1024 * 1024 * 10 - 1, 'd');
391 view()->saveImageFromDataURL(WebString::fromUTF8(large_data_url
));
392 ProcessPendingMessages();
393 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
394 ViewHostMsg_SaveImageFromDataURL::ID
);
397 ViewHostMsg_SaveImageFromDataURL::Param param2
;
398 ViewHostMsg_SaveImageFromDataURL::Read(msg3
, ¶m2
);
399 EXPECT_EQ(base::get
<1>(param2
).length(), large_data_url
.length());
400 EXPECT_EQ(base::get
<1>(param2
), large_data_url
);
402 ProcessPendingMessages();
403 render_thread_
->sink().ClearMessages();
405 const std::string
exceeded_data_url(1024 * 1024 * 10 + 1, 'd');
407 view()->saveImageFromDataURL(WebString::fromUTF8(exceeded_data_url
));
408 ProcessPendingMessages();
409 const IPC::Message
* msg4
= render_thread_
->sink().GetFirstMessageMatching(
410 ViewHostMsg_SaveImageFromDataURL::ID
);
414 // Test that we get form state change notifications when input fields change.
415 TEST_F(RenderViewImplTest
, DISABLED_OnNavStateChanged
) {
416 // Don't want any delay for form state sync changes. This will still post a
417 // message so updates will get coalesced, but as soon as we spin the message
418 // loop, it will generate an update.
419 view()->set_send_content_state_immediately(true);
421 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
423 // We should NOT have gotten a form state change notification yet.
424 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
425 ViewHostMsg_UpdateState::ID
));
426 render_thread_
->sink().ClearMessages();
428 // Change the value of the input. We should have gotten an update state
429 // notification. We need to spin the message loop to catch this update.
430 ExecuteJavaScriptForTests(
431 "document.getElementById('elt_text').value = 'foo';");
432 ProcessPendingMessages();
433 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
434 ViewHostMsg_UpdateState::ID
));
437 TEST_F(RenderViewImplTest
, OnNavigationHttpPost
) {
438 // An http url will trigger a resource load so cannot be used here.
439 CommonNavigationParams common_params
;
440 StartNavigationParams start_params
;
441 RequestNavigationParams request_params
;
442 common_params
.url
= GURL("data:text/html,<div>Page</div>");
443 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
444 common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
445 request_params
.page_id
= -1;
448 const unsigned char* raw_data
= reinterpret_cast<const unsigned char*>(
450 const unsigned int length
= 11;
451 const std::vector
<unsigned char> post_data(raw_data
, raw_data
+ length
);
452 start_params
.is_post
= true;
453 start_params
.browser_initiated_post_data
= post_data
;
455 frame()->Navigate(common_params
, start_params
, request_params
);
456 ProcessPendingMessages();
458 const IPC::Message
* frame_navigate_msg
=
459 render_thread_
->sink().GetUniqueMessageMatching(
460 FrameHostMsg_DidCommitProvisionalLoad::ID
);
461 EXPECT_TRUE(frame_navigate_msg
);
463 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params
;
464 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
466 EXPECT_TRUE(base::get
<0>(host_nav_params
).is_post
);
468 // Check post data sent to browser matches
469 EXPECT_TRUE(base::get
<0>(host_nav_params
).page_state
.IsValid());
470 scoped_ptr
<HistoryEntry
> entry
=
471 PageStateToHistoryEntry(base::get
<0>(host_nav_params
).page_state
);
472 blink::WebHTTPBody body
= entry
->root().httpBody();
473 blink::WebHTTPBody::Element element
;
474 bool successful
= body
.elementAt(0, element
);
475 EXPECT_TRUE(successful
);
476 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData
, element
.type
);
477 EXPECT_EQ(length
, element
.data
.size());
478 EXPECT_EQ(0, memcmp(raw_data
, element
.data
.data(), length
));
481 TEST_F(RenderViewImplTest
, DecideNavigationPolicy
) {
482 WebUITestWebUIControllerFactory factory
;
483 WebUIControllerFactory::RegisterFactory(&factory
);
486 state
.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
488 // Navigations to normal HTTP URLs can be handled locally.
489 blink::WebURLRequest
request(GURL("http://foo.com"));
490 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
491 policy_info
.frame
= GetMainFrame();
492 policy_info
.extraData
= &state
;
493 policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
494 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
495 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
497 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
498 switches::kEnableBrowserSideNavigation
)) {
499 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab
, policy
);
501 // If this is a renderer-initiated navigation that just begun, it should
502 // stop and be sent to the browser.
503 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
505 // If this a navigation that is ready to commit, it should be handled
507 request
.setCheckForBrowserSideNavigation(false);
508 policy
= frame()->decidePolicyForNavigation(policy_info
);
509 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab
, policy
);
512 // Verify that form posts to WebUI URLs will be sent to the browser process.
513 blink::WebURLRequest
form_request(GURL("chrome://foo"));
514 blink::WebFrameClient::NavigationPolicyInfo
form_policy_info(form_request
);
515 form_policy_info
.frame
= GetMainFrame();
516 form_policy_info
.extraData
= &state
;
517 form_policy_info
.navigationType
= blink::WebNavigationTypeFormSubmitted
;
518 form_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
519 form_request
.setHTTPMethod("POST");
520 policy
= frame()->decidePolicyForNavigation(form_policy_info
);
521 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
523 // Verify that popup links to WebUI URLs also are sent to browser.
524 blink::WebURLRequest
popup_request(GURL("chrome://foo"));
525 blink::WebFrameClient::NavigationPolicyInfo
popup_policy_info(popup_request
);
526 popup_policy_info
.frame
= GetMainFrame();
527 popup_policy_info
.extraData
= &state
;
528 popup_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
529 popup_policy_info
.defaultPolicy
= blink::WebNavigationPolicyNewForegroundTab
;
530 policy
= frame()->decidePolicyForNavigation(popup_policy_info
);
531 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
534 TEST_F(RenderViewImplTest
, DecideNavigationPolicyHandlesAllTopLevel
) {
536 state
.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
538 RendererPreferences prefs
= view()->renderer_preferences();
539 prefs
.browser_handles_all_top_level_requests
= true;
540 view()->OnSetRendererPrefs(prefs
);
542 const blink::WebNavigationType kNavTypes
[] = {
543 blink::WebNavigationTypeLinkClicked
,
544 blink::WebNavigationTypeFormSubmitted
,
545 blink::WebNavigationTypeBackForward
,
546 blink::WebNavigationTypeReload
,
547 blink::WebNavigationTypeFormResubmitted
,
548 blink::WebNavigationTypeOther
,
551 blink::WebURLRequest
request(GURL("http://foo.com"));
552 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
553 policy_info
.frame
= GetMainFrame();
554 policy_info
.extraData
= &state
;
555 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
557 for (size_t i
= 0; i
< arraysize(kNavTypes
); ++i
) {
558 policy_info
.navigationType
= kNavTypes
[i
];
560 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
562 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
566 TEST_F(RenderViewImplTest
, DecideNavigationPolicyForWebUI
) {
567 // Enable bindings to simulate a WebUI view.
568 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI
);
571 state
.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
573 // Navigations to normal HTTP URLs will be sent to browser process.
574 blink::WebURLRequest
request(GURL("http://foo.com"));
575 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
576 policy_info
.frame
= GetMainFrame();
577 policy_info
.extraData
= &state
;
578 policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
579 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
581 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
583 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
585 // Navigations to WebUI URLs will also be sent to browser process.
586 blink::WebURLRequest
webui_request(GURL("chrome://foo"));
587 blink::WebFrameClient::NavigationPolicyInfo
webui_policy_info(webui_request
);
588 webui_policy_info
.frame
= GetMainFrame();
589 webui_policy_info
.extraData
= &state
;
590 webui_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
591 webui_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
592 policy
= frame()->decidePolicyForNavigation(webui_policy_info
);
593 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
595 // Verify that form posts to data URLs will be sent to the browser process.
596 blink::WebURLRequest
data_request(GURL("data:text/html,foo"));
597 blink::WebFrameClient::NavigationPolicyInfo
data_policy_info(data_request
);
598 data_policy_info
.frame
= GetMainFrame();
599 data_policy_info
.extraData
= &state
;
600 data_policy_info
.navigationType
= blink::WebNavigationTypeFormSubmitted
;
601 data_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
602 data_request
.setHTTPMethod("POST");
603 policy
= frame()->decidePolicyForNavigation(data_policy_info
);
604 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
606 // Verify that a popup that creates a view first and then navigates to a
607 // normal HTTP URL will be sent to the browser process, even though the
608 // new view does not have any enabled_bindings_.
609 blink::WebURLRequest
popup_request(GURL("http://foo.com"));
610 blink::WebView
* new_web_view
= view()->createView(
611 GetMainFrame(), popup_request
, blink::WebWindowFeatures(), "foo",
612 blink::WebNavigationPolicyNewForegroundTab
, false);
613 RenderViewImpl
* new_view
= RenderViewImpl::FromWebView(new_web_view
);
614 blink::WebFrameClient::NavigationPolicyInfo
popup_policy_info(popup_request
);
615 popup_policy_info
.frame
= new_web_view
->mainFrame()->toWebLocalFrame();
616 popup_policy_info
.extraData
= &state
;
617 popup_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
618 popup_policy_info
.defaultPolicy
= blink::WebNavigationPolicyNewForegroundTab
;
619 policy
= static_cast<RenderFrameImpl
*>(new_view
->GetMainRenderFrame())->
620 decidePolicyForNavigation(popup_policy_info
);
621 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
623 // Clean up after the new view so we don't leak it.
628 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
629 // already swapped out. http://crbug.com/93427.
630 TEST_F(RenderViewImplTest
, SendSwapOutACK
) {
631 // This test is invalid in --site-per-process mode, as swapped-out is no
633 if (RenderFrameProxy::IsSwappedOutStateForbidden()) {
636 LoadHTML("<div>Page A</div>");
637 int initial_page_id
= view_page_id();
639 // Increment the ref count so that we don't exit when swapping out.
640 RenderProcess::current()->AddRefProcess();
642 // Respond to a swap out request.
643 frame()->SwapOut(kProxyRoutingId
, true, content::FrameReplicationState());
645 // Ensure the swap out commits synchronously.
646 EXPECT_NE(initial_page_id
, view_page_id());
648 // Check for a valid OnSwapOutACK.
649 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
650 FrameHostMsg_SwapOut_ACK::ID
);
653 // It is possible to get another swap out request. Ensure that we send
654 // an ACK, even if we don't have to do anything else.
655 render_thread_
->sink().ClearMessages();
656 frame()->SwapOut(kProxyRoutingId
, false, content::FrameReplicationState());
657 const IPC::Message
* msg2
= render_thread_
->sink().GetUniqueMessageMatching(
658 FrameHostMsg_SwapOut_ACK::ID
);
661 // If we navigate back to this RenderView, ensure we don't send a state
662 // update for the swapped out URL. (http://crbug.com/72235)
663 CommonNavigationParams common_params
;
664 RequestNavigationParams request_params
;
665 common_params
.url
= GURL("data:text/html,<div>Page B</div>");
666 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
667 common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
668 request_params
.current_history_list_length
= 1;
669 request_params
.current_history_list_offset
= 0;
670 request_params
.pending_history_list_offset
= 1;
671 request_params
.page_id
= -1;
672 frame()->Navigate(common_params
, StartNavigationParams(), request_params
);
673 ProcessPendingMessages();
674 const IPC::Message
* msg3
= render_thread_
->sink().GetUniqueMessageMatching(
675 ViewHostMsg_UpdateState::ID
);
679 // Ensure the RenderViewImpl reloads the previous page if a reload request
680 // arrives while it is showing swappedout://. http://crbug.com/143155.
681 TEST_F(RenderViewImplTest
, ReloadWhileSwappedOut
) {
682 // This test is invalid in --site-per-process mode, as swapped-out is no
684 if (RenderFrameProxy::IsSwappedOutStateForbidden()) {
689 LoadHTML("<div>Page A</div>");
691 // Load page B, which will trigger an UpdateState message for page A.
692 LoadHTML("<div>Page B</div>");
694 // Check for a valid UpdateState message for page A.
695 ProcessPendingMessages();
696 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
697 ViewHostMsg_UpdateState::ID
);
699 ViewHostMsg_UpdateState::Param params
;
700 ViewHostMsg_UpdateState::Read(msg_A
, ¶ms
);
701 int page_id_A
= base::get
<0>(params
);
702 PageState state_A
= base::get
<1>(params
);
703 EXPECT_EQ(1, page_id_A
);
704 render_thread_
->sink().ClearMessages();
706 // Back to page A (page_id 1) and commit.
707 CommonNavigationParams common_params_A
;
708 RequestNavigationParams request_params_A
;
709 common_params_A
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
710 common_params_A
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
711 request_params_A
.current_history_list_length
= 2;
712 request_params_A
.current_history_list_offset
= 1;
713 request_params_A
.pending_history_list_offset
= 0;
714 request_params_A
.page_id
= 1;
715 request_params_A
.nav_entry_id
= 1;
716 request_params_A
.page_state
= state_A
;
717 frame()->Navigate(common_params_A
, StartNavigationParams(), request_params_A
);
718 EXPECT_EQ(1, view()->historyBackListCount());
719 EXPECT_EQ(2, view()->historyBackListCount() +
720 view()->historyForwardListCount() + 1);
721 ProcessPendingMessages();
723 // Respond to a swap out request.
724 frame()->SwapOut(kProxyRoutingId
, true, content::FrameReplicationState());
726 // Check for a OnSwapOutACK.
727 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
728 FrameHostMsg_SwapOut_ACK::ID
);
730 render_thread_
->sink().ClearMessages();
732 // It is possible to get a reload request at this point, containing the
733 // params.page_state of the initial page (e.g., if the new page fails the
734 // provisional load in the renderer process, after we unload the old page).
735 // Ensure the old page gets reloaded, not swappedout://.
736 CommonNavigationParams common_params
;
737 RequestNavigationParams request_params
;
738 common_params
.url
= GURL("data:text/html,<div>Page A</div>");
739 common_params
.navigation_type
= FrameMsg_Navigate_Type::RELOAD
;
740 common_params
.transition
= ui::PAGE_TRANSITION_RELOAD
;
741 request_params
.current_history_list_length
= 2;
742 request_params
.current_history_list_offset
= 0;
743 request_params
.pending_history_list_offset
= 0;
744 request_params
.page_id
= 1;
745 request_params
.nav_entry_id
= 1;
746 request_params
.page_state
= state_A
;
747 frame()->Navigate(common_params
, StartNavigationParams(), request_params
);
748 ProcessPendingMessages();
750 // Verify page A committed, not swappedout://.
751 const IPC::Message
* frame_navigate_msg
=
752 render_thread_
->sink().GetUniqueMessageMatching(
753 FrameHostMsg_DidCommitProvisionalLoad::ID
);
754 EXPECT_TRUE(frame_navigate_msg
);
756 // Read URL out of the parent trait of the params object.
757 FrameHostMsg_DidCommitProvisionalLoad::Param commit_load_params
;
758 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
759 &commit_load_params
);
760 EXPECT_NE(GURL("swappedout://"), base::get
<0>(commit_load_params
).url
);
763 // Verify that security origins are replicated properly to RenderFrameProxies
764 // when swapping out.
765 TEST_F(RenderViewImplTest
, OriginReplicationForSwapOut
) {
766 // This test should only run with --site-per-process, since origin
767 // replication only happens in that mode.
768 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
769 switches::kSitePerProcess
))
773 "Hello <iframe src='data:text/html,frame 1'></iframe>"
774 "<iframe src='data:text/html,frame 2'></iframe>");
775 WebFrame
* web_frame
= frame()->GetWebFrame();
776 TestRenderFrame
* child_frame
= static_cast<TestRenderFrame
*>(
777 RenderFrame::FromWebFrame(web_frame
->firstChild()));
779 // Swap the child frame out and pass a replicated origin to be set for
781 content::FrameReplicationState replication_state
;
782 replication_state
.origin
= url::Origin(GURL("http://foo.com"));
783 child_frame
->SwapOut(kProxyRoutingId
, true, replication_state
);
785 // The child frame should now be a WebRemoteFrame.
786 EXPECT_TRUE(web_frame
->firstChild()->isWebRemoteFrame());
788 // Expect the origin to be updated properly.
789 blink::WebSecurityOrigin origin
= web_frame
->firstChild()->securityOrigin();
790 EXPECT_EQ(origin
.toString(),
791 WebString::fromUTF8(replication_state
.origin
.Serialize()));
793 // Now, swap out the second frame using a unique origin and verify that it is
794 // replicated correctly.
795 replication_state
.origin
= url::Origin();
796 TestRenderFrame
* child_frame2
= static_cast<TestRenderFrame
*>(
797 RenderFrame::FromWebFrame(web_frame
->lastChild()));
798 child_frame2
->SwapOut(kProxyRoutingId
+ 1, true, replication_state
);
799 EXPECT_TRUE(web_frame
->lastChild()->isWebRemoteFrame());
800 EXPECT_TRUE(web_frame
->lastChild()->securityOrigin().isUnique());
803 // Test that we get the correct UpdateState message when we go back twice
804 // quickly without committing. Regression test for http://crbug.com/58082.
805 // Disabled: http://crbug.com/157357 .
806 TEST_F(RenderViewImplTest
, DISABLED_LastCommittedUpdateState
) {
808 LoadHTML("<div>Page A</div>");
810 // Load page B, which will trigger an UpdateState message for page A.
811 LoadHTML("<div>Page B</div>");
813 // Check for a valid UpdateState message for page A.
814 ProcessPendingMessages();
815 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
816 ViewHostMsg_UpdateState::ID
);
818 ViewHostMsg_UpdateState::Param param
;
819 ViewHostMsg_UpdateState::Read(msg_A
, ¶m
);
820 int page_id_A
= base::get
<0>(param
);
821 PageState state_A
= base::get
<1>(param
);
822 EXPECT_EQ(1, page_id_A
);
823 render_thread_
->sink().ClearMessages();
825 // Load page C, which will trigger an UpdateState message for page B.
826 LoadHTML("<div>Page C</div>");
828 // Check for a valid UpdateState for page B.
829 ProcessPendingMessages();
830 const IPC::Message
* msg_B
= render_thread_
->sink().GetUniqueMessageMatching(
831 ViewHostMsg_UpdateState::ID
);
833 ViewHostMsg_UpdateState::Read(msg_B
, ¶m
);
834 int page_id_B
= base::get
<0>(param
);
835 PageState state_B
= base::get
<1>(param
);
836 EXPECT_EQ(2, page_id_B
);
837 EXPECT_NE(state_A
, state_B
);
838 render_thread_
->sink().ClearMessages();
840 // Load page D, which will trigger an UpdateState message for page C.
841 LoadHTML("<div>Page D</div>");
843 // Check for a valid UpdateState for page C.
844 ProcessPendingMessages();
845 const IPC::Message
* msg_C
= render_thread_
->sink().GetUniqueMessageMatching(
846 ViewHostMsg_UpdateState::ID
);
848 ViewHostMsg_UpdateState::Read(msg_C
, ¶m
);
849 int page_id_C
= base::get
<0>(param
);
850 PageState state_C
= base::get
<1>(param
);
851 EXPECT_EQ(3, page_id_C
);
852 EXPECT_NE(state_B
, state_C
);
853 render_thread_
->sink().ClearMessages();
855 // Go back to C and commit, preparing for our real test.
856 CommonNavigationParams common_params_C
;
857 RequestNavigationParams request_params_C
;
858 common_params_C
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
859 common_params_C
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
860 request_params_C
.current_history_list_length
= 4;
861 request_params_C
.current_history_list_offset
= 3;
862 request_params_C
.pending_history_list_offset
= 2;
863 request_params_C
.page_id
= 3;
864 request_params_C
.page_state
= state_C
;
865 frame()->Navigate(common_params_C
, StartNavigationParams(), request_params_C
);
866 ProcessPendingMessages();
867 render_thread_
->sink().ClearMessages();
869 // Go back twice quickly, such that page B does not have a chance to commit.
870 // This leads to two changes to the back/forward list but only one change to
871 // the RenderView's page ID.
873 // Back to page B (page_id 2), without committing.
874 CommonNavigationParams common_params_B
;
875 RequestNavigationParams request_params_B
;
876 common_params_B
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
877 common_params_B
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
878 request_params_B
.current_history_list_length
= 4;
879 request_params_B
.current_history_list_offset
= 2;
880 request_params_B
.pending_history_list_offset
= 1;
881 request_params_B
.page_id
= 2;
882 request_params_B
.page_state
= state_B
;
883 frame()->Navigate(common_params_B
, StartNavigationParams(), request_params_B
);
885 // Back to page A (page_id 1) and commit.
886 CommonNavigationParams common_params
;
887 RequestNavigationParams request_params
;
888 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
889 common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
890 request_params
.current_history_list_length
= 4;
891 request_params
.current_history_list_offset
= 2;
892 request_params
.pending_history_list_offset
= 0;
893 request_params
.page_id
= 1;
894 request_params
.page_state
= state_A
;
895 frame()->Navigate(common_params
, StartNavigationParams(), request_params
);
896 ProcessPendingMessages();
898 // Now ensure that the UpdateState message we receive is consistent
899 // and represents page C in both page_id and state.
900 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
901 ViewHostMsg_UpdateState::ID
);
903 ViewHostMsg_UpdateState::Read(msg
, ¶m
);
904 int page_id
= base::get
<0>(param
);
905 PageState state
= base::get
<1>(param
);
906 EXPECT_EQ(page_id_C
, page_id
);
907 EXPECT_NE(state_A
, state
);
908 EXPECT_NE(state_B
, state
);
909 EXPECT_EQ(state_C
, state
);
912 // Test that our IME backend sends a notification message when the input focus
914 TEST_F(RenderViewImplTest
, OnImeTypeChanged
) {
915 // Load an HTML page consisting of two input fields.
916 view()->set_send_content_state_immediately(true);
921 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
922 "<input id=\"test2\" type=\"password\"></input>"
923 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
924 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
925 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
926 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
928 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
930 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
931 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
932 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
933 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
934 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
935 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
936 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
937 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
940 render_thread_
->sink().ClearMessages();
942 struct InputModeTestCase
{
943 const char* input_id
;
944 ui::TextInputMode expected_mode
;
946 static const InputModeTestCase kInputModeTestCases
[] = {
947 {"test1", ui::TEXT_INPUT_MODE_DEFAULT
},
948 {"test3", ui::TEXT_INPUT_MODE_VERBATIM
},
949 {"test4", ui::TEXT_INPUT_MODE_LATIN
},
950 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME
},
951 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE
},
952 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN
},
953 {"test8", ui::TEXT_INPUT_MODE_KANA
},
954 {"test9", ui::TEXT_INPUT_MODE_KATAKANA
},
955 {"test10", ui::TEXT_INPUT_MODE_NUMERIC
},
956 {"test11", ui::TEXT_INPUT_MODE_TEL
},
957 {"test12", ui::TEXT_INPUT_MODE_EMAIL
},
958 {"test13", ui::TEXT_INPUT_MODE_URL
},
959 {"test14", ui::TEXT_INPUT_MODE_DEFAULT
},
960 {"test15", ui::TEXT_INPUT_MODE_VERBATIM
},
963 const int kRepeatCount
= 10;
964 for (int i
= 0; i
< kRepeatCount
; i
++) {
965 // Move the input focus to the first <input> element, where we should
967 ExecuteJavaScriptForTests("document.getElementById('test1').focus();");
968 ProcessPendingMessages();
969 render_thread_
->sink().ClearMessages();
971 // Update the IME status and verify if our IME backend sends an IPC message
973 view()->UpdateTextInputType();
974 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
975 EXPECT_TRUE(msg
!= NULL
);
976 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
977 ViewHostMsg_TextInputTypeChanged::Param params
;
978 ViewHostMsg_TextInputTypeChanged::Read(msg
, ¶ms
);
979 ui::TextInputType type
= base::get
<0>(params
);
980 ui::TextInputMode input_mode
= base::get
<1>(params
);
981 bool can_compose_inline
= base::get
<2>(params
);
982 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT
, type
);
983 EXPECT_EQ(true, can_compose_inline
);
985 // Move the input focus to the second <input> element, where we should
987 ExecuteJavaScriptForTests("document.getElementById('test2').focus();");
988 ProcessPendingMessages();
989 render_thread_
->sink().ClearMessages();
991 // Update the IME status and verify if our IME backend sends an IPC message
992 // to de-activate IMEs.
993 view()->UpdateTextInputType();
994 msg
= render_thread_
->sink().GetMessageAt(0);
995 EXPECT_TRUE(msg
!= NULL
);
996 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
997 ViewHostMsg_TextInputTypeChanged::Read(msg
, & params
);
998 type
= base::get
<0>(params
);
999 input_mode
= base::get
<1>(params
);
1000 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD
, type
);
1002 for (size_t i
= 0; i
< arraysize(kInputModeTestCases
); i
++) {
1003 const InputModeTestCase
* test_case
= &kInputModeTestCases
[i
];
1004 std::string javascript
=
1005 base::StringPrintf("document.getElementById('%s').focus();",
1006 test_case
->input_id
);
1007 // Move the input focus to the target <input> element, where we should
1009 ExecuteJavaScriptAndReturnIntValue(base::ASCIIToUTF16(javascript
), NULL
);
1010 ProcessPendingMessages();
1011 render_thread_
->sink().ClearMessages();
1013 // Update the IME status and verify if our IME backend sends an IPC
1014 // message to activate IMEs.
1015 view()->UpdateTextInputType();
1016 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
1017 EXPECT_TRUE(msg
!= NULL
);
1018 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
1019 ViewHostMsg_TextInputTypeChanged::Read(msg
, & params
);
1020 type
= base::get
<0>(params
);
1021 input_mode
= base::get
<1>(params
);
1022 EXPECT_EQ(test_case
->expected_mode
, input_mode
);
1027 // Test that our IME backend can compose CJK words.
1028 // Our IME front-end sends many platform-independent messages to the IME backend
1029 // while it composes CJK words. This test sends the minimal messages captured
1030 // on my local environment directly to the IME backend to verify if the backend
1031 // can compose CJK words without any problems.
1032 // This test uses an array of command sets because an IME composotion does not
1033 // only depends on IME events, but also depends on window events, e.g. moving
1034 // the window focus while composing a CJK text. To handle such complicated
1035 // cases, this test should not only call IME-related functions in the
1036 // RenderWidget class, but also call some RenderWidget members, e.g.
1037 // ExecuteJavaScriptForTests(), RenderWidget::OnSetFocus(), etc.
1038 TEST_F(RenderViewImplTest
, ImeComposition
) {
1044 IME_CONFIRMCOMPOSITION
,
1045 IME_CANCELCOMPOSITION
1050 int selection_start
;
1052 const wchar_t* ime_string
;
1053 const wchar_t* result
;
1055 static const ImeMessage kImeMessages
[] = {
1056 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
1057 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1058 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1059 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1060 {IME_SETCOMPOSITION
, false, 1, 1, L
"n", L
"n"},
1061 {IME_SETCOMPOSITION
, false, 2, 2, L
"ni", L
"ni"},
1062 {IME_SETCOMPOSITION
, false, 3, 3, L
"nih", L
"nih"},
1063 {IME_SETCOMPOSITION
, false, 4, 4, L
"niha", L
"niha"},
1064 {IME_SETCOMPOSITION
, false, 5, 5, L
"nihao", L
"nihao"},
1065 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"\x4F60\x597D", L
"\x4F60\x597D"},
1066 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
1067 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1068 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1069 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1070 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xFF4B", L
"\xFF4B"},
1071 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x304B", L
"\x304B"},
1072 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x304B\xFF4E", L
"\x304B\xFF4E"},
1073 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\xFF4A",
1074 L
"\x304B\x3093\xFF4A"},
1075 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\x3058",
1076 L
"\x304B\x3093\x3058"},
1077 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x611F\x3058", L
"\x611F\x3058"},
1078 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x6F22\x5B57", L
"\x6F22\x5B57"},
1079 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1080 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1081 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1082 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1083 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1084 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1085 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3147", L
"\x3147"},
1086 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC544", L
"\xC544"},
1087 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC548", L
"\xC548"},
1088 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1089 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3134", L
"\xC548\x3134"},
1090 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB140", L
"\xC548\xB140"},
1091 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1092 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1093 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1094 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548\xB155"},
1097 for (size_t i
= 0; i
< arraysize(kImeMessages
); i
++) {
1098 const ImeMessage
* ime_message
= &kImeMessages
[i
];
1099 switch (ime_message
->command
) {
1100 case IME_INITIALIZE
:
1101 // Load an HTML page consisting of a content-editable <div> element,
1102 // and move the input focus to the <div> element, where we can use
1104 view()->set_send_content_state_immediately(true);
1109 "<div id=\"test1\" contenteditable=\"true\"></div>"
1112 ExecuteJavaScriptForTests("document.getElementById('test1').focus();");
1115 case IME_SETINPUTMODE
:
1119 // Update the window focus.
1120 view()->OnSetFocus(ime_message
->enable
);
1123 case IME_SETCOMPOSITION
:
1124 view()->OnImeSetComposition(
1125 base::WideToUTF16(ime_message
->ime_string
),
1126 std::vector
<blink::WebCompositionUnderline
>(),
1127 ime_message
->selection_start
,
1128 ime_message
->selection_end
);
1131 case IME_CONFIRMCOMPOSITION
:
1132 view()->OnImeConfirmComposition(
1133 base::WideToUTF16(ime_message
->ime_string
),
1134 gfx::Range::InvalidRange(),
1138 case IME_CANCELCOMPOSITION
:
1139 view()->OnImeSetComposition(
1141 std::vector
<blink::WebCompositionUnderline
>(),
1146 // Update the status of our IME back-end.
1147 // TODO(hbono): we should verify messages to be sent from the back-end.
1148 view()->UpdateTextInputType();
1149 ProcessPendingMessages();
1150 render_thread_
->sink().ClearMessages();
1152 if (ime_message
->result
) {
1153 // Retrieve the content of this page and compare it with the expected
1155 const int kMaxOutputCharacters
= 128;
1156 base::string16 output
=
1157 GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1158 EXPECT_EQ(base::WideToUTF16(ime_message
->result
), output
);
1163 // Test that the RenderView::OnSetTextDirection() function can change the text
1164 // direction of the selected input element.
1165 TEST_F(RenderViewImplTest
, OnSetTextDirection
) {
1166 // Load an HTML page consisting of a <textarea> element and a <div> element.
1167 // This test changes the text direction of the <textarea> element, and
1168 // writes the values of its 'dir' attribute and its 'direction' property to
1169 // verify that the text direction is changed.
1170 view()->set_send_content_state_immediately(true);
1175 "<textarea id=\"test\"></textarea>"
1176 "<div id=\"result\" contenteditable=\"true\"></div>"
1179 render_thread_
->sink().ClearMessages();
1181 static const struct {
1182 WebTextDirection direction
;
1183 const wchar_t* expected_result
;
1184 } kTextDirection
[] = {
1185 { blink::WebTextDirectionRightToLeft
, L
"\x000A" L
"rtl,rtl" },
1186 { blink::WebTextDirectionLeftToRight
, L
"\x000A" L
"ltr,ltr" },
1188 for (size_t i
= 0; i
< arraysize(kTextDirection
); ++i
) {
1189 // Set the text direction of the <textarea> element.
1190 ExecuteJavaScriptForTests("document.getElementById('test').focus();");
1191 view()->OnSetTextDirection(kTextDirection
[i
].direction
);
1193 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1194 // property to the <div> element.
1195 ExecuteJavaScriptForTests(
1196 "var result = document.getElementById('result');"
1197 "var node = document.getElementById('test');"
1198 "var style = getComputedStyle(node, null);"
1199 "result.innerText ="
1200 " node.getAttribute('dir') + ',' +"
1201 " style.getPropertyValue('direction');");
1203 // Copy the document content to std::wstring and compare with the
1205 const int kMaxOutputCharacters
= 16;
1206 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1207 EXPECT_EQ(base::WideToUTF16(kTextDirection
[i
].expected_result
), output
);
1211 // Test that we can receive correct DOM events when we send input events
1212 // through the RenderWidget::OnHandleInputEvent() function.
1213 TEST_F(RenderViewImplTest
, OnHandleKeyboardEvent
) {
1214 #if !defined(OS_MACOSX)
1215 // Load an HTML page consisting of one <input> element and three
1216 // contentediable <div> elements.
1217 // The <input> element is used for sending keyboard events, and the <div>
1218 // elements are used for writing DOM events in the following format:
1219 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1220 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1221 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1222 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1223 view()->set_send_content_state_immediately(true);
1227 "<script type='text/javascript' language='javascript'>"
1228 "function OnKeyEvent(ev) {"
1229 " var result = document.getElementById(ev.type);"
1230 " result.innerText ="
1231 " (ev.which || ev.keyCode) + ',' +"
1232 " ev.shiftKey + ',' +"
1233 " ev.ctrlKey + ',' +"
1240 "<input id='test' type='text'"
1241 " onkeydown='return OnKeyEvent(event);'"
1242 " onkeypress='return OnKeyEvent(event);'"
1243 " onkeyup='return OnKeyEvent(event);'>"
1245 "<div id='keydown' contenteditable='true'>"
1247 "<div id='keypress' contenteditable='true'>"
1249 "<div id='keyup' contenteditable='true'>"
1253 ExecuteJavaScriptForTests("document.getElementById('test').focus();");
1254 render_thread_
->sink().ClearMessages();
1256 static const MockKeyboard::Layout kLayouts
[] = {
1258 // Since we ignore the mock keyboard layout on Linux and instead just use
1259 // the screen's keyboard layout, these trivially pass. They are commented
1260 // out to avoid the illusion that they work.
1261 MockKeyboard::LAYOUT_ARABIC
,
1262 MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1263 MockKeyboard::LAYOUT_FRENCH
,
1264 MockKeyboard::LAYOUT_HEBREW
,
1265 MockKeyboard::LAYOUT_RUSSIAN
,
1267 MockKeyboard::LAYOUT_UNITED_STATES
,
1270 for (size_t i
= 0; i
< arraysize(kLayouts
); ++i
) {
1271 // For each key code, we send three keyboard events.
1272 // * we press only the key;
1273 // * we press the key and a left-shift key, and;
1274 // * we press the key and a right-alt (AltGr) key.
1275 // For each modifiers, we need a string used for formatting its expected
1276 // result. (See the above comment for its format.)
1277 static const struct {
1278 MockKeyboard::Modifiers modifiers
;
1279 const char* expected_result
;
1280 } kModifierData
[] = {
1281 {MockKeyboard::NONE
, "false,false,false"},
1282 {MockKeyboard::LEFT_SHIFT
, "true,false,false"},
1284 {MockKeyboard::RIGHT_ALT
, "false,false,true"},
1288 MockKeyboard::Layout layout
= kLayouts
[i
];
1289 for (size_t j
= 0; j
< arraysize(kModifierData
); ++j
) {
1290 // Virtual key codes used for this test.
1291 static const int kKeyCodes
[] = {
1292 '0', '1', '2', '3', '4', '5', '6', '7',
1293 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1294 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1295 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1301 ui::VKEY_OEM_PERIOD
,
1309 // Not sure how to handle this key on Linux.
1314 MockKeyboard::Modifiers modifiers
= kModifierData
[j
].modifiers
;
1315 for (size_t k
= 0; k
< arraysize(kKeyCodes
); ++k
) {
1316 // Send a keyboard event to the RenderView object.
1317 // We should test a keyboard event only when the given keyboard-layout
1318 // driver is installed in a PC and the driver can assign a Unicode
1319 // charcter for the given tuple (key-code and modifiers).
1320 int key_code
= kKeyCodes
[k
];
1321 base::string16 char_code
;
1322 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1325 // Create an expected result from the virtual-key code, the character
1326 // code, and the modifier-key status.
1327 // We format a string that emulates a DOM-event string produced hy
1328 // our JavaScript function. (See the above comment for the format.)
1329 static char expected_result
[1024];
1330 expected_result
[0] = 0;
1331 base::snprintf(&expected_result
[0],
1332 sizeof(expected_result
),
1333 "\n" // texts in the <input> element
1334 "%d,%s\n" // texts in the first <div> element
1335 "%d,%s\n" // texts in the second <div> element
1336 "%d,%s", // texts in the third <div> element
1337 key_code
, kModifierData
[j
].expected_result
,
1338 static_cast<int>(char_code
[0]),
1339 kModifierData
[j
].expected_result
,
1340 key_code
, kModifierData
[j
].expected_result
);
1342 // Retrieve the text in the test page and compare it with the expected
1343 // text created from a virtual-key code, a character code, and the
1344 // modifier-key status.
1345 const int kMaxOutputCharacters
= 1024;
1346 std::string output
= base::UTF16ToUTF8(base::StringPiece16(
1347 GetMainFrame()->contentAsText(kMaxOutputCharacters
)));
1348 EXPECT_EQ(expected_result
, output
);
1357 // Test that our EditorClientImpl class can insert characters when we send
1358 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1359 // This test is for preventing regressions caused only when we use non-US
1360 // keyboards, such as Issue 10846.
1361 // see http://crbug.com/244562
1363 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1365 #define MAYBE_InsertCharacters InsertCharacters
1367 TEST_F(RenderViewImplTest
, MAYBE_InsertCharacters
) {
1368 #if !defined(OS_MACOSX)
1369 static const struct {
1370 MockKeyboard::Layout layout
;
1371 const wchar_t* expected_result
;
1374 // Disabled these keyboard layouts because buildbots do not have their
1375 // keyboard-layout drivers installed.
1376 {MockKeyboard::LAYOUT_ARABIC
,
1377 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1378 L
"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1379 L
"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1380 L
"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1381 L
"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1382 L
"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1383 L
"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1384 L
"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1385 L
"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1386 L
"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1387 L
"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1388 L
"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1389 L
"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1390 L
"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1391 L
"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1392 L
"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1393 L
"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1395 {MockKeyboard::LAYOUT_HEBREW
,
1396 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1397 L
"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1398 L
"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1399 L
"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1400 L
"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1401 L
"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1402 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1403 L
"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1404 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1405 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1406 L
"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1407 L
"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1408 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1409 L
"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1410 L
"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1411 L
"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1412 L
"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1413 L
"\x003b\x005d\x005c\x005b\x002c"
1417 // On Linux, the only way to test alternate keyboard layouts is to change
1418 // the keyboard layout of the whole screen. I'm worried about the side
1419 // effects this may have on the buildbots.
1420 {MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1421 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1422 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1423 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1424 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1425 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1426 L
"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1427 L
"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1428 L
"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1429 L
"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1430 L
"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1431 L
"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1432 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1433 L
"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1434 L
"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1435 L
"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1436 L
"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1439 {MockKeyboard::LAYOUT_FRENCH
,
1440 L
"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1441 L
"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1442 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1443 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1444 L
"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1445 L
"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1446 L
"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1447 L
"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1448 L
"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1449 L
"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1450 L
"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1451 L
"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1452 L
"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1453 L
"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1454 L
"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1455 L
"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1456 L
"\x003b\x003a\x00f9\x0029\x002a\x0021"
1458 {MockKeyboard::LAYOUT_RUSSIAN
,
1459 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1460 L
"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1461 L
"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1462 L
"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1463 L
"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1464 L
"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1465 L
"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1466 L
"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1467 L
"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1468 L
"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1469 L
"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1470 L
"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1471 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1472 L
"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1473 L
"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1474 L
"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1475 L
"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1476 L
"\x0451\x0445\x005c\x044a\x044d"
1478 #endif // defined(OS_WIN)
1479 {MockKeyboard::LAYOUT_UNITED_STATES
,
1480 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1481 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1482 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1483 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1484 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1485 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1486 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1487 L
"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1488 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1489 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1490 L
"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1491 L
"\x003f\x007e\x007b\x007c\x007d\x0022"
1493 // This is ifdefed out for Linux to correspond to the fact that we don't
1494 // test alt+keystroke for now.
1495 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1496 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1497 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1498 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1499 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1500 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1505 for (size_t i
= 0; i
< arraysize(kLayouts
); ++i
) {
1506 // Load an HTML page consisting of one <div> element.
1507 // This <div> element is used by the EditorClientImpl class to insert
1508 // characters received through the RenderWidget::OnHandleInputEvent()
1510 view()->set_send_content_state_immediately(true);
1516 "<div id='test' contenteditable='true'>"
1520 ExecuteJavaScriptForTests("document.getElementById('test').focus();");
1521 render_thread_
->sink().ClearMessages();
1523 // For each key code, we send three keyboard events.
1524 // * Pressing only the key;
1525 // * Pressing the key and a left-shift key, and;
1526 // * Pressing the key and a right-alt (AltGr) key.
1527 static const MockKeyboard::Modifiers kModifiers
[] = {
1529 MockKeyboard::LEFT_SHIFT
,
1531 MockKeyboard::RIGHT_ALT
,
1535 MockKeyboard::Layout layout
= kLayouts
[i
].layout
;
1536 for (size_t j
= 0; j
< arraysize(kModifiers
); ++j
) {
1537 // Virtual key codes used for this test.
1538 static const int kKeyCodes
[] = {
1539 '0', '1', '2', '3', '4', '5', '6', '7',
1540 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1541 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1542 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1548 ui::VKEY_OEM_PERIOD
,
1556 // Unclear how to handle this on Linux.
1561 MockKeyboard::Modifiers modifiers
= kModifiers
[j
];
1562 for (size_t k
= 0; k
< arraysize(kKeyCodes
); ++k
) {
1563 // Send a keyboard event to the RenderView object.
1564 // We should test a keyboard event only when the given keyboard-layout
1565 // driver is installed in a PC and the driver can assign a Unicode
1566 // charcter for the given tuple (layout, key-code, and modifiers).
1567 int key_code
= kKeyCodes
[k
];
1568 base::string16 char_code
;
1569 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1574 // Retrieve the text in the test page and compare it with the expected
1575 // text created from a virtual-key code, a character code, and the
1576 // modifier-key status.
1577 const int kMaxOutputCharacters
= 4096;
1578 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1579 EXPECT_EQ(base::WideToUTF16(kLayouts
[i
].expected_result
), output
);
1586 // Crashy, http://crbug.com/53247.
1587 TEST_F(RenderViewImplTest
, DISABLED_DidFailProvisionalLoadWithErrorForError
) {
1588 GetMainFrame()->enableViewSourceMode(true);
1590 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1591 error
.reason
= net::ERR_FILE_NOT_FOUND
;
1592 error
.unreachableURL
= GURL("http://foo");
1593 WebLocalFrame
* web_frame
= GetMainFrame();
1595 // Start a load that will reach provisional state synchronously,
1596 // but won't complete synchronously.
1597 CommonNavigationParams common_params
;
1598 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1599 common_params
.url
= GURL("data:text/html,test data");
1600 frame()->Navigate(common_params
, StartNavigationParams(),
1601 RequestNavigationParams());
1603 // An error occurred.
1604 view()->GetMainRenderFrame()->didFailProvisionalLoad(
1605 web_frame
, error
, blink::WebStandardCommit
);
1606 // Frame should exit view-source mode.
1607 EXPECT_FALSE(web_frame
->isViewSourceModeEnabled());
1610 TEST_F(RenderViewImplTest
, DidFailProvisionalLoadWithErrorForCancellation
) {
1611 GetMainFrame()->enableViewSourceMode(true);
1613 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1614 error
.reason
= net::ERR_ABORTED
;
1615 error
.unreachableURL
= GURL("http://foo");
1616 WebLocalFrame
* web_frame
= GetMainFrame();
1618 // Start a load that will reach provisional state synchronously,
1619 // but won't complete synchronously.
1620 CommonNavigationParams common_params
;
1621 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1622 common_params
.url
= GURL("data:text/html,test data");
1623 frame()->Navigate(common_params
, StartNavigationParams(),
1624 RequestNavigationParams());
1626 // A cancellation occurred.
1627 view()->GetMainRenderFrame()->didFailProvisionalLoad(
1628 web_frame
, error
, blink::WebStandardCommit
);
1629 // Frame should stay in view-source mode.
1630 EXPECT_TRUE(web_frame
->isViewSourceModeEnabled());
1633 // Regression test for http://crbug.com/41562
1634 TEST_F(RenderViewImplTest
, UpdateTargetURLWithInvalidURL
) {
1635 const GURL
invalid_gurl("http://");
1636 view()->setMouseOverURL(blink::WebURL(invalid_gurl
));
1637 EXPECT_EQ(invalid_gurl
, view()->target_url_
);
1640 TEST_F(RenderViewImplTest
, SetHistoryLengthAndOffset
) {
1641 // No history to merge; one committed page.
1642 view()->OnSetHistoryOffsetAndLength(0, 1);
1643 EXPECT_EQ(1, view()->history_list_length_
);
1644 EXPECT_EQ(0, view()->history_list_offset_
);
1646 // History of length 1 to merge; one committed page.
1647 view()->OnSetHistoryOffsetAndLength(1, 2);
1648 EXPECT_EQ(2, view()->history_list_length_
);
1649 EXPECT_EQ(1, view()->history_list_offset_
);
1652 TEST_F(RenderViewImplTest
, ContextMenu
) {
1653 LoadHTML("<div>Page A</div>");
1655 // Create a right click in the center of the iframe. (I'm hoping this will
1656 // make this a bit more robust in case of some other formatting or other bug.)
1657 WebMouseEvent mouse_event
;
1658 mouse_event
.type
= WebInputEvent::MouseDown
;
1659 mouse_event
.button
= WebMouseEvent::ButtonRight
;
1660 mouse_event
.x
= 250;
1661 mouse_event
.y
= 250;
1662 mouse_event
.globalX
= 250;
1663 mouse_event
.globalY
= 250;
1665 SendWebMouseEvent(mouse_event
);
1667 // Now simulate the corresponding up event which should display the menu
1668 mouse_event
.type
= WebInputEvent::MouseUp
;
1669 SendWebMouseEvent(mouse_event
);
1671 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
1672 FrameHostMsg_ContextMenu::ID
));
1675 TEST_F(RenderViewImplTest
, TestBackForward
) {
1676 LoadHTML("<div id=pagename>Page A</div>");
1677 PageState page_a_state
=
1678 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1679 int was_page_a
= -1;
1680 base::string16 check_page_a
=
1682 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1683 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1684 EXPECT_EQ(1, was_page_a
);
1686 LoadHTML("<div id=pagename>Page B</div>");
1687 int was_page_b
= -1;
1688 base::string16 check_page_b
=
1690 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1691 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1692 EXPECT_EQ(1, was_page_b
);
1694 PageState back_state
=
1695 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1697 LoadHTML("<div id=pagename>Page C</div>");
1698 int was_page_c
= -1;
1699 base::string16 check_page_c
=
1701 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1702 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1703 EXPECT_EQ(1, was_page_c
);
1705 PageState forward_state
=
1706 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1708 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1709 EXPECT_EQ(1, was_page_b
);
1711 PageState back_state2
=
1712 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1714 GoForward(forward_state
);
1715 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1716 EXPECT_EQ(1, was_page_c
);
1718 GoBack(back_state2
);
1719 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1720 EXPECT_EQ(1, was_page_b
);
1723 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1724 GoBack(page_a_state
);
1725 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1726 EXPECT_EQ(1, was_page_a
);
1728 GoForward(forward_state
);
1729 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1730 EXPECT_EQ(1, was_page_b
);
1733 #if defined(OS_MACOSX) || defined(USE_AURA)
1734 TEST_F(RenderViewImplTest
, GetCompositionCharacterBoundsTest
) {
1737 // http://crbug.com/304193
1738 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
1740 // http://crbug.com/508747
1741 if (base::win::GetVersion() >= base::win::VERSION_WIN10
)
1745 LoadHTML("<textarea id=\"test\"></textarea>");
1746 ExecuteJavaScriptForTests("document.getElementById('test').focus();");
1748 const base::string16 empty_string
;
1749 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1750 std::vector
<gfx::Rect
> bounds
;
1751 view()->OnSetFocus(true);
1753 // ASCII composition
1754 const base::string16 ascii_composition
= base::UTF8ToUTF16("aiueo");
1755 view()->OnImeSetComposition(ascii_composition
, empty_underline
, 0, 0);
1756 view()->GetCompositionCharacterBounds(&bounds
);
1757 ASSERT_EQ(ascii_composition
.size(), bounds
.size());
1758 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1759 EXPECT_LT(0, bounds
[i
].width());
1760 view()->OnImeConfirmComposition(
1761 empty_string
, gfx::Range::InvalidRange(), false);
1763 // Non surrogate pair unicode character.
1764 const base::string16 unicode_composition
= base::UTF8ToUTF16(
1765 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1766 view()->OnImeSetComposition(unicode_composition
, empty_underline
, 0, 0);
1767 view()->GetCompositionCharacterBounds(&bounds
);
1768 ASSERT_EQ(unicode_composition
.size(), bounds
.size());
1769 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1770 EXPECT_LT(0, bounds
[i
].width());
1771 view()->OnImeConfirmComposition(
1772 empty_string
, gfx::Range::InvalidRange(), false);
1774 // Surrogate pair character.
1775 const base::string16 surrogate_pair_char
=
1776 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1777 view()->OnImeSetComposition(surrogate_pair_char
,
1781 view()->GetCompositionCharacterBounds(&bounds
);
1782 ASSERT_EQ(surrogate_pair_char
.size(), bounds
.size());
1783 EXPECT_LT(0, bounds
[0].width());
1784 EXPECT_EQ(0, bounds
[1].width());
1785 view()->OnImeConfirmComposition(
1786 empty_string
, gfx::Range::InvalidRange(), false);
1789 const base::string16 surrogate_pair_mixed_composition
=
1790 surrogate_pair_char
+ base::UTF8ToUTF16("\xE3\x81\x82") +
1791 surrogate_pair_char
+ base::UTF8ToUTF16("b") + surrogate_pair_char
;
1792 const size_t utf16_length
= 8UL;
1793 const bool is_surrogate_pair_empty_rect
[8] = {
1794 false, true, false, false, true, false, false, true };
1795 view()->OnImeSetComposition(surrogate_pair_mixed_composition
,
1799 view()->GetCompositionCharacterBounds(&bounds
);
1800 ASSERT_EQ(utf16_length
, bounds
.size());
1801 for (size_t i
= 0; i
< utf16_length
; ++i
) {
1802 if (is_surrogate_pair_empty_rect
[i
]) {
1803 EXPECT_EQ(0, bounds
[i
].width());
1805 EXPECT_LT(0, bounds
[i
].width());
1808 view()->OnImeConfirmComposition(
1809 empty_string
, gfx::Range::InvalidRange(), false);
1813 TEST_F(RenderViewImplTest
, ZoomLimit
) {
1814 const double kMinZoomLevel
= ZoomFactorToZoomLevel(kMinimumZoomFactor
);
1815 const double kMaxZoomLevel
= ZoomFactorToZoomLevel(kMaximumZoomFactor
);
1817 // Verifies navigation to a URL with preset zoom level indeed sets the level.
1818 // Regression test for http://crbug.com/139559, where the level was not
1819 // properly set when it is out of the default zoom limits of WebView.
1820 CommonNavigationParams common_params
;
1821 common_params
.url
= GURL("data:text/html,min_zoomlimit_test");
1822 view()->OnSetZoomLevelForLoadingURL(common_params
.url
, kMinZoomLevel
);
1823 frame()->Navigate(common_params
, StartNavigationParams(),
1824 RequestNavigationParams());
1825 ProcessPendingMessages();
1826 EXPECT_DOUBLE_EQ(kMinZoomLevel
, view()->GetWebView()->zoomLevel());
1828 // It should work even when the zoom limit is temporarily changed in the page.
1829 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
1830 ZoomFactorToZoomLevel(1.0));
1831 common_params
.url
= GURL("data:text/html,max_zoomlimit_test");
1832 view()->OnSetZoomLevelForLoadingURL(common_params
.url
, kMaxZoomLevel
);
1833 frame()->Navigate(common_params
, StartNavigationParams(),
1834 RequestNavigationParams());
1835 ProcessPendingMessages();
1836 EXPECT_DOUBLE_EQ(kMaxZoomLevel
, view()->GetWebView()->zoomLevel());
1839 TEST_F(RenderViewImplTest
, SetEditableSelectionAndComposition
) {
1840 // Load an HTML page consisting of an input field.
1845 "<input id=\"test1\" value=\"some test text hello\"></input>"
1848 ExecuteJavaScriptForTests("document.getElementById('test1').focus();");
1849 frame()->SetEditableSelectionOffsets(4, 8);
1850 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1851 frame()->SetCompositionFromExistingText(7, 10, empty_underline
);
1852 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1853 EXPECT_EQ(4, info
.selectionStart
);
1854 EXPECT_EQ(8, info
.selectionEnd
);
1855 EXPECT_EQ(7, info
.compositionStart
);
1856 EXPECT_EQ(10, info
.compositionEnd
);
1857 frame()->Unselect();
1858 info
= view()->webview()->textInputInfo();
1859 EXPECT_EQ(0, info
.selectionStart
);
1860 EXPECT_EQ(0, info
.selectionEnd
);
1864 TEST_F(RenderViewImplTest
, OnExtendSelectionAndDelete
) {
1865 // Load an HTML page consisting of an input field.
1870 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
1873 ExecuteJavaScriptForTests("document.getElementById('test1').focus();");
1874 frame()->SetEditableSelectionOffsets(10, 10);
1875 frame()->ExtendSelectionAndDelete(3, 4);
1876 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1877 EXPECT_EQ("abcdefgopqrstuvwxyz", info
.value
);
1878 EXPECT_EQ(7, info
.selectionStart
);
1879 EXPECT_EQ(7, info
.selectionEnd
);
1880 frame()->SetEditableSelectionOffsets(4, 8);
1881 frame()->ExtendSelectionAndDelete(2, 5);
1882 info
= view()->webview()->textInputInfo();
1883 EXPECT_EQ("abuvwxyz", info
.value
);
1884 EXPECT_EQ(2, info
.selectionStart
);
1885 EXPECT_EQ(2, info
.selectionEnd
);
1888 // Test that the navigating specific frames works correctly.
1889 TEST_F(RenderViewImplTest
, NavigateSubframe
) {
1891 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
1893 // Navigate the frame only.
1894 CommonNavigationParams common_params
;
1895 RequestNavigationParams request_params
;
1896 common_params
.url
= GURL("data:text/html,world");
1897 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1898 common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
1899 request_params
.current_history_list_length
= 1;
1900 request_params
.current_history_list_offset
= 0;
1901 request_params
.pending_history_list_offset
= 1;
1902 request_params
.page_id
= -1;
1903 request_params
.browser_navigation_start
=
1904 base::TimeTicks::FromInternalValue(1);
1906 TestRenderFrame
* subframe
=
1907 static_cast<TestRenderFrame
*>(RenderFrameImpl::FromWebFrame(
1908 view()->webview()->findFrameByName("frame")));
1909 subframe
->Navigate(common_params
, StartNavigationParams(), request_params
);
1910 FrameLoadWaiter(subframe
).Wait();
1912 // Copy the document content to std::wstring and compare with the
1914 const int kMaxOutputCharacters
= 256;
1915 std::string output
= base::UTF16ToUTF8(base::StringPiece16(
1916 GetMainFrame()->contentAsText(kMaxOutputCharacters
)));
1917 EXPECT_EQ(output
, "hello \n\nworld");
1920 // This test ensures that a RenderFrame object is created for the top level
1921 // frame in the RenderView.
1922 TEST_F(RenderViewImplTest
, BasicRenderFrame
) {
1923 EXPECT_TRUE(view()->main_render_frame_
);
1926 TEST_F(RenderViewImplTest
, GetSSLStatusOfFrame
) {
1927 LoadHTML("<!DOCTYPE html><html><body></body></html>");
1929 WebLocalFrame
* frame
= GetMainFrame();
1930 SSLStatus ssl_status
= view()->GetSSLStatusOfFrame(frame
);
1931 EXPECT_FALSE(net::IsCertStatusError(ssl_status
.cert_status
));
1933 const_cast<blink::WebURLResponse
&>(frame
->dataSource()->response()).
1935 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS
, 0, 0,
1936 SignedCertificateTimestampIDStatusList()));
1937 ssl_status
= view()->GetSSLStatusOfFrame(frame
);
1938 EXPECT_TRUE(net::IsCertStatusError(ssl_status
.cert_status
));
1941 TEST_F(RenderViewImplTest
, MessageOrderInDidChangeSelection
) {
1942 view()->set_send_content_state_immediately(true);
1943 LoadHTML("<textarea id=\"test\"></textarea>");
1945 view()->handling_input_event_
= true;
1946 ExecuteJavaScriptForTests("document.getElementById('test').focus();");
1948 bool is_input_type_called
= false;
1949 bool is_selection_called
= false;
1950 size_t last_input_type
= 0;
1951 size_t last_selection
= 0;
1953 for (size_t i
= 0; i
< render_thread_
->sink().message_count(); ++i
) {
1954 const uint32 type
= render_thread_
->sink().GetMessageAt(i
)->type();
1955 if (type
== ViewHostMsg_TextInputTypeChanged::ID
) {
1956 is_input_type_called
= true;
1957 last_input_type
= i
;
1958 } else if (type
== ViewHostMsg_SelectionChanged::ID
) {
1959 is_selection_called
= true;
1964 EXPECT_TRUE(is_input_type_called
);
1965 EXPECT_TRUE(is_selection_called
);
1967 // InputTypeChange shold be called earlier than SelectionChanged.
1968 EXPECT_LT(last_input_type
, last_selection
);
1971 class RendererErrorPageTest
: public RenderViewImplTest
{
1973 ContentRendererClient
* CreateContentRendererClient() override
{
1974 return new TestContentRendererClient
;
1977 RenderViewImpl
* view() {
1978 return static_cast<RenderViewImpl
*>(view_
);
1981 RenderFrameImpl
* frame() {
1982 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
1986 class TestContentRendererClient
: public ContentRendererClient
{
1988 bool ShouldSuppressErrorPage(RenderFrame
* render_frame
,
1989 const GURL
& url
) override
{
1990 return url
== GURL("http://example.com/suppress");
1993 void GetNavigationErrorStrings(content::RenderView
* render_view
,
1994 blink::WebFrame
* frame
,
1995 const blink::WebURLRequest
& failed_request
,
1996 const blink::WebURLError
& error
,
1997 std::string
* error_html
,
1998 base::string16
* error_description
) override
{
2000 *error_html
= "A suffusion of yellow.";
2003 bool HasErrorPage(int http_status_code
,
2004 std::string
* error_domain
) override
{
2010 #if defined(OS_ANDROID)
2011 // Crashing on Android: http://crbug.com/311341
2012 #define MAYBE_Suppresses DISABLED_Suppresses
2014 #define MAYBE_Suppresses Suppresses
2017 TEST_F(RendererErrorPageTest
, MAYBE_Suppresses
) {
2019 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2020 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2021 error
.unreachableURL
= GURL("http://example.com/suppress");
2022 WebLocalFrame
* web_frame
= GetMainFrame();
2024 // Start a load that will reach provisional state synchronously,
2025 // but won't complete synchronously.
2026 CommonNavigationParams common_params
;
2027 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2028 common_params
.url
= GURL("data:text/html,test data");
2029 TestRenderFrame
* main_frame
= static_cast<TestRenderFrame
*>(frame());
2030 main_frame
->Navigate(common_params
, StartNavigationParams(),
2031 RequestNavigationParams());
2033 // An error occurred.
2034 main_frame
->didFailProvisionalLoad(web_frame
, error
,
2035 blink::WebStandardCommit
);
2036 const int kMaxOutputCharacters
= 22;
2037 EXPECT_EQ("", base::UTF16ToASCII(
2038 base::StringPiece16(web_frame
->contentAsText(kMaxOutputCharacters
))));
2041 #if defined(OS_ANDROID)
2042 // Crashing on Android: http://crbug.com/311341
2043 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2045 #define MAYBE_DoesNotSuppress DoesNotSuppress
2048 TEST_F(RendererErrorPageTest
, MAYBE_DoesNotSuppress
) {
2050 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2051 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2052 error
.unreachableURL
= GURL("http://example.com/dont-suppress");
2053 WebLocalFrame
* web_frame
= GetMainFrame();
2055 // Start a load that will reach provisional state synchronously,
2056 // but won't complete synchronously.
2057 CommonNavigationParams common_params
;
2058 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2059 common_params
.url
= GURL("data:text/html,test data");
2060 TestRenderFrame
* main_frame
= static_cast<TestRenderFrame
*>(frame());
2061 main_frame
->Navigate(common_params
, StartNavigationParams(),
2062 RequestNavigationParams());
2064 // An error occurred.
2065 main_frame
->didFailProvisionalLoad(web_frame
, error
,
2066 blink::WebStandardCommit
);
2068 // The error page itself is loaded asynchronously.
2069 FrameLoadWaiter(main_frame
).Wait();
2070 const int kMaxOutputCharacters
= 22;
2071 EXPECT_EQ("A suffusion of yellow.",
2072 base::UTF16ToASCII(base::StringPiece16(
2073 web_frame
->contentAsText(kMaxOutputCharacters
))));
2076 #if defined(OS_ANDROID)
2077 // Crashing on Android: http://crbug.com/311341
2078 #define MAYBE_HttpStatusCodeErrorWithEmptyBody \
2079 DISABLED_HttpStatusCodeErrorWithEmptyBody
2081 #define MAYBE_HttpStatusCodeErrorWithEmptyBody HttpStatusCodeErrorWithEmptyBody
2083 TEST_F(RendererErrorPageTest
, MAYBE_HttpStatusCodeErrorWithEmptyBody
) {
2084 blink::WebURLResponse response
;
2085 response
.initialize();
2086 response
.setHTTPStatusCode(503);
2087 WebLocalFrame
* web_frame
= GetMainFrame();
2089 // Start a load that will reach provisional state synchronously,
2090 // but won't complete synchronously.
2091 CommonNavigationParams common_params
;
2092 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2093 common_params
.url
= GURL("data:text/html,test data");
2094 TestRenderFrame
* main_frame
= static_cast<TestRenderFrame
*>(frame());
2095 main_frame
->Navigate(common_params
, StartNavigationParams(),
2096 RequestNavigationParams());
2098 // Emulate a 4xx/5xx main resource response with an empty body.
2099 main_frame
->didReceiveResponse(web_frame
, 1, response
);
2100 main_frame
->didFinishDocumentLoad(web_frame
, true);
2102 // The error page itself is loaded asynchronously.
2103 FrameLoadWaiter(main_frame
).Wait();
2104 const int kMaxOutputCharacters
= 22;
2105 EXPECT_EQ("A suffusion of yellow.",
2106 base::UTF16ToASCII(base::StringPiece16(
2107 web_frame
->contentAsText(kMaxOutputCharacters
))));
2110 // Ensure the render view sends favicon url update events correctly.
2111 TEST_F(RenderViewImplTest
, SendFaviconURLUpdateEvent
) {
2112 // An event should be sent when a favicon url exists.
2115 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2118 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
2119 ViewHostMsg_UpdateFaviconURL::ID
));
2120 render_thread_
->sink().ClearMessages();
2122 // An event should not be sent if no favicon url exists. This is an assumption
2123 // made by some of Chrome's favicon handling.
2128 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
2129 ViewHostMsg_UpdateFaviconURL::ID
));
2132 TEST_F(RenderViewImplTest
, FocusElementCallsFocusedNodeChanged
) {
2133 LoadHTML("<input id='test1' value='hello1'></input>"
2134 "<input id='test2' value='hello2'></input>");
2136 ExecuteJavaScriptForTests("document.getElementById('test1').focus();");
2137 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
2138 ViewHostMsg_FocusedNodeChanged::ID
);
2141 ViewHostMsg_FocusedNodeChanged::Param params
;
2142 ViewHostMsg_FocusedNodeChanged::Read(msg1
, ¶ms
);
2143 EXPECT_TRUE(base::get
<0>(params
));
2144 render_thread_
->sink().ClearMessages();
2146 ExecuteJavaScriptForTests("document.getElementById('test2').focus();");
2147 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
2148 ViewHostMsg_FocusedNodeChanged::ID
);
2150 ViewHostMsg_FocusedNodeChanged::Read(msg2
, ¶ms
);
2151 EXPECT_TRUE(base::get
<0>(params
));
2152 render_thread_
->sink().ClearMessages();
2154 view()->webview()->clearFocusedElement();
2155 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
2156 ViewHostMsg_FocusedNodeChanged::ID
);
2158 ViewHostMsg_FocusedNodeChanged::Read(msg3
, ¶ms
);
2159 EXPECT_FALSE(base::get
<0>(params
));
2160 render_thread_
->sink().ClearMessages();
2163 TEST_F(RenderViewImplTest
, ServiceWorkerNetworkProviderSetup
) {
2164 ServiceWorkerNetworkProvider
* provider
= NULL
;
2165 RequestExtraData
* extra_data
= NULL
;
2167 // Make sure each new document has a new provider and
2168 // that the main request is tagged with the provider's id.
2169 LoadHTML("<b>A Document</b>");
2170 ASSERT_TRUE(GetMainFrame()->dataSource());
2171 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2172 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2173 ASSERT_TRUE(provider
);
2174 extra_data
= static_cast<RequestExtraData
*>(
2175 GetMainFrame()->dataSource()->request().extraData());
2176 ASSERT_TRUE(extra_data
);
2177 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2178 provider
->provider_id());
2179 int provider1_id
= provider
->provider_id();
2181 LoadHTML("<b>New Document B Goes Here</b>");
2182 ASSERT_TRUE(GetMainFrame()->dataSource());
2183 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2184 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2185 ASSERT_TRUE(provider
);
2186 EXPECT_NE(provider1_id
, provider
->provider_id());
2187 extra_data
= static_cast<RequestExtraData
*>(
2188 GetMainFrame()->dataSource()->request().extraData());
2189 ASSERT_TRUE(extra_data
);
2190 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2191 provider
->provider_id());
2193 // See that subresource requests are also tagged with the provider's id.
2194 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2195 blink::WebURLRequest
request(GURL("http://foo.com"));
2196 request
.setRequestContext(blink::WebURLRequest::RequestContextSubresource
);
2197 blink::WebURLResponse redirect_response
;
2198 frame()->willSendRequest(GetMainFrame(), 0, request
, redirect_response
);
2199 extra_data
= static_cast<RequestExtraData
*>(request
.extraData());
2200 ASSERT_TRUE(extra_data
);
2201 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2202 provider
->provider_id());
2205 TEST_F(RenderViewImplTest
, OnSetAccessibilityMode
) {
2206 ASSERT_EQ(AccessibilityModeOff
, frame()->accessibility_mode());
2207 ASSERT_EQ((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2209 frame()->SetAccessibilityMode(AccessibilityModeTreeOnly
);
2210 ASSERT_EQ(AccessibilityModeTreeOnly
, frame()->accessibility_mode());
2211 ASSERT_NE((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2213 frame()->SetAccessibilityMode(AccessibilityModeOff
);
2214 ASSERT_EQ(AccessibilityModeOff
, frame()->accessibility_mode());
2215 ASSERT_EQ((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2217 frame()->SetAccessibilityMode(AccessibilityModeComplete
);
2218 ASSERT_EQ(AccessibilityModeComplete
, frame()->accessibility_mode());
2219 ASSERT_NE((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2222 TEST_F(RenderViewImplTest
, ScreenMetricsEmulation
) {
2223 LoadHTML("<body style='min-height:1000px;'></body>");
2225 blink::WebDeviceEmulationParams params
;
2226 base::string16 get_width
= base::ASCIIToUTF16("Number(window.innerWidth)");
2227 base::string16 get_height
= base::ASCIIToUTF16("Number(window.innerHeight)");
2230 params
.viewSize
.width
= 327;
2231 params
.viewSize
.height
= 415;
2232 view()->OnEnableDeviceEmulation(params
);
2233 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width
, &width
));
2234 EXPECT_EQ(params
.viewSize
.width
, width
);
2235 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height
, &height
));
2236 EXPECT_EQ(params
.viewSize
.height
, height
);
2238 params
.viewSize
.width
= 1005;
2239 params
.viewSize
.height
= 1102;
2240 view()->OnEnableDeviceEmulation(params
);
2241 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width
, &width
));
2242 EXPECT_EQ(params
.viewSize
.width
, width
);
2243 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height
, &height
));
2244 EXPECT_EQ(params
.viewSize
.height
, height
);
2246 view()->OnDisableDeviceEmulation();
2248 view()->OnEnableDeviceEmulation(params
);
2249 // Don't disable here to test that emulation is being shutdown properly.
2252 // Sanity checks for the Navigation Timing API |navigationStart| override. We
2253 // are asserting only most basic constraints, as TimeTicks (passed as the
2254 // override) are not comparable with the wall time (returned by the Blink API).
2255 TEST_F(RenderViewImplTest
, NavigationStartOverride
) {
2256 // Verify that a navigation that claims to have started at the earliest
2257 // possible TimeTicks is indeed reported as one that started before
2258 // OnNavigate() is called.
2259 base::Time before_navigation
= base::Time::Now();
2260 CommonNavigationParams early_common_params
;
2261 StartNavigationParams early_start_params
;
2262 RequestNavigationParams early_request_params
;
2263 early_common_params
.url
= GURL("data:text/html,<div>Page</div>");
2264 early_common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2265 early_common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
2266 early_start_params
.is_post
= true;
2267 early_request_params
.browser_navigation_start
=
2268 base::TimeTicks::FromInternalValue(1);
2270 frame()->Navigate(early_common_params
, early_start_params
,
2271 early_request_params
);
2272 ProcessPendingMessages();
2274 base::Time early_nav_reported_start
=
2275 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2276 EXPECT_LT(early_nav_reported_start
, before_navigation
);
2278 // Verify that a navigation that claims to have started in the future - 42
2279 // days from now is *not* reported as one that starts in the future; as we
2280 // sanitize the override allowing a maximum of ::Now().
2281 CommonNavigationParams late_common_params
;
2282 RequestNavigationParams late_request_params
;
2283 StartNavigationParams late_start_params
;
2284 late_common_params
.url
= GURL("data:text/html,<div>Another page</div>");
2285 late_common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2286 late_common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
2287 late_start_params
.is_post
= true;
2288 late_request_params
.browser_navigation_start
=
2289 base::TimeTicks::Now() + base::TimeDelta::FromDays(42);
2291 frame()->Navigate(late_common_params
, late_start_params
, late_request_params
);
2292 ProcessPendingMessages();
2293 base::Time after_navigation
=
2294 base::Time::Now() + base::TimeDelta::FromDays(1);
2296 base::Time late_nav_reported_start
=
2297 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2298 EXPECT_LE(late_nav_reported_start
, after_navigation
);
2301 TEST_F(RenderViewImplTest
, PreferredSizeZoomed
) {
2302 LoadHTML("<body style='margin:0;'><div style='display:inline-block; "
2303 "width:400px; height:400px;'/></body>");
2304 view()->webview()->mainFrame()->setCanHaveScrollbars(false);
2305 EnablePreferredSizeMode();
2307 gfx::Size size
= GetPreferredSize();
2308 EXPECT_EQ(gfx::Size(400, 400), size
);
2310 SetZoomLevel(ZoomFactorToZoomLevel(2.0));
2311 size
= GetPreferredSize();
2312 EXPECT_EQ(gfx::Size(800, 800), size
);
2315 // Ensure the RenderViewImpl history list is properly updated when starting a
2316 // new browser-initiated navigation.
2317 TEST_F(RenderViewImplTest
, HistoryIsProperlyUpdatedOnNavigation
) {
2318 EXPECT_EQ(0, view()->historyBackListCount());
2319 EXPECT_EQ(0, view()->historyBackListCount() +
2320 view()->historyForwardListCount() + 1);
2322 // Receive a Navigate message with history parameters.
2323 RequestNavigationParams request_params
;
2324 request_params
.current_history_list_length
= 2;
2325 request_params
.current_history_list_offset
= 1;
2326 request_params
.pending_history_list_offset
= 2;
2327 request_params
.page_id
= -1;
2328 frame()->Navigate(CommonNavigationParams(), StartNavigationParams(),
2331 // The history list in RenderView should have been updated.
2332 EXPECT_EQ(1, view()->historyBackListCount());
2333 EXPECT_EQ(2, view()->historyBackListCount() +
2334 view()->historyForwardListCount() + 1);
2337 TEST_F(RenderViewImplBlinkSettingsTest
, Default
) {
2339 EXPECT_EQ(blink::WebSettings::HoverTypeNone
, settings()->primaryHoverType());
2340 EXPECT_FALSE(settings()->viewportEnabled());
2343 TEST_F(RenderViewImplBlinkSettingsTest
, CommandLine
) {
2344 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
2345 switches::kBlinkSettings
, "primaryHoverType=4,viewportEnabled=true");
2347 EXPECT_EQ(blink::WebSettings::HoverTypeHover
, settings()->primaryHoverType());
2348 EXPECT_TRUE(settings()->viewportEnabled());
2351 TEST_F(DevToolsAgentTest
, DevToolsResumeOnClose
) {
2353 EXPECT_FALSE(IsPaused());
2354 DispatchDevToolsMessage("{\"id\":1,\"method\":\"Debugger.enable\"}");
2356 // Executing javascript will pause the thread and create nested message loop.
2357 // Posting task simulates message coming from browser.
2358 base::ThreadTaskRunnerHandle::Get()->PostTask(
2360 base::Bind(&DevToolsAgentTest::CloseWhilePaused
, base::Unretained(this)));
2361 ExecuteJavaScriptForTests("debugger;");
2363 // CloseWhilePaused should resume execution and continue here.
2364 EXPECT_FALSE(IsPaused());
2368 } // namespace content