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 "net/base/net_errors.h"
47 #include "net/cert/cert_status_flags.h"
48 #include "testing/gtest/include/gtest/gtest.h"
49 #include "third_party/WebKit/public/platform/WebData.h"
50 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
51 #include "third_party/WebKit/public/platform/WebString.h"
52 #include "third_party/WebKit/public/platform/WebURLResponse.h"
53 #include "third_party/WebKit/public/web/WebDataSource.h"
54 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
55 #include "third_party/WebKit/public/web/WebHistoryCommitType.h"
56 #include "third_party/WebKit/public/web/WebHistoryItem.h"
57 #include "third_party/WebKit/public/web/WebLocalFrame.h"
58 #include "third_party/WebKit/public/web/WebPerformance.h"
59 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
60 #include "third_party/WebKit/public/web/WebView.h"
61 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
62 #include "ui/events/event.h"
63 #include "ui/events/keycodes/keyboard_codes.h"
64 #include "ui/gfx/codec/jpeg_codec.h"
65 #include "ui/gfx/range/range.h"
67 #if defined(USE_AURA) && defined(USE_X11)
69 #include "ui/events/event_constants.h"
70 #include "ui/events/keycodes/keyboard_code_conversion.h"
71 #include "ui/events/test/events_test_utils.h"
72 #include "ui/events/test/events_test_utils_x11.h"
75 #if defined(USE_OZONE)
76 #include "ui/events/keycodes/keyboard_code_conversion.h"
79 using blink::WebFrame
;
80 using blink::WebInputEvent
;
81 using blink::WebLocalFrame
;
82 using blink::WebMouseEvent
;
83 using blink::WebRuntimeFeatures
;
84 using blink::WebString
;
85 using blink::WebTextDirection
;
86 using blink::WebURLError
;
92 static const int kProxyRoutingId
= 13;
94 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
95 // Converts MockKeyboard::Modifiers to ui::EventFlags.
96 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers
) {
97 static struct ModifierMap
{
98 MockKeyboard::Modifiers src
;
101 { MockKeyboard::LEFT_SHIFT
, ui::EF_SHIFT_DOWN
},
102 { MockKeyboard::RIGHT_SHIFT
, ui::EF_SHIFT_DOWN
},
103 { MockKeyboard::LEFT_CONTROL
, ui::EF_CONTROL_DOWN
},
104 { MockKeyboard::RIGHT_CONTROL
, ui::EF_CONTROL_DOWN
},
105 { MockKeyboard::LEFT_ALT
, ui::EF_ALT_DOWN
},
106 { MockKeyboard::RIGHT_ALT
, ui::EF_ALT_DOWN
},
109 for (size_t i
= 0; i
< arraysize(kModifierMap
); ++i
) {
110 if (kModifierMap
[i
].src
& modifiers
) {
111 flags
|= kModifierMap
[i
].dst
;
118 class WebUITestWebUIControllerFactory
: public WebUIControllerFactory
{
120 WebUIController
* CreateWebUIControllerForURL(WebUI
* web_ui
,
121 const GURL
& url
) const override
{
124 WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
125 const GURL
& url
) const override
{
126 return WebUI::kNoWebUI
;
128 bool UseWebUIForURL(BrowserContext
* browser_context
,
129 const GURL
& url
) const override
{
130 return HasWebUIScheme(url
);
132 bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
133 const GURL
& url
) const override
{
134 return HasWebUIScheme(url
);
140 class RenderViewImplTest
: public RenderViewTest
{
142 RenderViewImplTest() {
143 // Attach a pseudo keyboard device to this object.
144 mock_keyboard_
.reset(new MockKeyboard());
147 ~RenderViewImplTest() override
{}
149 void SetUp() override
{
150 RenderViewTest::SetUp();
151 // Enable Blink's experimental and test only features so that test code
152 // does not have to bother enabling each feature.
153 WebRuntimeFeatures::enableExperimentalFeatures(true);
154 WebRuntimeFeatures::enableTestOnlyFeatures(true);
157 RenderViewImpl
* view() {
158 return static_cast<RenderViewImpl
*>(view_
);
162 return view()->page_id_
;
165 RenderFrameImpl
* frame() {
166 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
169 // Sends IPC messages that emulates a key-press event.
170 int SendKeyEvent(MockKeyboard::Layout layout
,
172 MockKeyboard::Modifiers modifiers
,
173 base::string16
* output
) {
175 // Retrieve the Unicode character for the given tuple (keyboard-layout,
176 // key-code, and modifiers).
177 // Exit when a keyboard-layout driver cannot assign a Unicode character to
178 // the tuple to prevent sending an invalid key code to the RenderView
180 CHECK(mock_keyboard_
.get());
182 int length
= mock_keyboard_
->GetCharacters(layout
, key_code
, modifiers
,
187 // Create IPC messages from Windows messages and send them to our
189 // A keyboard event of Windows consists of three Windows messages:
190 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
191 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
192 // WM_CHAR sends a composed Unicode character.
193 MSG msg1
= { NULL
, WM_KEYDOWN
, key_code
, 0 };
194 ui::KeyEvent
evt1(msg1
);
195 NativeWebKeyboardEvent
keydown_event(evt1
);
196 SendNativeKeyEvent(keydown_event
);
198 MSG msg2
= { NULL
, WM_CHAR
, (*output
)[0], 0 };
199 ui::KeyEvent
evt2(msg2
);
200 NativeWebKeyboardEvent
char_event(evt2
);
201 SendNativeKeyEvent(char_event
);
203 MSG msg3
= { NULL
, WM_KEYUP
, key_code
, 0 };
204 ui::KeyEvent
evt3(msg3
);
205 NativeWebKeyboardEvent
keyup_event(evt3
);
206 SendNativeKeyEvent(keyup_event
);
209 #elif defined(USE_AURA) && defined(USE_X11)
210 // We ignore |layout|, which means we are only testing the layout of the
211 // current locale. TODO(mazda): fix this to respect |layout|.
213 const int flags
= ConvertMockKeyboardModifier(modifiers
);
215 ui::ScopedXI2Event xevent
;
216 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
217 static_cast<ui::KeyboardCode
>(key_code
),
219 ui::KeyEvent
event1(xevent
);
220 NativeWebKeyboardEvent
keydown_event(event1
);
221 SendNativeKeyEvent(keydown_event
);
223 // X11 doesn't actually have native character events, but give the test
225 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
226 static_cast<ui::KeyboardCode
>(key_code
),
228 ui::KeyEvent
event2(xevent
);
229 event2
.set_character(GetCharacterFromKeyCode(event2
.key_code(),
231 ui::KeyEventTestApi
test_event2(&event2
);
232 test_event2
.set_is_char(true);
233 NativeWebKeyboardEvent
char_event(event2
);
234 SendNativeKeyEvent(char_event
);
236 xevent
.InitKeyEvent(ui::ET_KEY_RELEASED
,
237 static_cast<ui::KeyboardCode
>(key_code
),
239 ui::KeyEvent
event3(xevent
);
240 NativeWebKeyboardEvent
keyup_event(event3
);
241 SendNativeKeyEvent(keyup_event
);
243 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
245 output
->assign(1, static_cast<base::char16
>(c
));
247 #elif defined(USE_OZONE)
248 const int flags
= ConvertMockKeyboardModifier(modifiers
);
250 ui::KeyEvent
keydown_event(ui::ET_KEY_PRESSED
,
251 static_cast<ui::KeyboardCode
>(key_code
),
253 NativeWebKeyboardEvent
keydown_web_event(keydown_event
);
254 SendNativeKeyEvent(keydown_web_event
);
256 ui::KeyEvent
char_event(keydown_event
.GetCharacter(),
257 static_cast<ui::KeyboardCode
>(key_code
),
259 NativeWebKeyboardEvent
char_web_event(char_event
);
260 SendNativeKeyEvent(char_web_event
);
262 ui::KeyEvent
keyup_event(ui::ET_KEY_RELEASED
,
263 static_cast<ui::KeyboardCode
>(key_code
),
265 NativeWebKeyboardEvent
keyup_web_event(keyup_event
);
266 SendNativeKeyEvent(keyup_web_event
);
268 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
270 output
->assign(1, static_cast<base::char16
>(c
));
278 void EnablePreferredSizeMode() {
279 view()->OnEnablePreferredSizeChangedMode();
282 const gfx::Size
& GetPreferredSize() {
283 view()->CheckPreferredSize();
284 return view()->preferred_size_
;
287 void SetZoomLevel(double level
) {
288 view()->OnSetZoomLevelForView(false, level
);
291 void NavigateMainFrame(const CommonNavigationParams
& common_params
,
292 const StartNavigationParams
& start_params
,
293 const RequestNavigationParams
& request_params
) {
294 NavigateFrame(frame(), common_params
, start_params
, request_params
);
297 void NavigateFrame(RenderFrameImpl
* frame
,
298 const CommonNavigationParams
& common_params
,
299 const StartNavigationParams
& start_params
,
300 const RequestNavigationParams
& request_params
) {
302 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
303 switches::kEnableBrowserSideNavigation
)) {
304 frame
->OnCommitNavigation(ResourceResponseHead(), common_params
.url
,
305 common_params
, request_params
);
308 frame
->OnNavigate(common_params
, start_params
, request_params
);
311 void SwapOut(RenderFrameImpl
* frame
,
312 int proxy_routing_id
,
314 const FrameReplicationState
& replicated_frame_state
) {
315 frame
->OnSwapOut(proxy_routing_id
, is_loading
, replicated_frame_state
);
318 void SetEditableSelectionOffsets(int start
, int end
) {
319 frame()->OnSetEditableSelectionOffsets(start
, end
);
322 void ExtendSelectionAndDelete(int before
, int after
) {
323 frame()->OnExtendSelectionAndDelete(before
, after
);
326 void Unselect() { frame()->OnUnselect(); }
328 void SetAccessibilityMode(AccessibilityMode new_mode
) {
329 frame()->OnSetAccessibilityMode(new_mode
);
332 void SetCompositionFromExistingText(
335 const std::vector
<blink::WebCompositionUnderline
>& underlines
) {
336 frame()->OnSetCompositionFromExistingText(start
, end
, underlines
);
340 scoped_ptr
<MockKeyboard
> mock_keyboard_
;
343 class DevToolsAgentTest
: public RenderViewImplTest
{
346 std::string host_id
= "host_id";
347 agent()->OnAttach(host_id
);
355 return agent()->paused_
;
358 void DispatchDevToolsMessage(const std::string
& message
) {
359 agent()->OnDispatchOnInspectorBackend(message
);
362 void CloseWhilePaused() {
363 EXPECT_TRUE(IsPaused());
364 view()->NotifyOnClose();
368 DevToolsAgent
* agent() {
369 return frame()->devtools_agent();
373 // Ensure that the main RenderFrame is deleted and cleared from the RenderView
375 TEST_F(RenderViewImplTest
, RenderFrameClearedAfterClose
) {
376 // Create a new main frame RenderFrame so that we don't interfere with the
377 // shutdown of frame() in RenderViewTest.TearDown.
378 blink::WebURLRequest
popup_request(GURL("http://foo.com"));
379 blink::WebView
* new_web_view
= view()->createView(
380 GetMainFrame(), popup_request
, blink::WebWindowFeatures(), "foo",
381 blink::WebNavigationPolicyNewForegroundTab
, false);
382 RenderViewImpl
* new_view
= RenderViewImpl::FromWebView(new_web_view
);
384 // Close the view, causing the main RenderFrame to be detached and deleted.
386 EXPECT_FALSE(new_view
->GetMainRenderFrame());
388 // Clean up after the new view so we don't leak it.
392 TEST_F(RenderViewImplTest
, SaveImageFromDataURL
) {
393 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
394 ViewHostMsg_SaveImageFromDataURL::ID
);
396 render_thread_
->sink().ClearMessages();
398 const std::string image_data_url
=
399 "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
401 view()->saveImageFromDataURL(WebString::fromUTF8(image_data_url
));
402 ProcessPendingMessages();
403 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
404 ViewHostMsg_SaveImageFromDataURL::ID
);
407 ViewHostMsg_SaveImageFromDataURL::Param param1
;
408 ViewHostMsg_SaveImageFromDataURL::Read(msg2
, ¶m1
);
409 EXPECT_EQ(base::get
<1>(param1
).length(), image_data_url
.length());
410 EXPECT_EQ(base::get
<1>(param1
), image_data_url
);
412 ProcessPendingMessages();
413 render_thread_
->sink().ClearMessages();
415 const std::string
large_data_url(1024 * 1024 * 10 - 1, 'd');
417 view()->saveImageFromDataURL(WebString::fromUTF8(large_data_url
));
418 ProcessPendingMessages();
419 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
420 ViewHostMsg_SaveImageFromDataURL::ID
);
423 ViewHostMsg_SaveImageFromDataURL::Param param2
;
424 ViewHostMsg_SaveImageFromDataURL::Read(msg3
, ¶m2
);
425 EXPECT_EQ(base::get
<1>(param2
).length(), large_data_url
.length());
426 EXPECT_EQ(base::get
<1>(param2
), large_data_url
);
428 ProcessPendingMessages();
429 render_thread_
->sink().ClearMessages();
431 const std::string
exceeded_data_url(1024 * 1024 * 10 + 1, 'd');
433 view()->saveImageFromDataURL(WebString::fromUTF8(exceeded_data_url
));
434 ProcessPendingMessages();
435 const IPC::Message
* msg4
= render_thread_
->sink().GetFirstMessageMatching(
436 ViewHostMsg_SaveImageFromDataURL::ID
);
440 // Test that we get form state change notifications when input fields change.
441 TEST_F(RenderViewImplTest
, DISABLED_OnNavStateChanged
) {
442 // Don't want any delay for form state sync changes. This will still post a
443 // message so updates will get coalesced, but as soon as we spin the message
444 // loop, it will generate an update.
445 view()->set_send_content_state_immediately(true);
447 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
449 // We should NOT have gotten a form state change notification yet.
450 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
451 ViewHostMsg_UpdateState::ID
));
452 render_thread_
->sink().ClearMessages();
454 // Change the value of the input. We should have gotten an update state
455 // notification. We need to spin the message loop to catch this update.
456 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';");
457 ProcessPendingMessages();
458 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
459 ViewHostMsg_UpdateState::ID
));
462 TEST_F(RenderViewImplTest
, OnNavigationHttpPost
) {
463 // An http url will trigger a resource load so cannot be used here.
464 CommonNavigationParams common_params
;
465 StartNavigationParams start_params
;
466 RequestNavigationParams request_params
;
467 common_params
.url
= GURL("data:text/html,<div>Page</div>");
468 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
469 common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
470 request_params
.page_id
= -1;
473 const unsigned char* raw_data
= reinterpret_cast<const unsigned char*>(
475 const unsigned int length
= 11;
476 const std::vector
<unsigned char> post_data(raw_data
, raw_data
+ length
);
477 start_params
.is_post
= true;
478 start_params
.browser_initiated_post_data
= post_data
;
480 NavigateMainFrame(common_params
, start_params
, request_params
);
481 ProcessPendingMessages();
483 const IPC::Message
* frame_navigate_msg
=
484 render_thread_
->sink().GetUniqueMessageMatching(
485 FrameHostMsg_DidCommitProvisionalLoad::ID
);
486 EXPECT_TRUE(frame_navigate_msg
);
488 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params
;
489 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
491 EXPECT_TRUE(base::get
<0>(host_nav_params
).is_post
);
493 // Check post data sent to browser matches
494 EXPECT_TRUE(base::get
<0>(host_nav_params
).page_state
.IsValid());
495 scoped_ptr
<HistoryEntry
> entry
=
496 PageStateToHistoryEntry(base::get
<0>(host_nav_params
).page_state
);
497 blink::WebHTTPBody body
= entry
->root().httpBody();
498 blink::WebHTTPBody::Element element
;
499 bool successful
= body
.elementAt(0, element
);
500 EXPECT_TRUE(successful
);
501 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData
, element
.type
);
502 EXPECT_EQ(length
, element
.data
.size());
503 EXPECT_EQ(0, memcmp(raw_data
, element
.data
.data(), length
));
506 TEST_F(RenderViewImplTest
, DecideNavigationPolicy
) {
507 WebUITestWebUIControllerFactory factory
;
508 WebUIControllerFactory::RegisterFactory(&factory
);
511 state
.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
513 // Navigations to normal HTTP URLs can be handled locally.
514 blink::WebURLRequest
request(GURL("http://foo.com"));
515 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
516 policy_info
.frame
= GetMainFrame();
517 policy_info
.extraData
= &state
;
518 policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
519 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
520 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
522 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab
, policy
);
524 // Verify that form posts to WebUI URLs will be sent to the browser process.
525 blink::WebURLRequest
form_request(GURL("chrome://foo"));
526 blink::WebFrameClient::NavigationPolicyInfo
form_policy_info(form_request
);
527 form_policy_info
.frame
= GetMainFrame();
528 form_policy_info
.extraData
= &state
;
529 form_policy_info
.navigationType
= blink::WebNavigationTypeFormSubmitted
;
530 form_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
531 form_request
.setHTTPMethod("POST");
532 policy
= frame()->decidePolicyForNavigation(form_policy_info
);
533 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
535 // Verify that popup links to WebUI URLs also are sent to browser.
536 blink::WebURLRequest
popup_request(GURL("chrome://foo"));
537 blink::WebFrameClient::NavigationPolicyInfo
popup_policy_info(popup_request
);
538 popup_policy_info
.frame
= GetMainFrame();
539 popup_policy_info
.extraData
= &state
;
540 popup_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
541 popup_policy_info
.defaultPolicy
= blink::WebNavigationPolicyNewForegroundTab
;
542 policy
= frame()->decidePolicyForNavigation(popup_policy_info
);
543 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
546 TEST_F(RenderViewImplTest
, DecideNavigationPolicyHandlesAllTopLevel
) {
548 state
.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
550 RendererPreferences prefs
= view()->renderer_preferences();
551 prefs
.browser_handles_all_top_level_requests
= true;
552 view()->OnSetRendererPrefs(prefs
);
554 const blink::WebNavigationType kNavTypes
[] = {
555 blink::WebNavigationTypeLinkClicked
,
556 blink::WebNavigationTypeFormSubmitted
,
557 blink::WebNavigationTypeBackForward
,
558 blink::WebNavigationTypeReload
,
559 blink::WebNavigationTypeFormResubmitted
,
560 blink::WebNavigationTypeOther
,
563 blink::WebURLRequest
request(GURL("http://foo.com"));
564 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
565 policy_info
.frame
= GetMainFrame();
566 policy_info
.extraData
= &state
;
567 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
569 for (size_t i
= 0; i
< arraysize(kNavTypes
); ++i
) {
570 policy_info
.navigationType
= kNavTypes
[i
];
572 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
574 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
578 TEST_F(RenderViewImplTest
, DecideNavigationPolicyForWebUI
) {
579 // Enable bindings to simulate a WebUI view.
580 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI
);
583 state
.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
585 // Navigations to normal HTTP URLs will be sent to browser process.
586 blink::WebURLRequest
request(GURL("http://foo.com"));
587 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
588 policy_info
.frame
= GetMainFrame();
589 policy_info
.extraData
= &state
;
590 policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
591 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
593 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
595 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
597 // Navigations to WebUI URLs will also be sent to browser process.
598 blink::WebURLRequest
webui_request(GURL("chrome://foo"));
599 blink::WebFrameClient::NavigationPolicyInfo
webui_policy_info(webui_request
);
600 webui_policy_info
.frame
= GetMainFrame();
601 webui_policy_info
.extraData
= &state
;
602 webui_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
603 webui_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
604 policy
= frame()->decidePolicyForNavigation(webui_policy_info
);
605 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
607 // Verify that form posts to data URLs will be sent to the browser process.
608 blink::WebURLRequest
data_request(GURL("data:text/html,foo"));
609 blink::WebFrameClient::NavigationPolicyInfo
data_policy_info(data_request
);
610 data_policy_info
.frame
= GetMainFrame();
611 data_policy_info
.extraData
= &state
;
612 data_policy_info
.navigationType
= blink::WebNavigationTypeFormSubmitted
;
613 data_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
614 data_request
.setHTTPMethod("POST");
615 policy
= frame()->decidePolicyForNavigation(data_policy_info
);
616 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
618 // Verify that a popup that creates a view first and then navigates to a
619 // normal HTTP URL will be sent to the browser process, even though the
620 // new view does not have any enabled_bindings_.
621 blink::WebURLRequest
popup_request(GURL("http://foo.com"));
622 blink::WebView
* new_web_view
= view()->createView(
623 GetMainFrame(), popup_request
, blink::WebWindowFeatures(), "foo",
624 blink::WebNavigationPolicyNewForegroundTab
, false);
625 RenderViewImpl
* new_view
= RenderViewImpl::FromWebView(new_web_view
);
626 blink::WebFrameClient::NavigationPolicyInfo
popup_policy_info(popup_request
);
627 popup_policy_info
.frame
= new_web_view
->mainFrame()->toWebLocalFrame();
628 popup_policy_info
.extraData
= &state
;
629 popup_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
630 popup_policy_info
.defaultPolicy
= blink::WebNavigationPolicyNewForegroundTab
;
631 policy
= static_cast<RenderFrameImpl
*>(new_view
->GetMainRenderFrame())->
632 decidePolicyForNavigation(popup_policy_info
);
633 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
635 // Clean up after the new view so we don't leak it.
640 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
641 // already swapped out. http://crbug.com/93427.
642 TEST_F(RenderViewImplTest
, SendSwapOutACK
) {
643 LoadHTML("<div>Page A</div>");
644 int initial_page_id
= view_page_id();
646 // Increment the ref count so that we don't exit when swapping out.
647 RenderProcess::current()->AddRefProcess();
649 // Respond to a swap out request.
650 SwapOut(frame(), kProxyRoutingId
, true, content::FrameReplicationState());
652 // Ensure the swap out commits synchronously.
653 EXPECT_NE(initial_page_id
, view_page_id());
655 // Check for a valid OnSwapOutACK.
656 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
657 FrameHostMsg_SwapOut_ACK::ID
);
660 // It is possible to get another swap out request. Ensure that we send
661 // an ACK, even if we don't have to do anything else.
662 render_thread_
->sink().ClearMessages();
663 SwapOut(frame(), kProxyRoutingId
, false, content::FrameReplicationState());
664 const IPC::Message
* msg2
= render_thread_
->sink().GetUniqueMessageMatching(
665 FrameHostMsg_SwapOut_ACK::ID
);
668 // If we navigate back to this RenderView, ensure we don't send a state
669 // update for the swapped out URL. (http://crbug.com/72235)
670 CommonNavigationParams common_params
;
671 RequestNavigationParams request_params
;
672 common_params
.url
= GURL("data:text/html,<div>Page B</div>");
673 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
674 common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
675 request_params
.current_history_list_length
= 1;
676 request_params
.current_history_list_offset
= 0;
677 request_params
.pending_history_list_offset
= 1;
678 request_params
.page_id
= -1;
679 NavigateMainFrame(common_params
, StartNavigationParams(), request_params
);
680 ProcessPendingMessages();
681 const IPC::Message
* msg3
= render_thread_
->sink().GetUniqueMessageMatching(
682 ViewHostMsg_UpdateState::ID
);
686 // Ensure the RenderViewImpl reloads the previous page if a reload request
687 // arrives while it is showing swappedout://. http://crbug.com/143155.
688 TEST_F(RenderViewImplTest
, ReloadWhileSwappedOut
) {
690 LoadHTML("<div>Page A</div>");
692 // Load page B, which will trigger an UpdateState message for page A.
693 LoadHTML("<div>Page B</div>");
695 // Check for a valid UpdateState message for page A.
696 ProcessPendingMessages();
697 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
698 ViewHostMsg_UpdateState::ID
);
700 ViewHostMsg_UpdateState::Param params
;
701 ViewHostMsg_UpdateState::Read(msg_A
, ¶ms
);
702 int page_id_A
= base::get
<0>(params
);
703 PageState state_A
= base::get
<1>(params
);
704 EXPECT_EQ(1, page_id_A
);
705 render_thread_
->sink().ClearMessages();
707 // Back to page A (page_id 1) and commit.
708 CommonNavigationParams common_params_A
;
709 RequestNavigationParams request_params_A
;
710 common_params_A
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
711 common_params_A
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
712 request_params_A
.current_history_list_length
= 2;
713 request_params_A
.current_history_list_offset
= 1;
714 request_params_A
.pending_history_list_offset
= 0;
715 request_params_A
.page_id
= 1;
716 request_params_A
.nav_entry_id
= 1;
717 request_params_A
.page_state
= state_A
;
718 NavigateMainFrame(common_params_A
, StartNavigationParams(), request_params_A
);
719 EXPECT_EQ(1, view()->historyBackListCount());
720 EXPECT_EQ(2, view()->historyBackListCount() +
721 view()->historyForwardListCount() + 1);
722 ProcessPendingMessages();
724 // Respond to a swap out request.
725 SwapOut(frame(), kProxyRoutingId
, true, content::FrameReplicationState());
727 // Check for a OnSwapOutACK.
728 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
729 FrameHostMsg_SwapOut_ACK::ID
);
731 render_thread_
->sink().ClearMessages();
733 // It is possible to get a reload request at this point, containing the
734 // params.page_state of the initial page (e.g., if the new page fails the
735 // provisional load in the renderer process, after we unload the old page).
736 // Ensure the old page gets reloaded, not swappedout://.
737 CommonNavigationParams common_params
;
738 RequestNavigationParams request_params
;
739 common_params
.url
= GURL("data:text/html,<div>Page A</div>");
740 common_params
.navigation_type
= FrameMsg_Navigate_Type::RELOAD
;
741 common_params
.transition
= ui::PAGE_TRANSITION_RELOAD
;
742 request_params
.current_history_list_length
= 2;
743 request_params
.current_history_list_offset
= 0;
744 request_params
.pending_history_list_offset
= 0;
745 request_params
.page_id
= 1;
746 request_params
.nav_entry_id
= 1;
747 request_params
.page_state
= state_A
;
748 NavigateMainFrame(common_params
, StartNavigationParams(), request_params
);
749 ProcessPendingMessages();
751 // Verify page A committed, not swappedout://.
752 const IPC::Message
* frame_navigate_msg
=
753 render_thread_
->sink().GetUniqueMessageMatching(
754 FrameHostMsg_DidCommitProvisionalLoad::ID
);
755 EXPECT_TRUE(frame_navigate_msg
);
757 // Read URL out of the parent trait of the params object.
758 FrameHostMsg_DidCommitProvisionalLoad::Param commit_load_params
;
759 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
760 &commit_load_params
);
761 EXPECT_NE(GURL("swappedout://"), base::get
<0>(commit_load_params
).url
);
764 // Verify that security origins are replicated properly to RenderFrameProxies
765 // when swapping out.
766 TEST_F(RenderViewImplTest
, OriginReplicationForSwapOut
) {
767 // This test should only run with --site-per-process, since origin
768 // replication only happens in that mode.
769 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
770 switches::kSitePerProcess
))
774 "Hello <iframe src='data:text/html,frame 1'></iframe>"
775 "<iframe src='data:text/html,frame 2'></iframe>");
776 WebFrame
* web_frame
= frame()->GetWebFrame();
777 RenderFrameImpl
* child_frame
= static_cast<RenderFrameImpl
*>(
778 RenderFrame::FromWebFrame(web_frame
->firstChild()));
780 // Swap the child frame out and pass a serialized origin to be set for
782 content::FrameReplicationState replication_state
;
783 replication_state
.origin
= url::Origin("http://foo.com");
784 SwapOut(child_frame
, kProxyRoutingId
, true, replication_state
);
786 // The child frame should now be a WebRemoteFrame.
787 EXPECT_TRUE(web_frame
->firstChild()->isWebRemoteFrame());
789 // Expect the origin to be updated properly.
790 blink::WebSecurityOrigin origin
= web_frame
->firstChild()->securityOrigin();
791 EXPECT_EQ(origin
.toString(),
792 WebString::fromUTF8(replication_state
.origin
.string()));
794 // Now, swap out the second frame using a unique origin and verify that it is
795 // replicated correctly.
796 replication_state
.origin
= url::Origin();
797 RenderFrameImpl
* child_frame2
= static_cast<RenderFrameImpl
*>(
798 RenderFrame::FromWebFrame(web_frame
->lastChild()));
799 SwapOut(child_frame2
, kProxyRoutingId
+ 1, true, replication_state
);
800 EXPECT_TRUE(web_frame
->lastChild()->isWebRemoteFrame());
801 EXPECT_TRUE(web_frame
->lastChild()->securityOrigin().isUnique());
804 // Test that we get the correct UpdateState message when we go back twice
805 // quickly without committing. Regression test for http://crbug.com/58082.
806 // Disabled: http://crbug.com/157357 .
807 TEST_F(RenderViewImplTest
, DISABLED_LastCommittedUpdateState
) {
809 LoadHTML("<div>Page A</div>");
811 // Load page B, which will trigger an UpdateState message for page A.
812 LoadHTML("<div>Page B</div>");
814 // Check for a valid UpdateState message for page A.
815 ProcessPendingMessages();
816 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
817 ViewHostMsg_UpdateState::ID
);
819 ViewHostMsg_UpdateState::Param param
;
820 ViewHostMsg_UpdateState::Read(msg_A
, ¶m
);
821 int page_id_A
= base::get
<0>(param
);
822 PageState state_A
= base::get
<1>(param
);
823 EXPECT_EQ(1, page_id_A
);
824 render_thread_
->sink().ClearMessages();
826 // Load page C, which will trigger an UpdateState message for page B.
827 LoadHTML("<div>Page C</div>");
829 // Check for a valid UpdateState for page B.
830 ProcessPendingMessages();
831 const IPC::Message
* msg_B
= render_thread_
->sink().GetUniqueMessageMatching(
832 ViewHostMsg_UpdateState::ID
);
834 ViewHostMsg_UpdateState::Read(msg_B
, ¶m
);
835 int page_id_B
= base::get
<0>(param
);
836 PageState state_B
= base::get
<1>(param
);
837 EXPECT_EQ(2, page_id_B
);
838 EXPECT_NE(state_A
, state_B
);
839 render_thread_
->sink().ClearMessages();
841 // Load page D, which will trigger an UpdateState message for page C.
842 LoadHTML("<div>Page D</div>");
844 // Check for a valid UpdateState for page C.
845 ProcessPendingMessages();
846 const IPC::Message
* msg_C
= render_thread_
->sink().GetUniqueMessageMatching(
847 ViewHostMsg_UpdateState::ID
);
849 ViewHostMsg_UpdateState::Read(msg_C
, ¶m
);
850 int page_id_C
= base::get
<0>(param
);
851 PageState state_C
= base::get
<1>(param
);
852 EXPECT_EQ(3, page_id_C
);
853 EXPECT_NE(state_B
, state_C
);
854 render_thread_
->sink().ClearMessages();
856 // Go back to C and commit, preparing for our real test.
857 CommonNavigationParams common_params_C
;
858 RequestNavigationParams request_params_C
;
859 common_params_C
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
860 common_params_C
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
861 request_params_C
.current_history_list_length
= 4;
862 request_params_C
.current_history_list_offset
= 3;
863 request_params_C
.pending_history_list_offset
= 2;
864 request_params_C
.page_id
= 3;
865 request_params_C
.page_state
= state_C
;
866 NavigateMainFrame(common_params_C
, StartNavigationParams(), request_params_C
);
867 ProcessPendingMessages();
868 render_thread_
->sink().ClearMessages();
870 // Go back twice quickly, such that page B does not have a chance to commit.
871 // This leads to two changes to the back/forward list but only one change to
872 // the RenderView's page ID.
874 // Back to page B (page_id 2), without committing.
875 CommonNavigationParams common_params_B
;
876 RequestNavigationParams request_params_B
;
877 common_params_B
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
878 common_params_B
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
879 request_params_B
.current_history_list_length
= 4;
880 request_params_B
.current_history_list_offset
= 2;
881 request_params_B
.pending_history_list_offset
= 1;
882 request_params_B
.page_id
= 2;
883 request_params_B
.page_state
= state_B
;
884 NavigateMainFrame(common_params_B
, StartNavigationParams(), request_params_B
);
886 // Back to page A (page_id 1) and commit.
887 CommonNavigationParams common_params
;
888 RequestNavigationParams request_params
;
889 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
890 common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
891 request_params
.current_history_list_length
= 4;
892 request_params
.current_history_list_offset
= 2;
893 request_params
.pending_history_list_offset
= 0;
894 request_params
.page_id
= 1;
895 request_params
.page_state
= state_A
;
896 NavigateMainFrame(common_params
, StartNavigationParams(), request_params
);
897 ProcessPendingMessages();
899 // Now ensure that the UpdateState message we receive is consistent
900 // and represents page C in both page_id and state.
901 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
902 ViewHostMsg_UpdateState::ID
);
904 ViewHostMsg_UpdateState::Read(msg
, ¶m
);
905 int page_id
= base::get
<0>(param
);
906 PageState state
= base::get
<1>(param
);
907 EXPECT_EQ(page_id_C
, page_id
);
908 EXPECT_NE(state_A
, state
);
909 EXPECT_NE(state_B
, state
);
910 EXPECT_EQ(state_C
, state
);
913 // Test that stale back/forward navigations arriving from the browser are
914 // ignored. See http://crbug.com/86758.
915 TEST_F(RenderViewImplTest
, StaleNavigationsIgnored
) {
917 LoadHTML("<div id=pagename>Page A</div>");
918 EXPECT_EQ(1, view()->history_list_length_
);
919 EXPECT_EQ(0, view()->history_list_offset_
);
921 // Load page B, which will trigger an UpdateState message for page A.
922 LoadHTML("<div id=pagename>Page B</div>");
923 EXPECT_EQ(2, view()->history_list_length_
);
924 EXPECT_EQ(1, view()->history_list_offset_
);
926 // Check for a valid UpdateState message for page A.
927 ProcessPendingMessages();
928 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
929 ViewHostMsg_UpdateState::ID
);
931 ViewHostMsg_UpdateState::Param param
;
932 ViewHostMsg_UpdateState::Read(msg_A
, ¶m
);
933 int page_id_A
= base::get
<0>(param
);
934 PageState state_A
= base::get
<1>(param
);
935 EXPECT_EQ(1, page_id_A
);
936 render_thread_
->sink().ClearMessages();
938 // Back to page A (nav_entry_id 1) and commit.
939 CommonNavigationParams common_params_A
;
940 RequestNavigationParams request_params_A
;
941 common_params_A
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
942 common_params_A
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
943 request_params_A
.current_history_list_length
= 2;
944 request_params_A
.current_history_list_offset
= 1;
945 request_params_A
.pending_history_list_offset
= 0;
946 request_params_A
.page_id
= 1;
947 request_params_A
.nav_entry_id
= 1;
948 request_params_A
.page_state
= state_A
;
949 NavigateMainFrame(common_params_A
, StartNavigationParams(), request_params_A
);
950 ProcessPendingMessages();
952 // A new navigation commits, clearing the forward history.
953 LoadHTML("<div id=pagename>Page C</div>");
954 EXPECT_EQ(2, view()->history_list_length_
);
955 EXPECT_EQ(1, view()->history_list_offset_
);
956 EXPECT_EQ(3, view()->page_id_
); // page C is now page id 3
958 base::string16 check_page_c
= base::ASCIIToUTF16(
959 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
960 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
961 EXPECT_EQ(1, was_page_c
);
963 // The browser then sends a stale navigation to B, which should be ignored.
964 CommonNavigationParams common_params_B
;
965 RequestNavigationParams request_params_B
;
966 common_params_B
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
967 common_params_B
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
968 request_params_B
.current_history_list_length
= 2;
969 request_params_B
.current_history_list_offset
= 0;
970 request_params_B
.pending_history_list_offset
= 1;
971 request_params_B
.page_id
= 2;
972 request_params_B
.nav_entry_id
= 2;
973 request_params_B
.page_state
=
974 state_A
; // Doesn't matter, just has to be present.
975 NavigateMainFrame(common_params_B
, StartNavigationParams(), request_params_B
);
977 // State should be unchanged.
978 EXPECT_EQ(2, view()->history_list_length_
);
979 EXPECT_EQ(1, view()->history_list_offset_
);
980 EXPECT_EQ(3, view()->page_id_
); // page C, not page B
982 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
983 EXPECT_EQ(1, was_page_c
);
985 // Check for a valid DidDropNavigation message.
986 ProcessPendingMessages();
987 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
988 FrameHostMsg_DidDropNavigation::ID
);
990 render_thread_
->sink().ClearMessages();
993 // Test that our IME backend sends a notification message when the input focus
995 TEST_F(RenderViewImplTest
, OnImeTypeChanged
) {
996 // Enable our IME backend code.
997 view()->OnSetInputMethodActive(true);
999 // Load an HTML page consisting of two input fields.
1000 view()->set_send_content_state_immediately(true);
1005 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
1006 "<input id=\"test2\" type=\"password\"></input>"
1007 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
1008 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
1009 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
1010 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
1012 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
1014 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
1015 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
1016 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
1017 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
1018 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
1019 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
1020 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
1021 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
1024 render_thread_
->sink().ClearMessages();
1026 struct InputModeTestCase
{
1027 const char* input_id
;
1028 ui::TextInputMode expected_mode
;
1030 static const InputModeTestCase kInputModeTestCases
[] = {
1031 {"test1", ui::TEXT_INPUT_MODE_DEFAULT
},
1032 {"test3", ui::TEXT_INPUT_MODE_VERBATIM
},
1033 {"test4", ui::TEXT_INPUT_MODE_LATIN
},
1034 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME
},
1035 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE
},
1036 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN
},
1037 {"test8", ui::TEXT_INPUT_MODE_KANA
},
1038 {"test9", ui::TEXT_INPUT_MODE_KATAKANA
},
1039 {"test10", ui::TEXT_INPUT_MODE_NUMERIC
},
1040 {"test11", ui::TEXT_INPUT_MODE_TEL
},
1041 {"test12", ui::TEXT_INPUT_MODE_EMAIL
},
1042 {"test13", ui::TEXT_INPUT_MODE_URL
},
1043 {"test14", ui::TEXT_INPUT_MODE_DEFAULT
},
1044 {"test15", ui::TEXT_INPUT_MODE_VERBATIM
},
1047 const int kRepeatCount
= 10;
1048 for (int i
= 0; i
< kRepeatCount
; i
++) {
1049 // Move the input focus to the first <input> element, where we should
1051 ExecuteJavaScript("document.getElementById('test1').focus();");
1052 ProcessPendingMessages();
1053 render_thread_
->sink().ClearMessages();
1055 // Update the IME status and verify if our IME backend sends an IPC message
1056 // to activate IMEs.
1057 view()->UpdateTextInputType();
1058 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
1059 EXPECT_TRUE(msg
!= NULL
);
1060 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
1061 ViewHostMsg_TextInputTypeChanged::Param params
;
1062 ViewHostMsg_TextInputTypeChanged::Read(msg
, ¶ms
);
1063 ui::TextInputType type
= base::get
<0>(params
);
1064 ui::TextInputMode input_mode
= base::get
<1>(params
);
1065 bool can_compose_inline
= base::get
<2>(params
);
1066 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT
, type
);
1067 EXPECT_EQ(true, can_compose_inline
);
1069 // Move the input focus to the second <input> element, where we should
1070 // de-activate IMEs.
1071 ExecuteJavaScript("document.getElementById('test2').focus();");
1072 ProcessPendingMessages();
1073 render_thread_
->sink().ClearMessages();
1075 // Update the IME status and verify if our IME backend sends an IPC message
1076 // to de-activate IMEs.
1077 view()->UpdateTextInputType();
1078 msg
= render_thread_
->sink().GetMessageAt(0);
1079 EXPECT_TRUE(msg
!= NULL
);
1080 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
1081 ViewHostMsg_TextInputTypeChanged::Read(msg
, & params
);
1082 type
= base::get
<0>(params
);
1083 input_mode
= base::get
<1>(params
);
1084 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD
, type
);
1086 for (size_t i
= 0; i
< arraysize(kInputModeTestCases
); i
++) {
1087 const InputModeTestCase
* test_case
= &kInputModeTestCases
[i
];
1088 std::string javascript
=
1089 base::StringPrintf("document.getElementById('%s').focus();",
1090 test_case
->input_id
);
1091 // Move the input focus to the target <input> element, where we should
1093 ExecuteJavaScriptAndReturnIntValue(base::ASCIIToUTF16(javascript
), NULL
);
1094 ProcessPendingMessages();
1095 render_thread_
->sink().ClearMessages();
1097 // Update the IME status and verify if our IME backend sends an IPC
1098 // message to activate IMEs.
1099 view()->UpdateTextInputType();
1100 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
1101 EXPECT_TRUE(msg
!= NULL
);
1102 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
1103 ViewHostMsg_TextInputTypeChanged::Read(msg
, & params
);
1104 type
= base::get
<0>(params
);
1105 input_mode
= base::get
<1>(params
);
1106 EXPECT_EQ(test_case
->expected_mode
, input_mode
);
1111 // Test that our IME backend can compose CJK words.
1112 // Our IME front-end sends many platform-independent messages to the IME backend
1113 // while it composes CJK words. This test sends the minimal messages captured
1114 // on my local environment directly to the IME backend to verify if the backend
1115 // can compose CJK words without any problems.
1116 // This test uses an array of command sets because an IME composotion does not
1117 // only depends on IME events, but also depends on window events, e.g. moving
1118 // the window focus while composing a CJK text. To handle such complicated
1119 // cases, this test should not only call IME-related functions in the
1120 // RenderWidget class, but also call some RenderWidget members, e.g.
1121 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc.
1122 TEST_F(RenderViewImplTest
, ImeComposition
) {
1128 IME_CONFIRMCOMPOSITION
,
1129 IME_CANCELCOMPOSITION
1134 int selection_start
;
1136 const wchar_t* ime_string
;
1137 const wchar_t* result
;
1139 static const ImeMessage kImeMessages
[] = {
1140 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
1141 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1142 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1143 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1144 {IME_SETCOMPOSITION
, false, 1, 1, L
"n", L
"n"},
1145 {IME_SETCOMPOSITION
, false, 2, 2, L
"ni", L
"ni"},
1146 {IME_SETCOMPOSITION
, false, 3, 3, L
"nih", L
"nih"},
1147 {IME_SETCOMPOSITION
, false, 4, 4, L
"niha", L
"niha"},
1148 {IME_SETCOMPOSITION
, false, 5, 5, L
"nihao", L
"nihao"},
1149 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"\x4F60\x597D", L
"\x4F60\x597D"},
1150 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
1151 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1152 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1153 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1154 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xFF4B", L
"\xFF4B"},
1155 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x304B", L
"\x304B"},
1156 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x304B\xFF4E", L
"\x304B\xFF4E"},
1157 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\xFF4A",
1158 L
"\x304B\x3093\xFF4A"},
1159 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\x3058",
1160 L
"\x304B\x3093\x3058"},
1161 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x611F\x3058", L
"\x611F\x3058"},
1162 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x6F22\x5B57", L
"\x6F22\x5B57"},
1163 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1164 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1165 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1166 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1167 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1168 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1169 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3147", L
"\x3147"},
1170 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC544", L
"\xC544"},
1171 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC548", L
"\xC548"},
1172 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1173 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3134", L
"\xC548\x3134"},
1174 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB140", L
"\xC548\xB140"},
1175 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1176 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1177 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1178 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548\xB155"},
1181 for (size_t i
= 0; i
< arraysize(kImeMessages
); i
++) {
1182 const ImeMessage
* ime_message
= &kImeMessages
[i
];
1183 switch (ime_message
->command
) {
1184 case IME_INITIALIZE
:
1185 // Load an HTML page consisting of a content-editable <div> element,
1186 // and move the input focus to the <div> element, where we can use
1188 view()->OnSetInputMethodActive(ime_message
->enable
);
1189 view()->set_send_content_state_immediately(true);
1194 "<div id=\"test1\" contenteditable=\"true\"></div>"
1197 ExecuteJavaScript("document.getElementById('test1').focus();");
1200 case IME_SETINPUTMODE
:
1201 // Activate (or deactivate) our IME back-end.
1202 view()->OnSetInputMethodActive(ime_message
->enable
);
1206 // Update the window focus.
1207 view()->OnSetFocus(ime_message
->enable
);
1210 case IME_SETCOMPOSITION
:
1211 view()->OnImeSetComposition(
1212 base::WideToUTF16(ime_message
->ime_string
),
1213 std::vector
<blink::WebCompositionUnderline
>(),
1214 ime_message
->selection_start
,
1215 ime_message
->selection_end
);
1218 case IME_CONFIRMCOMPOSITION
:
1219 view()->OnImeConfirmComposition(
1220 base::WideToUTF16(ime_message
->ime_string
),
1221 gfx::Range::InvalidRange(),
1225 case IME_CANCELCOMPOSITION
:
1226 view()->OnImeSetComposition(
1228 std::vector
<blink::WebCompositionUnderline
>(),
1233 // Update the status of our IME back-end.
1234 // TODO(hbono): we should verify messages to be sent from the back-end.
1235 view()->UpdateTextInputType();
1236 ProcessPendingMessages();
1237 render_thread_
->sink().ClearMessages();
1239 if (ime_message
->result
) {
1240 // Retrieve the content of this page and compare it with the expected
1242 const int kMaxOutputCharacters
= 128;
1243 base::string16 output
=
1244 GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1245 EXPECT_EQ(base::WideToUTF16(ime_message
->result
), output
);
1250 // Test that the RenderView::OnSetTextDirection() function can change the text
1251 // direction of the selected input element.
1252 TEST_F(RenderViewImplTest
, OnSetTextDirection
) {
1253 // Load an HTML page consisting of a <textarea> element and a <div> element.
1254 // This test changes the text direction of the <textarea> element, and
1255 // writes the values of its 'dir' attribute and its 'direction' property to
1256 // verify that the text direction is changed.
1257 view()->set_send_content_state_immediately(true);
1262 "<textarea id=\"test\"></textarea>"
1263 "<div id=\"result\" contenteditable=\"true\"></div>"
1266 render_thread_
->sink().ClearMessages();
1268 static const struct {
1269 WebTextDirection direction
;
1270 const wchar_t* expected_result
;
1271 } kTextDirection
[] = {
1272 { blink::WebTextDirectionRightToLeft
, L
"\x000A" L
"rtl,rtl" },
1273 { blink::WebTextDirectionLeftToRight
, L
"\x000A" L
"ltr,ltr" },
1275 for (size_t i
= 0; i
< arraysize(kTextDirection
); ++i
) {
1276 // Set the text direction of the <textarea> element.
1277 ExecuteJavaScript("document.getElementById('test').focus();");
1278 view()->OnSetTextDirection(kTextDirection
[i
].direction
);
1280 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1281 // property to the <div> element.
1282 ExecuteJavaScript("var result = document.getElementById('result');"
1283 "var node = document.getElementById('test');"
1284 "var style = getComputedStyle(node, null);"
1285 "result.innerText ="
1286 " node.getAttribute('dir') + ',' +"
1287 " style.getPropertyValue('direction');");
1289 // Copy the document content to std::wstring and compare with the
1291 const int kMaxOutputCharacters
= 16;
1292 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1293 EXPECT_EQ(base::WideToUTF16(kTextDirection
[i
].expected_result
), output
);
1297 // see http://crbug.com/238750
1299 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent
1301 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent
1304 // Test that we can receive correct DOM events when we send input events
1305 // through the RenderWidget::OnHandleInputEvent() function.
1306 TEST_F(RenderViewImplTest
, MAYBE_OnHandleKeyboardEvent
) {
1307 #if !defined(OS_MACOSX)
1308 // Load an HTML page consisting of one <input> element and three
1309 // contentediable <div> elements.
1310 // The <input> element is used for sending keyboard events, and the <div>
1311 // elements are used for writing DOM events in the following format:
1312 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1313 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1314 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1315 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1316 view()->set_send_content_state_immediately(true);
1320 "<script type='text/javascript' language='javascript'>"
1321 "function OnKeyEvent(ev) {"
1322 " var result = document.getElementById(ev.type);"
1323 " result.innerText ="
1324 " (ev.which || ev.keyCode) + ',' +"
1325 " ev.shiftKey + ',' +"
1326 " ev.ctrlKey + ',' +"
1333 "<input id='test' type='text'"
1334 " onkeydown='return OnKeyEvent(event);'"
1335 " onkeypress='return OnKeyEvent(event);'"
1336 " onkeyup='return OnKeyEvent(event);'>"
1338 "<div id='keydown' contenteditable='true'>"
1340 "<div id='keypress' contenteditable='true'>"
1342 "<div id='keyup' contenteditable='true'>"
1346 ExecuteJavaScript("document.getElementById('test').focus();");
1347 render_thread_
->sink().ClearMessages();
1349 static const MockKeyboard::Layout kLayouts
[] = {
1351 // Since we ignore the mock keyboard layout on Linux and instead just use
1352 // the screen's keyboard layout, these trivially pass. They are commented
1353 // out to avoid the illusion that they work.
1354 MockKeyboard::LAYOUT_ARABIC
,
1355 MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1356 MockKeyboard::LAYOUT_FRENCH
,
1357 MockKeyboard::LAYOUT_HEBREW
,
1358 MockKeyboard::LAYOUT_RUSSIAN
,
1360 MockKeyboard::LAYOUT_UNITED_STATES
,
1363 for (size_t i
= 0; i
< arraysize(kLayouts
); ++i
) {
1364 // For each key code, we send three keyboard events.
1365 // * we press only the key;
1366 // * we press the key and a left-shift key, and;
1367 // * we press the key and a right-alt (AltGr) key.
1368 // For each modifiers, we need a string used for formatting its expected
1369 // result. (See the above comment for its format.)
1370 static const struct {
1371 MockKeyboard::Modifiers modifiers
;
1372 const char* expected_result
;
1373 } kModifierData
[] = {
1374 {MockKeyboard::NONE
, "false,false,false"},
1375 {MockKeyboard::LEFT_SHIFT
, "true,false,false"},
1377 {MockKeyboard::RIGHT_ALT
, "false,false,true"},
1381 MockKeyboard::Layout layout
= kLayouts
[i
];
1382 for (size_t j
= 0; j
< arraysize(kModifierData
); ++j
) {
1383 // Virtual key codes used for this test.
1384 static const int kKeyCodes
[] = {
1385 '0', '1', '2', '3', '4', '5', '6', '7',
1386 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1387 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1388 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1394 ui::VKEY_OEM_PERIOD
,
1402 // Not sure how to handle this key on Linux.
1407 MockKeyboard::Modifiers modifiers
= kModifierData
[j
].modifiers
;
1408 for (size_t k
= 0; k
< arraysize(kKeyCodes
); ++k
) {
1409 // Send a keyboard event to the RenderView object.
1410 // We should test a keyboard event only when the given keyboard-layout
1411 // driver is installed in a PC and the driver can assign a Unicode
1412 // charcter for the given tuple (key-code and modifiers).
1413 int key_code
= kKeyCodes
[k
];
1414 base::string16 char_code
;
1415 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1418 // Create an expected result from the virtual-key code, the character
1419 // code, and the modifier-key status.
1420 // We format a string that emulates a DOM-event string produced hy
1421 // our JavaScript function. (See the above comment for the format.)
1422 static char expected_result
[1024];
1423 expected_result
[0] = 0;
1424 base::snprintf(&expected_result
[0],
1425 sizeof(expected_result
),
1426 "\n" // texts in the <input> element
1427 "%d,%s\n" // texts in the first <div> element
1428 "%d,%s\n" // texts in the second <div> element
1429 "%d,%s", // texts in the third <div> element
1430 key_code
, kModifierData
[j
].expected_result
,
1431 static_cast<int>(char_code
[0]),
1432 kModifierData
[j
].expected_result
,
1433 key_code
, kModifierData
[j
].expected_result
);
1435 // Retrieve the text in the test page and compare it with the expected
1436 // text created from a virtual-key code, a character code, and the
1437 // modifier-key status.
1438 const int kMaxOutputCharacters
= 1024;
1439 std::string output
= base::UTF16ToUTF8(
1440 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
1441 EXPECT_EQ(expected_result
, output
);
1450 // Test that our EditorClientImpl class can insert characters when we send
1451 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1452 // This test is for preventing regressions caused only when we use non-US
1453 // keyboards, such as Issue 10846.
1454 // see http://crbug.com/244562
1456 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1458 #define MAYBE_InsertCharacters InsertCharacters
1460 TEST_F(RenderViewImplTest
, MAYBE_InsertCharacters
) {
1461 #if !defined(OS_MACOSX)
1462 static const struct {
1463 MockKeyboard::Layout layout
;
1464 const wchar_t* expected_result
;
1467 // Disabled these keyboard layouts because buildbots do not have their
1468 // keyboard-layout drivers installed.
1469 {MockKeyboard::LAYOUT_ARABIC
,
1470 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1471 L
"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1472 L
"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1473 L
"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1474 L
"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1475 L
"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1476 L
"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1477 L
"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1478 L
"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1479 L
"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1480 L
"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1481 L
"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1482 L
"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1483 L
"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1484 L
"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1485 L
"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1486 L
"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1488 {MockKeyboard::LAYOUT_HEBREW
,
1489 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1490 L
"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1491 L
"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1492 L
"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1493 L
"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1494 L
"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1495 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1496 L
"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1497 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1498 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1499 L
"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1500 L
"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1501 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1502 L
"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1503 L
"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1504 L
"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1505 L
"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1506 L
"\x003b\x005d\x005c\x005b\x002c"
1510 // On Linux, the only way to test alternate keyboard layouts is to change
1511 // the keyboard layout of the whole screen. I'm worried about the side
1512 // effects this may have on the buildbots.
1513 {MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1514 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1515 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1516 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1517 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1518 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1519 L
"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1520 L
"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1521 L
"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1522 L
"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1523 L
"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1524 L
"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1525 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1526 L
"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1527 L
"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1528 L
"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1529 L
"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1532 {MockKeyboard::LAYOUT_FRENCH
,
1533 L
"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1534 L
"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1535 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1536 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1537 L
"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1538 L
"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1539 L
"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1540 L
"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1541 L
"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1542 L
"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1543 L
"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1544 L
"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1545 L
"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1546 L
"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1547 L
"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1548 L
"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1549 L
"\x003b\x003a\x00f9\x0029\x002a\x0021"
1551 {MockKeyboard::LAYOUT_RUSSIAN
,
1552 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1553 L
"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1554 L
"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1555 L
"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1556 L
"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1557 L
"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1558 L
"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1559 L
"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1560 L
"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1561 L
"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1562 L
"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1563 L
"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1564 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1565 L
"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1566 L
"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1567 L
"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1568 L
"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1569 L
"\x0451\x0445\x005c\x044a\x044d"
1571 #endif // defined(OS_WIN)
1572 {MockKeyboard::LAYOUT_UNITED_STATES
,
1573 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1574 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1575 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1576 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1577 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1578 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1579 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1580 L
"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1581 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1582 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1583 L
"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1584 L
"\x003f\x007e\x007b\x007c\x007d\x0022"
1586 // This is ifdefed out for Linux to correspond to the fact that we don't
1587 // test alt+keystroke for now.
1588 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1589 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1590 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1591 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1592 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1593 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1598 for (size_t i
= 0; i
< arraysize(kLayouts
); ++i
) {
1599 // Load an HTML page consisting of one <div> element.
1600 // This <div> element is used by the EditorClientImpl class to insert
1601 // characters received through the RenderWidget::OnHandleInputEvent()
1603 view()->set_send_content_state_immediately(true);
1609 "<div id='test' contenteditable='true'>"
1613 ExecuteJavaScript("document.getElementById('test').focus();");
1614 render_thread_
->sink().ClearMessages();
1616 // For each key code, we send three keyboard events.
1617 // * Pressing only the key;
1618 // * Pressing the key and a left-shift key, and;
1619 // * Pressing the key and a right-alt (AltGr) key.
1620 static const MockKeyboard::Modifiers kModifiers
[] = {
1622 MockKeyboard::LEFT_SHIFT
,
1624 MockKeyboard::RIGHT_ALT
,
1628 MockKeyboard::Layout layout
= kLayouts
[i
].layout
;
1629 for (size_t j
= 0; j
< arraysize(kModifiers
); ++j
) {
1630 // Virtual key codes used for this test.
1631 static const int kKeyCodes
[] = {
1632 '0', '1', '2', '3', '4', '5', '6', '7',
1633 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1634 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1635 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1641 ui::VKEY_OEM_PERIOD
,
1649 // Unclear how to handle this on Linux.
1654 MockKeyboard::Modifiers modifiers
= kModifiers
[j
];
1655 for (size_t k
= 0; k
< arraysize(kKeyCodes
); ++k
) {
1656 // Send a keyboard event to the RenderView object.
1657 // We should test a keyboard event only when the given keyboard-layout
1658 // driver is installed in a PC and the driver can assign a Unicode
1659 // charcter for the given tuple (layout, key-code, and modifiers).
1660 int key_code
= kKeyCodes
[k
];
1661 base::string16 char_code
;
1662 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1667 // Retrieve the text in the test page and compare it with the expected
1668 // text created from a virtual-key code, a character code, and the
1669 // modifier-key status.
1670 const int kMaxOutputCharacters
= 4096;
1671 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1672 EXPECT_EQ(base::WideToUTF16(kLayouts
[i
].expected_result
), output
);
1679 // Crashy, http://crbug.com/53247.
1680 TEST_F(RenderViewImplTest
, DISABLED_DidFailProvisionalLoadWithErrorForError
) {
1681 GetMainFrame()->enableViewSourceMode(true);
1683 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1684 error
.reason
= net::ERR_FILE_NOT_FOUND
;
1685 error
.unreachableURL
= GURL("http://foo");
1686 WebLocalFrame
* web_frame
= GetMainFrame();
1688 // Start a load that will reach provisional state synchronously,
1689 // but won't complete synchronously.
1690 CommonNavigationParams common_params
;
1691 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1692 common_params
.url
= GURL("data:text/html,test data");
1693 NavigateMainFrame(common_params
, StartNavigationParams(),
1694 RequestNavigationParams());
1696 // An error occurred.
1697 view()->GetMainRenderFrame()->didFailProvisionalLoad(
1698 web_frame
, error
, blink::WebStandardCommit
);
1699 // Frame should exit view-source mode.
1700 EXPECT_FALSE(web_frame
->isViewSourceModeEnabled());
1703 TEST_F(RenderViewImplTest
, DidFailProvisionalLoadWithErrorForCancellation
) {
1704 GetMainFrame()->enableViewSourceMode(true);
1706 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1707 error
.reason
= net::ERR_ABORTED
;
1708 error
.unreachableURL
= GURL("http://foo");
1709 WebLocalFrame
* web_frame
= GetMainFrame();
1711 // Start a load that will reach provisional state synchronously,
1712 // but won't complete synchronously.
1713 CommonNavigationParams common_params
;
1714 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1715 common_params
.url
= GURL("data:text/html,test data");
1716 NavigateMainFrame(common_params
, StartNavigationParams(),
1717 RequestNavigationParams());
1719 // A cancellation occurred.
1720 view()->GetMainRenderFrame()->didFailProvisionalLoad(
1721 web_frame
, error
, blink::WebStandardCommit
);
1722 // Frame should stay in view-source mode.
1723 EXPECT_TRUE(web_frame
->isViewSourceModeEnabled());
1726 // Regression test for http://crbug.com/41562
1727 TEST_F(RenderViewImplTest
, UpdateTargetURLWithInvalidURL
) {
1728 const GURL
invalid_gurl("http://");
1729 view()->setMouseOverURL(blink::WebURL(invalid_gurl
));
1730 EXPECT_EQ(invalid_gurl
, view()->target_url_
);
1733 TEST_F(RenderViewImplTest
, SetHistoryLengthAndOffset
) {
1734 // No history to merge; one committed page.
1735 view()->OnSetHistoryOffsetAndLength(0, 1);
1736 EXPECT_EQ(1, view()->history_list_length_
);
1737 EXPECT_EQ(0, view()->history_list_offset_
);
1739 // History of length 1 to merge; one committed page.
1740 view()->OnSetHistoryOffsetAndLength(1, 2);
1741 EXPECT_EQ(2, view()->history_list_length_
);
1742 EXPECT_EQ(1, view()->history_list_offset_
);
1745 TEST_F(RenderViewImplTest
, ContextMenu
) {
1746 LoadHTML("<div>Page A</div>");
1748 // Create a right click in the center of the iframe. (I'm hoping this will
1749 // make this a bit more robust in case of some other formatting or other bug.)
1750 WebMouseEvent mouse_event
;
1751 mouse_event
.type
= WebInputEvent::MouseDown
;
1752 mouse_event
.button
= WebMouseEvent::ButtonRight
;
1753 mouse_event
.x
= 250;
1754 mouse_event
.y
= 250;
1755 mouse_event
.globalX
= 250;
1756 mouse_event
.globalY
= 250;
1758 SendWebMouseEvent(mouse_event
);
1760 // Now simulate the corresponding up event which should display the menu
1761 mouse_event
.type
= WebInputEvent::MouseUp
;
1762 SendWebMouseEvent(mouse_event
);
1764 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
1765 FrameHostMsg_ContextMenu::ID
));
1768 TEST_F(RenderViewImplTest
, TestBackForward
) {
1769 LoadHTML("<div id=pagename>Page A</div>");
1770 PageState page_a_state
=
1771 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1772 int was_page_a
= -1;
1773 base::string16 check_page_a
=
1775 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1776 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1777 EXPECT_EQ(1, was_page_a
);
1779 LoadHTML("<div id=pagename>Page B</div>");
1780 int was_page_b
= -1;
1781 base::string16 check_page_b
=
1783 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1784 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1785 EXPECT_EQ(1, was_page_b
);
1787 PageState back_state
=
1788 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1790 LoadHTML("<div id=pagename>Page C</div>");
1791 int was_page_c
= -1;
1792 base::string16 check_page_c
=
1794 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1795 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1796 EXPECT_EQ(1, was_page_c
);
1798 PageState forward_state
=
1799 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1801 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1802 EXPECT_EQ(1, was_page_b
);
1804 PageState back_state2
=
1805 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1807 GoForward(forward_state
);
1808 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1809 EXPECT_EQ(1, was_page_c
);
1811 GoBack(back_state2
);
1812 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1813 EXPECT_EQ(1, was_page_b
);
1816 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1817 GoBack(page_a_state
);
1818 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1819 EXPECT_EQ(1, was_page_a
);
1821 GoForward(forward_state
);
1822 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1823 EXPECT_EQ(1, was_page_b
);
1826 #if defined(OS_MACOSX) || defined(USE_AURA)
1827 TEST_F(RenderViewImplTest
, GetCompositionCharacterBoundsTest
) {
1830 // http://crbug.com/304193
1831 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
1835 LoadHTML("<textarea id=\"test\"></textarea>");
1836 ExecuteJavaScript("document.getElementById('test').focus();");
1838 const base::string16 empty_string
;
1839 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1840 std::vector
<gfx::Rect
> bounds
;
1841 view()->OnSetFocus(true);
1842 view()->OnSetInputMethodActive(true);
1844 // ASCII composition
1845 const base::string16 ascii_composition
= base::UTF8ToUTF16("aiueo");
1846 view()->OnImeSetComposition(ascii_composition
, empty_underline
, 0, 0);
1847 view()->GetCompositionCharacterBounds(&bounds
);
1848 ASSERT_EQ(ascii_composition
.size(), bounds
.size());
1849 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1850 EXPECT_LT(0, bounds
[i
].width());
1851 view()->OnImeConfirmComposition(
1852 empty_string
, gfx::Range::InvalidRange(), false);
1854 // Non surrogate pair unicode character.
1855 const base::string16 unicode_composition
= base::UTF8ToUTF16(
1856 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1857 view()->OnImeSetComposition(unicode_composition
, empty_underline
, 0, 0);
1858 view()->GetCompositionCharacterBounds(&bounds
);
1859 ASSERT_EQ(unicode_composition
.size(), bounds
.size());
1860 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1861 EXPECT_LT(0, bounds
[i
].width());
1862 view()->OnImeConfirmComposition(
1863 empty_string
, gfx::Range::InvalidRange(), false);
1865 // Surrogate pair character.
1866 const base::string16 surrogate_pair_char
=
1867 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1868 view()->OnImeSetComposition(surrogate_pair_char
,
1872 view()->GetCompositionCharacterBounds(&bounds
);
1873 ASSERT_EQ(surrogate_pair_char
.size(), bounds
.size());
1874 EXPECT_LT(0, bounds
[0].width());
1875 EXPECT_EQ(0, bounds
[1].width());
1876 view()->OnImeConfirmComposition(
1877 empty_string
, gfx::Range::InvalidRange(), false);
1880 const base::string16 surrogate_pair_mixed_composition
=
1881 surrogate_pair_char
+ base::UTF8ToUTF16("\xE3\x81\x82") +
1882 surrogate_pair_char
+ base::UTF8ToUTF16("b") + surrogate_pair_char
;
1883 const size_t utf16_length
= 8UL;
1884 const bool is_surrogate_pair_empty_rect
[8] = {
1885 false, true, false, false, true, false, false, true };
1886 view()->OnImeSetComposition(surrogate_pair_mixed_composition
,
1890 view()->GetCompositionCharacterBounds(&bounds
);
1891 ASSERT_EQ(utf16_length
, bounds
.size());
1892 for (size_t i
= 0; i
< utf16_length
; ++i
) {
1893 if (is_surrogate_pair_empty_rect
[i
]) {
1894 EXPECT_EQ(0, bounds
[i
].width());
1896 EXPECT_LT(0, bounds
[i
].width());
1899 view()->OnImeConfirmComposition(
1900 empty_string
, gfx::Range::InvalidRange(), false);
1904 TEST_F(RenderViewImplTest
, ZoomLimit
) {
1905 const double kMinZoomLevel
= ZoomFactorToZoomLevel(kMinimumZoomFactor
);
1906 const double kMaxZoomLevel
= ZoomFactorToZoomLevel(kMaximumZoomFactor
);
1908 // Verifies navigation to a URL with preset zoom level indeed sets the level.
1909 // Regression test for http://crbug.com/139559, where the level was not
1910 // properly set when it is out of the default zoom limits of WebView.
1911 CommonNavigationParams common_params
;
1912 common_params
.url
= GURL("data:text/html,min_zoomlimit_test");
1913 view()->OnSetZoomLevelForLoadingURL(common_params
.url
, kMinZoomLevel
);
1914 NavigateMainFrame(common_params
, StartNavigationParams(),
1915 RequestNavigationParams());
1916 ProcessPendingMessages();
1917 EXPECT_DOUBLE_EQ(kMinZoomLevel
, view()->GetWebView()->zoomLevel());
1919 // It should work even when the zoom limit is temporarily changed in the page.
1920 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
1921 ZoomFactorToZoomLevel(1.0));
1922 common_params
.url
= GURL("data:text/html,max_zoomlimit_test");
1923 view()->OnSetZoomLevelForLoadingURL(common_params
.url
, kMaxZoomLevel
);
1924 NavigateMainFrame(common_params
, StartNavigationParams(),
1925 RequestNavigationParams());
1926 ProcessPendingMessages();
1927 EXPECT_DOUBLE_EQ(kMaxZoomLevel
, view()->GetWebView()->zoomLevel());
1930 TEST_F(RenderViewImplTest
, SetEditableSelectionAndComposition
) {
1931 // Load an HTML page consisting of an input field.
1936 "<input id=\"test1\" value=\"some test text hello\"></input>"
1939 ExecuteJavaScript("document.getElementById('test1').focus();");
1940 SetEditableSelectionOffsets(4, 8);
1941 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1942 SetCompositionFromExistingText(7, 10, empty_underline
);
1943 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1944 EXPECT_EQ(4, info
.selectionStart
);
1945 EXPECT_EQ(8, info
.selectionEnd
);
1946 EXPECT_EQ(7, info
.compositionStart
);
1947 EXPECT_EQ(10, info
.compositionEnd
);
1949 info
= view()->webview()->textInputInfo();
1950 EXPECT_EQ(0, info
.selectionStart
);
1951 EXPECT_EQ(0, info
.selectionEnd
);
1955 TEST_F(RenderViewImplTest
, OnExtendSelectionAndDelete
) {
1956 // Load an HTML page consisting of an input field.
1961 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
1964 ExecuteJavaScript("document.getElementById('test1').focus();");
1965 SetEditableSelectionOffsets(10, 10);
1966 ExtendSelectionAndDelete(3, 4);
1967 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1968 EXPECT_EQ("abcdefgopqrstuvwxyz", info
.value
);
1969 EXPECT_EQ(7, info
.selectionStart
);
1970 EXPECT_EQ(7, info
.selectionEnd
);
1971 SetEditableSelectionOffsets(4, 8);
1972 ExtendSelectionAndDelete(2, 5);
1973 info
= view()->webview()->textInputInfo();
1974 EXPECT_EQ("abuvwxyz", info
.value
);
1975 EXPECT_EQ(2, info
.selectionStart
);
1976 EXPECT_EQ(2, info
.selectionEnd
);
1979 // Test that the navigating specific frames works correctly.
1980 TEST_F(RenderViewImplTest
, NavigateSubframe
) {
1982 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
1984 // Navigate the frame only.
1985 CommonNavigationParams common_params
;
1986 RequestNavigationParams request_params
;
1987 common_params
.url
= GURL("data:text/html,world");
1988 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1989 common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
1990 request_params
.current_history_list_length
= 1;
1991 request_params
.current_history_list_offset
= 0;
1992 request_params
.pending_history_list_offset
= 1;
1993 request_params
.page_id
= -1;
1994 request_params
.browser_navigation_start
=
1995 base::TimeTicks::FromInternalValue(1);
1997 RenderFrameImpl
* subframe
= RenderFrameImpl::FromWebFrame(
1998 view()->webview()->findFrameByName("frame"));
1999 NavigateFrame(subframe
, common_params
, StartNavigationParams(),
2001 FrameLoadWaiter(subframe
).Wait();
2003 // Copy the document content to std::wstring and compare with the
2005 const int kMaxOutputCharacters
= 256;
2006 std::string output
= base::UTF16ToUTF8(
2007 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
2008 EXPECT_EQ(output
, "hello \n\nworld");
2011 // This test ensures that a RenderFrame object is created for the top level
2012 // frame in the RenderView.
2013 TEST_F(RenderViewImplTest
, BasicRenderFrame
) {
2014 EXPECT_TRUE(view()->main_render_frame_
);
2017 TEST_F(RenderViewImplTest
, GetSSLStatusOfFrame
) {
2018 LoadHTML("<!DOCTYPE html><html><body></body></html>");
2020 WebLocalFrame
* frame
= GetMainFrame();
2021 SSLStatus ssl_status
= view()->GetSSLStatusOfFrame(frame
);
2022 EXPECT_FALSE(net::IsCertStatusError(ssl_status
.cert_status
));
2024 const_cast<blink::WebURLResponse
&>(frame
->dataSource()->response()).
2026 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS
, 0, 0,
2027 SignedCertificateTimestampIDStatusList()));
2028 ssl_status
= view()->GetSSLStatusOfFrame(frame
);
2029 EXPECT_TRUE(net::IsCertStatusError(ssl_status
.cert_status
));
2032 TEST_F(RenderViewImplTest
, MessageOrderInDidChangeSelection
) {
2033 view()->OnSetInputMethodActive(true);
2034 view()->set_send_content_state_immediately(true);
2035 LoadHTML("<textarea id=\"test\"></textarea>");
2037 view()->handling_input_event_
= true;
2038 ExecuteJavaScript("document.getElementById('test').focus();");
2040 bool is_input_type_called
= false;
2041 bool is_selection_called
= false;
2042 size_t last_input_type
= 0;
2043 size_t last_selection
= 0;
2045 for (size_t i
= 0; i
< render_thread_
->sink().message_count(); ++i
) {
2046 const uint32 type
= render_thread_
->sink().GetMessageAt(i
)->type();
2047 if (type
== ViewHostMsg_TextInputTypeChanged::ID
) {
2048 is_input_type_called
= true;
2049 last_input_type
= i
;
2050 } else if (type
== ViewHostMsg_SelectionChanged::ID
) {
2051 is_selection_called
= true;
2056 EXPECT_TRUE(is_input_type_called
);
2057 EXPECT_TRUE(is_selection_called
);
2059 // InputTypeChange shold be called earlier than SelectionChanged.
2060 EXPECT_LT(last_input_type
, last_selection
);
2063 class SuppressErrorPageTest
: public RenderViewImplTest
{
2065 ContentRendererClient
* CreateContentRendererClient() override
{
2066 return new TestContentRendererClient
;
2069 RenderViewImpl
* view() {
2070 return static_cast<RenderViewImpl
*>(view_
);
2073 RenderFrameImpl
* frame() {
2074 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
2078 class TestContentRendererClient
: public ContentRendererClient
{
2080 bool ShouldSuppressErrorPage(RenderFrame
* render_frame
,
2081 const GURL
& url
) override
{
2082 return url
== GURL("http://example.com/suppress");
2085 void GetNavigationErrorStrings(content::RenderView
* render_view
,
2086 blink::WebFrame
* frame
,
2087 const blink::WebURLRequest
& failed_request
,
2088 const blink::WebURLError
& error
,
2089 std::string
* error_html
,
2090 base::string16
* error_description
) override
{
2092 *error_html
= "A suffusion of yellow.";
2097 #if defined(OS_ANDROID)
2098 // Crashing on Android: http://crbug.com/311341
2099 #define MAYBE_Suppresses DISABLED_Suppresses
2101 #define MAYBE_Suppresses Suppresses
2104 TEST_F(SuppressErrorPageTest
, MAYBE_Suppresses
) {
2106 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2107 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2108 error
.unreachableURL
= GURL("http://example.com/suppress");
2109 WebLocalFrame
* web_frame
= GetMainFrame();
2111 // Start a load that will reach provisional state synchronously,
2112 // but won't complete synchronously.
2113 CommonNavigationParams common_params
;
2114 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2115 common_params
.url
= GURL("data:text/html,test data");
2116 NavigateMainFrame(common_params
, StartNavigationParams(),
2117 RequestNavigationParams());
2119 // An error occurred.
2120 view()->GetMainRenderFrame()->didFailProvisionalLoad(
2121 web_frame
, error
, blink::WebStandardCommit
);
2122 const int kMaxOutputCharacters
= 22;
2124 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2127 #if defined(OS_ANDROID)
2128 // Crashing on Android: http://crbug.com/311341
2129 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2131 #define MAYBE_DoesNotSuppress DoesNotSuppress
2134 TEST_F(SuppressErrorPageTest
, MAYBE_DoesNotSuppress
) {
2136 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2137 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2138 error
.unreachableURL
= GURL("http://example.com/dont-suppress");
2139 WebLocalFrame
* web_frame
= GetMainFrame();
2141 // Start a load that will reach provisional state synchronously,
2142 // but won't complete synchronously.
2143 CommonNavigationParams common_params
;
2144 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2145 common_params
.url
= GURL("data:text/html,test data");
2146 NavigateMainFrame(common_params
, StartNavigationParams(),
2147 RequestNavigationParams());
2149 // An error occurred.
2150 view()->GetMainRenderFrame()->didFailProvisionalLoad(
2151 web_frame
, error
, blink::WebStandardCommit
);
2152 // The error page itself is loaded asynchronously.
2153 FrameLoadWaiter(frame()).Wait();
2154 const int kMaxOutputCharacters
= 22;
2155 EXPECT_EQ("A suffusion of yellow.",
2156 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2159 // Ensure the render view sends favicon url update events correctly.
2160 TEST_F(RenderViewImplTest
, SendFaviconURLUpdateEvent
) {
2161 // An event should be sent when a favicon url exists.
2164 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2167 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
2168 ViewHostMsg_UpdateFaviconURL::ID
));
2169 render_thread_
->sink().ClearMessages();
2171 // An event should not be sent if no favicon url exists. This is an assumption
2172 // made by some of Chrome's favicon handling.
2177 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
2178 ViewHostMsg_UpdateFaviconURL::ID
));
2181 TEST_F(RenderViewImplTest
, FocusElementCallsFocusedNodeChanged
) {
2182 LoadHTML("<input id='test1' value='hello1'></input>"
2183 "<input id='test2' value='hello2'></input>");
2185 ExecuteJavaScript("document.getElementById('test1').focus();");
2186 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
2187 ViewHostMsg_FocusedNodeChanged::ID
);
2190 ViewHostMsg_FocusedNodeChanged::Param params
;
2191 ViewHostMsg_FocusedNodeChanged::Read(msg1
, ¶ms
);
2192 EXPECT_TRUE(base::get
<0>(params
));
2193 render_thread_
->sink().ClearMessages();
2195 ExecuteJavaScript("document.getElementById('test2').focus();");
2196 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
2197 ViewHostMsg_FocusedNodeChanged::ID
);
2199 ViewHostMsg_FocusedNodeChanged::Read(msg2
, ¶ms
);
2200 EXPECT_TRUE(base::get
<0>(params
));
2201 render_thread_
->sink().ClearMessages();
2203 view()->webview()->clearFocusedElement();
2204 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
2205 ViewHostMsg_FocusedNodeChanged::ID
);
2207 ViewHostMsg_FocusedNodeChanged::Read(msg3
, ¶ms
);
2208 EXPECT_FALSE(base::get
<0>(params
));
2209 render_thread_
->sink().ClearMessages();
2212 TEST_F(RenderViewImplTest
, ServiceWorkerNetworkProviderSetup
) {
2213 ServiceWorkerNetworkProvider
* provider
= NULL
;
2214 RequestExtraData
* extra_data
= NULL
;
2216 // Make sure each new document has a new provider and
2217 // that the main request is tagged with the provider's id.
2218 LoadHTML("<b>A Document</b>");
2219 ASSERT_TRUE(GetMainFrame()->dataSource());
2220 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2221 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2222 ASSERT_TRUE(provider
);
2223 extra_data
= static_cast<RequestExtraData
*>(
2224 GetMainFrame()->dataSource()->request().extraData());
2225 ASSERT_TRUE(extra_data
);
2226 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2227 provider
->provider_id());
2228 int provider1_id
= provider
->provider_id();
2230 LoadHTML("<b>New Document B Goes Here</b>");
2231 ASSERT_TRUE(GetMainFrame()->dataSource());
2232 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2233 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2234 ASSERT_TRUE(provider
);
2235 EXPECT_NE(provider1_id
, provider
->provider_id());
2236 extra_data
= static_cast<RequestExtraData
*>(
2237 GetMainFrame()->dataSource()->request().extraData());
2238 ASSERT_TRUE(extra_data
);
2239 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2240 provider
->provider_id());
2242 // See that subresource requests are also tagged with the provider's id.
2243 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2244 blink::WebURLRequest
request(GURL("http://foo.com"));
2245 request
.setRequestContext(blink::WebURLRequest::RequestContextSubresource
);
2246 blink::WebURLResponse redirect_response
;
2247 frame()->willSendRequest(GetMainFrame(), 0, request
, redirect_response
);
2248 extra_data
= static_cast<RequestExtraData
*>(request
.extraData());
2249 ASSERT_TRUE(extra_data
);
2250 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2251 provider
->provider_id());
2254 TEST_F(RenderViewImplTest
, OnSetAccessibilityMode
) {
2255 ASSERT_EQ(AccessibilityModeOff
, frame()->accessibility_mode());
2256 ASSERT_EQ((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2258 SetAccessibilityMode(AccessibilityModeTreeOnly
);
2259 ASSERT_EQ(AccessibilityModeTreeOnly
, frame()->accessibility_mode());
2260 ASSERT_NE((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2262 SetAccessibilityMode(AccessibilityModeOff
);
2263 ASSERT_EQ(AccessibilityModeOff
, frame()->accessibility_mode());
2264 ASSERT_EQ((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2266 SetAccessibilityMode(AccessibilityModeComplete
);
2267 ASSERT_EQ(AccessibilityModeComplete
, frame()->accessibility_mode());
2268 ASSERT_NE((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2271 TEST_F(RenderViewImplTest
, ScreenMetricsEmulation
) {
2272 LoadHTML("<body style='min-height:1000px;'></body>");
2274 blink::WebDeviceEmulationParams params
;
2275 base::string16 get_width
= base::ASCIIToUTF16("Number(window.innerWidth)");
2276 base::string16 get_height
= base::ASCIIToUTF16("Number(window.innerHeight)");
2279 params
.viewSize
.width
= 327;
2280 params
.viewSize
.height
= 415;
2281 view()->OnEnableDeviceEmulation(params
);
2282 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width
, &width
));
2283 EXPECT_EQ(params
.viewSize
.width
, width
);
2284 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height
, &height
));
2285 EXPECT_EQ(params
.viewSize
.height
, height
);
2287 params
.viewSize
.width
= 1005;
2288 params
.viewSize
.height
= 1102;
2289 view()->OnEnableDeviceEmulation(params
);
2290 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width
, &width
));
2291 EXPECT_EQ(params
.viewSize
.width
, width
);
2292 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height
, &height
));
2293 EXPECT_EQ(params
.viewSize
.height
, height
);
2295 view()->OnDisableDeviceEmulation();
2297 view()->OnEnableDeviceEmulation(params
);
2298 // Don't disable here to test that emulation is being shutdown properly.
2301 // Sanity checks for the Navigation Timing API |navigationStart| override. We
2302 // are asserting only most basic constraints, as TimeTicks (passed as the
2303 // override) are not comparable with the wall time (returned by the Blink API).
2304 TEST_F(RenderViewImplTest
, NavigationStartOverride
) {
2305 // Verify that a navigation that claims to have started at the earliest
2306 // possible TimeTicks is indeed reported as one that started before
2307 // OnNavigate() is called.
2308 base::Time before_navigation
= base::Time::Now();
2309 CommonNavigationParams early_common_params
;
2310 StartNavigationParams early_start_params
;
2311 RequestNavigationParams early_request_params
;
2312 early_common_params
.url
= GURL("data:text/html,<div>Page</div>");
2313 early_common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2314 early_common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
2315 early_start_params
.is_post
= true;
2316 early_request_params
.browser_navigation_start
=
2317 base::TimeTicks::FromInternalValue(1);
2319 NavigateMainFrame(early_common_params
, early_start_params
,
2320 early_request_params
);
2321 ProcessPendingMessages();
2323 base::Time early_nav_reported_start
=
2324 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2325 EXPECT_LT(early_nav_reported_start
, before_navigation
);
2327 // Verify that a navigation that claims to have started in the future - 42
2328 // days from now is *not* reported as one that starts in the future; as we
2329 // sanitize the override allowing a maximum of ::Now().
2330 CommonNavigationParams late_common_params
;
2331 RequestNavigationParams late_request_params
;
2332 StartNavigationParams late_start_params
;
2333 late_common_params
.url
= GURL("data:text/html,<div>Another page</div>");
2334 late_common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2335 late_common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
2336 late_start_params
.is_post
= true;
2337 late_request_params
.browser_navigation_start
=
2338 base::TimeTicks::Now() + base::TimeDelta::FromDays(42);
2340 NavigateMainFrame(late_common_params
, late_start_params
, late_request_params
);
2341 ProcessPendingMessages();
2342 base::Time after_navigation
=
2343 base::Time::Now() + base::TimeDelta::FromDays(1);
2345 base::Time late_nav_reported_start
=
2346 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2347 EXPECT_LE(late_nav_reported_start
, after_navigation
);
2350 TEST_F(RenderViewImplTest
, PreferredSizeZoomed
) {
2351 LoadHTML("<body style='margin:0;'><div style='display:inline-block; "
2352 "width:400px; height:400px;'/></body>");
2353 view()->webview()->mainFrame()->setCanHaveScrollbars(false);
2354 EnablePreferredSizeMode();
2356 gfx::Size size
= GetPreferredSize();
2357 EXPECT_EQ(gfx::Size(400, 400), size
);
2359 SetZoomLevel(ZoomFactorToZoomLevel(2.0));
2360 size
= GetPreferredSize();
2361 EXPECT_EQ(gfx::Size(800, 800), size
);
2364 // Ensure the RenderViewImpl history list is properly updated when starting a
2365 // new browser-initiated navigation.
2366 TEST_F(RenderViewImplTest
, HistoryIsProperlyUpdatedOnNavigation
) {
2367 EXPECT_EQ(0, view()->historyBackListCount());
2368 EXPECT_EQ(0, view()->historyBackListCount() +
2369 view()->historyForwardListCount() + 1);
2371 // Receive a Navigate message with history parameters.
2372 RequestNavigationParams request_params
;
2373 request_params
.current_history_list_length
= 2;
2374 request_params
.current_history_list_offset
= 1;
2375 request_params
.pending_history_list_offset
= 2;
2376 request_params
.page_id
= -1;
2377 NavigateMainFrame(CommonNavigationParams(), StartNavigationParams(),
2380 // The history list in RenderView should have been updated.
2381 EXPECT_EQ(1, view()->historyBackListCount());
2382 EXPECT_EQ(2, view()->historyBackListCount() +
2383 view()->historyForwardListCount() + 1);
2386 TEST_F(DevToolsAgentTest
, DevToolsResumeOnClose
) {
2388 EXPECT_FALSE(IsPaused());
2389 DispatchDevToolsMessage("{\"id\":1,\"method\":\"Debugger.enable\"}");
2391 // Executing javascript will pause the thread and create nested message loop.
2392 // Posting task simulates message coming from browser.
2393 base::ThreadTaskRunnerHandle::Get()->PostTask(
2395 base::Bind(&DevToolsAgentTest::CloseWhilePaused
, base::Unretained(this)));
2396 ExecuteJavaScript("debugger;");
2398 // CloseWhilePaused should resume execution and continue here.
2399 EXPECT_FALSE(IsPaused());
2403 } // namespace content