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/memory/shared_memory.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/time/time.h"
12 #include "base/win/windows_version.h"
13 #include "content/child/request_extra_data.h"
14 #include "content/child/service_worker/service_worker_network_provider.h"
15 #include "content/common/frame_messages.h"
16 #include "content/common/ssl_status_serialization.h"
17 #include "content/common/view_messages.h"
18 #include "content/public/browser/browser_context.h"
19 #include "content/public/browser/native_web_keyboard_event.h"
20 #include "content/public/browser/web_ui_controller_factory.h"
21 #include "content/public/common/bindings_policy.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/page_zoom.h"
24 #include "content/public/common/url_constants.h"
25 #include "content/public/common/url_utils.h"
26 #include "content/public/renderer/content_renderer_client.h"
27 #include "content/public/renderer/document_state.h"
28 #include "content/public/renderer/navigation_state.h"
29 #include "content/public/test/browser_test_utils.h"
30 #include "content/public/test/frame_load_waiter.h"
31 #include "content/public/test/render_view_test.h"
32 #include "content/public/test/test_utils.h"
33 #include "content/renderer/accessibility/renderer_accessibility.h"
34 #include "content/renderer/devtools/devtools_agent.h"
35 #include "content/renderer/history_controller.h"
36 #include "content/renderer/history_serialization.h"
37 #include "content/renderer/navigation_state_impl.h"
38 #include "content/renderer/render_process.h"
39 #include "content/renderer/render_view_impl.h"
40 #include "content/shell/browser/shell.h"
41 #include "content/shell/browser/shell_browser_context.h"
42 #include "content/test/mock_keyboard.h"
43 #include "net/base/net_errors.h"
44 #include "net/cert/cert_status_flags.h"
45 #include "testing/gtest/include/gtest/gtest.h"
46 #include "third_party/WebKit/public/platform/WebData.h"
47 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
48 #include "third_party/WebKit/public/platform/WebString.h"
49 #include "third_party/WebKit/public/platform/WebURLResponse.h"
50 #include "third_party/WebKit/public/web/WebDataSource.h"
51 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
52 #include "third_party/WebKit/public/web/WebHistoryCommitType.h"
53 #include "third_party/WebKit/public/web/WebHistoryItem.h"
54 #include "third_party/WebKit/public/web/WebLocalFrame.h"
55 #include "third_party/WebKit/public/web/WebPerformance.h"
56 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
57 #include "third_party/WebKit/public/web/WebView.h"
58 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
59 #include "ui/events/event.h"
60 #include "ui/events/keycodes/keyboard_codes.h"
61 #include "ui/gfx/codec/jpeg_codec.h"
62 #include "ui/gfx/range/range.h"
64 #if defined(USE_AURA) && defined(USE_X11)
66 #include "ui/events/event_constants.h"
67 #include "ui/events/keycodes/keyboard_code_conversion.h"
68 #include "ui/events/test/events_test_utils.h"
69 #include "ui/events/test/events_test_utils_x11.h"
72 #if defined(USE_OZONE)
73 #include "ui/events/keycodes/keyboard_code_conversion.h"
76 using blink::WebFrame
;
77 using blink::WebInputEvent
;
78 using blink::WebLocalFrame
;
79 using blink::WebMouseEvent
;
80 using blink::WebRuntimeFeatures
;
81 using blink::WebString
;
82 using blink::WebTextDirection
;
83 using blink::WebURLError
;
89 static const int kProxyRoutingId
= 13;
91 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
92 // Converts MockKeyboard::Modifiers to ui::EventFlags.
93 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers
) {
94 static struct ModifierMap
{
95 MockKeyboard::Modifiers src
;
98 { MockKeyboard::LEFT_SHIFT
, ui::EF_SHIFT_DOWN
},
99 { MockKeyboard::RIGHT_SHIFT
, ui::EF_SHIFT_DOWN
},
100 { MockKeyboard::LEFT_CONTROL
, ui::EF_CONTROL_DOWN
},
101 { MockKeyboard::RIGHT_CONTROL
, ui::EF_CONTROL_DOWN
},
102 { MockKeyboard::LEFT_ALT
, ui::EF_ALT_DOWN
},
103 { MockKeyboard::RIGHT_ALT
, ui::EF_ALT_DOWN
},
106 for (size_t i
= 0; i
< arraysize(kModifierMap
); ++i
) {
107 if (kModifierMap
[i
].src
& modifiers
) {
108 flags
|= kModifierMap
[i
].dst
;
115 class WebUITestWebUIControllerFactory
: public WebUIControllerFactory
{
117 WebUIController
* CreateWebUIControllerForURL(WebUI
* web_ui
,
118 const GURL
& url
) const override
{
121 WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
122 const GURL
& url
) const override
{
123 return WebUI::kNoWebUI
;
125 bool UseWebUIForURL(BrowserContext
* browser_context
,
126 const GURL
& url
) const override
{
127 return HasWebUIScheme(url
);
129 bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
130 const GURL
& url
) const override
{
131 return HasWebUIScheme(url
);
137 class RenderViewImplTest
: public RenderViewTest
{
139 RenderViewImplTest() {
140 // Attach a pseudo keyboard device to this object.
141 mock_keyboard_
.reset(new MockKeyboard());
144 ~RenderViewImplTest() override
{}
146 void SetUp() override
{
147 RenderViewTest::SetUp();
148 // Enable Blink's experimental and test only features so that test code
149 // does not have to bother enabling each feature.
150 WebRuntimeFeatures::enableExperimentalFeatures(true);
151 WebRuntimeFeatures::enableTestOnlyFeatures(true);
154 RenderViewImpl
* view() {
155 return static_cast<RenderViewImpl
*>(view_
);
159 return view()->page_id_
;
162 RenderFrameImpl
* frame() {
163 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
166 // Sends IPC messages that emulates a key-press event.
167 int SendKeyEvent(MockKeyboard::Layout layout
,
169 MockKeyboard::Modifiers modifiers
,
170 base::string16
* output
) {
172 // Retrieve the Unicode character for the given tuple (keyboard-layout,
173 // key-code, and modifiers).
174 // Exit when a keyboard-layout driver cannot assign a Unicode character to
175 // the tuple to prevent sending an invalid key code to the RenderView
177 CHECK(mock_keyboard_
.get());
179 int length
= mock_keyboard_
->GetCharacters(layout
, key_code
, modifiers
,
184 // Create IPC messages from Windows messages and send them to our
186 // A keyboard event of Windows consists of three Windows messages:
187 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
188 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
189 // WM_CHAR sends a composed Unicode character.
190 MSG msg1
= { NULL
, WM_KEYDOWN
, key_code
, 0 };
191 ui::KeyEvent
evt1(msg1
);
192 NativeWebKeyboardEvent
keydown_event(evt1
);
193 SendNativeKeyEvent(keydown_event
);
195 MSG msg2
= { NULL
, WM_CHAR
, (*output
)[0], 0 };
196 ui::KeyEvent
evt2(msg2
);
197 NativeWebKeyboardEvent
char_event(evt2
);
198 SendNativeKeyEvent(char_event
);
200 MSG msg3
= { NULL
, WM_KEYUP
, key_code
, 0 };
201 ui::KeyEvent
evt3(msg3
);
202 NativeWebKeyboardEvent
keyup_event(evt3
);
203 SendNativeKeyEvent(keyup_event
);
206 #elif defined(USE_AURA) && defined(USE_X11)
207 // We ignore |layout|, which means we are only testing the layout of the
208 // current locale. TODO(mazda): fix this to respect |layout|.
210 const int flags
= ConvertMockKeyboardModifier(modifiers
);
212 ui::ScopedXI2Event xevent
;
213 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
214 static_cast<ui::KeyboardCode
>(key_code
),
216 ui::KeyEvent
event1(xevent
);
217 NativeWebKeyboardEvent
keydown_event(event1
);
218 SendNativeKeyEvent(keydown_event
);
220 // X11 doesn't actually have native character events, but give the test
222 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
223 static_cast<ui::KeyboardCode
>(key_code
),
225 ui::KeyEvent
event2(xevent
);
226 event2
.set_character(GetCharacterFromKeyCode(event2
.key_code(),
228 ui::KeyEventTestApi
test_event2(&event2
);
229 test_event2
.set_is_char(true);
230 NativeWebKeyboardEvent
char_event(event2
);
231 SendNativeKeyEvent(char_event
);
233 xevent
.InitKeyEvent(ui::ET_KEY_RELEASED
,
234 static_cast<ui::KeyboardCode
>(key_code
),
236 ui::KeyEvent
event3(xevent
);
237 NativeWebKeyboardEvent
keyup_event(event3
);
238 SendNativeKeyEvent(keyup_event
);
240 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
242 output
->assign(1, static_cast<base::char16
>(c
));
244 #elif defined(USE_OZONE)
245 const int flags
= ConvertMockKeyboardModifier(modifiers
);
247 ui::KeyEvent
keydown_event(ui::ET_KEY_PRESSED
,
248 static_cast<ui::KeyboardCode
>(key_code
),
250 NativeWebKeyboardEvent
keydown_web_event(keydown_event
);
251 SendNativeKeyEvent(keydown_web_event
);
253 ui::KeyEvent
char_event(keydown_event
.GetCharacter(),
254 static_cast<ui::KeyboardCode
>(key_code
),
256 NativeWebKeyboardEvent
char_web_event(char_event
);
257 SendNativeKeyEvent(char_web_event
);
259 ui::KeyEvent
keyup_event(ui::ET_KEY_RELEASED
,
260 static_cast<ui::KeyboardCode
>(key_code
),
262 NativeWebKeyboardEvent
keyup_web_event(keyup_event
);
263 SendNativeKeyEvent(keyup_web_event
);
265 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
267 output
->assign(1, static_cast<base::char16
>(c
));
275 void EnablePreferredSizeMode() {
276 view()->OnEnablePreferredSizeChangedMode();
279 const gfx::Size
& GetPreferredSize() {
280 view()->CheckPreferredSize();
281 return view()->preferred_size_
;
284 void SetZoomLevel(double level
) {
285 view()->OnSetZoomLevelForView(false, level
);
288 void NavigateFrame(const CommonNavigationParams
& common_params
,
289 const StartNavigationParams
& start_params
,
290 const RequestNavigationParams
& request_params
) {
292 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
293 switches::kEnableBrowserSideNavigation
)) {
294 frame()->OnCommitNavigation(ResourceResponseHead(), common_params
.url
,
295 common_params
, request_params
);
298 frame()->OnNavigate(common_params
, start_params
, request_params
);
301 void SwapOut(RenderFrameImpl
* frame
,
302 int proxy_routing_id
,
304 const FrameReplicationState
& replicated_frame_state
) {
305 frame
->OnSwapOut(proxy_routing_id
, is_loading
, replicated_frame_state
);
308 void SetEditableSelectionOffsets(int start
, int end
) {
309 frame()->OnSetEditableSelectionOffsets(start
, end
);
312 void ExtendSelectionAndDelete(int before
, int after
) {
313 frame()->OnExtendSelectionAndDelete(before
, after
);
316 void Unselect() { frame()->OnUnselect(); }
318 void SetAccessibilityMode(AccessibilityMode new_mode
) {
319 frame()->OnSetAccessibilityMode(new_mode
);
322 void SetCompositionFromExistingText(
325 const std::vector
<blink::WebCompositionUnderline
>& underlines
) {
326 frame()->OnSetCompositionFromExistingText(start
, end
, underlines
);
330 scoped_ptr
<MockKeyboard
> mock_keyboard_
;
333 class DevToolsAgentTest
: public RenderViewImplTest
{
336 std::string host_id
= "host_id";
337 agent()->OnAttach(host_id
);
345 return agent()->paused_
;
348 void DispatchDevToolsMessage(const std::string
& message
) {
349 agent()->OnDispatchOnInspectorBackend(message
);
352 void CloseWhilePaused() {
353 EXPECT_TRUE(IsPaused());
354 view()->NotifyOnClose();
358 DevToolsAgent
* agent() {
359 return frame()->devtools_agent();
363 // Test for https://crbug.com/461191.
364 TEST_F(RenderViewImplTest
, RenderFrameMessageAfterDetach
) {
365 // Create a new main frame RenderFrame so that we don't interfere with the
366 // shutdown of frame() in RenderViewTest.TearDown.
367 blink::WebURLRequest
popup_request(GURL("http://foo.com"));
368 blink::WebView
* new_web_view
= view()->createView(
369 GetMainFrame(), popup_request
, blink::WebWindowFeatures(), "foo",
370 blink::WebNavigationPolicyNewForegroundTab
, false);
371 RenderViewImpl
* new_view
= RenderViewImpl::FromWebView(new_web_view
);
372 RenderFrameImpl
* new_frame
=
373 static_cast<RenderFrameImpl
*>(new_view
->GetMainRenderFrame());
375 // Detach the main frame.
378 // Before the frame is asynchronously deleted, it may receive a message.
379 // We should not crash here, and the message should not be processed.
380 scoped_ptr
<const IPC::Message
> msg(
381 new FrameMsg_Stop(frame()->GetRoutingID()));
382 EXPECT_FALSE(new_frame
->OnMessageReceived(*msg
));
384 // Clean up after the new view so we don't leak it.
388 TEST_F(RenderViewImplTest
, SaveImageFromDataURL
) {
389 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
390 ViewHostMsg_SaveImageFromDataURL::ID
);
392 render_thread_
->sink().ClearMessages();
394 const std::string image_data_url
=
395 "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
397 view()->saveImageFromDataURL(WebString::fromUTF8(image_data_url
));
398 ProcessPendingMessages();
399 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
400 ViewHostMsg_SaveImageFromDataURL::ID
);
403 ViewHostMsg_SaveImageFromDataURL::Param param1
;
404 ViewHostMsg_SaveImageFromDataURL::Read(msg2
, ¶m1
);
405 EXPECT_EQ(get
<1>(param1
).length(), image_data_url
.length());
406 EXPECT_EQ(get
<1>(param1
), image_data_url
);
408 ProcessPendingMessages();
409 render_thread_
->sink().ClearMessages();
411 const std::string
large_data_url(1024 * 1024 * 10 - 1, 'd');
413 view()->saveImageFromDataURL(WebString::fromUTF8(large_data_url
));
414 ProcessPendingMessages();
415 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
416 ViewHostMsg_SaveImageFromDataURL::ID
);
419 ViewHostMsg_SaveImageFromDataURL::Param param2
;
420 ViewHostMsg_SaveImageFromDataURL::Read(msg3
, ¶m2
);
421 EXPECT_EQ(get
<1>(param2
).length(), large_data_url
.length());
422 EXPECT_EQ(get
<1>(param2
), large_data_url
);
424 ProcessPendingMessages();
425 render_thread_
->sink().ClearMessages();
427 const std::string
exceeded_data_url(1024 * 1024 * 10 + 1, 'd');
429 view()->saveImageFromDataURL(WebString::fromUTF8(exceeded_data_url
));
430 ProcessPendingMessages();
431 const IPC::Message
* msg4
= render_thread_
->sink().GetFirstMessageMatching(
432 ViewHostMsg_SaveImageFromDataURL::ID
);
436 // Test that we get form state change notifications when input fields change.
437 TEST_F(RenderViewImplTest
, DISABLED_OnNavStateChanged
) {
438 // Don't want any delay for form state sync changes. This will still post a
439 // message so updates will get coalesced, but as soon as we spin the message
440 // loop, it will generate an update.
441 view()->set_send_content_state_immediately(true);
443 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
445 // We should NOT have gotten a form state change notification yet.
446 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
447 ViewHostMsg_UpdateState::ID
));
448 render_thread_
->sink().ClearMessages();
450 // Change the value of the input. We should have gotten an update state
451 // notification. We need to spin the message loop to catch this update.
452 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';");
453 ProcessPendingMessages();
454 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
455 ViewHostMsg_UpdateState::ID
));
458 TEST_F(RenderViewImplTest
, OnNavigationHttpPost
) {
459 // An http url will trigger a resource load so cannot be used here.
460 CommonNavigationParams common_params
;
461 StartNavigationParams start_params
;
462 RequestNavigationParams request_params
;
463 common_params
.url
= GURL("data:text/html,<div>Page</div>");
464 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
465 common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
466 request_params
.page_id
= -1;
469 const unsigned char* raw_data
= reinterpret_cast<const unsigned char*>(
471 const unsigned int length
= 11;
472 const std::vector
<unsigned char> post_data(raw_data
, raw_data
+ length
);
473 start_params
.is_post
= true;
474 start_params
.browser_initiated_post_data
= post_data
;
476 NavigateFrame(common_params
, start_params
, request_params
);
477 ProcessPendingMessages();
479 const IPC::Message
* frame_navigate_msg
=
480 render_thread_
->sink().GetUniqueMessageMatching(
481 FrameHostMsg_DidCommitProvisionalLoad::ID
);
482 EXPECT_TRUE(frame_navigate_msg
);
484 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params
;
485 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
487 EXPECT_TRUE(get
<0>(host_nav_params
).is_post
);
489 // Check post data sent to browser matches
490 EXPECT_TRUE(get
<0>(host_nav_params
).page_state
.IsValid());
491 scoped_ptr
<HistoryEntry
> entry
=
492 PageStateToHistoryEntry(get
<0>(host_nav_params
).page_state
);
493 blink::WebHTTPBody body
= entry
->root().httpBody();
494 blink::WebHTTPBody::Element element
;
495 bool successful
= body
.elementAt(0, element
);
496 EXPECT_TRUE(successful
);
497 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData
, element
.type
);
498 EXPECT_EQ(length
, element
.data
.size());
499 EXPECT_EQ(0, memcmp(raw_data
, element
.data
.data(), length
));
502 TEST_F(RenderViewImplTest
, DecideNavigationPolicy
) {
503 WebUITestWebUIControllerFactory factory
;
504 WebUIControllerFactory::RegisterFactory(&factory
);
507 state
.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
509 // Navigations to normal HTTP URLs can be handled locally.
510 blink::WebURLRequest
request(GURL("http://foo.com"));
511 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
512 policy_info
.frame
= GetMainFrame();
513 policy_info
.extraData
= &state
;
514 policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
515 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
516 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
518 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab
, policy
);
520 // Verify that form posts to WebUI URLs will be sent to the browser process.
521 blink::WebURLRequest
form_request(GURL("chrome://foo"));
522 blink::WebFrameClient::NavigationPolicyInfo
form_policy_info(form_request
);
523 form_policy_info
.frame
= GetMainFrame();
524 form_policy_info
.extraData
= &state
;
525 form_policy_info
.navigationType
= blink::WebNavigationTypeFormSubmitted
;
526 form_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
527 form_request
.setHTTPMethod("POST");
528 policy
= frame()->decidePolicyForNavigation(form_policy_info
);
529 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
531 // Verify that popup links to WebUI URLs also are sent to browser.
532 blink::WebURLRequest
popup_request(GURL("chrome://foo"));
533 blink::WebFrameClient::NavigationPolicyInfo
popup_policy_info(popup_request
);
534 popup_policy_info
.frame
= GetMainFrame();
535 popup_policy_info
.extraData
= &state
;
536 popup_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
537 popup_policy_info
.defaultPolicy
= blink::WebNavigationPolicyNewForegroundTab
;
538 policy
= frame()->decidePolicyForNavigation(popup_policy_info
);
539 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
542 TEST_F(RenderViewImplTest
, DecideNavigationPolicyHandlesAllTopLevel
) {
544 state
.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
546 RendererPreferences prefs
= view()->renderer_preferences();
547 prefs
.browser_handles_all_top_level_requests
= true;
548 view()->OnSetRendererPrefs(prefs
);
550 const blink::WebNavigationType kNavTypes
[] = {
551 blink::WebNavigationTypeLinkClicked
,
552 blink::WebNavigationTypeFormSubmitted
,
553 blink::WebNavigationTypeBackForward
,
554 blink::WebNavigationTypeReload
,
555 blink::WebNavigationTypeFormResubmitted
,
556 blink::WebNavigationTypeOther
,
559 blink::WebURLRequest
request(GURL("http://foo.com"));
560 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
561 policy_info
.frame
= GetMainFrame();
562 policy_info
.extraData
= &state
;
563 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
565 for (size_t i
= 0; i
< arraysize(kNavTypes
); ++i
) {
566 policy_info
.navigationType
= kNavTypes
[i
];
568 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
570 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
574 TEST_F(RenderViewImplTest
, DecideNavigationPolicyForWebUI
) {
575 // Enable bindings to simulate a WebUI view.
576 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI
);
579 state
.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
581 // Navigations to normal HTTP URLs will be sent to browser process.
582 blink::WebURLRequest
request(GURL("http://foo.com"));
583 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
584 policy_info
.frame
= GetMainFrame();
585 policy_info
.extraData
= &state
;
586 policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
587 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
589 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
591 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
593 // Navigations to WebUI URLs will also be sent to browser process.
594 blink::WebURLRequest
webui_request(GURL("chrome://foo"));
595 blink::WebFrameClient::NavigationPolicyInfo
webui_policy_info(webui_request
);
596 webui_policy_info
.frame
= GetMainFrame();
597 webui_policy_info
.extraData
= &state
;
598 webui_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
599 webui_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
600 policy
= frame()->decidePolicyForNavigation(webui_policy_info
);
601 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
603 // Verify that form posts to data URLs will be sent to the browser process.
604 blink::WebURLRequest
data_request(GURL("data:text/html,foo"));
605 blink::WebFrameClient::NavigationPolicyInfo
data_policy_info(data_request
);
606 data_policy_info
.frame
= GetMainFrame();
607 data_policy_info
.extraData
= &state
;
608 data_policy_info
.navigationType
= blink::WebNavigationTypeFormSubmitted
;
609 data_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
610 data_request
.setHTTPMethod("POST");
611 policy
= frame()->decidePolicyForNavigation(data_policy_info
);
612 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
614 // Verify that a popup that creates a view first and then navigates to a
615 // normal HTTP URL will be sent to the browser process, even though the
616 // new view does not have any enabled_bindings_.
617 blink::WebURLRequest
popup_request(GURL("http://foo.com"));
618 blink::WebView
* new_web_view
= view()->createView(
619 GetMainFrame(), popup_request
, blink::WebWindowFeatures(), "foo",
620 blink::WebNavigationPolicyNewForegroundTab
, false);
621 RenderViewImpl
* new_view
= RenderViewImpl::FromWebView(new_web_view
);
622 blink::WebFrameClient::NavigationPolicyInfo
popup_policy_info(popup_request
);
623 popup_policy_info
.frame
= new_web_view
->mainFrame()->toWebLocalFrame();
624 popup_policy_info
.extraData
= &state
;
625 popup_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
626 popup_policy_info
.defaultPolicy
= blink::WebNavigationPolicyNewForegroundTab
;
627 policy
= static_cast<RenderFrameImpl
*>(new_view
->GetMainRenderFrame())->
628 decidePolicyForNavigation(popup_policy_info
);
629 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
631 // Clean up after the new view so we don't leak it.
636 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
637 // already swapped out. http://crbug.com/93427.
638 TEST_F(RenderViewImplTest
, SendSwapOutACK
) {
639 LoadHTML("<div>Page A</div>");
640 int initial_page_id
= view_page_id();
642 // Increment the ref count so that we don't exit when swapping out.
643 RenderProcess::current()->AddRefProcess();
645 // Respond to a swap out request.
646 SwapOut(frame(), kProxyRoutingId
, true, content::FrameReplicationState());
648 // Ensure the swap out commits synchronously.
649 EXPECT_NE(initial_page_id
, view_page_id());
651 // Check for a valid OnSwapOutACK.
652 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
653 FrameHostMsg_SwapOut_ACK::ID
);
656 // It is possible to get another swap out request. Ensure that we send
657 // an ACK, even if we don't have to do anything else.
658 render_thread_
->sink().ClearMessages();
659 SwapOut(frame(), kProxyRoutingId
, false, content::FrameReplicationState());
660 const IPC::Message
* msg2
= render_thread_
->sink().GetUniqueMessageMatching(
661 FrameHostMsg_SwapOut_ACK::ID
);
664 // If we navigate back to this RenderView, ensure we don't send a state
665 // update for the swapped out URL. (http://crbug.com/72235)
666 CommonNavigationParams common_params
;
667 RequestNavigationParams request_params
;
668 common_params
.url
= GURL("data:text/html,<div>Page B</div>");
669 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
670 common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
671 request_params
.current_history_list_length
= 1;
672 request_params
.current_history_list_offset
= 0;
673 request_params
.pending_history_list_offset
= 1;
674 request_params
.page_id
= -1;
675 NavigateFrame(common_params
, StartNavigationParams(), request_params
);
676 ProcessPendingMessages();
677 const IPC::Message
* msg3
= render_thread_
->sink().GetUniqueMessageMatching(
678 ViewHostMsg_UpdateState::ID
);
682 // Ensure the RenderViewImpl reloads the previous page if a reload request
683 // arrives while it is showing swappedout://. http://crbug.com/143155.
684 TEST_F(RenderViewImplTest
, ReloadWhileSwappedOut
) {
686 LoadHTML("<div>Page A</div>");
688 // Load page B, which will trigger an UpdateState message for page A.
689 LoadHTML("<div>Page B</div>");
691 // Check for a valid UpdateState message for page A.
692 ProcessPendingMessages();
693 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
694 ViewHostMsg_UpdateState::ID
);
696 ViewHostMsg_UpdateState::Param params
;
697 ViewHostMsg_UpdateState::Read(msg_A
, ¶ms
);
698 int page_id_A
= get
<0>(params
);
699 PageState state_A
= get
<1>(params
);
700 EXPECT_EQ(1, page_id_A
);
701 render_thread_
->sink().ClearMessages();
703 // Back to page A (page_id 1) and commit.
704 CommonNavigationParams common_params_A
;
705 RequestNavigationParams request_params_A
;
706 common_params_A
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
707 common_params_A
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
708 request_params_A
.current_history_list_length
= 2;
709 request_params_A
.current_history_list_offset
= 1;
710 request_params_A
.pending_history_list_offset
= 0;
711 request_params_A
.page_id
= 1;
712 request_params_A
.page_state
= state_A
;
713 NavigateFrame(common_params_A
, StartNavigationParams(), request_params_A
);
714 EXPECT_EQ(1, view()->historyBackListCount());
715 EXPECT_EQ(2, view()->historyBackListCount() +
716 view()->historyForwardListCount() + 1);
717 ProcessPendingMessages();
719 // Respond to a swap out request.
720 SwapOut(frame(), kProxyRoutingId
, true, content::FrameReplicationState());
722 // Check for a OnSwapOutACK.
723 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
724 FrameHostMsg_SwapOut_ACK::ID
);
726 render_thread_
->sink().ClearMessages();
728 // It is possible to get a reload request at this point, containing the
729 // params.page_state of the initial page (e.g., if the new page fails the
730 // provisional load in the renderer process, after we unload the old page).
731 // Ensure the old page gets reloaded, not swappedout://.
732 CommonNavigationParams common_params
;
733 RequestNavigationParams request_params
;
734 common_params
.url
= GURL("data:text/html,<div>Page A</div>");
735 common_params
.navigation_type
= FrameMsg_Navigate_Type::RELOAD
;
736 common_params
.transition
= ui::PAGE_TRANSITION_RELOAD
;
737 request_params
.current_history_list_length
= 2;
738 request_params
.current_history_list_offset
= 0;
739 request_params
.pending_history_list_offset
= 0;
740 request_params
.page_id
= 1;
741 request_params
.page_state
= state_A
;
742 NavigateFrame(common_params
, StartNavigationParams(), request_params
);
743 ProcessPendingMessages();
745 // Verify page A committed, not swappedout://.
746 const IPC::Message
* frame_navigate_msg
=
747 render_thread_
->sink().GetUniqueMessageMatching(
748 FrameHostMsg_DidCommitProvisionalLoad::ID
);
749 EXPECT_TRUE(frame_navigate_msg
);
751 // Read URL out of the parent trait of the params object.
752 FrameHostMsg_DidCommitProvisionalLoad::Param commit_load_params
;
753 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
754 &commit_load_params
);
755 EXPECT_NE(GURL("swappedout://"), get
<0>(commit_load_params
).url
);
758 // Verify that security origins are replicated properly to RenderFrameProxies
759 // when swapping out.
760 TEST_F(RenderViewImplTest
, OriginReplicationForSwapOut
) {
761 // This test should only run with --site-per-process, since origin
762 // replication only happens in that mode.
763 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
764 switches::kSitePerProcess
))
768 "Hello <iframe src='data:text/html,frame 1'></iframe>"
769 "<iframe src='data:text/html,frame 2'></iframe>");
770 WebFrame
* web_frame
= frame()->GetWebFrame();
771 RenderFrameImpl
* child_frame
= static_cast<RenderFrameImpl
*>(
772 RenderFrame::FromWebFrame(web_frame
->firstChild()));
774 // Swap the child frame out and pass a serialized origin to be set for
776 content::FrameReplicationState replication_state
;
777 replication_state
.origin
= url::Origin("http://foo.com");
778 SwapOut(child_frame
, kProxyRoutingId
, true, replication_state
);
780 // The child frame should now be a WebRemoteFrame.
781 EXPECT_TRUE(web_frame
->firstChild()->isWebRemoteFrame());
783 // Expect the origin to be updated properly.
784 blink::WebSecurityOrigin origin
= web_frame
->firstChild()->securityOrigin();
785 EXPECT_EQ(origin
.toString(),
786 WebString::fromUTF8(replication_state
.origin
.string()));
788 // Now, swap out the second frame using a unique origin and verify that it is
789 // replicated correctly.
790 replication_state
.origin
= url::Origin();
791 RenderFrameImpl
* child_frame2
= static_cast<RenderFrameImpl
*>(
792 RenderFrame::FromWebFrame(web_frame
->lastChild()));
793 SwapOut(child_frame2
, kProxyRoutingId
+ 1, true, replication_state
);
794 EXPECT_TRUE(web_frame
->lastChild()->isWebRemoteFrame());
795 EXPECT_TRUE(web_frame
->lastChild()->securityOrigin().isUnique());
798 // Test that we get the correct UpdateState message when we go back twice
799 // quickly without committing. Regression test for http://crbug.com/58082.
800 // Disabled: http://crbug.com/157357 .
801 TEST_F(RenderViewImplTest
, DISABLED_LastCommittedUpdateState
) {
803 LoadHTML("<div>Page A</div>");
805 // Load page B, which will trigger an UpdateState message for page A.
806 LoadHTML("<div>Page B</div>");
808 // Check for a valid UpdateState message for page A.
809 ProcessPendingMessages();
810 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
811 ViewHostMsg_UpdateState::ID
);
813 ViewHostMsg_UpdateState::Param param
;
814 ViewHostMsg_UpdateState::Read(msg_A
, ¶m
);
815 int page_id_A
= get
<0>(param
);
816 PageState state_A
= get
<1>(param
);
817 EXPECT_EQ(1, page_id_A
);
818 render_thread_
->sink().ClearMessages();
820 // Load page C, which will trigger an UpdateState message for page B.
821 LoadHTML("<div>Page C</div>");
823 // Check for a valid UpdateState for page B.
824 ProcessPendingMessages();
825 const IPC::Message
* msg_B
= render_thread_
->sink().GetUniqueMessageMatching(
826 ViewHostMsg_UpdateState::ID
);
828 ViewHostMsg_UpdateState::Read(msg_B
, ¶m
);
829 int page_id_B
= get
<0>(param
);
830 PageState state_B
= get
<1>(param
);
831 EXPECT_EQ(2, page_id_B
);
832 EXPECT_NE(state_A
, state_B
);
833 render_thread_
->sink().ClearMessages();
835 // Load page D, which will trigger an UpdateState message for page C.
836 LoadHTML("<div>Page D</div>");
838 // Check for a valid UpdateState for page C.
839 ProcessPendingMessages();
840 const IPC::Message
* msg_C
= render_thread_
->sink().GetUniqueMessageMatching(
841 ViewHostMsg_UpdateState::ID
);
843 ViewHostMsg_UpdateState::Read(msg_C
, ¶m
);
844 int page_id_C
= get
<0>(param
);
845 PageState state_C
= get
<1>(param
);
846 EXPECT_EQ(3, page_id_C
);
847 EXPECT_NE(state_B
, state_C
);
848 render_thread_
->sink().ClearMessages();
850 // Go back to C and commit, preparing for our real test.
851 CommonNavigationParams common_params_C
;
852 RequestNavigationParams request_params_C
;
853 common_params_C
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
854 common_params_C
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
855 request_params_C
.current_history_list_length
= 4;
856 request_params_C
.current_history_list_offset
= 3;
857 request_params_C
.pending_history_list_offset
= 2;
858 request_params_C
.page_id
= 3;
859 request_params_C
.page_state
= state_C
;
860 NavigateFrame(common_params_C
, StartNavigationParams(), request_params_C
);
861 ProcessPendingMessages();
862 render_thread_
->sink().ClearMessages();
864 // Go back twice quickly, such that page B does not have a chance to commit.
865 // This leads to two changes to the back/forward list but only one change to
866 // the RenderView's page ID.
868 // Back to page B (page_id 2), without committing.
869 CommonNavigationParams common_params_B
;
870 RequestNavigationParams request_params_B
;
871 common_params_B
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
872 common_params_B
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
873 request_params_B
.current_history_list_length
= 4;
874 request_params_B
.current_history_list_offset
= 2;
875 request_params_B
.pending_history_list_offset
= 1;
876 request_params_B
.page_id
= 2;
877 request_params_B
.page_state
= state_B
;
878 NavigateFrame(common_params_B
, StartNavigationParams(), request_params_B
);
880 // Back to page A (page_id 1) and commit.
881 CommonNavigationParams common_params
;
882 RequestNavigationParams request_params
;
883 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
884 common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
885 request_params
.current_history_list_length
= 4;
886 request_params
.current_history_list_offset
= 2;
887 request_params
.pending_history_list_offset
= 0;
888 request_params
.page_id
= 1;
889 request_params
.page_state
= state_A
;
890 NavigateFrame(common_params
, StartNavigationParams(), request_params
);
891 ProcessPendingMessages();
893 // Now ensure that the UpdateState message we receive is consistent
894 // and represents page C in both page_id and state.
895 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
896 ViewHostMsg_UpdateState::ID
);
898 ViewHostMsg_UpdateState::Read(msg
, ¶m
);
899 int page_id
= get
<0>(param
);
900 PageState state
= get
<1>(param
);
901 EXPECT_EQ(page_id_C
, page_id
);
902 EXPECT_NE(state_A
, state
);
903 EXPECT_NE(state_B
, state
);
904 EXPECT_EQ(state_C
, state
);
907 // Test that stale back/forward navigations arriving from the browser are
908 // ignored. See http://crbug.com/86758.
909 TEST_F(RenderViewImplTest
, StaleNavigationsIgnored
) {
911 LoadHTML("<div>Page A</div>");
912 EXPECT_EQ(1, view()->history_list_length_
);
913 EXPECT_EQ(0, view()->history_list_offset_
);
915 // Load page B, which will trigger an UpdateState message for page A.
916 LoadHTML("<div>Page B</div>");
917 EXPECT_EQ(2, view()->history_list_length_
);
918 EXPECT_EQ(1, view()->history_list_offset_
);
920 // Check for a valid UpdateState message for page A.
921 ProcessPendingMessages();
922 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
923 ViewHostMsg_UpdateState::ID
);
925 ViewHostMsg_UpdateState::Param param
;
926 ViewHostMsg_UpdateState::Read(msg_A
, ¶m
);
927 int page_id_A
= get
<0>(param
);
928 PageState state_A
= get
<1>(param
);
929 EXPECT_EQ(1, page_id_A
);
930 render_thread_
->sink().ClearMessages();
932 // Back to page A (page_id 1) and commit.
933 CommonNavigationParams common_params_A
;
934 RequestNavigationParams request_params_A
;
935 common_params_A
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
936 common_params_A
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
937 request_params_A
.current_history_list_length
= 2;
938 request_params_A
.current_history_list_offset
= 1;
939 request_params_A
.pending_history_list_offset
= 0;
940 request_params_A
.page_id
= 1;
941 request_params_A
.page_state
= state_A
;
942 NavigateFrame(common_params_A
, StartNavigationParams(), request_params_A
);
943 ProcessPendingMessages();
945 // A new navigation commits, clearing the forward history.
946 LoadHTML("<div>Page C</div>");
947 EXPECT_EQ(2, view()->history_list_length_
);
948 EXPECT_EQ(1, view()->history_list_offset_
);
949 EXPECT_EQ(3, view()->page_id_
); // page C is now page id 3
951 // The browser then sends a stale navigation to B, which should be ignored.
952 CommonNavigationParams common_params_B
;
953 RequestNavigationParams request_params_B
;
954 common_params_B
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
955 common_params_B
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
956 request_params_B
.current_history_list_length
= 2;
957 request_params_B
.current_history_list_offset
= 0;
958 request_params_B
.pending_history_list_offset
= 1;
959 request_params_B
.page_id
= 2;
960 request_params_B
.page_state
=
961 state_A
; // Doesn't matter, just has to be present.
962 NavigateFrame(common_params_B
, StartNavigationParams(), request_params_B
);
964 // State should be unchanged.
965 EXPECT_EQ(2, view()->history_list_length_
);
966 EXPECT_EQ(1, view()->history_list_offset_
);
967 EXPECT_EQ(3, view()->page_id_
); // page C, not page B
969 // Check for a valid DidDropNavigation message.
970 ProcessPendingMessages();
971 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
972 FrameHostMsg_DidDropNavigation::ID
);
974 render_thread_
->sink().ClearMessages();
977 // Test that our IME backend sends a notification message when the input focus
979 TEST_F(RenderViewImplTest
, OnImeTypeChanged
) {
980 // Enable our IME backend code.
981 view()->OnSetInputMethodActive(true);
983 // Load an HTML page consisting of two input fields.
984 view()->set_send_content_state_immediately(true);
989 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
990 "<input id=\"test2\" type=\"password\"></input>"
991 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
992 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
993 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
994 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
996 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
998 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
999 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
1000 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
1001 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
1002 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
1003 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
1004 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
1005 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
1008 render_thread_
->sink().ClearMessages();
1010 struct InputModeTestCase
{
1011 const char* input_id
;
1012 ui::TextInputMode expected_mode
;
1014 static const InputModeTestCase kInputModeTestCases
[] = {
1015 {"test1", ui::TEXT_INPUT_MODE_DEFAULT
},
1016 {"test3", ui::TEXT_INPUT_MODE_VERBATIM
},
1017 {"test4", ui::TEXT_INPUT_MODE_LATIN
},
1018 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME
},
1019 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE
},
1020 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN
},
1021 {"test8", ui::TEXT_INPUT_MODE_KANA
},
1022 {"test9", ui::TEXT_INPUT_MODE_KATAKANA
},
1023 {"test10", ui::TEXT_INPUT_MODE_NUMERIC
},
1024 {"test11", ui::TEXT_INPUT_MODE_TEL
},
1025 {"test12", ui::TEXT_INPUT_MODE_EMAIL
},
1026 {"test13", ui::TEXT_INPUT_MODE_URL
},
1027 {"test14", ui::TEXT_INPUT_MODE_DEFAULT
},
1028 {"test15", ui::TEXT_INPUT_MODE_VERBATIM
},
1031 const int kRepeatCount
= 10;
1032 for (int i
= 0; i
< kRepeatCount
; i
++) {
1033 // Move the input focus to the first <input> element, where we should
1035 ExecuteJavaScript("document.getElementById('test1').focus();");
1036 ProcessPendingMessages();
1037 render_thread_
->sink().ClearMessages();
1039 // Update the IME status and verify if our IME backend sends an IPC message
1040 // to activate IMEs.
1041 view()->UpdateTextInputType();
1042 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
1043 EXPECT_TRUE(msg
!= NULL
);
1044 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
1045 ViewHostMsg_TextInputTypeChanged::Param params
;
1046 ViewHostMsg_TextInputTypeChanged::Read(msg
, ¶ms
);
1047 ui::TextInputType type
= get
<0>(params
);
1048 ui::TextInputMode input_mode
= get
<1>(params
);
1049 bool can_compose_inline
= get
<2>(params
);
1050 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT
, type
);
1051 EXPECT_EQ(true, can_compose_inline
);
1053 // Move the input focus to the second <input> element, where we should
1054 // de-activate IMEs.
1055 ExecuteJavaScript("document.getElementById('test2').focus();");
1056 ProcessPendingMessages();
1057 render_thread_
->sink().ClearMessages();
1059 // Update the IME status and verify if our IME backend sends an IPC message
1060 // to de-activate IMEs.
1061 view()->UpdateTextInputType();
1062 msg
= render_thread_
->sink().GetMessageAt(0);
1063 EXPECT_TRUE(msg
!= NULL
);
1064 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
1065 ViewHostMsg_TextInputTypeChanged::Read(msg
, & params
);
1066 type
= get
<0>(params
);
1067 input_mode
= get
<1>(params
);
1068 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD
, type
);
1070 for (size_t i
= 0; i
< arraysize(kInputModeTestCases
); i
++) {
1071 const InputModeTestCase
* test_case
= &kInputModeTestCases
[i
];
1072 std::string javascript
=
1073 base::StringPrintf("document.getElementById('%s').focus();",
1074 test_case
->input_id
);
1075 // Move the input focus to the target <input> element, where we should
1077 ExecuteJavaScriptAndReturnIntValue(base::ASCIIToUTF16(javascript
), NULL
);
1078 ProcessPendingMessages();
1079 render_thread_
->sink().ClearMessages();
1081 // Update the IME status and verify if our IME backend sends an IPC
1082 // message to activate IMEs.
1083 view()->UpdateTextInputType();
1084 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
1085 EXPECT_TRUE(msg
!= NULL
);
1086 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
1087 ViewHostMsg_TextInputTypeChanged::Read(msg
, & params
);
1088 type
= get
<0>(params
);
1089 input_mode
= get
<1>(params
);
1090 EXPECT_EQ(test_case
->expected_mode
, input_mode
);
1095 // Test that our IME backend can compose CJK words.
1096 // Our IME front-end sends many platform-independent messages to the IME backend
1097 // while it composes CJK words. This test sends the minimal messages captured
1098 // on my local environment directly to the IME backend to verify if the backend
1099 // can compose CJK words without any problems.
1100 // This test uses an array of command sets because an IME composotion does not
1101 // only depends on IME events, but also depends on window events, e.g. moving
1102 // the window focus while composing a CJK text. To handle such complicated
1103 // cases, this test should not only call IME-related functions in the
1104 // RenderWidget class, but also call some RenderWidget members, e.g.
1105 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc.
1106 TEST_F(RenderViewImplTest
, ImeComposition
) {
1112 IME_CONFIRMCOMPOSITION
,
1113 IME_CANCELCOMPOSITION
1118 int selection_start
;
1120 const wchar_t* ime_string
;
1121 const wchar_t* result
;
1123 static const ImeMessage kImeMessages
[] = {
1124 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
1125 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1126 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1127 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1128 {IME_SETCOMPOSITION
, false, 1, 1, L
"n", L
"n"},
1129 {IME_SETCOMPOSITION
, false, 2, 2, L
"ni", L
"ni"},
1130 {IME_SETCOMPOSITION
, false, 3, 3, L
"nih", L
"nih"},
1131 {IME_SETCOMPOSITION
, false, 4, 4, L
"niha", L
"niha"},
1132 {IME_SETCOMPOSITION
, false, 5, 5, L
"nihao", L
"nihao"},
1133 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"\x4F60\x597D", L
"\x4F60\x597D"},
1134 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
1135 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1136 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1137 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1138 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xFF4B", L
"\xFF4B"},
1139 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x304B", L
"\x304B"},
1140 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x304B\xFF4E", L
"\x304B\xFF4E"},
1141 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\xFF4A",
1142 L
"\x304B\x3093\xFF4A"},
1143 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\x3058",
1144 L
"\x304B\x3093\x3058"},
1145 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x611F\x3058", L
"\x611F\x3058"},
1146 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x6F22\x5B57", L
"\x6F22\x5B57"},
1147 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1148 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1149 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1150 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1151 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1152 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1153 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3147", L
"\x3147"},
1154 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC544", L
"\xC544"},
1155 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC548", L
"\xC548"},
1156 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1157 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3134", L
"\xC548\x3134"},
1158 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB140", L
"\xC548\xB140"},
1159 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1160 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1161 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1162 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548\xB155"},
1165 for (size_t i
= 0; i
< arraysize(kImeMessages
); i
++) {
1166 const ImeMessage
* ime_message
= &kImeMessages
[i
];
1167 switch (ime_message
->command
) {
1168 case IME_INITIALIZE
:
1169 // Load an HTML page consisting of a content-editable <div> element,
1170 // and move the input focus to the <div> element, where we can use
1172 view()->OnSetInputMethodActive(ime_message
->enable
);
1173 view()->set_send_content_state_immediately(true);
1178 "<div id=\"test1\" contenteditable=\"true\"></div>"
1181 ExecuteJavaScript("document.getElementById('test1').focus();");
1184 case IME_SETINPUTMODE
:
1185 // Activate (or deactivate) our IME back-end.
1186 view()->OnSetInputMethodActive(ime_message
->enable
);
1190 // Update the window focus.
1191 view()->OnSetFocus(ime_message
->enable
);
1194 case IME_SETCOMPOSITION
:
1195 view()->OnImeSetComposition(
1196 base::WideToUTF16(ime_message
->ime_string
),
1197 std::vector
<blink::WebCompositionUnderline
>(),
1198 ime_message
->selection_start
,
1199 ime_message
->selection_end
);
1202 case IME_CONFIRMCOMPOSITION
:
1203 view()->OnImeConfirmComposition(
1204 base::WideToUTF16(ime_message
->ime_string
),
1205 gfx::Range::InvalidRange(),
1209 case IME_CANCELCOMPOSITION
:
1210 view()->OnImeSetComposition(
1212 std::vector
<blink::WebCompositionUnderline
>(),
1217 // Update the status of our IME back-end.
1218 // TODO(hbono): we should verify messages to be sent from the back-end.
1219 view()->UpdateTextInputType();
1220 ProcessPendingMessages();
1221 render_thread_
->sink().ClearMessages();
1223 if (ime_message
->result
) {
1224 // Retrieve the content of this page and compare it with the expected
1226 const int kMaxOutputCharacters
= 128;
1227 base::string16 output
=
1228 GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1229 EXPECT_EQ(base::WideToUTF16(ime_message
->result
), output
);
1234 // Test that the RenderView::OnSetTextDirection() function can change the text
1235 // direction of the selected input element.
1236 TEST_F(RenderViewImplTest
, OnSetTextDirection
) {
1237 // Load an HTML page consisting of a <textarea> element and a <div> element.
1238 // This test changes the text direction of the <textarea> element, and
1239 // writes the values of its 'dir' attribute and its 'direction' property to
1240 // verify that the text direction is changed.
1241 view()->set_send_content_state_immediately(true);
1246 "<textarea id=\"test\"></textarea>"
1247 "<div id=\"result\" contenteditable=\"true\"></div>"
1250 render_thread_
->sink().ClearMessages();
1252 static const struct {
1253 WebTextDirection direction
;
1254 const wchar_t* expected_result
;
1255 } kTextDirection
[] = {
1256 { blink::WebTextDirectionRightToLeft
, L
"\x000A" L
"rtl,rtl" },
1257 { blink::WebTextDirectionLeftToRight
, L
"\x000A" L
"ltr,ltr" },
1259 for (size_t i
= 0; i
< arraysize(kTextDirection
); ++i
) {
1260 // Set the text direction of the <textarea> element.
1261 ExecuteJavaScript("document.getElementById('test').focus();");
1262 view()->OnSetTextDirection(kTextDirection
[i
].direction
);
1264 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1265 // property to the <div> element.
1266 ExecuteJavaScript("var result = document.getElementById('result');"
1267 "var node = document.getElementById('test');"
1268 "var style = getComputedStyle(node, null);"
1269 "result.innerText ="
1270 " node.getAttribute('dir') + ',' +"
1271 " style.getPropertyValue('direction');");
1273 // Copy the document content to std::wstring and compare with the
1275 const int kMaxOutputCharacters
= 16;
1276 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1277 EXPECT_EQ(base::WideToUTF16(kTextDirection
[i
].expected_result
), output
);
1281 // see http://crbug.com/238750
1283 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent
1285 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent
1288 // Test that we can receive correct DOM events when we send input events
1289 // through the RenderWidget::OnHandleInputEvent() function.
1290 TEST_F(RenderViewImplTest
, MAYBE_OnHandleKeyboardEvent
) {
1291 #if !defined(OS_MACOSX)
1292 // Load an HTML page consisting of one <input> element and three
1293 // contentediable <div> elements.
1294 // The <input> element is used for sending keyboard events, and the <div>
1295 // elements are used for writing DOM events in the following format:
1296 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1297 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1298 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1299 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1300 view()->set_send_content_state_immediately(true);
1304 "<script type='text/javascript' language='javascript'>"
1305 "function OnKeyEvent(ev) {"
1306 " var result = document.getElementById(ev.type);"
1307 " result.innerText ="
1308 " (ev.which || ev.keyCode) + ',' +"
1309 " ev.shiftKey + ',' +"
1310 " ev.ctrlKey + ',' +"
1317 "<input id='test' type='text'"
1318 " onkeydown='return OnKeyEvent(event);'"
1319 " onkeypress='return OnKeyEvent(event);'"
1320 " onkeyup='return OnKeyEvent(event);'>"
1322 "<div id='keydown' contenteditable='true'>"
1324 "<div id='keypress' contenteditable='true'>"
1326 "<div id='keyup' contenteditable='true'>"
1330 ExecuteJavaScript("document.getElementById('test').focus();");
1331 render_thread_
->sink().ClearMessages();
1333 static const MockKeyboard::Layout kLayouts
[] = {
1335 // Since we ignore the mock keyboard layout on Linux and instead just use
1336 // the screen's keyboard layout, these trivially pass. They are commented
1337 // out to avoid the illusion that they work.
1338 MockKeyboard::LAYOUT_ARABIC
,
1339 MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1340 MockKeyboard::LAYOUT_FRENCH
,
1341 MockKeyboard::LAYOUT_HEBREW
,
1342 MockKeyboard::LAYOUT_RUSSIAN
,
1344 MockKeyboard::LAYOUT_UNITED_STATES
,
1347 for (size_t i
= 0; i
< arraysize(kLayouts
); ++i
) {
1348 // For each key code, we send three keyboard events.
1349 // * we press only the key;
1350 // * we press the key and a left-shift key, and;
1351 // * we press the key and a right-alt (AltGr) key.
1352 // For each modifiers, we need a string used for formatting its expected
1353 // result. (See the above comment for its format.)
1354 static const struct {
1355 MockKeyboard::Modifiers modifiers
;
1356 const char* expected_result
;
1357 } kModifierData
[] = {
1358 {MockKeyboard::NONE
, "false,false,false"},
1359 {MockKeyboard::LEFT_SHIFT
, "true,false,false"},
1361 {MockKeyboard::RIGHT_ALT
, "false,false,true"},
1365 MockKeyboard::Layout layout
= kLayouts
[i
];
1366 for (size_t j
= 0; j
< arraysize(kModifierData
); ++j
) {
1367 // Virtual key codes used for this test.
1368 static const int kKeyCodes
[] = {
1369 '0', '1', '2', '3', '4', '5', '6', '7',
1370 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1371 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1372 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1378 ui::VKEY_OEM_PERIOD
,
1386 // Not sure how to handle this key on Linux.
1391 MockKeyboard::Modifiers modifiers
= kModifierData
[j
].modifiers
;
1392 for (size_t k
= 0; k
< arraysize(kKeyCodes
); ++k
) {
1393 // Send a keyboard event to the RenderView object.
1394 // We should test a keyboard event only when the given keyboard-layout
1395 // driver is installed in a PC and the driver can assign a Unicode
1396 // charcter for the given tuple (key-code and modifiers).
1397 int key_code
= kKeyCodes
[k
];
1398 base::string16 char_code
;
1399 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1402 // Create an expected result from the virtual-key code, the character
1403 // code, and the modifier-key status.
1404 // We format a string that emulates a DOM-event string produced hy
1405 // our JavaScript function. (See the above comment for the format.)
1406 static char expected_result
[1024];
1407 expected_result
[0] = 0;
1408 base::snprintf(&expected_result
[0],
1409 sizeof(expected_result
),
1410 "\n" // texts in the <input> element
1411 "%d,%s\n" // texts in the first <div> element
1412 "%d,%s\n" // texts in the second <div> element
1413 "%d,%s", // texts in the third <div> element
1414 key_code
, kModifierData
[j
].expected_result
,
1415 static_cast<int>(char_code
[0]),
1416 kModifierData
[j
].expected_result
,
1417 key_code
, kModifierData
[j
].expected_result
);
1419 // Retrieve the text in the test page and compare it with the expected
1420 // text created from a virtual-key code, a character code, and the
1421 // modifier-key status.
1422 const int kMaxOutputCharacters
= 1024;
1423 std::string output
= base::UTF16ToUTF8(
1424 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
1425 EXPECT_EQ(expected_result
, output
);
1434 // Test that our EditorClientImpl class can insert characters when we send
1435 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1436 // This test is for preventing regressions caused only when we use non-US
1437 // keyboards, such as Issue 10846.
1438 // see http://crbug.com/244562
1440 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1442 #define MAYBE_InsertCharacters InsertCharacters
1444 TEST_F(RenderViewImplTest
, MAYBE_InsertCharacters
) {
1445 #if !defined(OS_MACOSX)
1446 static const struct {
1447 MockKeyboard::Layout layout
;
1448 const wchar_t* expected_result
;
1451 // Disabled these keyboard layouts because buildbots do not have their
1452 // keyboard-layout drivers installed.
1453 {MockKeyboard::LAYOUT_ARABIC
,
1454 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1455 L
"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1456 L
"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1457 L
"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1458 L
"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1459 L
"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1460 L
"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1461 L
"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1462 L
"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1463 L
"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1464 L
"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1465 L
"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1466 L
"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1467 L
"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1468 L
"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1469 L
"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1470 L
"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1472 {MockKeyboard::LAYOUT_HEBREW
,
1473 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1474 L
"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1475 L
"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1476 L
"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1477 L
"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1478 L
"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1479 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1480 L
"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1481 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1482 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1483 L
"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1484 L
"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1485 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1486 L
"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1487 L
"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1488 L
"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1489 L
"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1490 L
"\x003b\x005d\x005c\x005b\x002c"
1494 // On Linux, the only way to test alternate keyboard layouts is to change
1495 // the keyboard layout of the whole screen. I'm worried about the side
1496 // effects this may have on the buildbots.
1497 {MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1498 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1499 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1500 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1501 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1502 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1503 L
"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1504 L
"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1505 L
"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1506 L
"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1507 L
"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1508 L
"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1509 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1510 L
"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1511 L
"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1512 L
"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1513 L
"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1516 {MockKeyboard::LAYOUT_FRENCH
,
1517 L
"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1518 L
"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1519 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1520 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1521 L
"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1522 L
"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1523 L
"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1524 L
"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1525 L
"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1526 L
"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1527 L
"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1528 L
"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1529 L
"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1530 L
"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1531 L
"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1532 L
"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1533 L
"\x003b\x003a\x00f9\x0029\x002a\x0021"
1535 {MockKeyboard::LAYOUT_RUSSIAN
,
1536 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1537 L
"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1538 L
"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1539 L
"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1540 L
"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1541 L
"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1542 L
"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1543 L
"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1544 L
"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1545 L
"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1546 L
"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1547 L
"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1548 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1549 L
"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1550 L
"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1551 L
"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1552 L
"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1553 L
"\x0451\x0445\x005c\x044a\x044d"
1555 #endif // defined(OS_WIN)
1556 {MockKeyboard::LAYOUT_UNITED_STATES
,
1557 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1558 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1559 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1560 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1561 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1562 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1563 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1564 L
"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1565 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1566 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1567 L
"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1568 L
"\x003f\x007e\x007b\x007c\x007d\x0022"
1570 // This is ifdefed out for Linux to correspond to the fact that we don't
1571 // test alt+keystroke for now.
1572 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1573 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1574 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1575 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1576 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1577 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1582 for (size_t i
= 0; i
< arraysize(kLayouts
); ++i
) {
1583 // Load an HTML page consisting of one <div> element.
1584 // This <div> element is used by the EditorClientImpl class to insert
1585 // characters received through the RenderWidget::OnHandleInputEvent()
1587 view()->set_send_content_state_immediately(true);
1593 "<div id='test' contenteditable='true'>"
1597 ExecuteJavaScript("document.getElementById('test').focus();");
1598 render_thread_
->sink().ClearMessages();
1600 // For each key code, we send three keyboard events.
1601 // * Pressing only the key;
1602 // * Pressing the key and a left-shift key, and;
1603 // * Pressing the key and a right-alt (AltGr) key.
1604 static const MockKeyboard::Modifiers kModifiers
[] = {
1606 MockKeyboard::LEFT_SHIFT
,
1608 MockKeyboard::RIGHT_ALT
,
1612 MockKeyboard::Layout layout
= kLayouts
[i
].layout
;
1613 for (size_t j
= 0; j
< arraysize(kModifiers
); ++j
) {
1614 // Virtual key codes used for this test.
1615 static const int kKeyCodes
[] = {
1616 '0', '1', '2', '3', '4', '5', '6', '7',
1617 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1618 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1619 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1625 ui::VKEY_OEM_PERIOD
,
1633 // Unclear how to handle this on Linux.
1638 MockKeyboard::Modifiers modifiers
= kModifiers
[j
];
1639 for (size_t k
= 0; k
< arraysize(kKeyCodes
); ++k
) {
1640 // Send a keyboard event to the RenderView object.
1641 // We should test a keyboard event only when the given keyboard-layout
1642 // driver is installed in a PC and the driver can assign a Unicode
1643 // charcter for the given tuple (layout, key-code, and modifiers).
1644 int key_code
= kKeyCodes
[k
];
1645 base::string16 char_code
;
1646 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1651 // Retrieve the text in the test page and compare it with the expected
1652 // text created from a virtual-key code, a character code, and the
1653 // modifier-key status.
1654 const int kMaxOutputCharacters
= 4096;
1655 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1656 EXPECT_EQ(base::WideToUTF16(kLayouts
[i
].expected_result
), output
);
1663 // Crashy, http://crbug.com/53247.
1664 TEST_F(RenderViewImplTest
, DISABLED_DidFailProvisionalLoadWithErrorForError
) {
1665 GetMainFrame()->enableViewSourceMode(true);
1667 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1668 error
.reason
= net::ERR_FILE_NOT_FOUND
;
1669 error
.unreachableURL
= GURL("http://foo");
1670 WebLocalFrame
* web_frame
= GetMainFrame();
1672 // Start a load that will reach provisional state synchronously,
1673 // but won't complete synchronously.
1674 CommonNavigationParams common_params
;
1675 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1676 common_params
.url
= GURL("data:text/html,test data");
1677 NavigateFrame(common_params
, StartNavigationParams(),
1678 RequestNavigationParams());
1680 // An error occurred.
1681 view()->GetMainRenderFrame()->didFailProvisionalLoad(
1682 web_frame
, error
, blink::WebStandardCommit
);
1683 // Frame should exit view-source mode.
1684 EXPECT_FALSE(web_frame
->isViewSourceModeEnabled());
1687 TEST_F(RenderViewImplTest
, DidFailProvisionalLoadWithErrorForCancellation
) {
1688 GetMainFrame()->enableViewSourceMode(true);
1690 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1691 error
.reason
= net::ERR_ABORTED
;
1692 error
.unreachableURL
= GURL("http://foo");
1693 WebLocalFrame
* web_frame
= GetMainFrame();
1695 // Start a load that will reach provisional state synchronously,
1696 // but won't complete synchronously.
1697 CommonNavigationParams common_params
;
1698 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1699 common_params
.url
= GURL("data:text/html,test data");
1700 NavigateFrame(common_params
, StartNavigationParams(),
1701 RequestNavigationParams());
1703 // A cancellation occurred.
1704 view()->GetMainRenderFrame()->didFailProvisionalLoad(
1705 web_frame
, error
, blink::WebStandardCommit
);
1706 // Frame should stay in view-source mode.
1707 EXPECT_TRUE(web_frame
->isViewSourceModeEnabled());
1710 // Regression test for http://crbug.com/41562
1711 TEST_F(RenderViewImplTest
, UpdateTargetURLWithInvalidURL
) {
1712 const GURL
invalid_gurl("http://");
1713 view()->setMouseOverURL(blink::WebURL(invalid_gurl
));
1714 EXPECT_EQ(invalid_gurl
, view()->target_url_
);
1717 TEST_F(RenderViewImplTest
, SetHistoryLengthAndOffset
) {
1718 // No history to merge; one committed page.
1719 view()->OnSetHistoryOffsetAndLength(0, 1);
1720 EXPECT_EQ(1, view()->history_list_length_
);
1721 EXPECT_EQ(0, view()->history_list_offset_
);
1723 // History of length 1 to merge; one committed page.
1724 view()->OnSetHistoryOffsetAndLength(1, 2);
1725 EXPECT_EQ(2, view()->history_list_length_
);
1726 EXPECT_EQ(1, view()->history_list_offset_
);
1729 TEST_F(RenderViewImplTest
, ContextMenu
) {
1730 LoadHTML("<div>Page A</div>");
1732 // Create a right click in the center of the iframe. (I'm hoping this will
1733 // make this a bit more robust in case of some other formatting or other bug.)
1734 WebMouseEvent mouse_event
;
1735 mouse_event
.type
= WebInputEvent::MouseDown
;
1736 mouse_event
.button
= WebMouseEvent::ButtonRight
;
1737 mouse_event
.x
= 250;
1738 mouse_event
.y
= 250;
1739 mouse_event
.globalX
= 250;
1740 mouse_event
.globalY
= 250;
1742 SendWebMouseEvent(mouse_event
);
1744 // Now simulate the corresponding up event which should display the menu
1745 mouse_event
.type
= WebInputEvent::MouseUp
;
1746 SendWebMouseEvent(mouse_event
);
1748 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
1749 FrameHostMsg_ContextMenu::ID
));
1752 TEST_F(RenderViewImplTest
, TestBackForward
) {
1753 LoadHTML("<div id=pagename>Page A</div>");
1754 PageState page_a_state
=
1755 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1756 int was_page_a
= -1;
1757 base::string16 check_page_a
=
1759 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1760 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1761 EXPECT_EQ(1, was_page_a
);
1763 LoadHTML("<div id=pagename>Page B</div>");
1764 int was_page_b
= -1;
1765 base::string16 check_page_b
=
1767 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1768 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1769 EXPECT_EQ(1, was_page_b
);
1771 PageState back_state
=
1772 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1774 LoadHTML("<div id=pagename>Page C</div>");
1775 int was_page_c
= -1;
1776 base::string16 check_page_c
=
1778 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1779 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1780 EXPECT_EQ(1, was_page_c
);
1782 PageState forward_state
=
1783 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1785 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1786 EXPECT_EQ(1, was_page_b
);
1788 PageState back_state2
=
1789 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1791 GoForward(forward_state
);
1792 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1793 EXPECT_EQ(1, was_page_c
);
1795 GoBack(back_state2
);
1796 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1797 EXPECT_EQ(1, was_page_b
);
1800 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1801 GoBack(page_a_state
);
1802 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1803 EXPECT_EQ(1, was_page_a
);
1805 GoForward(forward_state
);
1806 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1807 EXPECT_EQ(1, was_page_b
);
1810 #if defined(OS_MACOSX) || defined(USE_AURA)
1811 TEST_F(RenderViewImplTest
, GetCompositionCharacterBoundsTest
) {
1814 // http://crbug.com/304193
1815 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
1819 LoadHTML("<textarea id=\"test\"></textarea>");
1820 ExecuteJavaScript("document.getElementById('test').focus();");
1822 const base::string16 empty_string
;
1823 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1824 std::vector
<gfx::Rect
> bounds
;
1825 view()->OnSetFocus(true);
1826 view()->OnSetInputMethodActive(true);
1828 // ASCII composition
1829 const base::string16 ascii_composition
= base::UTF8ToUTF16("aiueo");
1830 view()->OnImeSetComposition(ascii_composition
, empty_underline
, 0, 0);
1831 view()->GetCompositionCharacterBounds(&bounds
);
1832 ASSERT_EQ(ascii_composition
.size(), bounds
.size());
1833 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1834 EXPECT_LT(0, bounds
[i
].width());
1835 view()->OnImeConfirmComposition(
1836 empty_string
, gfx::Range::InvalidRange(), false);
1838 // Non surrogate pair unicode character.
1839 const base::string16 unicode_composition
= base::UTF8ToUTF16(
1840 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1841 view()->OnImeSetComposition(unicode_composition
, empty_underline
, 0, 0);
1842 view()->GetCompositionCharacterBounds(&bounds
);
1843 ASSERT_EQ(unicode_composition
.size(), bounds
.size());
1844 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1845 EXPECT_LT(0, bounds
[i
].width());
1846 view()->OnImeConfirmComposition(
1847 empty_string
, gfx::Range::InvalidRange(), false);
1849 // Surrogate pair character.
1850 const base::string16 surrogate_pair_char
=
1851 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1852 view()->OnImeSetComposition(surrogate_pair_char
,
1856 view()->GetCompositionCharacterBounds(&bounds
);
1857 ASSERT_EQ(surrogate_pair_char
.size(), bounds
.size());
1858 EXPECT_LT(0, bounds
[0].width());
1859 EXPECT_EQ(0, bounds
[1].width());
1860 view()->OnImeConfirmComposition(
1861 empty_string
, gfx::Range::InvalidRange(), false);
1864 const base::string16 surrogate_pair_mixed_composition
=
1865 surrogate_pair_char
+ base::UTF8ToUTF16("\xE3\x81\x82") +
1866 surrogate_pair_char
+ base::UTF8ToUTF16("b") + surrogate_pair_char
;
1867 const size_t utf16_length
= 8UL;
1868 const bool is_surrogate_pair_empty_rect
[8] = {
1869 false, true, false, false, true, false, false, true };
1870 view()->OnImeSetComposition(surrogate_pair_mixed_composition
,
1874 view()->GetCompositionCharacterBounds(&bounds
);
1875 ASSERT_EQ(utf16_length
, bounds
.size());
1876 for (size_t i
= 0; i
< utf16_length
; ++i
) {
1877 if (is_surrogate_pair_empty_rect
[i
]) {
1878 EXPECT_EQ(0, bounds
[i
].width());
1880 EXPECT_LT(0, bounds
[i
].width());
1883 view()->OnImeConfirmComposition(
1884 empty_string
, gfx::Range::InvalidRange(), false);
1888 TEST_F(RenderViewImplTest
, ZoomLimit
) {
1889 const double kMinZoomLevel
= ZoomFactorToZoomLevel(kMinimumZoomFactor
);
1890 const double kMaxZoomLevel
= ZoomFactorToZoomLevel(kMaximumZoomFactor
);
1892 // Verifies navigation to a URL with preset zoom level indeed sets the level.
1893 // Regression test for http://crbug.com/139559, where the level was not
1894 // properly set when it is out of the default zoom limits of WebView.
1895 CommonNavigationParams common_params
;
1896 common_params
.url
= GURL("data:text/html,min_zoomlimit_test");
1897 view()->OnSetZoomLevelForLoadingURL(common_params
.url
, kMinZoomLevel
);
1898 NavigateFrame(common_params
, StartNavigationParams(),
1899 RequestNavigationParams());
1900 ProcessPendingMessages();
1901 EXPECT_DOUBLE_EQ(kMinZoomLevel
, view()->GetWebView()->zoomLevel());
1903 // It should work even when the zoom limit is temporarily changed in the page.
1904 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
1905 ZoomFactorToZoomLevel(1.0));
1906 common_params
.url
= GURL("data:text/html,max_zoomlimit_test");
1907 view()->OnSetZoomLevelForLoadingURL(common_params
.url
, kMaxZoomLevel
);
1908 NavigateFrame(common_params
, StartNavigationParams(),
1909 RequestNavigationParams());
1910 ProcessPendingMessages();
1911 EXPECT_DOUBLE_EQ(kMaxZoomLevel
, view()->GetWebView()->zoomLevel());
1914 TEST_F(RenderViewImplTest
, SetEditableSelectionAndComposition
) {
1915 // Load an HTML page consisting of an input field.
1920 "<input id=\"test1\" value=\"some test text hello\"></input>"
1923 ExecuteJavaScript("document.getElementById('test1').focus();");
1924 SetEditableSelectionOffsets(4, 8);
1925 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1926 SetCompositionFromExistingText(7, 10, empty_underline
);
1927 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1928 EXPECT_EQ(4, info
.selectionStart
);
1929 EXPECT_EQ(8, info
.selectionEnd
);
1930 EXPECT_EQ(7, info
.compositionStart
);
1931 EXPECT_EQ(10, info
.compositionEnd
);
1933 info
= view()->webview()->textInputInfo();
1934 EXPECT_EQ(0, info
.selectionStart
);
1935 EXPECT_EQ(0, info
.selectionEnd
);
1939 TEST_F(RenderViewImplTest
, OnExtendSelectionAndDelete
) {
1940 // Load an HTML page consisting of an input field.
1945 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
1948 ExecuteJavaScript("document.getElementById('test1').focus();");
1949 SetEditableSelectionOffsets(10, 10);
1950 ExtendSelectionAndDelete(3, 4);
1951 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1952 EXPECT_EQ("abcdefgopqrstuvwxyz", info
.value
);
1953 EXPECT_EQ(7, info
.selectionStart
);
1954 EXPECT_EQ(7, info
.selectionEnd
);
1955 SetEditableSelectionOffsets(4, 8);
1956 ExtendSelectionAndDelete(2, 5);
1957 info
= view()->webview()->textInputInfo();
1958 EXPECT_EQ("abuvwxyz", info
.value
);
1959 EXPECT_EQ(2, info
.selectionStart
);
1960 EXPECT_EQ(2, info
.selectionEnd
);
1963 // Test that the navigating specific frames works correctly.
1964 TEST_F(RenderViewImplTest
, NavigateFrame
) {
1966 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
1968 // Navigate the frame only.
1969 CommonNavigationParams common_params
;
1970 RequestNavigationParams request_params
;
1971 common_params
.url
= GURL("data:text/html,world");
1972 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1973 common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
1974 request_params
.current_history_list_length
= 1;
1975 request_params
.current_history_list_offset
= 0;
1976 request_params
.pending_history_list_offset
= 1;
1977 request_params
.page_id
= -1;
1978 request_params
.frame_to_navigate
= "frame";
1979 request_params
.browser_navigation_start
=
1980 base::TimeTicks::FromInternalValue(1);
1981 NavigateFrame(common_params
, StartNavigationParams(), request_params
);
1983 RenderFrame::FromWebFrame(frame()->GetWebFrame()->firstChild())).Wait();
1985 // Copy the document content to std::wstring and compare with the
1987 const int kMaxOutputCharacters
= 256;
1988 std::string output
= base::UTF16ToUTF8(
1989 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
1990 EXPECT_EQ(output
, "hello \n\nworld");
1993 // This test ensures that a RenderFrame object is created for the top level
1994 // frame in the RenderView.
1995 TEST_F(RenderViewImplTest
, BasicRenderFrame
) {
1996 EXPECT_TRUE(view()->main_render_frame_
.get());
1999 TEST_F(RenderViewImplTest
, GetSSLStatusOfFrame
) {
2000 LoadHTML("<!DOCTYPE html><html><body></body></html>");
2002 WebLocalFrame
* frame
= GetMainFrame();
2003 SSLStatus ssl_status
= view()->GetSSLStatusOfFrame(frame
);
2004 EXPECT_FALSE(net::IsCertStatusError(ssl_status
.cert_status
));
2006 const_cast<blink::WebURLResponse
&>(frame
->dataSource()->response()).
2008 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS
, 0, 0,
2009 SignedCertificateTimestampIDStatusList()));
2010 ssl_status
= view()->GetSSLStatusOfFrame(frame
);
2011 EXPECT_TRUE(net::IsCertStatusError(ssl_status
.cert_status
));
2014 TEST_F(RenderViewImplTest
, MessageOrderInDidChangeSelection
) {
2015 view()->OnSetInputMethodActive(true);
2016 view()->set_send_content_state_immediately(true);
2017 LoadHTML("<textarea id=\"test\"></textarea>");
2019 view()->handling_input_event_
= true;
2020 ExecuteJavaScript("document.getElementById('test').focus();");
2022 bool is_input_type_called
= false;
2023 bool is_selection_called
= false;
2024 size_t last_input_type
= 0;
2025 size_t last_selection
= 0;
2027 for (size_t i
= 0; i
< render_thread_
->sink().message_count(); ++i
) {
2028 const uint32 type
= render_thread_
->sink().GetMessageAt(i
)->type();
2029 if (type
== ViewHostMsg_TextInputTypeChanged::ID
) {
2030 is_input_type_called
= true;
2031 last_input_type
= i
;
2032 } else if (type
== ViewHostMsg_SelectionChanged::ID
) {
2033 is_selection_called
= true;
2038 EXPECT_TRUE(is_input_type_called
);
2039 EXPECT_TRUE(is_selection_called
);
2041 // InputTypeChange shold be called earlier than SelectionChanged.
2042 EXPECT_LT(last_input_type
, last_selection
);
2045 class SuppressErrorPageTest
: public RenderViewImplTest
{
2047 ContentRendererClient
* CreateContentRendererClient() override
{
2048 return new TestContentRendererClient
;
2051 RenderViewImpl
* view() {
2052 return static_cast<RenderViewImpl
*>(view_
);
2055 RenderFrameImpl
* frame() {
2056 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
2060 class TestContentRendererClient
: public ContentRendererClient
{
2062 bool ShouldSuppressErrorPage(RenderFrame
* render_frame
,
2063 const GURL
& url
) override
{
2064 return url
== GURL("http://example.com/suppress");
2067 void GetNavigationErrorStrings(content::RenderView
* render_view
,
2068 blink::WebFrame
* frame
,
2069 const blink::WebURLRequest
& failed_request
,
2070 const blink::WebURLError
& error
,
2071 std::string
* error_html
,
2072 base::string16
* error_description
) override
{
2074 *error_html
= "A suffusion of yellow.";
2079 #if defined(OS_ANDROID)
2080 // Crashing on Android: http://crbug.com/311341
2081 #define MAYBE_Suppresses DISABLED_Suppresses
2083 #define MAYBE_Suppresses Suppresses
2086 TEST_F(SuppressErrorPageTest
, MAYBE_Suppresses
) {
2088 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2089 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2090 error
.unreachableURL
= GURL("http://example.com/suppress");
2091 WebLocalFrame
* web_frame
= GetMainFrame();
2093 // Start a load that will reach provisional state synchronously,
2094 // but won't complete synchronously.
2095 CommonNavigationParams common_params
;
2096 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2097 common_params
.url
= GURL("data:text/html,test data");
2098 NavigateFrame(common_params
, StartNavigationParams(),
2099 RequestNavigationParams());
2101 // An error occurred.
2102 view()->GetMainRenderFrame()->didFailProvisionalLoad(
2103 web_frame
, error
, blink::WebStandardCommit
);
2104 const int kMaxOutputCharacters
= 22;
2106 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2109 #if defined(OS_ANDROID)
2110 // Crashing on Android: http://crbug.com/311341
2111 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2113 #define MAYBE_DoesNotSuppress DoesNotSuppress
2116 TEST_F(SuppressErrorPageTest
, MAYBE_DoesNotSuppress
) {
2118 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2119 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2120 error
.unreachableURL
= GURL("http://example.com/dont-suppress");
2121 WebLocalFrame
* web_frame
= GetMainFrame();
2123 // Start a load that will reach provisional state synchronously,
2124 // but won't complete synchronously.
2125 CommonNavigationParams common_params
;
2126 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2127 common_params
.url
= GURL("data:text/html,test data");
2128 NavigateFrame(common_params
, StartNavigationParams(),
2129 RequestNavigationParams());
2131 // An error occurred.
2132 view()->GetMainRenderFrame()->didFailProvisionalLoad(
2133 web_frame
, error
, blink::WebStandardCommit
);
2134 // The error page itself is loaded asynchronously.
2135 FrameLoadWaiter(frame()).Wait();
2136 const int kMaxOutputCharacters
= 22;
2137 EXPECT_EQ("A suffusion of yellow.",
2138 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2141 // Tests if IME API's candidatewindow* events sent from browser are handled
2143 TEST_F(RenderViewImplTest
, SendCandidateWindowEvents
) {
2144 // Sends an HTML with an <input> element and scripts to the renderer.
2145 // The script handles all 3 of candidatewindow* events for an
2146 // InputMethodContext object and once it received 'show', 'update', 'hide'
2147 // should appear in the result div.
2148 LoadHTML("<input id='test'>"
2149 "<div id='result'>Result: </div>"
2151 "window.onload = function() {"
2152 " var result = document.getElementById('result');"
2153 " var test = document.getElementById('test');"
2155 " var context = test.inputMethodContext;"
2157 " context.oncandidatewindowshow = function() {"
2158 " result.innerText += 'show'; };"
2159 " context.oncandidatewindowupdate = function(){"
2160 " result.innerText += 'update'; };"
2161 " context.oncandidatewindowhide = function(){"
2162 " result.innerText += 'hide'; };"
2167 // Fire candidatewindow events.
2168 view()->OnCandidateWindowShown();
2169 view()->OnCandidateWindowUpdated();
2170 view()->OnCandidateWindowHidden();
2172 // Retrieve the content and check if it is expected.
2173 const int kMaxOutputCharacters
= 50;
2174 std::string output
= base::UTF16ToUTF8(
2175 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
2176 EXPECT_EQ(output
, "\nResult:showupdatehide");
2179 // Ensure the render view sends favicon url update events correctly.
2180 TEST_F(RenderViewImplTest
, SendFaviconURLUpdateEvent
) {
2181 // An event should be sent when a favicon url exists.
2184 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2187 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
2188 ViewHostMsg_UpdateFaviconURL::ID
));
2189 render_thread_
->sink().ClearMessages();
2191 // An event should not be sent if no favicon url exists. This is an assumption
2192 // made by some of Chrome's favicon handling.
2197 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
2198 ViewHostMsg_UpdateFaviconURL::ID
));
2201 TEST_F(RenderViewImplTest
, FocusElementCallsFocusedNodeChanged
) {
2202 LoadHTML("<input id='test1' value='hello1'></input>"
2203 "<input id='test2' value='hello2'></input>");
2205 ExecuteJavaScript("document.getElementById('test1').focus();");
2206 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
2207 ViewHostMsg_FocusedNodeChanged::ID
);
2210 ViewHostMsg_FocusedNodeChanged::Param params
;
2211 ViewHostMsg_FocusedNodeChanged::Read(msg1
, ¶ms
);
2212 EXPECT_TRUE(get
<0>(params
));
2213 render_thread_
->sink().ClearMessages();
2215 ExecuteJavaScript("document.getElementById('test2').focus();");
2216 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
2217 ViewHostMsg_FocusedNodeChanged::ID
);
2219 ViewHostMsg_FocusedNodeChanged::Read(msg2
, ¶ms
);
2220 EXPECT_TRUE(get
<0>(params
));
2221 render_thread_
->sink().ClearMessages();
2223 view()->webview()->clearFocusedElement();
2224 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
2225 ViewHostMsg_FocusedNodeChanged::ID
);
2227 ViewHostMsg_FocusedNodeChanged::Read(msg3
, ¶ms
);
2228 EXPECT_FALSE(get
<0>(params
));
2229 render_thread_
->sink().ClearMessages();
2232 TEST_F(RenderViewImplTest
, ServiceWorkerNetworkProviderSetup
) {
2233 ServiceWorkerNetworkProvider
* provider
= NULL
;
2234 RequestExtraData
* extra_data
= NULL
;
2236 // Make sure each new document has a new provider and
2237 // that the main request is tagged with the provider's id.
2238 LoadHTML("<b>A Document</b>");
2239 ASSERT_TRUE(GetMainFrame()->dataSource());
2240 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2241 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2242 ASSERT_TRUE(provider
);
2243 extra_data
= static_cast<RequestExtraData
*>(
2244 GetMainFrame()->dataSource()->request().extraData());
2245 ASSERT_TRUE(extra_data
);
2246 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2247 provider
->provider_id());
2248 int provider1_id
= provider
->provider_id();
2250 LoadHTML("<b>New Document B Goes Here</b>");
2251 ASSERT_TRUE(GetMainFrame()->dataSource());
2252 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2253 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2254 ASSERT_TRUE(provider
);
2255 EXPECT_NE(provider1_id
, provider
->provider_id());
2256 extra_data
= static_cast<RequestExtraData
*>(
2257 GetMainFrame()->dataSource()->request().extraData());
2258 ASSERT_TRUE(extra_data
);
2259 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2260 provider
->provider_id());
2262 // See that subresource requests are also tagged with the provider's id.
2263 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2264 blink::WebURLRequest
request(GURL("http://foo.com"));
2265 request
.setRequestContext(blink::WebURLRequest::RequestContextSubresource
);
2266 blink::WebURLResponse redirect_response
;
2267 frame()->willSendRequest(GetMainFrame(), 0, request
, redirect_response
);
2268 extra_data
= static_cast<RequestExtraData
*>(request
.extraData());
2269 ASSERT_TRUE(extra_data
);
2270 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2271 provider
->provider_id());
2274 TEST_F(RenderViewImplTest
, OnSetAccessibilityMode
) {
2275 ASSERT_EQ(AccessibilityModeOff
, frame()->accessibility_mode());
2276 ASSERT_EQ((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2278 SetAccessibilityMode(AccessibilityModeTreeOnly
);
2279 ASSERT_EQ(AccessibilityModeTreeOnly
, frame()->accessibility_mode());
2280 ASSERT_NE((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2282 SetAccessibilityMode(AccessibilityModeOff
);
2283 ASSERT_EQ(AccessibilityModeOff
, frame()->accessibility_mode());
2284 ASSERT_EQ((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2286 SetAccessibilityMode(AccessibilityModeComplete
);
2287 ASSERT_EQ(AccessibilityModeComplete
, frame()->accessibility_mode());
2288 ASSERT_NE((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2291 TEST_F(RenderViewImplTest
, ScreenMetricsEmulation
) {
2292 LoadHTML("<body style='min-height:1000px;'></body>");
2294 blink::WebDeviceEmulationParams params
;
2295 base::string16 get_width
= base::ASCIIToUTF16("Number(window.innerWidth)");
2296 base::string16 get_height
= base::ASCIIToUTF16("Number(window.innerHeight)");
2299 params
.viewSize
.width
= 327;
2300 params
.viewSize
.height
= 415;
2301 view()->OnEnableDeviceEmulation(params
);
2302 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width
, &width
));
2303 EXPECT_EQ(params
.viewSize
.width
, width
);
2304 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height
, &height
));
2305 EXPECT_EQ(params
.viewSize
.height
, height
);
2307 params
.viewSize
.width
= 1005;
2308 params
.viewSize
.height
= 1102;
2309 view()->OnEnableDeviceEmulation(params
);
2310 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width
, &width
));
2311 EXPECT_EQ(params
.viewSize
.width
, width
);
2312 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height
, &height
));
2313 EXPECT_EQ(params
.viewSize
.height
, height
);
2315 view()->OnDisableDeviceEmulation();
2317 view()->OnEnableDeviceEmulation(params
);
2318 // Don't disable here to test that emulation is being shutdown properly.
2321 // Sanity checks for the Navigation Timing API |navigationStart| override. We
2322 // are asserting only most basic constraints, as TimeTicks (passed as the
2323 // override) are not comparable with the wall time (returned by the Blink API).
2324 TEST_F(RenderViewImplTest
, NavigationStartOverride
) {
2325 // Verify that a navigation that claims to have started at the earliest
2326 // possible TimeTicks is indeed reported as one that started before
2327 // OnNavigate() is called.
2328 base::Time before_navigation
= base::Time::Now();
2329 CommonNavigationParams early_common_params
;
2330 StartNavigationParams early_start_params
;
2331 RequestNavigationParams early_request_params
;
2332 early_common_params
.url
= GURL("data:text/html,<div>Page</div>");
2333 early_common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2334 early_common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
2335 early_start_params
.is_post
= true;
2336 early_request_params
.browser_navigation_start
=
2337 base::TimeTicks::FromInternalValue(1);
2339 NavigateFrame(early_common_params
, early_start_params
, early_request_params
);
2340 ProcessPendingMessages();
2342 base::Time early_nav_reported_start
=
2343 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2344 EXPECT_LT(early_nav_reported_start
, before_navigation
);
2346 // Verify that a navigation that claims to have started in the future - 42
2347 // days from now is *not* reported as one that starts in the future; as we
2348 // sanitize the override allowing a maximum of ::Now().
2349 CommonNavigationParams late_common_params
;
2350 RequestNavigationParams late_request_params
;
2351 StartNavigationParams late_start_params
;
2352 late_common_params
.url
= GURL("data:text/html,<div>Another page</div>");
2353 late_common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2354 late_common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
2355 late_start_params
.is_post
= true;
2356 late_request_params
.browser_navigation_start
=
2357 base::TimeTicks::Now() + base::TimeDelta::FromDays(42);
2359 NavigateFrame(late_common_params
, late_start_params
, late_request_params
);
2360 ProcessPendingMessages();
2361 base::Time after_navigation
=
2362 base::Time::Now() + base::TimeDelta::FromDays(1);
2364 base::Time late_nav_reported_start
=
2365 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2366 EXPECT_LE(late_nav_reported_start
, after_navigation
);
2369 TEST_F(RenderViewImplTest
, PreferredSizeZoomed
) {
2370 LoadHTML("<body style='margin:0;'><div style='display:inline-block; "
2371 "width:400px; height:400px;'/></body>");
2372 view()->webview()->mainFrame()->setCanHaveScrollbars(false);
2373 EnablePreferredSizeMode();
2375 gfx::Size size
= GetPreferredSize();
2376 EXPECT_EQ(gfx::Size(400, 400), size
);
2378 SetZoomLevel(ZoomFactorToZoomLevel(2.0));
2379 size
= GetPreferredSize();
2380 EXPECT_EQ(gfx::Size(800, 800), size
);
2383 // Ensure the RenderViewImpl history list is properly updated when starting a
2384 // new browser-initiated navigation.
2385 TEST_F(RenderViewImplTest
, HistoryIsProperlyUpdatedOnNavigation
) {
2386 EXPECT_EQ(0, view()->historyBackListCount());
2387 EXPECT_EQ(0, view()->historyBackListCount() +
2388 view()->historyForwardListCount() + 1);
2390 // Receive a Navigate message with history parameters.
2391 RequestNavigationParams request_params
;
2392 request_params
.current_history_list_length
= 2;
2393 request_params
.current_history_list_offset
= 1;
2394 request_params
.pending_history_list_offset
= 2;
2395 request_params
.page_id
= -1;
2396 NavigateFrame(CommonNavigationParams(), StartNavigationParams(),
2399 // The history list in RenderView should have been updated.
2400 EXPECT_EQ(1, view()->historyBackListCount());
2401 EXPECT_EQ(2, view()->historyBackListCount() +
2402 view()->historyForwardListCount() + 1);
2405 TEST_F(DevToolsAgentTest
, DevToolsResumeOnClose
) {
2407 EXPECT_FALSE(IsPaused());
2408 DispatchDevToolsMessage("{\"id\":1,\"method\":\"Debugger.enable\"}");
2410 // Executing javascript will pause the thread and create nested message loop.
2411 // Posting task simulates message coming from browser.
2412 base::MessageLoop::current()->PostTask(FROM_HERE
, base::Bind(
2413 &DevToolsAgentTest::CloseWhilePaused
, base::Unretained(this)));
2414 ExecuteJavaScript("debugger;");
2416 // CloseWhilePaused should resume execution and continue here.
2417 EXPECT_FALSE(IsPaused());
2421 } // namespace content