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/history_controller.h"
35 #include "content/renderer/history_serialization.h"
36 #include "content/renderer/navigation_state_impl.h"
37 #include "content/renderer/render_process.h"
38 #include "content/renderer/render_view_impl.h"
39 #include "content/shell/browser/shell.h"
40 #include "content/shell/browser/shell_browser_context.h"
41 #include "content/test/mock_keyboard.h"
42 #include "net/base/net_errors.h"
43 #include "net/cert/cert_status_flags.h"
44 #include "testing/gtest/include/gtest/gtest.h"
45 #include "third_party/WebKit/public/platform/WebData.h"
46 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
47 #include "third_party/WebKit/public/platform/WebString.h"
48 #include "third_party/WebKit/public/platform/WebURLResponse.h"
49 #include "third_party/WebKit/public/web/WebDataSource.h"
50 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
51 #include "third_party/WebKit/public/web/WebHistoryItem.h"
52 #include "third_party/WebKit/public/web/WebLocalFrame.h"
53 #include "third_party/WebKit/public/web/WebPerformance.h"
54 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
55 #include "third_party/WebKit/public/web/WebView.h"
56 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
57 #include "ui/events/event.h"
58 #include "ui/events/keycodes/keyboard_codes.h"
59 #include "ui/gfx/codec/jpeg_codec.h"
60 #include "ui/gfx/range/range.h"
62 #if defined(USE_AURA) && defined(USE_X11)
64 #include "ui/events/event_constants.h"
65 #include "ui/events/keycodes/keyboard_code_conversion.h"
66 #include "ui/events/test/events_test_utils.h"
67 #include "ui/events/test/events_test_utils_x11.h"
70 #if defined(USE_OZONE)
71 #include "ui/events/keycodes/keyboard_code_conversion.h"
74 using blink::WebFrame
;
75 using blink::WebInputEvent
;
76 using blink::WebLocalFrame
;
77 using blink::WebMouseEvent
;
78 using blink::WebRuntimeFeatures
;
79 using blink::WebString
;
80 using blink::WebTextDirection
;
81 using blink::WebURLError
;
87 static const int kProxyRoutingId
= 13;
89 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
90 // Converts MockKeyboard::Modifiers to ui::EventFlags.
91 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers
) {
92 static struct ModifierMap
{
93 MockKeyboard::Modifiers src
;
96 { MockKeyboard::LEFT_SHIFT
, ui::EF_SHIFT_DOWN
},
97 { MockKeyboard::RIGHT_SHIFT
, ui::EF_SHIFT_DOWN
},
98 { MockKeyboard::LEFT_CONTROL
, ui::EF_CONTROL_DOWN
},
99 { MockKeyboard::RIGHT_CONTROL
, ui::EF_CONTROL_DOWN
},
100 { MockKeyboard::LEFT_ALT
, ui::EF_ALT_DOWN
},
101 { MockKeyboard::RIGHT_ALT
, ui::EF_ALT_DOWN
},
104 for (size_t i
= 0; i
< arraysize(kModifierMap
); ++i
) {
105 if (kModifierMap
[i
].src
& modifiers
) {
106 flags
|= kModifierMap
[i
].dst
;
113 class WebUITestWebUIControllerFactory
: public WebUIControllerFactory
{
115 WebUIController
* CreateWebUIControllerForURL(WebUI
* web_ui
,
116 const GURL
& url
) const override
{
119 WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
120 const GURL
& url
) const override
{
121 return WebUI::kNoWebUI
;
123 bool UseWebUIForURL(BrowserContext
* browser_context
,
124 const GURL
& url
) const override
{
125 return HasWebUIScheme(url
);
127 bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
128 const GURL
& url
) const override
{
129 return HasWebUIScheme(url
);
135 class RenderViewImplTest
: public RenderViewTest
{
137 RenderViewImplTest() {
138 // Attach a pseudo keyboard device to this object.
139 mock_keyboard_
.reset(new MockKeyboard());
142 ~RenderViewImplTest() override
{}
144 void SetUp() override
{
145 RenderViewTest::SetUp();
146 // Enable Blink's experimental and test only features so that test code
147 // does not have to bother enabling each feature.
148 WebRuntimeFeatures::enableExperimentalFeatures(true);
149 WebRuntimeFeatures::enableTestOnlyFeatures(true);
152 RenderViewImpl
* view() {
153 return static_cast<RenderViewImpl
*>(view_
);
157 return view()->page_id_
;
160 RenderFrameImpl
* frame() {
161 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
164 // Sends IPC messages that emulates a key-press event.
165 int SendKeyEvent(MockKeyboard::Layout layout
,
167 MockKeyboard::Modifiers modifiers
,
168 base::string16
* output
) {
170 // Retrieve the Unicode character for the given tuple (keyboard-layout,
171 // key-code, and modifiers).
172 // Exit when a keyboard-layout driver cannot assign a Unicode character to
173 // the tuple to prevent sending an invalid key code to the RenderView
175 CHECK(mock_keyboard_
.get());
177 int length
= mock_keyboard_
->GetCharacters(layout
, key_code
, modifiers
,
182 // Create IPC messages from Windows messages and send them to our
184 // A keyboard event of Windows consists of three Windows messages:
185 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
186 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
187 // WM_CHAR sends a composed Unicode character.
188 MSG msg1
= { NULL
, WM_KEYDOWN
, key_code
, 0 };
189 ui::KeyEvent
evt1(msg1
);
190 NativeWebKeyboardEvent
keydown_event(evt1
);
191 SendNativeKeyEvent(keydown_event
);
193 MSG msg2
= { NULL
, WM_CHAR
, (*output
)[0], 0 };
194 ui::KeyEvent
evt2(msg2
);
195 NativeWebKeyboardEvent
char_event(evt2
);
196 SendNativeKeyEvent(char_event
);
198 MSG msg3
= { NULL
, WM_KEYUP
, key_code
, 0 };
199 ui::KeyEvent
evt3(msg3
);
200 NativeWebKeyboardEvent
keyup_event(evt3
);
201 SendNativeKeyEvent(keyup_event
);
204 #elif defined(USE_AURA) && defined(USE_X11)
205 // We ignore |layout|, which means we are only testing the layout of the
206 // current locale. TODO(mazda): fix this to respect |layout|.
208 const int flags
= ConvertMockKeyboardModifier(modifiers
);
210 ui::ScopedXI2Event xevent
;
211 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
212 static_cast<ui::KeyboardCode
>(key_code
),
214 ui::KeyEvent
event1(xevent
);
215 NativeWebKeyboardEvent
keydown_event(event1
);
216 SendNativeKeyEvent(keydown_event
);
218 // X11 doesn't actually have native character events, but give the test
220 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
221 static_cast<ui::KeyboardCode
>(key_code
),
223 ui::KeyEvent
event2(xevent
);
224 event2
.set_character(GetCharacterFromKeyCode(event2
.key_code(),
226 ui::KeyEventTestApi
test_event2(&event2
);
227 test_event2
.set_is_char(true);
228 NativeWebKeyboardEvent
char_event(event2
);
229 SendNativeKeyEvent(char_event
);
231 xevent
.InitKeyEvent(ui::ET_KEY_RELEASED
,
232 static_cast<ui::KeyboardCode
>(key_code
),
234 ui::KeyEvent
event3(xevent
);
235 NativeWebKeyboardEvent
keyup_event(event3
);
236 SendNativeKeyEvent(keyup_event
);
238 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
240 output
->assign(1, static_cast<base::char16
>(c
));
242 #elif defined(USE_OZONE)
243 const int flags
= ConvertMockKeyboardModifier(modifiers
);
245 ui::KeyEvent
keydown_event(ui::ET_KEY_PRESSED
,
246 static_cast<ui::KeyboardCode
>(key_code
),
248 NativeWebKeyboardEvent
keydown_web_event(keydown_event
);
249 SendNativeKeyEvent(keydown_web_event
);
251 ui::KeyEvent
char_event(keydown_event
.GetCharacter(),
252 static_cast<ui::KeyboardCode
>(key_code
),
254 NativeWebKeyboardEvent
char_web_event(char_event
);
255 SendNativeKeyEvent(char_web_event
);
257 ui::KeyEvent
keyup_event(ui::ET_KEY_RELEASED
,
258 static_cast<ui::KeyboardCode
>(key_code
),
260 NativeWebKeyboardEvent
keyup_web_event(keyup_event
);
261 SendNativeKeyEvent(keyup_web_event
);
263 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
265 output
->assign(1, static_cast<base::char16
>(c
));
273 void EnablePreferredSizeMode() {
274 view()->OnEnablePreferredSizeChangedMode();
277 const gfx::Size
& GetPreferredSize() {
278 view()->CheckPreferredSize();
279 return view()->preferred_size_
;
282 void SetZoomLevel(double level
) {
283 view()->OnSetZoomLevelForView(false, level
);
287 scoped_ptr
<MockKeyboard
> mock_keyboard_
;
290 // Test for https://crbug.com/461191.
291 TEST_F(RenderViewImplTest
, RenderFrameMessageAfterDetach
) {
292 // Create a new main frame RenderFrame so that we don't interfere with the
293 // shutdown of frame() in RenderViewTest.TearDown.
294 blink::WebURLRequest
popup_request(GURL("http://foo.com"));
295 blink::WebView
* new_web_view
= view()->createView(
296 GetMainFrame(), popup_request
, blink::WebWindowFeatures(), "foo",
297 blink::WebNavigationPolicyNewForegroundTab
, false);
298 RenderViewImpl
* new_view
= RenderViewImpl::FromWebView(new_web_view
);
299 RenderFrameImpl
* new_frame
=
300 static_cast<RenderFrameImpl
*>(new_view
->GetMainRenderFrame());
302 // Detach the main frame.
305 // Before the frame is asynchronously deleted, it may receive a message.
306 // We should not crash here, and the message should not be processed.
307 scoped_ptr
<const IPC::Message
> msg(
308 new FrameMsg_Stop(frame()->GetRoutingID()));
309 EXPECT_FALSE(new_frame
->OnMessageReceived(*msg
));
311 // Clean up after the new view so we don't leak it.
315 TEST_F(RenderViewImplTest
, SaveImageFromDataURL
) {
316 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
317 ViewHostMsg_SaveImageFromDataURL::ID
);
319 render_thread_
->sink().ClearMessages();
321 const std::string image_data_url
=
322 "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
324 view()->saveImageFromDataURL(WebString::fromUTF8(image_data_url
));
325 ProcessPendingMessages();
326 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
327 ViewHostMsg_SaveImageFromDataURL::ID
);
330 ViewHostMsg_SaveImageFromDataURL::Param param1
;
331 ViewHostMsg_SaveImageFromDataURL::Read(msg2
, ¶m1
);
332 EXPECT_EQ(get
<1>(param1
).length(), image_data_url
.length());
333 EXPECT_EQ(get
<1>(param1
), image_data_url
);
335 ProcessPendingMessages();
336 render_thread_
->sink().ClearMessages();
338 const std::string
large_data_url(1024 * 1024 * 10 - 1, 'd');
340 view()->saveImageFromDataURL(WebString::fromUTF8(large_data_url
));
341 ProcessPendingMessages();
342 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
343 ViewHostMsg_SaveImageFromDataURL::ID
);
346 ViewHostMsg_SaveImageFromDataURL::Param param2
;
347 ViewHostMsg_SaveImageFromDataURL::Read(msg3
, ¶m2
);
348 EXPECT_EQ(get
<1>(param2
).length(), large_data_url
.length());
349 EXPECT_EQ(get
<1>(param2
), large_data_url
);
351 ProcessPendingMessages();
352 render_thread_
->sink().ClearMessages();
354 const std::string
exceeded_data_url(1024 * 1024 * 10 + 1, 'd');
356 view()->saveImageFromDataURL(WebString::fromUTF8(exceeded_data_url
));
357 ProcessPendingMessages();
358 const IPC::Message
* msg4
= render_thread_
->sink().GetFirstMessageMatching(
359 ViewHostMsg_SaveImageFromDataURL::ID
);
363 // Test that we get form state change notifications when input fields change.
364 TEST_F(RenderViewImplTest
, DISABLED_OnNavStateChanged
) {
365 // Don't want any delay for form state sync changes. This will still post a
366 // message so updates will get coalesced, but as soon as we spin the message
367 // loop, it will generate an update.
368 view()->set_send_content_state_immediately(true);
370 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
372 // We should NOT have gotten a form state change notification yet.
373 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
374 ViewHostMsg_UpdateState::ID
));
375 render_thread_
->sink().ClearMessages();
377 // Change the value of the input. We should have gotten an update state
378 // notification. We need to spin the message loop to catch this update.
379 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';");
380 ProcessPendingMessages();
381 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
382 ViewHostMsg_UpdateState::ID
));
385 TEST_F(RenderViewImplTest
, OnNavigationHttpPost
) {
386 // An http url will trigger a resource load so cannot be used here.
387 CommonNavigationParams common_params
;
388 StartNavigationParams start_params
;
389 RequestNavigationParams request_params
;
390 common_params
.url
= GURL("data:text/html,<div>Page</div>");
391 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
392 common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
393 request_params
.page_id
= -1;
396 const unsigned char* raw_data
= reinterpret_cast<const unsigned char*>(
398 const unsigned int length
= 11;
399 const std::vector
<unsigned char> post_data(raw_data
, raw_data
+ length
);
400 start_params
.is_post
= true;
401 start_params
.browser_initiated_post_data
= post_data
;
403 frame()->OnNavigate(common_params
, start_params
, request_params
);
404 ProcessPendingMessages();
406 const IPC::Message
* frame_navigate_msg
=
407 render_thread_
->sink().GetUniqueMessageMatching(
408 FrameHostMsg_DidCommitProvisionalLoad::ID
);
409 EXPECT_TRUE(frame_navigate_msg
);
411 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params
;
412 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
414 EXPECT_TRUE(get
<0>(host_nav_params
).is_post
);
416 // Check post data sent to browser matches
417 EXPECT_TRUE(get
<0>(host_nav_params
).page_state
.IsValid());
418 scoped_ptr
<HistoryEntry
> entry
=
419 PageStateToHistoryEntry(get
<0>(host_nav_params
).page_state
);
420 blink::WebHTTPBody body
= entry
->root().httpBody();
421 blink::WebHTTPBody::Element element
;
422 bool successful
= body
.elementAt(0, element
);
423 EXPECT_TRUE(successful
);
424 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData
, element
.type
);
425 EXPECT_EQ(length
, element
.data
.size());
426 EXPECT_EQ(0, memcmp(raw_data
, element
.data
.data(), length
));
429 TEST_F(RenderViewImplTest
, DecideNavigationPolicy
) {
430 WebUITestWebUIControllerFactory factory
;
431 WebUIControllerFactory::RegisterFactory(&factory
);
434 state
.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
436 // Navigations to normal HTTP URLs can be handled locally.
437 blink::WebURLRequest
request(GURL("http://foo.com"));
438 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
439 policy_info
.frame
= GetMainFrame();
440 policy_info
.extraData
= &state
;
441 policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
442 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
443 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
445 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab
, policy
);
447 // Verify that form posts to WebUI URLs will be sent to the browser process.
448 blink::WebURLRequest
form_request(GURL("chrome://foo"));
449 blink::WebFrameClient::NavigationPolicyInfo
form_policy_info(form_request
);
450 form_policy_info
.frame
= GetMainFrame();
451 form_policy_info
.extraData
= &state
;
452 form_policy_info
.navigationType
= blink::WebNavigationTypeFormSubmitted
;
453 form_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
454 form_request
.setHTTPMethod("POST");
455 policy
= frame()->decidePolicyForNavigation(form_policy_info
);
456 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
458 // Verify that popup links to WebUI URLs also are sent to browser.
459 blink::WebURLRequest
popup_request(GURL("chrome://foo"));
460 blink::WebFrameClient::NavigationPolicyInfo
popup_policy_info(popup_request
);
461 popup_policy_info
.frame
= GetMainFrame();
462 popup_policy_info
.extraData
= &state
;
463 popup_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
464 popup_policy_info
.defaultPolicy
= blink::WebNavigationPolicyNewForegroundTab
;
465 policy
= frame()->decidePolicyForNavigation(popup_policy_info
);
466 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
469 TEST_F(RenderViewImplTest
, DecideNavigationPolicyHandlesAllTopLevel
) {
471 state
.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
473 RendererPreferences prefs
= view()->renderer_preferences();
474 prefs
.browser_handles_all_top_level_requests
= true;
475 view()->OnSetRendererPrefs(prefs
);
477 const blink::WebNavigationType kNavTypes
[] = {
478 blink::WebNavigationTypeLinkClicked
,
479 blink::WebNavigationTypeFormSubmitted
,
480 blink::WebNavigationTypeBackForward
,
481 blink::WebNavigationTypeReload
,
482 blink::WebNavigationTypeFormResubmitted
,
483 blink::WebNavigationTypeOther
,
486 blink::WebURLRequest
request(GURL("http://foo.com"));
487 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
488 policy_info
.frame
= GetMainFrame();
489 policy_info
.extraData
= &state
;
490 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
492 for (size_t i
= 0; i
< arraysize(kNavTypes
); ++i
) {
493 policy_info
.navigationType
= kNavTypes
[i
];
495 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
497 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
501 TEST_F(RenderViewImplTest
, DecideNavigationPolicyForWebUI
) {
502 // Enable bindings to simulate a WebUI view.
503 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI
);
506 state
.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
508 // Navigations to normal HTTP URLs will be sent to browser process.
509 blink::WebURLRequest
request(GURL("http://foo.com"));
510 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
511 policy_info
.frame
= GetMainFrame();
512 policy_info
.extraData
= &state
;
513 policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
514 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
516 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
518 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
520 // Navigations to WebUI URLs will also be sent to browser process.
521 blink::WebURLRequest
webui_request(GURL("chrome://foo"));
522 blink::WebFrameClient::NavigationPolicyInfo
webui_policy_info(webui_request
);
523 webui_policy_info
.frame
= GetMainFrame();
524 webui_policy_info
.extraData
= &state
;
525 webui_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
526 webui_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
527 policy
= frame()->decidePolicyForNavigation(webui_policy_info
);
528 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
530 // Verify that form posts to data URLs will be sent to the browser process.
531 blink::WebURLRequest
data_request(GURL("data:text/html,foo"));
532 blink::WebFrameClient::NavigationPolicyInfo
data_policy_info(data_request
);
533 data_policy_info
.frame
= GetMainFrame();
534 data_policy_info
.extraData
= &state
;
535 data_policy_info
.navigationType
= blink::WebNavigationTypeFormSubmitted
;
536 data_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
537 data_request
.setHTTPMethod("POST");
538 policy
= frame()->decidePolicyForNavigation(data_policy_info
);
539 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
541 // Verify that a popup that creates a view first and then navigates to a
542 // normal HTTP URL will be sent to the browser process, even though the
543 // new view does not have any enabled_bindings_.
544 blink::WebURLRequest
popup_request(GURL("http://foo.com"));
545 blink::WebView
* new_web_view
= view()->createView(
546 GetMainFrame(), popup_request
, blink::WebWindowFeatures(), "foo",
547 blink::WebNavigationPolicyNewForegroundTab
, false);
548 RenderViewImpl
* new_view
= RenderViewImpl::FromWebView(new_web_view
);
549 blink::WebFrameClient::NavigationPolicyInfo
popup_policy_info(popup_request
);
550 popup_policy_info
.frame
= new_web_view
->mainFrame()->toWebLocalFrame();
551 popup_policy_info
.extraData
= &state
;
552 popup_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
553 popup_policy_info
.defaultPolicy
= blink::WebNavigationPolicyNewForegroundTab
;
554 policy
= static_cast<RenderFrameImpl
*>(new_view
->GetMainRenderFrame())->
555 decidePolicyForNavigation(popup_policy_info
);
556 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
558 // Clean up after the new view so we don't leak it.
563 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
564 // already swapped out. http://crbug.com/93427.
565 TEST_F(RenderViewImplTest
, SendSwapOutACK
) {
566 LoadHTML("<div>Page A</div>");
567 int initial_page_id
= view_page_id();
569 // Increment the ref count so that we don't exit when swapping out.
570 RenderProcess::current()->AddRefProcess();
572 // Respond to a swap out request.
573 view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId
, true,
574 content::FrameReplicationState());
576 // Ensure the swap out commits synchronously.
577 EXPECT_NE(initial_page_id
, view_page_id());
579 // Check for a valid OnSwapOutACK.
580 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
581 FrameHostMsg_SwapOut_ACK::ID
);
584 // It is possible to get another swap out request. Ensure that we send
585 // an ACK, even if we don't have to do anything else.
586 render_thread_
->sink().ClearMessages();
587 view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId
, false,
588 content::FrameReplicationState());
589 const IPC::Message
* msg2
= render_thread_
->sink().GetUniqueMessageMatching(
590 FrameHostMsg_SwapOut_ACK::ID
);
593 // If we navigate back to this RenderView, ensure we don't send a state
594 // update for the swapped out URL. (http://crbug.com/72235)
595 CommonNavigationParams common_params
;
596 RequestNavigationParams request_params
;
597 common_params
.url
= GURL("data:text/html,<div>Page B</div>");
598 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
599 common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
600 request_params
.current_history_list_length
= 1;
601 request_params
.current_history_list_offset
= 0;
602 request_params
.pending_history_list_offset
= 1;
603 request_params
.page_id
= -1;
604 frame()->OnNavigate(common_params
, StartNavigationParams(), request_params
);
605 ProcessPendingMessages();
606 const IPC::Message
* msg3
= render_thread_
->sink().GetUniqueMessageMatching(
607 ViewHostMsg_UpdateState::ID
);
611 // Ensure the RenderViewImpl reloads the previous page if a reload request
612 // arrives while it is showing swappedout://. http://crbug.com/143155.
613 TEST_F(RenderViewImplTest
, ReloadWhileSwappedOut
) {
615 LoadHTML("<div>Page A</div>");
617 // Load page B, which will trigger an UpdateState message for page A.
618 LoadHTML("<div>Page B</div>");
620 // Check for a valid UpdateState message for page A.
621 ProcessPendingMessages();
622 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
623 ViewHostMsg_UpdateState::ID
);
625 ViewHostMsg_UpdateState::Param params
;
626 ViewHostMsg_UpdateState::Read(msg_A
, ¶ms
);
627 int page_id_A
= get
<0>(params
);
628 PageState state_A
= get
<1>(params
);
629 EXPECT_EQ(1, page_id_A
);
630 render_thread_
->sink().ClearMessages();
632 // Back to page A (page_id 1) and commit.
633 CommonNavigationParams common_params_A
;
634 RequestNavigationParams request_params_A
;
635 common_params_A
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
636 common_params_A
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
637 request_params_A
.current_history_list_length
= 2;
638 request_params_A
.current_history_list_offset
= 1;
639 request_params_A
.pending_history_list_offset
= 0;
640 request_params_A
.page_id
= 1;
641 request_params_A
.page_state
= state_A
;
642 frame()->OnNavigate(common_params_A
, StartNavigationParams(),
644 EXPECT_EQ(1, view()->historyBackListCount());
645 EXPECT_EQ(2, view()->historyBackListCount() +
646 view()->historyForwardListCount() + 1);
647 ProcessPendingMessages();
649 // Respond to a swap out request.
650 view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId
, true,
651 content::FrameReplicationState());
653 // Check for a OnSwapOutACK.
654 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
655 FrameHostMsg_SwapOut_ACK::ID
);
657 render_thread_
->sink().ClearMessages();
659 // It is possible to get a reload request at this point, containing the
660 // params.page_state of the initial page (e.g., if the new page fails the
661 // provisional load in the renderer process, after we unload the old page).
662 // Ensure the old page gets reloaded, not swappedout://.
663 CommonNavigationParams common_params
;
664 RequestNavigationParams request_params
;
665 common_params
.url
= GURL("data:text/html,<div>Page A</div>");
666 common_params
.navigation_type
= FrameMsg_Navigate_Type::RELOAD
;
667 common_params
.transition
= ui::PAGE_TRANSITION_RELOAD
;
668 request_params
.current_history_list_length
= 2;
669 request_params
.current_history_list_offset
= 0;
670 request_params
.pending_history_list_offset
= 0;
671 request_params
.page_id
= 1;
672 request_params
.page_state
= state_A
;
673 frame()->OnNavigate(common_params
, StartNavigationParams(), request_params
);
674 ProcessPendingMessages();
676 // Verify page A committed, not swappedout://.
677 const IPC::Message
* frame_navigate_msg
=
678 render_thread_
->sink().GetUniqueMessageMatching(
679 FrameHostMsg_DidCommitProvisionalLoad::ID
);
680 EXPECT_TRUE(frame_navigate_msg
);
682 // Read URL out of the parent trait of the params object.
683 FrameHostMsg_DidCommitProvisionalLoad::Param commit_load_params
;
684 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
685 &commit_load_params
);
686 EXPECT_NE(GURL("swappedout://"), get
<0>(commit_load_params
).url
);
689 // Verify that security origins are replicated properly to RenderFrameProxies
690 // when swapping out.
691 TEST_F(RenderViewImplTest
, OriginReplicationForSwapOut
) {
692 // This test should only run with --site-per-process, since origin
693 // replication only happens in that mode.
694 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
695 switches::kSitePerProcess
))
699 "Hello <iframe src='data:text/html,frame 1'></iframe>"
700 "<iframe src='data:text/html,frame 2'></iframe>");
701 WebFrame
* web_frame
= frame()->GetWebFrame();
702 RenderFrameImpl
* child_frame
= static_cast<RenderFrameImpl
*>(
703 RenderFrame::FromWebFrame(web_frame
->firstChild()));
705 // Swap the child frame out and pass a serialized origin to be set for
707 content::FrameReplicationState replication_state
;
708 replication_state
.origin
= url::Origin("http://foo.com");
709 child_frame
->OnSwapOut(kProxyRoutingId
, true, replication_state
);
711 // The child frame should now be a WebRemoteFrame.
712 EXPECT_TRUE(web_frame
->firstChild()->isWebRemoteFrame());
714 // Expect the origin to be updated properly.
715 blink::WebSecurityOrigin origin
= web_frame
->firstChild()->securityOrigin();
716 EXPECT_EQ(origin
.toString(),
717 WebString::fromUTF8(replication_state
.origin
.string()));
719 // Now, swap out the second frame using a unique origin and verify that it is
720 // replicated correctly.
721 replication_state
.origin
= url::Origin();
722 RenderFrameImpl
* child_frame2
= static_cast<RenderFrameImpl
*>(
723 RenderFrame::FromWebFrame(web_frame
->lastChild()));
724 child_frame2
->OnSwapOut(kProxyRoutingId
+ 1, true, replication_state
);
725 EXPECT_TRUE(web_frame
->lastChild()->isWebRemoteFrame());
726 EXPECT_TRUE(web_frame
->lastChild()->securityOrigin().isUnique());
729 // Test that we get the correct UpdateState message when we go back twice
730 // quickly without committing. Regression test for http://crbug.com/58082.
731 // Disabled: http://crbug.com/157357 .
732 TEST_F(RenderViewImplTest
, DISABLED_LastCommittedUpdateState
) {
734 LoadHTML("<div>Page A</div>");
736 // Load page B, which will trigger an UpdateState message for page A.
737 LoadHTML("<div>Page B</div>");
739 // Check for a valid UpdateState message for page A.
740 ProcessPendingMessages();
741 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
742 ViewHostMsg_UpdateState::ID
);
744 ViewHostMsg_UpdateState::Param param
;
745 ViewHostMsg_UpdateState::Read(msg_A
, ¶m
);
746 int page_id_A
= get
<0>(param
);
747 PageState state_A
= get
<1>(param
);
748 EXPECT_EQ(1, page_id_A
);
749 render_thread_
->sink().ClearMessages();
751 // Load page C, which will trigger an UpdateState message for page B.
752 LoadHTML("<div>Page C</div>");
754 // Check for a valid UpdateState for page B.
755 ProcessPendingMessages();
756 const IPC::Message
* msg_B
= render_thread_
->sink().GetUniqueMessageMatching(
757 ViewHostMsg_UpdateState::ID
);
759 ViewHostMsg_UpdateState::Read(msg_B
, ¶m
);
760 int page_id_B
= get
<0>(param
);
761 PageState state_B
= get
<1>(param
);
762 EXPECT_EQ(2, page_id_B
);
763 EXPECT_NE(state_A
, state_B
);
764 render_thread_
->sink().ClearMessages();
766 // Load page D, which will trigger an UpdateState message for page C.
767 LoadHTML("<div>Page D</div>");
769 // Check for a valid UpdateState for page C.
770 ProcessPendingMessages();
771 const IPC::Message
* msg_C
= render_thread_
->sink().GetUniqueMessageMatching(
772 ViewHostMsg_UpdateState::ID
);
774 ViewHostMsg_UpdateState::Read(msg_C
, ¶m
);
775 int page_id_C
= get
<0>(param
);
776 PageState state_C
= get
<1>(param
);
777 EXPECT_EQ(3, page_id_C
);
778 EXPECT_NE(state_B
, state_C
);
779 render_thread_
->sink().ClearMessages();
781 // Go back to C and commit, preparing for our real test.
782 CommonNavigationParams common_params_C
;
783 RequestNavigationParams request_params_C
;
784 common_params_C
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
785 common_params_C
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
786 request_params_C
.current_history_list_length
= 4;
787 request_params_C
.current_history_list_offset
= 3;
788 request_params_C
.pending_history_list_offset
= 2;
789 request_params_C
.page_id
= 3;
790 request_params_C
.page_state
= state_C
;
791 frame()->OnNavigate(common_params_C
, StartNavigationParams(),
793 ProcessPendingMessages();
794 render_thread_
->sink().ClearMessages();
796 // Go back twice quickly, such that page B does not have a chance to commit.
797 // This leads to two changes to the back/forward list but only one change to
798 // the RenderView's page ID.
800 // Back to page B (page_id 2), without committing.
801 CommonNavigationParams common_params_B
;
802 RequestNavigationParams request_params_B
;
803 common_params_B
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
804 common_params_B
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
805 request_params_B
.current_history_list_length
= 4;
806 request_params_B
.current_history_list_offset
= 2;
807 request_params_B
.pending_history_list_offset
= 1;
808 request_params_B
.page_id
= 2;
809 request_params_B
.page_state
= state_B
;
810 frame()->OnNavigate(common_params_B
, StartNavigationParams(),
813 // Back to page A (page_id 1) and commit.
814 CommonNavigationParams common_params
;
815 RequestNavigationParams request_params
;
816 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
817 common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
818 request_params
.current_history_list_length
= 4;
819 request_params
.current_history_list_offset
= 2;
820 request_params
.pending_history_list_offset
= 0;
821 request_params
.page_id
= 1;
822 request_params
.page_state
= state_A
;
823 frame()->OnNavigate(common_params
, StartNavigationParams(), request_params
);
824 ProcessPendingMessages();
826 // Now ensure that the UpdateState message we receive is consistent
827 // and represents page C in both page_id and state.
828 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
829 ViewHostMsg_UpdateState::ID
);
831 ViewHostMsg_UpdateState::Read(msg
, ¶m
);
832 int page_id
= get
<0>(param
);
833 PageState state
= get
<1>(param
);
834 EXPECT_EQ(page_id_C
, page_id
);
835 EXPECT_NE(state_A
, state
);
836 EXPECT_NE(state_B
, state
);
837 EXPECT_EQ(state_C
, state
);
840 // Test that stale back/forward navigations arriving from the browser are
841 // ignored. See http://crbug.com/86758.
842 TEST_F(RenderViewImplTest
, StaleNavigationsIgnored
) {
844 LoadHTML("<div>Page A</div>");
845 EXPECT_EQ(1, view()->history_list_length_
);
846 EXPECT_EQ(0, view()->history_list_offset_
);
848 // Load page B, which will trigger an UpdateState message for page A.
849 LoadHTML("<div>Page B</div>");
850 EXPECT_EQ(2, view()->history_list_length_
);
851 EXPECT_EQ(1, view()->history_list_offset_
);
853 // Check for a valid UpdateState message for page A.
854 ProcessPendingMessages();
855 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
856 ViewHostMsg_UpdateState::ID
);
858 ViewHostMsg_UpdateState::Param param
;
859 ViewHostMsg_UpdateState::Read(msg_A
, ¶m
);
860 int page_id_A
= get
<0>(param
);
861 PageState state_A
= get
<1>(param
);
862 EXPECT_EQ(1, page_id_A
);
863 render_thread_
->sink().ClearMessages();
865 // Back to page A (page_id 1) and commit.
866 CommonNavigationParams common_params_A
;
867 RequestNavigationParams request_params_A
;
868 common_params_A
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
869 common_params_A
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
870 request_params_A
.current_history_list_length
= 2;
871 request_params_A
.current_history_list_offset
= 1;
872 request_params_A
.pending_history_list_offset
= 0;
873 request_params_A
.page_id
= 1;
874 request_params_A
.page_state
= state_A
;
875 frame()->OnNavigate(common_params_A
, StartNavigationParams(),
877 ProcessPendingMessages();
879 // A new navigation commits, clearing the forward history.
880 LoadHTML("<div>Page C</div>");
881 EXPECT_EQ(2, view()->history_list_length_
);
882 EXPECT_EQ(1, view()->history_list_offset_
);
883 EXPECT_EQ(3, view()->page_id_
); // page C is now page id 3
885 // The browser then sends a stale navigation to B, which should be ignored.
886 CommonNavigationParams common_params_B
;
887 RequestNavigationParams request_params_B
;
888 common_params_B
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
889 common_params_B
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
890 request_params_B
.current_history_list_length
= 2;
891 request_params_B
.current_history_list_offset
= 0;
892 request_params_B
.pending_history_list_offset
= 1;
893 request_params_B
.page_id
= 2;
894 request_params_B
.page_state
=
895 state_A
; // Doesn't matter, just has to be present.
896 frame()->OnNavigate(common_params_B
, StartNavigationParams(),
899 // State should be unchanged.
900 EXPECT_EQ(2, view()->history_list_length_
);
901 EXPECT_EQ(1, view()->history_list_offset_
);
902 EXPECT_EQ(3, view()->page_id_
); // page C, not page B
904 // Check for a valid DidDropNavigation message.
905 ProcessPendingMessages();
906 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
907 FrameHostMsg_DidDropNavigation::ID
);
909 render_thread_
->sink().ClearMessages();
912 // Test that our IME backend sends a notification message when the input focus
914 TEST_F(RenderViewImplTest
, OnImeTypeChanged
) {
915 // Enable our IME backend code.
916 view()->OnSetInputMethodActive(true);
918 // Load an HTML page consisting of two input fields.
919 view()->set_send_content_state_immediately(true);
924 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
925 "<input id=\"test2\" type=\"password\"></input>"
926 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
927 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
928 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
929 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
931 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
933 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
934 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
935 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
936 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
937 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
938 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
939 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
940 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
943 render_thread_
->sink().ClearMessages();
945 struct InputModeTestCase
{
946 const char* input_id
;
947 ui::TextInputMode expected_mode
;
949 static const InputModeTestCase kInputModeTestCases
[] = {
950 {"test1", ui::TEXT_INPUT_MODE_DEFAULT
},
951 {"test3", ui::TEXT_INPUT_MODE_VERBATIM
},
952 {"test4", ui::TEXT_INPUT_MODE_LATIN
},
953 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME
},
954 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE
},
955 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN
},
956 {"test8", ui::TEXT_INPUT_MODE_KANA
},
957 {"test9", ui::TEXT_INPUT_MODE_KATAKANA
},
958 {"test10", ui::TEXT_INPUT_MODE_NUMERIC
},
959 {"test11", ui::TEXT_INPUT_MODE_TEL
},
960 {"test12", ui::TEXT_INPUT_MODE_EMAIL
},
961 {"test13", ui::TEXT_INPUT_MODE_URL
},
962 {"test14", ui::TEXT_INPUT_MODE_DEFAULT
},
963 {"test15", ui::TEXT_INPUT_MODE_VERBATIM
},
966 const int kRepeatCount
= 10;
967 for (int i
= 0; i
< kRepeatCount
; i
++) {
968 // Move the input focus to the first <input> element, where we should
970 ExecuteJavaScript("document.getElementById('test1').focus();");
971 ProcessPendingMessages();
972 render_thread_
->sink().ClearMessages();
974 // Update the IME status and verify if our IME backend sends an IPC message
976 view()->UpdateTextInputType();
977 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
978 EXPECT_TRUE(msg
!= NULL
);
979 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
980 ViewHostMsg_TextInputTypeChanged::Param params
;
981 ViewHostMsg_TextInputTypeChanged::Read(msg
, ¶ms
);
982 ui::TextInputType type
= get
<0>(params
);
983 ui::TextInputMode input_mode
= get
<1>(params
);
984 bool can_compose_inline
= get
<2>(params
);
985 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT
, type
);
986 EXPECT_EQ(true, can_compose_inline
);
988 // Move the input focus to the second <input> element, where we should
990 ExecuteJavaScript("document.getElementById('test2').focus();");
991 ProcessPendingMessages();
992 render_thread_
->sink().ClearMessages();
994 // Update the IME status and verify if our IME backend sends an IPC message
995 // to de-activate IMEs.
996 view()->UpdateTextInputType();
997 msg
= render_thread_
->sink().GetMessageAt(0);
998 EXPECT_TRUE(msg
!= NULL
);
999 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
1000 ViewHostMsg_TextInputTypeChanged::Read(msg
, & params
);
1001 type
= get
<0>(params
);
1002 input_mode
= get
<1>(params
);
1003 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD
, type
);
1005 for (size_t i
= 0; i
< arraysize(kInputModeTestCases
); i
++) {
1006 const InputModeTestCase
* test_case
= &kInputModeTestCases
[i
];
1007 std::string javascript
=
1008 base::StringPrintf("document.getElementById('%s').focus();",
1009 test_case
->input_id
);
1010 // Move the input focus to the target <input> element, where we should
1012 ExecuteJavaScriptAndReturnIntValue(base::ASCIIToUTF16(javascript
), NULL
);
1013 ProcessPendingMessages();
1014 render_thread_
->sink().ClearMessages();
1016 // Update the IME status and verify if our IME backend sends an IPC
1017 // message to activate IMEs.
1018 view()->UpdateTextInputType();
1019 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
1020 EXPECT_TRUE(msg
!= NULL
);
1021 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
1022 ViewHostMsg_TextInputTypeChanged::Read(msg
, & params
);
1023 type
= get
<0>(params
);
1024 input_mode
= get
<1>(params
);
1025 EXPECT_EQ(test_case
->expected_mode
, input_mode
);
1030 // Test that our IME backend can compose CJK words.
1031 // Our IME front-end sends many platform-independent messages to the IME backend
1032 // while it composes CJK words. This test sends the minimal messages captured
1033 // on my local environment directly to the IME backend to verify if the backend
1034 // can compose CJK words without any problems.
1035 // This test uses an array of command sets because an IME composotion does not
1036 // only depends on IME events, but also depends on window events, e.g. moving
1037 // the window focus while composing a CJK text. To handle such complicated
1038 // cases, this test should not only call IME-related functions in the
1039 // RenderWidget class, but also call some RenderWidget members, e.g.
1040 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc.
1041 TEST_F(RenderViewImplTest
, ImeComposition
) {
1047 IME_CONFIRMCOMPOSITION
,
1048 IME_CANCELCOMPOSITION
1053 int selection_start
;
1055 const wchar_t* ime_string
;
1056 const wchar_t* result
;
1058 static const ImeMessage kImeMessages
[] = {
1059 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
1060 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1061 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1062 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1063 {IME_SETCOMPOSITION
, false, 1, 1, L
"n", L
"n"},
1064 {IME_SETCOMPOSITION
, false, 2, 2, L
"ni", L
"ni"},
1065 {IME_SETCOMPOSITION
, false, 3, 3, L
"nih", L
"nih"},
1066 {IME_SETCOMPOSITION
, false, 4, 4, L
"niha", L
"niha"},
1067 {IME_SETCOMPOSITION
, false, 5, 5, L
"nihao", L
"nihao"},
1068 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"\x4F60\x597D", L
"\x4F60\x597D"},
1069 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
1070 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1071 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1072 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1073 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xFF4B", L
"\xFF4B"},
1074 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x304B", L
"\x304B"},
1075 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x304B\xFF4E", L
"\x304B\xFF4E"},
1076 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\xFF4A",
1077 L
"\x304B\x3093\xFF4A"},
1078 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\x3058",
1079 L
"\x304B\x3093\x3058"},
1080 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x611F\x3058", L
"\x611F\x3058"},
1081 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x6F22\x5B57", L
"\x6F22\x5B57"},
1082 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1083 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1084 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1085 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1086 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1087 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1088 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3147", L
"\x3147"},
1089 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC544", L
"\xC544"},
1090 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC548", L
"\xC548"},
1091 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1092 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3134", L
"\xC548\x3134"},
1093 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB140", L
"\xC548\xB140"},
1094 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1095 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1096 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1097 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548\xB155"},
1100 for (size_t i
= 0; i
< arraysize(kImeMessages
); i
++) {
1101 const ImeMessage
* ime_message
= &kImeMessages
[i
];
1102 switch (ime_message
->command
) {
1103 case IME_INITIALIZE
:
1104 // Load an HTML page consisting of a content-editable <div> element,
1105 // and move the input focus to the <div> element, where we can use
1107 view()->OnSetInputMethodActive(ime_message
->enable
);
1108 view()->set_send_content_state_immediately(true);
1113 "<div id=\"test1\" contenteditable=\"true\"></div>"
1116 ExecuteJavaScript("document.getElementById('test1').focus();");
1119 case IME_SETINPUTMODE
:
1120 // Activate (or deactivate) our IME back-end.
1121 view()->OnSetInputMethodActive(ime_message
->enable
);
1125 // Update the window focus.
1126 view()->OnSetFocus(ime_message
->enable
);
1129 case IME_SETCOMPOSITION
:
1130 view()->OnImeSetComposition(
1131 base::WideToUTF16(ime_message
->ime_string
),
1132 std::vector
<blink::WebCompositionUnderline
>(),
1133 ime_message
->selection_start
,
1134 ime_message
->selection_end
);
1137 case IME_CONFIRMCOMPOSITION
:
1138 view()->OnImeConfirmComposition(
1139 base::WideToUTF16(ime_message
->ime_string
),
1140 gfx::Range::InvalidRange(),
1144 case IME_CANCELCOMPOSITION
:
1145 view()->OnImeSetComposition(
1147 std::vector
<blink::WebCompositionUnderline
>(),
1152 // Update the status of our IME back-end.
1153 // TODO(hbono): we should verify messages to be sent from the back-end.
1154 view()->UpdateTextInputType();
1155 ProcessPendingMessages();
1156 render_thread_
->sink().ClearMessages();
1158 if (ime_message
->result
) {
1159 // Retrieve the content of this page and compare it with the expected
1161 const int kMaxOutputCharacters
= 128;
1162 base::string16 output
=
1163 GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1164 EXPECT_EQ(base::WideToUTF16(ime_message
->result
), output
);
1169 // Test that the RenderView::OnSetTextDirection() function can change the text
1170 // direction of the selected input element.
1171 TEST_F(RenderViewImplTest
, OnSetTextDirection
) {
1172 // Load an HTML page consisting of a <textarea> element and a <div> element.
1173 // This test changes the text direction of the <textarea> element, and
1174 // writes the values of its 'dir' attribute and its 'direction' property to
1175 // verify that the text direction is changed.
1176 view()->set_send_content_state_immediately(true);
1181 "<textarea id=\"test\"></textarea>"
1182 "<div id=\"result\" contenteditable=\"true\"></div>"
1185 render_thread_
->sink().ClearMessages();
1187 static const struct {
1188 WebTextDirection direction
;
1189 const wchar_t* expected_result
;
1190 } kTextDirection
[] = {
1191 { blink::WebTextDirectionRightToLeft
, L
"\x000A" L
"rtl,rtl" },
1192 { blink::WebTextDirectionLeftToRight
, L
"\x000A" L
"ltr,ltr" },
1194 for (size_t i
= 0; i
< arraysize(kTextDirection
); ++i
) {
1195 // Set the text direction of the <textarea> element.
1196 ExecuteJavaScript("document.getElementById('test').focus();");
1197 view()->OnSetTextDirection(kTextDirection
[i
].direction
);
1199 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1200 // property to the <div> element.
1201 ExecuteJavaScript("var result = document.getElementById('result');"
1202 "var node = document.getElementById('test');"
1203 "var style = getComputedStyle(node, null);"
1204 "result.innerText ="
1205 " node.getAttribute('dir') + ',' +"
1206 " style.getPropertyValue('direction');");
1208 // Copy the document content to std::wstring and compare with the
1210 const int kMaxOutputCharacters
= 16;
1211 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1212 EXPECT_EQ(base::WideToUTF16(kTextDirection
[i
].expected_result
), output
);
1216 // see http://crbug.com/238750
1218 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent
1220 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent
1223 // Test that we can receive correct DOM events when we send input events
1224 // through the RenderWidget::OnHandleInputEvent() function.
1225 TEST_F(RenderViewImplTest
, MAYBE_OnHandleKeyboardEvent
) {
1226 #if !defined(OS_MACOSX)
1227 // Load an HTML page consisting of one <input> element and three
1228 // contentediable <div> elements.
1229 // The <input> element is used for sending keyboard events, and the <div>
1230 // elements are used for writing DOM events in the following format:
1231 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1232 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1233 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1234 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1235 view()->set_send_content_state_immediately(true);
1239 "<script type='text/javascript' language='javascript'>"
1240 "function OnKeyEvent(ev) {"
1241 " var result = document.getElementById(ev.type);"
1242 " result.innerText ="
1243 " (ev.which || ev.keyCode) + ',' +"
1244 " ev.shiftKey + ',' +"
1245 " ev.ctrlKey + ',' +"
1252 "<input id='test' type='text'"
1253 " onkeydown='return OnKeyEvent(event);'"
1254 " onkeypress='return OnKeyEvent(event);'"
1255 " onkeyup='return OnKeyEvent(event);'>"
1257 "<div id='keydown' contenteditable='true'>"
1259 "<div id='keypress' contenteditable='true'>"
1261 "<div id='keyup' contenteditable='true'>"
1265 ExecuteJavaScript("document.getElementById('test').focus();");
1266 render_thread_
->sink().ClearMessages();
1268 static const MockKeyboard::Layout kLayouts
[] = {
1270 // Since we ignore the mock keyboard layout on Linux and instead just use
1271 // the screen's keyboard layout, these trivially pass. They are commented
1272 // out to avoid the illusion that they work.
1273 MockKeyboard::LAYOUT_ARABIC
,
1274 MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1275 MockKeyboard::LAYOUT_FRENCH
,
1276 MockKeyboard::LAYOUT_HEBREW
,
1277 MockKeyboard::LAYOUT_RUSSIAN
,
1279 MockKeyboard::LAYOUT_UNITED_STATES
,
1282 for (size_t i
= 0; i
< arraysize(kLayouts
); ++i
) {
1283 // For each key code, we send three keyboard events.
1284 // * we press only the key;
1285 // * we press the key and a left-shift key, and;
1286 // * we press the key and a right-alt (AltGr) key.
1287 // For each modifiers, we need a string used for formatting its expected
1288 // result. (See the above comment for its format.)
1289 static const struct {
1290 MockKeyboard::Modifiers modifiers
;
1291 const char* expected_result
;
1292 } kModifierData
[] = {
1293 {MockKeyboard::NONE
, "false,false,false"},
1294 {MockKeyboard::LEFT_SHIFT
, "true,false,false"},
1296 {MockKeyboard::RIGHT_ALT
, "false,false,true"},
1300 MockKeyboard::Layout layout
= kLayouts
[i
];
1301 for (size_t j
= 0; j
< arraysize(kModifierData
); ++j
) {
1302 // Virtual key codes used for this test.
1303 static const int kKeyCodes
[] = {
1304 '0', '1', '2', '3', '4', '5', '6', '7',
1305 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1306 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1307 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1313 ui::VKEY_OEM_PERIOD
,
1321 // Not sure how to handle this key on Linux.
1326 MockKeyboard::Modifiers modifiers
= kModifierData
[j
].modifiers
;
1327 for (size_t k
= 0; k
< arraysize(kKeyCodes
); ++k
) {
1328 // Send a keyboard event to the RenderView object.
1329 // We should test a keyboard event only when the given keyboard-layout
1330 // driver is installed in a PC and the driver can assign a Unicode
1331 // charcter for the given tuple (key-code and modifiers).
1332 int key_code
= kKeyCodes
[k
];
1333 base::string16 char_code
;
1334 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1337 // Create an expected result from the virtual-key code, the character
1338 // code, and the modifier-key status.
1339 // We format a string that emulates a DOM-event string produced hy
1340 // our JavaScript function. (See the above comment for the format.)
1341 static char expected_result
[1024];
1342 expected_result
[0] = 0;
1343 base::snprintf(&expected_result
[0],
1344 sizeof(expected_result
),
1345 "\n" // texts in the <input> element
1346 "%d,%s\n" // texts in the first <div> element
1347 "%d,%s\n" // texts in the second <div> element
1348 "%d,%s", // texts in the third <div> element
1349 key_code
, kModifierData
[j
].expected_result
,
1350 static_cast<int>(char_code
[0]),
1351 kModifierData
[j
].expected_result
,
1352 key_code
, kModifierData
[j
].expected_result
);
1354 // Retrieve the text in the test page and compare it with the expected
1355 // text created from a virtual-key code, a character code, and the
1356 // modifier-key status.
1357 const int kMaxOutputCharacters
= 1024;
1358 std::string output
= base::UTF16ToUTF8(
1359 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
1360 EXPECT_EQ(expected_result
, output
);
1369 // Test that our EditorClientImpl class can insert characters when we send
1370 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1371 // This test is for preventing regressions caused only when we use non-US
1372 // keyboards, such as Issue 10846.
1373 // see http://crbug.com/244562
1375 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1377 #define MAYBE_InsertCharacters InsertCharacters
1379 TEST_F(RenderViewImplTest
, MAYBE_InsertCharacters
) {
1380 #if !defined(OS_MACOSX)
1381 static const struct {
1382 MockKeyboard::Layout layout
;
1383 const wchar_t* expected_result
;
1386 // Disabled these keyboard layouts because buildbots do not have their
1387 // keyboard-layout drivers installed.
1388 {MockKeyboard::LAYOUT_ARABIC
,
1389 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1390 L
"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1391 L
"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1392 L
"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1393 L
"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1394 L
"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1395 L
"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1396 L
"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1397 L
"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1398 L
"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1399 L
"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1400 L
"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1401 L
"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1402 L
"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1403 L
"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1404 L
"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1405 L
"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1407 {MockKeyboard::LAYOUT_HEBREW
,
1408 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1409 L
"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1410 L
"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1411 L
"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1412 L
"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1413 L
"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1414 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1415 L
"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1416 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1417 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1418 L
"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1419 L
"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1420 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1421 L
"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1422 L
"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1423 L
"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1424 L
"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1425 L
"\x003b\x005d\x005c\x005b\x002c"
1429 // On Linux, the only way to test alternate keyboard layouts is to change
1430 // the keyboard layout of the whole screen. I'm worried about the side
1431 // effects this may have on the buildbots.
1432 {MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1433 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1434 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1435 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1436 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1437 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1438 L
"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1439 L
"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1440 L
"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1441 L
"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1442 L
"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1443 L
"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1444 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1445 L
"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1446 L
"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1447 L
"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1448 L
"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1451 {MockKeyboard::LAYOUT_FRENCH
,
1452 L
"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1453 L
"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1454 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1455 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1456 L
"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1457 L
"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1458 L
"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1459 L
"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1460 L
"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1461 L
"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1462 L
"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1463 L
"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1464 L
"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1465 L
"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1466 L
"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1467 L
"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1468 L
"\x003b\x003a\x00f9\x0029\x002a\x0021"
1470 {MockKeyboard::LAYOUT_RUSSIAN
,
1471 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1472 L
"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1473 L
"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1474 L
"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1475 L
"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1476 L
"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1477 L
"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1478 L
"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1479 L
"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1480 L
"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1481 L
"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1482 L
"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1483 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1484 L
"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1485 L
"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1486 L
"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1487 L
"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1488 L
"\x0451\x0445\x005c\x044a\x044d"
1490 #endif // defined(OS_WIN)
1491 {MockKeyboard::LAYOUT_UNITED_STATES
,
1492 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1493 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1494 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1495 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1496 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1497 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1498 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1499 L
"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1500 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1501 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1502 L
"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1503 L
"\x003f\x007e\x007b\x007c\x007d\x0022"
1505 // This is ifdefed out for Linux to correspond to the fact that we don't
1506 // test alt+keystroke for now.
1507 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1508 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1509 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1510 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1511 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1512 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1517 for (size_t i
= 0; i
< arraysize(kLayouts
); ++i
) {
1518 // Load an HTML page consisting of one <div> element.
1519 // This <div> element is used by the EditorClientImpl class to insert
1520 // characters received through the RenderWidget::OnHandleInputEvent()
1522 view()->set_send_content_state_immediately(true);
1528 "<div id='test' contenteditable='true'>"
1532 ExecuteJavaScript("document.getElementById('test').focus();");
1533 render_thread_
->sink().ClearMessages();
1535 // For each key code, we send three keyboard events.
1536 // * Pressing only the key;
1537 // * Pressing the key and a left-shift key, and;
1538 // * Pressing the key and a right-alt (AltGr) key.
1539 static const MockKeyboard::Modifiers kModifiers
[] = {
1541 MockKeyboard::LEFT_SHIFT
,
1543 MockKeyboard::RIGHT_ALT
,
1547 MockKeyboard::Layout layout
= kLayouts
[i
].layout
;
1548 for (size_t j
= 0; j
< arraysize(kModifiers
); ++j
) {
1549 // Virtual key codes used for this test.
1550 static const int kKeyCodes
[] = {
1551 '0', '1', '2', '3', '4', '5', '6', '7',
1552 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1553 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1554 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1560 ui::VKEY_OEM_PERIOD
,
1568 // Unclear how to handle this on Linux.
1573 MockKeyboard::Modifiers modifiers
= kModifiers
[j
];
1574 for (size_t k
= 0; k
< arraysize(kKeyCodes
); ++k
) {
1575 // Send a keyboard event to the RenderView object.
1576 // We should test a keyboard event only when the given keyboard-layout
1577 // driver is installed in a PC and the driver can assign a Unicode
1578 // charcter for the given tuple (layout, key-code, and modifiers).
1579 int key_code
= kKeyCodes
[k
];
1580 base::string16 char_code
;
1581 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1586 // Retrieve the text in the test page and compare it with the expected
1587 // text created from a virtual-key code, a character code, and the
1588 // modifier-key status.
1589 const int kMaxOutputCharacters
= 4096;
1590 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1591 EXPECT_EQ(base::WideToUTF16(kLayouts
[i
].expected_result
), output
);
1598 // Crashy, http://crbug.com/53247.
1599 TEST_F(RenderViewImplTest
, DISABLED_DidFailProvisionalLoadWithErrorForError
) {
1600 GetMainFrame()->enableViewSourceMode(true);
1602 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1603 error
.reason
= net::ERR_FILE_NOT_FOUND
;
1604 error
.unreachableURL
= GURL("http://foo");
1605 WebLocalFrame
* web_frame
= GetMainFrame();
1607 // Start a load that will reach provisional state synchronously,
1608 // but won't complete synchronously.
1609 CommonNavigationParams common_params
;
1610 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1611 common_params
.url
= GURL("data:text/html,test data");
1612 frame()->OnNavigate(common_params
, StartNavigationParams(),
1613 RequestNavigationParams());
1615 // An error occurred.
1616 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame
, error
);
1617 // Frame should exit view-source mode.
1618 EXPECT_FALSE(web_frame
->isViewSourceModeEnabled());
1621 TEST_F(RenderViewImplTest
, DidFailProvisionalLoadWithErrorForCancellation
) {
1622 GetMainFrame()->enableViewSourceMode(true);
1624 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1625 error
.reason
= net::ERR_ABORTED
;
1626 error
.unreachableURL
= GURL("http://foo");
1627 WebLocalFrame
* web_frame
= GetMainFrame();
1629 // Start a load that will reach provisional state synchronously,
1630 // but won't complete synchronously.
1631 CommonNavigationParams common_params
;
1632 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1633 common_params
.url
= GURL("data:text/html,test data");
1634 frame()->OnNavigate(common_params
, StartNavigationParams(),
1635 RequestNavigationParams());
1637 // A cancellation occurred.
1638 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame
, error
);
1639 // Frame should stay in view-source mode.
1640 EXPECT_TRUE(web_frame
->isViewSourceModeEnabled());
1643 // Regression test for http://crbug.com/41562
1644 TEST_F(RenderViewImplTest
, UpdateTargetURLWithInvalidURL
) {
1645 const GURL
invalid_gurl("http://");
1646 view()->setMouseOverURL(blink::WebURL(invalid_gurl
));
1647 EXPECT_EQ(invalid_gurl
, view()->target_url_
);
1650 TEST_F(RenderViewImplTest
, SetHistoryLengthAndOffset
) {
1651 // No history to merge; one committed page.
1652 view()->OnSetHistoryOffsetAndLength(0, 1);
1653 EXPECT_EQ(1, view()->history_list_length_
);
1654 EXPECT_EQ(0, view()->history_list_offset_
);
1656 // History of length 1 to merge; one committed page.
1657 view()->OnSetHistoryOffsetAndLength(1, 2);
1658 EXPECT_EQ(2, view()->history_list_length_
);
1659 EXPECT_EQ(1, view()->history_list_offset_
);
1662 TEST_F(RenderViewImplTest
, ContextMenu
) {
1663 LoadHTML("<div>Page A</div>");
1665 // Create a right click in the center of the iframe. (I'm hoping this will
1666 // make this a bit more robust in case of some other formatting or other bug.)
1667 WebMouseEvent mouse_event
;
1668 mouse_event
.type
= WebInputEvent::MouseDown
;
1669 mouse_event
.button
= WebMouseEvent::ButtonRight
;
1670 mouse_event
.x
= 250;
1671 mouse_event
.y
= 250;
1672 mouse_event
.globalX
= 250;
1673 mouse_event
.globalY
= 250;
1675 SendWebMouseEvent(mouse_event
);
1677 // Now simulate the corresponding up event which should display the menu
1678 mouse_event
.type
= WebInputEvent::MouseUp
;
1679 SendWebMouseEvent(mouse_event
);
1681 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
1682 FrameHostMsg_ContextMenu::ID
));
1685 TEST_F(RenderViewImplTest
, TestBackForward
) {
1686 LoadHTML("<div id=pagename>Page A</div>");
1687 PageState page_a_state
=
1688 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1689 int was_page_a
= -1;
1690 base::string16 check_page_a
=
1692 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1693 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1694 EXPECT_EQ(1, was_page_a
);
1696 LoadHTML("<div id=pagename>Page B</div>");
1697 int was_page_b
= -1;
1698 base::string16 check_page_b
=
1700 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1701 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1702 EXPECT_EQ(1, was_page_b
);
1704 PageState back_state
=
1705 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1707 LoadHTML("<div id=pagename>Page C</div>");
1708 int was_page_c
= -1;
1709 base::string16 check_page_c
=
1711 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1712 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1713 EXPECT_EQ(1, was_page_c
);
1715 PageState forward_state
=
1716 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1718 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1719 EXPECT_EQ(1, was_page_b
);
1721 PageState back_state2
=
1722 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1724 GoForward(forward_state
);
1725 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1726 EXPECT_EQ(1, was_page_c
);
1728 GoBack(back_state2
);
1729 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1730 EXPECT_EQ(1, was_page_b
);
1733 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1734 GoBack(page_a_state
);
1735 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1736 EXPECT_EQ(1, was_page_a
);
1738 GoForward(forward_state
);
1739 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1740 EXPECT_EQ(1, was_page_b
);
1743 #if defined(OS_MACOSX) || defined(USE_AURA)
1744 TEST_F(RenderViewImplTest
, GetCompositionCharacterBoundsTest
) {
1747 // http://crbug.com/304193
1748 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
1752 LoadHTML("<textarea id=\"test\"></textarea>");
1753 ExecuteJavaScript("document.getElementById('test').focus();");
1755 const base::string16 empty_string
;
1756 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1757 std::vector
<gfx::Rect
> bounds
;
1758 view()->OnSetFocus(true);
1759 view()->OnSetInputMethodActive(true);
1761 // ASCII composition
1762 const base::string16 ascii_composition
= base::UTF8ToUTF16("aiueo");
1763 view()->OnImeSetComposition(ascii_composition
, empty_underline
, 0, 0);
1764 view()->GetCompositionCharacterBounds(&bounds
);
1765 ASSERT_EQ(ascii_composition
.size(), bounds
.size());
1766 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1767 EXPECT_LT(0, bounds
[i
].width());
1768 view()->OnImeConfirmComposition(
1769 empty_string
, gfx::Range::InvalidRange(), false);
1771 // Non surrogate pair unicode character.
1772 const base::string16 unicode_composition
= base::UTF8ToUTF16(
1773 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1774 view()->OnImeSetComposition(unicode_composition
, empty_underline
, 0, 0);
1775 view()->GetCompositionCharacterBounds(&bounds
);
1776 ASSERT_EQ(unicode_composition
.size(), bounds
.size());
1777 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1778 EXPECT_LT(0, bounds
[i
].width());
1779 view()->OnImeConfirmComposition(
1780 empty_string
, gfx::Range::InvalidRange(), false);
1782 // Surrogate pair character.
1783 const base::string16 surrogate_pair_char
=
1784 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1785 view()->OnImeSetComposition(surrogate_pair_char
,
1789 view()->GetCompositionCharacterBounds(&bounds
);
1790 ASSERT_EQ(surrogate_pair_char
.size(), bounds
.size());
1791 EXPECT_LT(0, bounds
[0].width());
1792 EXPECT_EQ(0, bounds
[1].width());
1793 view()->OnImeConfirmComposition(
1794 empty_string
, gfx::Range::InvalidRange(), false);
1797 const base::string16 surrogate_pair_mixed_composition
=
1798 surrogate_pair_char
+ base::UTF8ToUTF16("\xE3\x81\x82") +
1799 surrogate_pair_char
+ base::UTF8ToUTF16("b") + surrogate_pair_char
;
1800 const size_t utf16_length
= 8UL;
1801 const bool is_surrogate_pair_empty_rect
[8] = {
1802 false, true, false, false, true, false, false, true };
1803 view()->OnImeSetComposition(surrogate_pair_mixed_composition
,
1807 view()->GetCompositionCharacterBounds(&bounds
);
1808 ASSERT_EQ(utf16_length
, bounds
.size());
1809 for (size_t i
= 0; i
< utf16_length
; ++i
) {
1810 if (is_surrogate_pair_empty_rect
[i
]) {
1811 EXPECT_EQ(0, bounds
[i
].width());
1813 EXPECT_LT(0, bounds
[i
].width());
1816 view()->OnImeConfirmComposition(
1817 empty_string
, gfx::Range::InvalidRange(), false);
1821 TEST_F(RenderViewImplTest
, ZoomLimit
) {
1822 const double kMinZoomLevel
= ZoomFactorToZoomLevel(kMinimumZoomFactor
);
1823 const double kMaxZoomLevel
= ZoomFactorToZoomLevel(kMaximumZoomFactor
);
1825 // Verifies navigation to a URL with preset zoom level indeed sets the level.
1826 // Regression test for http://crbug.com/139559, where the level was not
1827 // properly set when it is out of the default zoom limits of WebView.
1828 CommonNavigationParams common_params
;
1829 common_params
.url
= GURL("data:text/html,min_zoomlimit_test");
1830 view()->OnSetZoomLevelForLoadingURL(common_params
.url
, kMinZoomLevel
);
1831 frame()->OnNavigate(common_params
, StartNavigationParams(),
1832 RequestNavigationParams());
1833 ProcessPendingMessages();
1834 EXPECT_DOUBLE_EQ(kMinZoomLevel
, view()->GetWebView()->zoomLevel());
1836 // It should work even when the zoom limit is temporarily changed in the page.
1837 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
1838 ZoomFactorToZoomLevel(1.0));
1839 common_params
.url
= GURL("data:text/html,max_zoomlimit_test");
1840 view()->OnSetZoomLevelForLoadingURL(common_params
.url
, kMaxZoomLevel
);
1841 frame()->OnNavigate(common_params
, StartNavigationParams(),
1842 RequestNavigationParams());
1843 ProcessPendingMessages();
1844 EXPECT_DOUBLE_EQ(kMaxZoomLevel
, view()->GetWebView()->zoomLevel());
1847 TEST_F(RenderViewImplTest
, SetEditableSelectionAndComposition
) {
1848 // Load an HTML page consisting of an input field.
1853 "<input id=\"test1\" value=\"some test text hello\"></input>"
1856 ExecuteJavaScript("document.getElementById('test1').focus();");
1857 frame()->OnSetEditableSelectionOffsets(4, 8);
1858 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1859 frame()->OnSetCompositionFromExistingText(7, 10, empty_underline
);
1860 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1861 EXPECT_EQ(4, info
.selectionStart
);
1862 EXPECT_EQ(8, info
.selectionEnd
);
1863 EXPECT_EQ(7, info
.compositionStart
);
1864 EXPECT_EQ(10, info
.compositionEnd
);
1865 frame()->OnUnselect();
1866 info
= view()->webview()->textInputInfo();
1867 EXPECT_EQ(0, info
.selectionStart
);
1868 EXPECT_EQ(0, info
.selectionEnd
);
1872 TEST_F(RenderViewImplTest
, OnExtendSelectionAndDelete
) {
1873 // Load an HTML page consisting of an input field.
1878 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
1881 ExecuteJavaScript("document.getElementById('test1').focus();");
1882 frame()->OnSetEditableSelectionOffsets(10, 10);
1883 frame()->OnExtendSelectionAndDelete(3, 4);
1884 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1885 EXPECT_EQ("abcdefgopqrstuvwxyz", info
.value
);
1886 EXPECT_EQ(7, info
.selectionStart
);
1887 EXPECT_EQ(7, info
.selectionEnd
);
1888 frame()->OnSetEditableSelectionOffsets(4, 8);
1889 frame()->OnExtendSelectionAndDelete(2, 5);
1890 info
= view()->webview()->textInputInfo();
1891 EXPECT_EQ("abuvwxyz", info
.value
);
1892 EXPECT_EQ(2, info
.selectionStart
);
1893 EXPECT_EQ(2, info
.selectionEnd
);
1896 // Test that the navigating specific frames works correctly.
1897 TEST_F(RenderViewImplTest
, NavigateFrame
) {
1899 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
1901 // Navigate the frame only.
1902 CommonNavigationParams common_params
;
1903 RequestNavigationParams request_params
;
1904 common_params
.url
= GURL("data:text/html,world");
1905 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1906 common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
1907 request_params
.current_history_list_length
= 1;
1908 request_params
.current_history_list_offset
= 0;
1909 request_params
.pending_history_list_offset
= 1;
1910 request_params
.page_id
= -1;
1911 request_params
.frame_to_navigate
= "frame";
1912 request_params
.browser_navigation_start
=
1913 base::TimeTicks::FromInternalValue(1);
1914 frame()->OnNavigate(common_params
, StartNavigationParams(), request_params
);
1916 RenderFrame::FromWebFrame(frame()->GetWebFrame()->firstChild())).Wait();
1918 // Copy the document content to std::wstring and compare with the
1920 const int kMaxOutputCharacters
= 256;
1921 std::string output
= base::UTF16ToUTF8(
1922 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
1923 EXPECT_EQ(output
, "hello \n\nworld");
1926 // This test ensures that a RenderFrame object is created for the top level
1927 // frame in the RenderView.
1928 TEST_F(RenderViewImplTest
, BasicRenderFrame
) {
1929 EXPECT_TRUE(view()->main_render_frame_
.get());
1932 TEST_F(RenderViewImplTest
, GetSSLStatusOfFrame
) {
1933 LoadHTML("<!DOCTYPE html><html><body></body></html>");
1935 WebLocalFrame
* frame
= GetMainFrame();
1936 SSLStatus ssl_status
= view()->GetSSLStatusOfFrame(frame
);
1937 EXPECT_FALSE(net::IsCertStatusError(ssl_status
.cert_status
));
1939 const_cast<blink::WebURLResponse
&>(frame
->dataSource()->response()).
1941 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS
, 0, 0,
1942 SignedCertificateTimestampIDStatusList()));
1943 ssl_status
= view()->GetSSLStatusOfFrame(frame
);
1944 EXPECT_TRUE(net::IsCertStatusError(ssl_status
.cert_status
));
1947 TEST_F(RenderViewImplTest
, MessageOrderInDidChangeSelection
) {
1948 view()->OnSetInputMethodActive(true);
1949 view()->set_send_content_state_immediately(true);
1950 LoadHTML("<textarea id=\"test\"></textarea>");
1952 view()->handling_input_event_
= true;
1953 ExecuteJavaScript("document.getElementById('test').focus();");
1955 bool is_input_type_called
= false;
1956 bool is_selection_called
= false;
1957 size_t last_input_type
= 0;
1958 size_t last_selection
= 0;
1960 for (size_t i
= 0; i
< render_thread_
->sink().message_count(); ++i
) {
1961 const uint32 type
= render_thread_
->sink().GetMessageAt(i
)->type();
1962 if (type
== ViewHostMsg_TextInputTypeChanged::ID
) {
1963 is_input_type_called
= true;
1964 last_input_type
= i
;
1965 } else if (type
== ViewHostMsg_SelectionChanged::ID
) {
1966 is_selection_called
= true;
1971 EXPECT_TRUE(is_input_type_called
);
1972 EXPECT_TRUE(is_selection_called
);
1974 // InputTypeChange shold be called earlier than SelectionChanged.
1975 EXPECT_LT(last_input_type
, last_selection
);
1978 class SuppressErrorPageTest
: public RenderViewTest
{
1980 ContentRendererClient
* CreateContentRendererClient() override
{
1981 return new TestContentRendererClient
;
1984 RenderViewImpl
* view() {
1985 return static_cast<RenderViewImpl
*>(view_
);
1988 RenderFrameImpl
* frame() {
1989 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
1993 class TestContentRendererClient
: public ContentRendererClient
{
1995 bool ShouldSuppressErrorPage(RenderFrame
* render_frame
,
1996 const GURL
& url
) override
{
1997 return url
== GURL("http://example.com/suppress");
2000 void GetNavigationErrorStrings(content::RenderView
* render_view
,
2001 blink::WebFrame
* frame
,
2002 const blink::WebURLRequest
& failed_request
,
2003 const blink::WebURLError
& error
,
2004 std::string
* error_html
,
2005 base::string16
* error_description
) override
{
2007 *error_html
= "A suffusion of yellow.";
2012 #if defined(OS_ANDROID)
2013 // Crashing on Android: http://crbug.com/311341
2014 #define MAYBE_Suppresses DISABLED_Suppresses
2016 #define MAYBE_Suppresses Suppresses
2019 TEST_F(SuppressErrorPageTest
, MAYBE_Suppresses
) {
2021 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2022 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2023 error
.unreachableURL
= GURL("http://example.com/suppress");
2024 WebLocalFrame
* web_frame
= GetMainFrame();
2026 // Start a load that will reach provisional state synchronously,
2027 // but won't complete synchronously.
2028 CommonNavigationParams common_params
;
2029 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2030 common_params
.url
= GURL("data:text/html,test data");
2031 frame()->OnNavigate(common_params
, StartNavigationParams(),
2032 RequestNavigationParams());
2034 // An error occurred.
2035 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame
, error
);
2036 const int kMaxOutputCharacters
= 22;
2038 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2041 #if defined(OS_ANDROID)
2042 // Crashing on Android: http://crbug.com/311341
2043 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2045 #define MAYBE_DoesNotSuppress DoesNotSuppress
2048 TEST_F(SuppressErrorPageTest
, MAYBE_DoesNotSuppress
) {
2050 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2051 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2052 error
.unreachableURL
= GURL("http://example.com/dont-suppress");
2053 WebLocalFrame
* web_frame
= GetMainFrame();
2055 // Start a load that will reach provisional state synchronously,
2056 // but won't complete synchronously.
2057 CommonNavigationParams common_params
;
2058 common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2059 common_params
.url
= GURL("data:text/html,test data");
2060 frame()->OnNavigate(common_params
, StartNavigationParams(),
2061 RequestNavigationParams());
2063 // An error occurred.
2064 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame
, error
);
2065 // The error page itself is loaded asynchronously.
2066 FrameLoadWaiter(frame()).Wait();
2067 const int kMaxOutputCharacters
= 22;
2068 EXPECT_EQ("A suffusion of yellow.",
2069 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2072 // Tests if IME API's candidatewindow* events sent from browser are handled
2074 TEST_F(RenderViewImplTest
, SendCandidateWindowEvents
) {
2075 // Sends an HTML with an <input> element and scripts to the renderer.
2076 // The script handles all 3 of candidatewindow* events for an
2077 // InputMethodContext object and once it received 'show', 'update', 'hide'
2078 // should appear in the result div.
2079 LoadHTML("<input id='test'>"
2080 "<div id='result'>Result: </div>"
2082 "window.onload = function() {"
2083 " var result = document.getElementById('result');"
2084 " var test = document.getElementById('test');"
2086 " var context = test.inputMethodContext;"
2088 " context.oncandidatewindowshow = function() {"
2089 " result.innerText += 'show'; };"
2090 " context.oncandidatewindowupdate = function(){"
2091 " result.innerText += 'update'; };"
2092 " context.oncandidatewindowhide = function(){"
2093 " result.innerText += 'hide'; };"
2098 // Fire candidatewindow events.
2099 view()->OnCandidateWindowShown();
2100 view()->OnCandidateWindowUpdated();
2101 view()->OnCandidateWindowHidden();
2103 // Retrieve the content and check if it is expected.
2104 const int kMaxOutputCharacters
= 50;
2105 std::string output
= base::UTF16ToUTF8(
2106 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
2107 EXPECT_EQ(output
, "\nResult:showupdatehide");
2110 // Ensure the render view sends favicon url update events correctly.
2111 TEST_F(RenderViewImplTest
, SendFaviconURLUpdateEvent
) {
2112 // An event should be sent when a favicon url exists.
2115 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2118 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
2119 ViewHostMsg_UpdateFaviconURL::ID
));
2120 render_thread_
->sink().ClearMessages();
2122 // An event should not be sent if no favicon url exists. This is an assumption
2123 // made by some of Chrome's favicon handling.
2128 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
2129 ViewHostMsg_UpdateFaviconURL::ID
));
2132 TEST_F(RenderViewImplTest
, FocusElementCallsFocusedNodeChanged
) {
2133 LoadHTML("<input id='test1' value='hello1'></input>"
2134 "<input id='test2' value='hello2'></input>");
2136 ExecuteJavaScript("document.getElementById('test1').focus();");
2137 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
2138 ViewHostMsg_FocusedNodeChanged::ID
);
2141 ViewHostMsg_FocusedNodeChanged::Param params
;
2142 ViewHostMsg_FocusedNodeChanged::Read(msg1
, ¶ms
);
2143 EXPECT_TRUE(get
<0>(params
));
2144 render_thread_
->sink().ClearMessages();
2146 ExecuteJavaScript("document.getElementById('test2').focus();");
2147 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
2148 ViewHostMsg_FocusedNodeChanged::ID
);
2150 ViewHostMsg_FocusedNodeChanged::Read(msg2
, ¶ms
);
2151 EXPECT_TRUE(get
<0>(params
));
2152 render_thread_
->sink().ClearMessages();
2154 view()->webview()->clearFocusedElement();
2155 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
2156 ViewHostMsg_FocusedNodeChanged::ID
);
2158 ViewHostMsg_FocusedNodeChanged::Read(msg3
, ¶ms
);
2159 EXPECT_FALSE(get
<0>(params
));
2160 render_thread_
->sink().ClearMessages();
2163 TEST_F(RenderViewImplTest
, ServiceWorkerNetworkProviderSetup
) {
2164 ServiceWorkerNetworkProvider
* provider
= NULL
;
2165 RequestExtraData
* extra_data
= NULL
;
2167 // Make sure each new document has a new provider and
2168 // that the main request is tagged with the provider's id.
2169 LoadHTML("<b>A Document</b>");
2170 ASSERT_TRUE(GetMainFrame()->dataSource());
2171 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2172 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2173 ASSERT_TRUE(provider
);
2174 extra_data
= static_cast<RequestExtraData
*>(
2175 GetMainFrame()->dataSource()->request().extraData());
2176 ASSERT_TRUE(extra_data
);
2177 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2178 provider
->provider_id());
2179 int provider1_id
= provider
->provider_id();
2181 LoadHTML("<b>New Document B Goes Here</b>");
2182 ASSERT_TRUE(GetMainFrame()->dataSource());
2183 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2184 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2185 ASSERT_TRUE(provider
);
2186 EXPECT_NE(provider1_id
, provider
->provider_id());
2187 extra_data
= static_cast<RequestExtraData
*>(
2188 GetMainFrame()->dataSource()->request().extraData());
2189 ASSERT_TRUE(extra_data
);
2190 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2191 provider
->provider_id());
2193 // See that subresource requests are also tagged with the provider's id.
2194 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2195 blink::WebURLRequest
request(GURL("http://foo.com"));
2196 request
.setRequestContext(blink::WebURLRequest::RequestContextSubresource
);
2197 blink::WebURLResponse redirect_response
;
2198 frame()->willSendRequest(GetMainFrame(), 0, request
, redirect_response
);
2199 extra_data
= static_cast<RequestExtraData
*>(request
.extraData());
2200 ASSERT_TRUE(extra_data
);
2201 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2202 provider
->provider_id());
2205 TEST_F(RenderViewImplTest
, OnSetAccessibilityMode
) {
2206 ASSERT_EQ(AccessibilityModeOff
, frame()->accessibility_mode());
2207 ASSERT_EQ((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2209 frame()->OnSetAccessibilityMode(AccessibilityModeTreeOnly
);
2210 ASSERT_EQ(AccessibilityModeTreeOnly
, frame()->accessibility_mode());
2211 ASSERT_NE((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2213 frame()->OnSetAccessibilityMode(AccessibilityModeOff
);
2214 ASSERT_EQ(AccessibilityModeOff
, frame()->accessibility_mode());
2215 ASSERT_EQ((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2217 frame()->OnSetAccessibilityMode(AccessibilityModeComplete
);
2218 ASSERT_EQ(AccessibilityModeComplete
, frame()->accessibility_mode());
2219 ASSERT_NE((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2222 TEST_F(RenderViewImplTest
, ScreenMetricsEmulation
) {
2223 LoadHTML("<body style='min-height:1000px;'></body>");
2225 blink::WebDeviceEmulationParams params
;
2226 base::string16 get_width
= base::ASCIIToUTF16("Number(window.innerWidth)");
2227 base::string16 get_height
= base::ASCIIToUTF16("Number(window.innerHeight)");
2230 params
.viewSize
.width
= 327;
2231 params
.viewSize
.height
= 415;
2232 view()->OnEnableDeviceEmulation(params
);
2233 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width
, &width
));
2234 EXPECT_EQ(params
.viewSize
.width
, width
);
2235 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height
, &height
));
2236 EXPECT_EQ(params
.viewSize
.height
, height
);
2238 params
.viewSize
.width
= 1005;
2239 params
.viewSize
.height
= 1102;
2240 view()->OnEnableDeviceEmulation(params
);
2241 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width
, &width
));
2242 EXPECT_EQ(params
.viewSize
.width
, width
);
2243 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height
, &height
));
2244 EXPECT_EQ(params
.viewSize
.height
, height
);
2246 view()->OnDisableDeviceEmulation();
2248 view()->OnEnableDeviceEmulation(params
);
2249 // Don't disable here to test that emulation is being shutdown properly.
2252 // Sanity checks for the Navigation Timing API |navigationStart| override. We
2253 // are asserting only most basic constraints, as TimeTicks (passed as the
2254 // override) are not comparable with the wall time (returned by the Blink API).
2255 TEST_F(RenderViewImplTest
, NavigationStartOverride
) {
2256 // Verify that a navigation that claims to have started at the earliest
2257 // possible TimeTicks is indeed reported as one that started before
2258 // OnNavigate() is called.
2259 base::Time before_navigation
= base::Time::Now();
2260 CommonNavigationParams early_common_params
;
2261 StartNavigationParams early_start_params
;
2262 RequestNavigationParams early_request_params
;
2263 early_common_params
.url
= GURL("data:text/html,<div>Page</div>");
2264 early_common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2265 early_common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
2266 early_start_params
.is_post
= true;
2267 early_request_params
.browser_navigation_start
=
2268 base::TimeTicks::FromInternalValue(1);
2270 frame()->OnNavigate(early_common_params
, early_start_params
,
2271 early_request_params
);
2272 ProcessPendingMessages();
2274 base::Time early_nav_reported_start
=
2275 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2276 EXPECT_LT(early_nav_reported_start
, before_navigation
);
2278 // Verify that a navigation that claims to have started in the future - 42
2279 // days from now is *not* reported as one that starts in the future; as we
2280 // sanitize the override allowing a maximum of ::Now().
2281 CommonNavigationParams late_common_params
;
2282 RequestNavigationParams late_request_params
;
2283 StartNavigationParams late_start_params
;
2284 late_common_params
.url
= GURL("data:text/html,<div>Another page</div>");
2285 late_common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2286 late_common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
2287 late_start_params
.is_post
= true;
2288 late_request_params
.browser_navigation_start
=
2289 base::TimeTicks::Now() + base::TimeDelta::FromDays(42);
2291 frame()->OnNavigate(late_common_params
, late_start_params
,
2292 late_request_params
);
2293 ProcessPendingMessages();
2294 base::Time after_navigation
=
2295 base::Time::Now() + base::TimeDelta::FromDays(1);
2297 base::Time late_nav_reported_start
=
2298 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2299 EXPECT_LE(late_nav_reported_start
, after_navigation
);
2302 TEST_F(RenderViewImplTest
, PreferredSizeZoomed
) {
2303 LoadHTML("<body style='margin:0;'><div style='display:inline-block; "
2304 "width:400px; height:400px;'/></body>");
2305 view()->webview()->mainFrame()->setCanHaveScrollbars(false);
2306 EnablePreferredSizeMode();
2308 gfx::Size size
= GetPreferredSize();
2309 EXPECT_EQ(gfx::Size(400, 400), size
);
2311 SetZoomLevel(ZoomFactorToZoomLevel(2.0));
2312 size
= GetPreferredSize();
2313 EXPECT_EQ(gfx::Size(800, 800), size
);
2316 // Ensure the RenderViewImpl history list is properly updated when starting a
2317 // new browser-initiated navigation.
2318 TEST_F(RenderViewImplTest
, HistoryIsProperlyUpdatedOnNavigation
) {
2319 EXPECT_EQ(0, view()->historyBackListCount());
2320 EXPECT_EQ(0, view()->historyBackListCount() +
2321 view()->historyForwardListCount() + 1);
2323 // Receive a Navigate message with history parameters.
2324 RequestNavigationParams request_params
;
2325 request_params
.current_history_list_length
= 2;
2326 request_params
.current_history_list_offset
= 1;
2327 request_params
.pending_history_list_offset
= 2;
2328 request_params
.page_id
= -1;
2329 frame()->OnNavigate(CommonNavigationParams(), StartNavigationParams(),
2332 // The history list in RenderView should have been updated.
2333 EXPECT_EQ(1, view()->historyBackListCount());
2334 EXPECT_EQ(2, view()->historyBackListCount() +
2335 view()->historyForwardListCount() + 1);
2338 } // namespace content