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/render_process.h"
37 #include "content/renderer/render_view_impl.h"
38 #include "content/shell/browser/shell.h"
39 #include "content/shell/browser/shell_browser_context.h"
40 #include "content/test/mock_keyboard.h"
41 #include "net/base/net_errors.h"
42 #include "net/cert/cert_status_flags.h"
43 #include "testing/gtest/include/gtest/gtest.h"
44 #include "third_party/WebKit/public/platform/WebData.h"
45 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
46 #include "third_party/WebKit/public/platform/WebString.h"
47 #include "third_party/WebKit/public/platform/WebURLResponse.h"
48 #include "third_party/WebKit/public/web/WebDataSource.h"
49 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
50 #include "third_party/WebKit/public/web/WebHistoryItem.h"
51 #include "third_party/WebKit/public/web/WebLocalFrame.h"
52 #include "third_party/WebKit/public/web/WebPerformance.h"
53 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
54 #include "third_party/WebKit/public/web/WebView.h"
55 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
56 #include "ui/events/event.h"
57 #include "ui/events/keycodes/keyboard_codes.h"
58 #include "ui/gfx/codec/jpeg_codec.h"
59 #include "ui/gfx/range/range.h"
61 #if defined(USE_AURA) && defined(USE_X11)
63 #include "ui/events/event_constants.h"
64 #include "ui/events/keycodes/keyboard_code_conversion.h"
65 #include "ui/events/test/events_test_utils.h"
66 #include "ui/events/test/events_test_utils_x11.h"
69 #if defined(USE_OZONE)
70 #include "ui/events/keycodes/keyboard_code_conversion.h"
73 using blink::WebFrame
;
74 using blink::WebInputEvent
;
75 using blink::WebLocalFrame
;
76 using blink::WebMouseEvent
;
77 using blink::WebRuntimeFeatures
;
78 using blink::WebString
;
79 using blink::WebTextDirection
;
80 using blink::WebURLError
;
86 static const int kProxyRoutingId
= 13;
88 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
89 // Converts MockKeyboard::Modifiers to ui::EventFlags.
90 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers
) {
91 static struct ModifierMap
{
92 MockKeyboard::Modifiers src
;
95 { MockKeyboard::LEFT_SHIFT
, ui::EF_SHIFT_DOWN
},
96 { MockKeyboard::RIGHT_SHIFT
, ui::EF_SHIFT_DOWN
},
97 { MockKeyboard::LEFT_CONTROL
, ui::EF_CONTROL_DOWN
},
98 { MockKeyboard::RIGHT_CONTROL
, ui::EF_CONTROL_DOWN
},
99 { MockKeyboard::LEFT_ALT
, ui::EF_ALT_DOWN
},
100 { MockKeyboard::RIGHT_ALT
, ui::EF_ALT_DOWN
},
103 for (size_t i
= 0; i
< arraysize(kModifierMap
); ++i
) {
104 if (kModifierMap
[i
].src
& modifiers
) {
105 flags
|= kModifierMap
[i
].dst
;
112 class WebUITestWebUIControllerFactory
: public WebUIControllerFactory
{
114 WebUIController
* CreateWebUIControllerForURL(WebUI
* web_ui
,
115 const GURL
& url
) const override
{
118 WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
119 const GURL
& url
) const override
{
120 return WebUI::kNoWebUI
;
122 bool UseWebUIForURL(BrowserContext
* browser_context
,
123 const GURL
& url
) const override
{
124 return HasWebUIScheme(url
);
126 bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
127 const GURL
& url
) const override
{
128 return HasWebUIScheme(url
);
134 class RenderViewImplTest
: public RenderViewTest
{
136 RenderViewImplTest() {
137 // Attach a pseudo keyboard device to this object.
138 mock_keyboard_
.reset(new MockKeyboard());
141 ~RenderViewImplTest() override
{}
143 void SetUp() override
{
144 RenderViewTest::SetUp();
145 // Enable Blink's experimental and test only features so that test code
146 // does not have to bother enabling each feature.
147 WebRuntimeFeatures::enableExperimentalFeatures(true);
148 WebRuntimeFeatures::enableTestOnlyFeatures(true);
151 RenderViewImpl
* view() {
152 return static_cast<RenderViewImpl
*>(view_
);
156 return view()->page_id_
;
159 RenderFrameImpl
* frame() {
160 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
163 // Sends IPC messages that emulates a key-press event.
164 int SendKeyEvent(MockKeyboard::Layout layout
,
166 MockKeyboard::Modifiers modifiers
,
167 base::string16
* output
) {
169 // Retrieve the Unicode character for the given tuple (keyboard-layout,
170 // key-code, and modifiers).
171 // Exit when a keyboard-layout driver cannot assign a Unicode character to
172 // the tuple to prevent sending an invalid key code to the RenderView
174 CHECK(mock_keyboard_
.get());
176 int length
= mock_keyboard_
->GetCharacters(layout
, key_code
, modifiers
,
181 // Create IPC messages from Windows messages and send them to our
183 // A keyboard event of Windows consists of three Windows messages:
184 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
185 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
186 // WM_CHAR sends a composed Unicode character.
187 MSG msg1
= { NULL
, WM_KEYDOWN
, key_code
, 0 };
188 ui::KeyEvent
evt1(msg1
);
189 NativeWebKeyboardEvent
keydown_event(evt1
);
190 SendNativeKeyEvent(keydown_event
);
192 MSG msg2
= { NULL
, WM_CHAR
, (*output
)[0], 0 };
193 ui::KeyEvent
evt2(msg2
);
194 NativeWebKeyboardEvent
char_event(evt2
);
195 SendNativeKeyEvent(char_event
);
197 MSG msg3
= { NULL
, WM_KEYUP
, key_code
, 0 };
198 ui::KeyEvent
evt3(msg3
);
199 NativeWebKeyboardEvent
keyup_event(evt3
);
200 SendNativeKeyEvent(keyup_event
);
203 #elif defined(USE_AURA) && defined(USE_X11)
204 // We ignore |layout|, which means we are only testing the layout of the
205 // current locale. TODO(mazda): fix this to respect |layout|.
207 const int flags
= ConvertMockKeyboardModifier(modifiers
);
209 ui::ScopedXI2Event xevent
;
210 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
211 static_cast<ui::KeyboardCode
>(key_code
),
213 ui::KeyEvent
event1(xevent
);
214 NativeWebKeyboardEvent
keydown_event(event1
);
215 SendNativeKeyEvent(keydown_event
);
217 // X11 doesn't actually have native character events, but give the test
219 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
220 static_cast<ui::KeyboardCode
>(key_code
),
222 ui::KeyEvent
event2(xevent
);
223 event2
.set_character(GetCharacterFromKeyCode(event2
.key_code(),
225 ui::KeyEventTestApi
test_event2(&event2
);
226 test_event2
.set_is_char(true);
227 NativeWebKeyboardEvent
char_event(event2
);
228 SendNativeKeyEvent(char_event
);
230 xevent
.InitKeyEvent(ui::ET_KEY_RELEASED
,
231 static_cast<ui::KeyboardCode
>(key_code
),
233 ui::KeyEvent
event3(xevent
);
234 NativeWebKeyboardEvent
keyup_event(event3
);
235 SendNativeKeyEvent(keyup_event
);
237 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
239 output
->assign(1, static_cast<base::char16
>(c
));
241 #elif defined(USE_OZONE)
242 const int flags
= ConvertMockKeyboardModifier(modifiers
);
244 ui::KeyEvent
keydown_event(ui::ET_KEY_PRESSED
,
245 static_cast<ui::KeyboardCode
>(key_code
),
247 NativeWebKeyboardEvent
keydown_web_event(keydown_event
);
248 SendNativeKeyEvent(keydown_web_event
);
250 ui::KeyEvent
char_event(keydown_event
.GetCharacter(),
251 static_cast<ui::KeyboardCode
>(key_code
),
253 NativeWebKeyboardEvent
char_web_event(char_event
);
254 SendNativeKeyEvent(char_web_event
);
256 ui::KeyEvent
keyup_event(ui::ET_KEY_RELEASED
,
257 static_cast<ui::KeyboardCode
>(key_code
),
259 NativeWebKeyboardEvent
keyup_web_event(keyup_event
);
260 SendNativeKeyEvent(keyup_web_event
);
262 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
264 output
->assign(1, static_cast<base::char16
>(c
));
272 void EnablePreferredSizeMode() {
273 view()->OnEnablePreferredSizeChangedMode();
276 const gfx::Size
& GetPreferredSize() {
277 view()->CheckPreferredSize();
278 return view()->preferred_size_
;
281 void SetZoomLevel(double level
) {
282 view()->OnSetZoomLevelForView(false, level
);
286 scoped_ptr
<MockKeyboard
> mock_keyboard_
;
289 TEST_F(RenderViewImplTest
, SaveImageFromDataURL
) {
290 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
291 ViewHostMsg_SaveImageFromDataURL::ID
);
293 render_thread_
->sink().ClearMessages();
295 const std::string image_data_url
=
296 "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
298 view()->saveImageFromDataURL(WebString::fromUTF8(image_data_url
));
299 ProcessPendingMessages();
300 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
301 ViewHostMsg_SaveImageFromDataURL::ID
);
304 ViewHostMsg_SaveImageFromDataURL::Param param1
;
305 ViewHostMsg_SaveImageFromDataURL::Read(msg2
, ¶m1
);
306 EXPECT_EQ(get
<1>(param1
).length(), image_data_url
.length());
307 EXPECT_EQ(get
<1>(param1
), image_data_url
);
309 ProcessPendingMessages();
310 render_thread_
->sink().ClearMessages();
312 const std::string
large_data_url(1024 * 1024 * 10 - 1, 'd');
314 view()->saveImageFromDataURL(WebString::fromUTF8(large_data_url
));
315 ProcessPendingMessages();
316 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
317 ViewHostMsg_SaveImageFromDataURL::ID
);
320 ViewHostMsg_SaveImageFromDataURL::Param param2
;
321 ViewHostMsg_SaveImageFromDataURL::Read(msg3
, ¶m2
);
322 EXPECT_EQ(get
<1>(param2
).length(), large_data_url
.length());
323 EXPECT_EQ(get
<1>(param2
), large_data_url
);
325 ProcessPendingMessages();
326 render_thread_
->sink().ClearMessages();
328 const std::string
exceeded_data_url(1024 * 1024 * 10 + 1, 'd');
330 view()->saveImageFromDataURL(WebString::fromUTF8(exceeded_data_url
));
331 ProcessPendingMessages();
332 const IPC::Message
* msg4
= render_thread_
->sink().GetFirstMessageMatching(
333 ViewHostMsg_SaveImageFromDataURL::ID
);
337 // Test that we get form state change notifications when input fields change.
338 TEST_F(RenderViewImplTest
, DISABLED_OnNavStateChanged
) {
339 // Don't want any delay for form state sync changes. This will still post a
340 // message so updates will get coalesced, but as soon as we spin the message
341 // loop, it will generate an update.
342 view()->set_send_content_state_immediately(true);
344 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
346 // We should NOT have gotten a form state change notification yet.
347 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
348 ViewHostMsg_UpdateState::ID
));
349 render_thread_
->sink().ClearMessages();
351 // Change the value of the input. We should have gotten an update state
352 // notification. We need to spin the message loop to catch this update.
353 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';");
354 ProcessPendingMessages();
355 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
356 ViewHostMsg_UpdateState::ID
));
359 TEST_F(RenderViewImplTest
, OnNavigationHttpPost
) {
360 FrameMsg_Navigate_Params nav_params
;
362 // An http url will trigger a resource load so cannot be used here.
363 nav_params
.common_params
.url
= GURL("data:text/html,<div>Page</div>");
364 nav_params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
365 nav_params
.common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
366 nav_params
.page_id
= -1;
367 nav_params
.is_post
= true;
368 nav_params
.commit_params
.browser_navigation_start
=
369 base::TimeTicks::FromInternalValue(1);
372 const unsigned char* raw_data
= reinterpret_cast<const unsigned char*>(
374 const unsigned int length
= 11;
375 const std::vector
<unsigned char> post_data(raw_data
, raw_data
+ length
);
376 nav_params
.browser_initiated_post_data
= post_data
;
378 frame()->OnNavigate(nav_params
);
379 ProcessPendingMessages();
381 const IPC::Message
* frame_navigate_msg
=
382 render_thread_
->sink().GetUniqueMessageMatching(
383 FrameHostMsg_DidCommitProvisionalLoad::ID
);
384 EXPECT_TRUE(frame_navigate_msg
);
386 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params
;
387 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
389 EXPECT_TRUE(get
<0>(host_nav_params
).is_post
);
391 // Check post data sent to browser matches
392 EXPECT_TRUE(get
<0>(host_nav_params
).page_state
.IsValid());
393 scoped_ptr
<HistoryEntry
> entry
=
394 PageStateToHistoryEntry(get
<0>(host_nav_params
).page_state
);
395 blink::WebHTTPBody body
= entry
->root().httpBody();
396 blink::WebHTTPBody::Element element
;
397 bool successful
= body
.elementAt(0, element
);
398 EXPECT_TRUE(successful
);
399 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData
, element
.type
);
400 EXPECT_EQ(length
, element
.data
.size());
401 EXPECT_EQ(0, memcmp(raw_data
, element
.data
.data(), length
));
404 TEST_F(RenderViewImplTest
, DecideNavigationPolicy
) {
405 WebUITestWebUIControllerFactory factory
;
406 WebUIControllerFactory::RegisterFactory(&factory
);
409 state
.set_navigation_state(NavigationState::CreateContentInitiated());
411 // Navigations to normal HTTP URLs can be handled locally.
412 blink::WebURLRequest
request(GURL("http://foo.com"));
413 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
414 policy_info
.frame
= GetMainFrame();
415 policy_info
.extraData
= &state
;
416 policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
417 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
418 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
420 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab
, policy
);
422 // Verify that form posts to WebUI URLs will be sent to the browser process.
423 blink::WebURLRequest
form_request(GURL("chrome://foo"));
424 blink::WebFrameClient::NavigationPolicyInfo
form_policy_info(form_request
);
425 form_policy_info
.frame
= GetMainFrame();
426 form_policy_info
.extraData
= &state
;
427 form_policy_info
.navigationType
= blink::WebNavigationTypeFormSubmitted
;
428 form_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
429 form_request
.setHTTPMethod("POST");
430 policy
= frame()->decidePolicyForNavigation(form_policy_info
);
431 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
433 // Verify that popup links to WebUI URLs also are sent to browser.
434 blink::WebURLRequest
popup_request(GURL("chrome://foo"));
435 blink::WebFrameClient::NavigationPolicyInfo
popup_policy_info(popup_request
);
436 popup_policy_info
.frame
= GetMainFrame();
437 popup_policy_info
.extraData
= &state
;
438 popup_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
439 popup_policy_info
.defaultPolicy
= blink::WebNavigationPolicyNewForegroundTab
;
440 policy
= frame()->decidePolicyForNavigation(popup_policy_info
);
441 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
444 TEST_F(RenderViewImplTest
, DecideNavigationPolicyHandlesAllTopLevel
) {
446 state
.set_navigation_state(NavigationState::CreateContentInitiated());
448 RendererPreferences prefs
= view()->renderer_preferences();
449 prefs
.browser_handles_all_top_level_requests
= true;
450 view()->OnSetRendererPrefs(prefs
);
452 const blink::WebNavigationType kNavTypes
[] = {
453 blink::WebNavigationTypeLinkClicked
,
454 blink::WebNavigationTypeFormSubmitted
,
455 blink::WebNavigationTypeBackForward
,
456 blink::WebNavigationTypeReload
,
457 blink::WebNavigationTypeFormResubmitted
,
458 blink::WebNavigationTypeOther
,
461 blink::WebURLRequest
request(GURL("http://foo.com"));
462 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
463 policy_info
.frame
= GetMainFrame();
464 policy_info
.extraData
= &state
;
465 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
467 for (size_t i
= 0; i
< arraysize(kNavTypes
); ++i
) {
468 policy_info
.navigationType
= kNavTypes
[i
];
470 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
472 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
476 TEST_F(RenderViewImplTest
, DecideNavigationPolicyForWebUI
) {
477 // Enable bindings to simulate a WebUI view.
478 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI
);
481 state
.set_navigation_state(NavigationState::CreateContentInitiated());
483 // Navigations to normal HTTP URLs will be sent to browser process.
484 blink::WebURLRequest
request(GURL("http://foo.com"));
485 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
486 policy_info
.frame
= GetMainFrame();
487 policy_info
.extraData
= &state
;
488 policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
489 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
491 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
493 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
495 // Navigations to WebUI URLs will also be sent to browser process.
496 blink::WebURLRequest
webui_request(GURL("chrome://foo"));
497 blink::WebFrameClient::NavigationPolicyInfo
webui_policy_info(webui_request
);
498 webui_policy_info
.frame
= GetMainFrame();
499 webui_policy_info
.extraData
= &state
;
500 webui_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
501 webui_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
502 policy
= frame()->decidePolicyForNavigation(webui_policy_info
);
503 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
505 // Verify that form posts to data URLs will be sent to the browser process.
506 blink::WebURLRequest
data_request(GURL("data:text/html,foo"));
507 blink::WebFrameClient::NavigationPolicyInfo
data_policy_info(data_request
);
508 data_policy_info
.frame
= GetMainFrame();
509 data_policy_info
.extraData
= &state
;
510 data_policy_info
.navigationType
= blink::WebNavigationTypeFormSubmitted
;
511 data_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
512 data_request
.setHTTPMethod("POST");
513 policy
= frame()->decidePolicyForNavigation(data_policy_info
);
514 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
516 // Verify that a popup that creates a view first and then navigates to a
517 // normal HTTP URL will be sent to the browser process, even though the
518 // new view does not have any enabled_bindings_.
519 blink::WebURLRequest
popup_request(GURL("http://foo.com"));
520 blink::WebView
* new_web_view
= view()->createView(
521 GetMainFrame(), popup_request
, blink::WebWindowFeatures(), "foo",
522 blink::WebNavigationPolicyNewForegroundTab
, false);
523 RenderViewImpl
* new_view
= RenderViewImpl::FromWebView(new_web_view
);
524 blink::WebFrameClient::NavigationPolicyInfo
popup_policy_info(popup_request
);
525 popup_policy_info
.frame
= new_web_view
->mainFrame()->toWebLocalFrame();
526 popup_policy_info
.extraData
= &state
;
527 popup_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
528 popup_policy_info
.defaultPolicy
= blink::WebNavigationPolicyNewForegroundTab
;
529 policy
= static_cast<RenderFrameImpl
*>(new_view
->GetMainRenderFrame())->
530 decidePolicyForNavigation(popup_policy_info
);
531 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
533 // Clean up after the new view so we don't leak it.
538 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
539 // already swapped out. http://crbug.com/93427.
540 TEST_F(RenderViewImplTest
, SendSwapOutACK
) {
541 LoadHTML("<div>Page A</div>");
542 int initial_page_id
= view_page_id();
544 // Increment the ref count so that we don't exit when swapping out.
545 RenderProcess::current()->AddRefProcess();
547 // Respond to a swap out request.
548 view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId
, true,
549 content::FrameReplicationState());
551 // Ensure the swap out commits synchronously.
552 EXPECT_NE(initial_page_id
, view_page_id());
554 // Check for a valid OnSwapOutACK.
555 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
556 FrameHostMsg_SwapOut_ACK::ID
);
559 // It is possible to get another swap out request. Ensure that we send
560 // an ACK, even if we don't have to do anything else.
561 render_thread_
->sink().ClearMessages();
562 view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId
, false,
563 content::FrameReplicationState());
564 const IPC::Message
* msg2
= render_thread_
->sink().GetUniqueMessageMatching(
565 FrameHostMsg_SwapOut_ACK::ID
);
568 // If we navigate back to this RenderView, ensure we don't send a state
569 // update for the swapped out URL. (http://crbug.com/72235)
570 FrameMsg_Navigate_Params nav_params
;
571 nav_params
.common_params
.url
= GURL("data:text/html,<div>Page B</div>");
572 nav_params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
573 nav_params
.common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
574 nav_params
.current_history_list_length
= 1;
575 nav_params
.current_history_list_offset
= 0;
576 nav_params
.pending_history_list_offset
= 1;
577 nav_params
.page_id
= -1;
578 nav_params
.commit_params
.browser_navigation_start
=
579 base::TimeTicks::FromInternalValue(1);
580 frame()->OnNavigate(nav_params
);
581 ProcessPendingMessages();
582 const IPC::Message
* msg3
= render_thread_
->sink().GetUniqueMessageMatching(
583 ViewHostMsg_UpdateState::ID
);
587 // Ensure the RenderViewImpl reloads the previous page if a reload request
588 // arrives while it is showing swappedout://. http://crbug.com/143155.
589 TEST_F(RenderViewImplTest
, ReloadWhileSwappedOut
) {
591 LoadHTML("<div>Page A</div>");
593 // Load page B, which will trigger an UpdateState message for page A.
594 LoadHTML("<div>Page B</div>");
596 // Check for a valid UpdateState message for page A.
597 ProcessPendingMessages();
598 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
599 ViewHostMsg_UpdateState::ID
);
601 ViewHostMsg_UpdateState::Param params
;
602 ViewHostMsg_UpdateState::Read(msg_A
, ¶ms
);
603 int page_id_A
= get
<0>(params
);
604 PageState state_A
= get
<1>(params
);
605 EXPECT_EQ(1, page_id_A
);
606 render_thread_
->sink().ClearMessages();
608 // Back to page A (page_id 1) and commit.
609 FrameMsg_Navigate_Params params_A
;
610 params_A
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
611 params_A
.common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
612 params_A
.current_history_list_length
= 2;
613 params_A
.current_history_list_offset
= 1;
614 params_A
.pending_history_list_offset
= 0;
615 params_A
.page_id
= 1;
616 params_A
.commit_params
.page_state
= state_A
;
617 params_A
.commit_params
.browser_navigation_start
=
618 base::TimeTicks::FromInternalValue(1);
619 frame()->OnNavigate(params_A
);
620 ProcessPendingMessages();
622 // Respond to a swap out request.
623 view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId
, true,
624 content::FrameReplicationState());
626 // Check for a OnSwapOutACK.
627 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
628 FrameHostMsg_SwapOut_ACK::ID
);
630 render_thread_
->sink().ClearMessages();
632 // It is possible to get a reload request at this point, containing the
633 // params.page_state of the initial page (e.g., if the new page fails the
634 // provisional load in the renderer process, after we unload the old page).
635 // Ensure the old page gets reloaded, not swappedout://.
636 FrameMsg_Navigate_Params nav_params
;
637 nav_params
.common_params
.url
= GURL("data:text/html,<div>Page A</div>");
638 nav_params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::RELOAD
;
639 nav_params
.common_params
.transition
= ui::PAGE_TRANSITION_RELOAD
;
640 nav_params
.current_history_list_length
= 2;
641 nav_params
.current_history_list_offset
= 0;
642 nav_params
.pending_history_list_offset
= 0;
643 nav_params
.page_id
= 1;
644 nav_params
.commit_params
.page_state
= state_A
;
645 nav_params
.commit_params
.browser_navigation_start
=
646 base::TimeTicks::FromInternalValue(1);
647 frame()->OnNavigate(nav_params
);
648 ProcessPendingMessages();
650 // Verify page A committed, not swappedout://.
651 const IPC::Message
* frame_navigate_msg
=
652 render_thread_
->sink().GetUniqueMessageMatching(
653 FrameHostMsg_DidCommitProvisionalLoad::ID
);
654 EXPECT_TRUE(frame_navigate_msg
);
656 // Read URL out of the parent trait of the params object.
657 FrameHostMsg_DidCommitProvisionalLoad::Param commit_params
;
658 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
660 EXPECT_NE(GURL("swappedout://"), get
<0>(commit_params
).url
);
663 // Verify that security origins are replicated properly to RenderFrameProxies
664 // when swapping out.
665 TEST_F(RenderViewImplTest
, OriginReplicationForSwapOut
) {
666 // This test should only run with --site-per-process, since origin
667 // replication only happens in that mode.
668 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
669 switches::kSitePerProcess
))
673 "Hello <iframe src='data:text/html,frame 1'></iframe>"
674 "<iframe src='data:text/html,frame 2'></iframe>");
675 WebFrame
* web_frame
= frame()->GetWebFrame();
676 RenderFrameImpl
* child_frame
= static_cast<RenderFrameImpl
*>(
677 RenderFrame::FromWebFrame(web_frame
->firstChild()));
679 // Swap the child frame out and pass a serialized origin to be set for
681 content::FrameReplicationState replication_state
;
682 replication_state
.origin
= url::Origin("http://foo.com");
683 child_frame
->OnSwapOut(kProxyRoutingId
, true, replication_state
);
685 // The child frame should now be a WebRemoteFrame.
686 EXPECT_TRUE(web_frame
->firstChild()->isWebRemoteFrame());
688 // Expect the origin to be updated properly.
689 blink::WebSecurityOrigin origin
= web_frame
->firstChild()->securityOrigin();
690 EXPECT_EQ(origin
.toString(),
691 WebString::fromUTF8(replication_state
.origin
.string()));
693 // Now, swap out the second frame using a unique origin and verify that it is
694 // replicated correctly.
695 replication_state
.origin
= url::Origin();
696 RenderFrameImpl
* child_frame2
= static_cast<RenderFrameImpl
*>(
697 RenderFrame::FromWebFrame(web_frame
->lastChild()));
698 child_frame2
->OnSwapOut(kProxyRoutingId
+ 1, true, replication_state
);
699 EXPECT_TRUE(web_frame
->lastChild()->isWebRemoteFrame());
700 EXPECT_TRUE(web_frame
->lastChild()->securityOrigin().isUnique());
703 // Test that we get the correct UpdateState message when we go back twice
704 // quickly without committing. Regression test for http://crbug.com/58082.
705 // Disabled: http://crbug.com/157357 .
706 TEST_F(RenderViewImplTest
, DISABLED_LastCommittedUpdateState
) {
708 LoadHTML("<div>Page A</div>");
710 // Load page B, which will trigger an UpdateState message for page A.
711 LoadHTML("<div>Page B</div>");
713 // Check for a valid UpdateState message for page A.
714 ProcessPendingMessages();
715 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
716 ViewHostMsg_UpdateState::ID
);
718 ViewHostMsg_UpdateState::Param param
;
719 ViewHostMsg_UpdateState::Read(msg_A
, ¶m
);
720 int page_id_A
= get
<0>(param
);
721 PageState state_A
= get
<1>(param
);
722 EXPECT_EQ(1, page_id_A
);
723 render_thread_
->sink().ClearMessages();
725 // Load page C, which will trigger an UpdateState message for page B.
726 LoadHTML("<div>Page C</div>");
728 // Check for a valid UpdateState for page B.
729 ProcessPendingMessages();
730 const IPC::Message
* msg_B
= render_thread_
->sink().GetUniqueMessageMatching(
731 ViewHostMsg_UpdateState::ID
);
733 ViewHostMsg_UpdateState::Read(msg_B
, ¶m
);
734 int page_id_B
= get
<0>(param
);
735 PageState state_B
= get
<1>(param
);
736 EXPECT_EQ(2, page_id_B
);
737 EXPECT_NE(state_A
, state_B
);
738 render_thread_
->sink().ClearMessages();
740 // Load page D, which will trigger an UpdateState message for page C.
741 LoadHTML("<div>Page D</div>");
743 // Check for a valid UpdateState for page C.
744 ProcessPendingMessages();
745 const IPC::Message
* msg_C
= render_thread_
->sink().GetUniqueMessageMatching(
746 ViewHostMsg_UpdateState::ID
);
748 ViewHostMsg_UpdateState::Read(msg_C
, ¶m
);
749 int page_id_C
= get
<0>(param
);
750 PageState state_C
= get
<1>(param
);
751 EXPECT_EQ(3, page_id_C
);
752 EXPECT_NE(state_B
, state_C
);
753 render_thread_
->sink().ClearMessages();
755 // Go back to C and commit, preparing for our real test.
756 FrameMsg_Navigate_Params params_C
;
757 params_C
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
758 params_C
.common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
759 params_C
.current_history_list_length
= 4;
760 params_C
.current_history_list_offset
= 3;
761 params_C
.pending_history_list_offset
= 2;
762 params_C
.page_id
= 3;
763 params_C
.commit_params
.page_state
= state_C
;
764 params_C
.commit_params
.browser_navigation_start
=
765 base::TimeTicks::FromInternalValue(1);
766 frame()->OnNavigate(params_C
);
767 ProcessPendingMessages();
768 render_thread_
->sink().ClearMessages();
770 // Go back twice quickly, such that page B does not have a chance to commit.
771 // This leads to two changes to the back/forward list but only one change to
772 // the RenderView's page ID.
774 // Back to page B (page_id 2), without committing.
775 FrameMsg_Navigate_Params params_B
;
776 params_B
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
777 params_B
.common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
778 params_B
.current_history_list_length
= 4;
779 params_B
.current_history_list_offset
= 2;
780 params_B
.pending_history_list_offset
= 1;
781 params_B
.page_id
= 2;
782 params_B
.commit_params
.page_state
= state_B
;
783 params_B
.commit_params
.browser_navigation_start
=
784 base::TimeTicks::FromInternalValue(1);
785 frame()->OnNavigate(params_B
);
787 // Back to page A (page_id 1) and commit.
788 FrameMsg_Navigate_Params params
;
789 params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
790 params
.common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
791 params_B
.current_history_list_length
= 4;
792 params_B
.current_history_list_offset
= 2;
793 params_B
.pending_history_list_offset
= 0;
795 params
.commit_params
.page_state
= state_A
;
796 params
.commit_params
.browser_navigation_start
=
797 base::TimeTicks::FromInternalValue(1);
798 frame()->OnNavigate(params
);
799 ProcessPendingMessages();
801 // Now ensure that the UpdateState message we receive is consistent
802 // and represents page C in both page_id and state.
803 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
804 ViewHostMsg_UpdateState::ID
);
806 ViewHostMsg_UpdateState::Read(msg
, ¶m
);
807 int page_id
= get
<0>(param
);
808 PageState state
= get
<1>(param
);
809 EXPECT_EQ(page_id_C
, page_id
);
810 EXPECT_NE(state_A
, state
);
811 EXPECT_NE(state_B
, state
);
812 EXPECT_EQ(state_C
, state
);
815 // Test that stale back/forward navigations arriving from the browser are
816 // ignored. See http://crbug.com/86758.
817 TEST_F(RenderViewImplTest
, StaleNavigationsIgnored
) {
819 LoadHTML("<div>Page A</div>");
820 EXPECT_EQ(1, view()->history_list_length_
);
821 EXPECT_EQ(0, view()->history_list_offset_
);
823 // Load page B, which will trigger an UpdateState message for page A.
824 LoadHTML("<div>Page B</div>");
825 EXPECT_EQ(2, view()->history_list_length_
);
826 EXPECT_EQ(1, view()->history_list_offset_
);
828 // Check for a valid UpdateState message for page A.
829 ProcessPendingMessages();
830 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
831 ViewHostMsg_UpdateState::ID
);
833 ViewHostMsg_UpdateState::Param param
;
834 ViewHostMsg_UpdateState::Read(msg_A
, ¶m
);
835 int page_id_A
= get
<0>(param
);
836 PageState state_A
= get
<1>(param
);
837 EXPECT_EQ(1, page_id_A
);
838 render_thread_
->sink().ClearMessages();
840 // Back to page A (page_id 1) and commit.
841 FrameMsg_Navigate_Params params_A
;
842 params_A
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
843 params_A
.common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
844 params_A
.current_history_list_length
= 2;
845 params_A
.current_history_list_offset
= 1;
846 params_A
.pending_history_list_offset
= 0;
847 params_A
.page_id
= 1;
848 params_A
.commit_params
.page_state
= state_A
;
849 params_A
.commit_params
.browser_navigation_start
=
850 base::TimeTicks::FromInternalValue(1);
851 frame()->OnNavigate(params_A
);
852 ProcessPendingMessages();
854 // A new navigation commits, clearing the forward history.
855 LoadHTML("<div>Page C</div>");
856 EXPECT_EQ(2, view()->history_list_length_
);
857 EXPECT_EQ(1, view()->history_list_offset_
);
858 EXPECT_EQ(3, view()->page_id_
); // page C is now page id 3
860 // The browser then sends a stale navigation to B, which should be ignored.
861 FrameMsg_Navigate_Params params_B
;
862 params_B
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
863 params_B
.common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
864 params_B
.current_history_list_length
= 2;
865 params_B
.current_history_list_offset
= 0;
866 params_B
.pending_history_list_offset
= 1;
867 params_B
.page_id
= 2;
868 params_B
.commit_params
.page_state
=
869 state_A
; // Doesn't matter, just has to be present.
870 params_B
.commit_params
.browser_navigation_start
=
871 base::TimeTicks::FromInternalValue(1);
872 frame()->OnNavigate(params_B
);
874 // State should be unchanged.
875 EXPECT_EQ(2, view()->history_list_length_
);
876 EXPECT_EQ(1, view()->history_list_offset_
);
877 EXPECT_EQ(3, view()->page_id_
); // page C, not page B
879 // Check for a valid DidDropNavigation message.
880 ProcessPendingMessages();
881 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
882 FrameHostMsg_DidDropNavigation::ID
);
884 render_thread_
->sink().ClearMessages();
887 // Test that our IME backend sends a notification message when the input focus
889 TEST_F(RenderViewImplTest
, OnImeTypeChanged
) {
890 // Enable our IME backend code.
891 view()->OnSetInputMethodActive(true);
893 // Load an HTML page consisting of two input fields.
894 view()->set_send_content_state_immediately(true);
899 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
900 "<input id=\"test2\" type=\"password\"></input>"
901 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
902 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
903 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
904 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
906 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
908 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
909 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
910 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
911 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
912 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
913 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
914 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
915 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
918 render_thread_
->sink().ClearMessages();
920 struct InputModeTestCase
{
921 const char* input_id
;
922 ui::TextInputMode expected_mode
;
924 static const InputModeTestCase kInputModeTestCases
[] = {
925 {"test1", ui::TEXT_INPUT_MODE_DEFAULT
},
926 {"test3", ui::TEXT_INPUT_MODE_VERBATIM
},
927 {"test4", ui::TEXT_INPUT_MODE_LATIN
},
928 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME
},
929 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE
},
930 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN
},
931 {"test8", ui::TEXT_INPUT_MODE_KANA
},
932 {"test9", ui::TEXT_INPUT_MODE_KATAKANA
},
933 {"test10", ui::TEXT_INPUT_MODE_NUMERIC
},
934 {"test11", ui::TEXT_INPUT_MODE_TEL
},
935 {"test12", ui::TEXT_INPUT_MODE_EMAIL
},
936 {"test13", ui::TEXT_INPUT_MODE_URL
},
937 {"test14", ui::TEXT_INPUT_MODE_DEFAULT
},
938 {"test15", ui::TEXT_INPUT_MODE_VERBATIM
},
941 const int kRepeatCount
= 10;
942 for (int i
= 0; i
< kRepeatCount
; i
++) {
943 // Move the input focus to the first <input> element, where we should
945 ExecuteJavaScript("document.getElementById('test1').focus();");
946 ProcessPendingMessages();
947 render_thread_
->sink().ClearMessages();
949 // Update the IME status and verify if our IME backend sends an IPC message
951 view()->UpdateTextInputType();
952 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
953 EXPECT_TRUE(msg
!= NULL
);
954 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
955 ViewHostMsg_TextInputTypeChanged::Param params
;
956 ViewHostMsg_TextInputTypeChanged::Read(msg
, ¶ms
);
957 ui::TextInputType type
= get
<0>(params
);
958 ui::TextInputMode input_mode
= get
<1>(params
);
959 bool can_compose_inline
= get
<2>(params
);
960 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT
, type
);
961 EXPECT_EQ(true, can_compose_inline
);
963 // Move the input focus to the second <input> element, where we should
965 ExecuteJavaScript("document.getElementById('test2').focus();");
966 ProcessPendingMessages();
967 render_thread_
->sink().ClearMessages();
969 // Update the IME status and verify if our IME backend sends an IPC message
970 // to de-activate IMEs.
971 view()->UpdateTextInputType();
972 msg
= render_thread_
->sink().GetMessageAt(0);
973 EXPECT_TRUE(msg
!= NULL
);
974 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
975 ViewHostMsg_TextInputTypeChanged::Read(msg
, & params
);
976 type
= get
<0>(params
);
977 input_mode
= get
<1>(params
);
978 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD
, type
);
980 for (size_t i
= 0; i
< arraysize(kInputModeTestCases
); i
++) {
981 const InputModeTestCase
* test_case
= &kInputModeTestCases
[i
];
982 std::string javascript
=
983 base::StringPrintf("document.getElementById('%s').focus();",
984 test_case
->input_id
);
985 // Move the input focus to the target <input> element, where we should
987 ExecuteJavaScriptAndReturnIntValue(base::ASCIIToUTF16(javascript
), NULL
);
988 ProcessPendingMessages();
989 render_thread_
->sink().ClearMessages();
991 // Update the IME status and verify if our IME backend sends an IPC
992 // message to activate IMEs.
993 view()->UpdateTextInputType();
994 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
995 EXPECT_TRUE(msg
!= NULL
);
996 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
997 ViewHostMsg_TextInputTypeChanged::Read(msg
, & params
);
998 type
= get
<0>(params
);
999 input_mode
= get
<1>(params
);
1000 EXPECT_EQ(test_case
->expected_mode
, input_mode
);
1005 // Test that our IME backend can compose CJK words.
1006 // Our IME front-end sends many platform-independent messages to the IME backend
1007 // while it composes CJK words. This test sends the minimal messages captured
1008 // on my local environment directly to the IME backend to verify if the backend
1009 // can compose CJK words without any problems.
1010 // This test uses an array of command sets because an IME composotion does not
1011 // only depends on IME events, but also depends on window events, e.g. moving
1012 // the window focus while composing a CJK text. To handle such complicated
1013 // cases, this test should not only call IME-related functions in the
1014 // RenderWidget class, but also call some RenderWidget members, e.g.
1015 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc.
1016 TEST_F(RenderViewImplTest
, ImeComposition
) {
1022 IME_CONFIRMCOMPOSITION
,
1023 IME_CANCELCOMPOSITION
1028 int selection_start
;
1030 const wchar_t* ime_string
;
1031 const wchar_t* result
;
1033 static const ImeMessage kImeMessages
[] = {
1034 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
1035 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1036 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1037 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1038 {IME_SETCOMPOSITION
, false, 1, 1, L
"n", L
"n"},
1039 {IME_SETCOMPOSITION
, false, 2, 2, L
"ni", L
"ni"},
1040 {IME_SETCOMPOSITION
, false, 3, 3, L
"nih", L
"nih"},
1041 {IME_SETCOMPOSITION
, false, 4, 4, L
"niha", L
"niha"},
1042 {IME_SETCOMPOSITION
, false, 5, 5, L
"nihao", L
"nihao"},
1043 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"\x4F60\x597D", L
"\x4F60\x597D"},
1044 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
1045 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1046 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1047 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1048 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xFF4B", L
"\xFF4B"},
1049 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x304B", L
"\x304B"},
1050 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x304B\xFF4E", L
"\x304B\xFF4E"},
1051 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\xFF4A",
1052 L
"\x304B\x3093\xFF4A"},
1053 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\x3058",
1054 L
"\x304B\x3093\x3058"},
1055 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x611F\x3058", L
"\x611F\x3058"},
1056 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x6F22\x5B57", L
"\x6F22\x5B57"},
1057 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1058 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1059 // Scenario 3: input a Korean word with Microsot 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, 0, 1, L
"\x3147", L
"\x3147"},
1064 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC544", L
"\xC544"},
1065 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC548", L
"\xC548"},
1066 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1067 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3134", L
"\xC548\x3134"},
1068 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB140", L
"\xC548\xB140"},
1069 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1070 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1071 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1072 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548\xB155"},
1075 for (size_t i
= 0; i
< arraysize(kImeMessages
); i
++) {
1076 const ImeMessage
* ime_message
= &kImeMessages
[i
];
1077 switch (ime_message
->command
) {
1078 case IME_INITIALIZE
:
1079 // Load an HTML page consisting of a content-editable <div> element,
1080 // and move the input focus to the <div> element, where we can use
1082 view()->OnSetInputMethodActive(ime_message
->enable
);
1083 view()->set_send_content_state_immediately(true);
1088 "<div id=\"test1\" contenteditable=\"true\"></div>"
1091 ExecuteJavaScript("document.getElementById('test1').focus();");
1094 case IME_SETINPUTMODE
:
1095 // Activate (or deactivate) our IME back-end.
1096 view()->OnSetInputMethodActive(ime_message
->enable
);
1100 // Update the window focus.
1101 view()->OnSetFocus(ime_message
->enable
);
1104 case IME_SETCOMPOSITION
:
1105 view()->OnImeSetComposition(
1106 base::WideToUTF16(ime_message
->ime_string
),
1107 std::vector
<blink::WebCompositionUnderline
>(),
1108 ime_message
->selection_start
,
1109 ime_message
->selection_end
);
1112 case IME_CONFIRMCOMPOSITION
:
1113 view()->OnImeConfirmComposition(
1114 base::WideToUTF16(ime_message
->ime_string
),
1115 gfx::Range::InvalidRange(),
1119 case IME_CANCELCOMPOSITION
:
1120 view()->OnImeSetComposition(
1122 std::vector
<blink::WebCompositionUnderline
>(),
1127 // Update the status of our IME back-end.
1128 // TODO(hbono): we should verify messages to be sent from the back-end.
1129 view()->UpdateTextInputType();
1130 ProcessPendingMessages();
1131 render_thread_
->sink().ClearMessages();
1133 if (ime_message
->result
) {
1134 // Retrieve the content of this page and compare it with the expected
1136 const int kMaxOutputCharacters
= 128;
1137 base::string16 output
=
1138 GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1139 EXPECT_EQ(base::WideToUTF16(ime_message
->result
), output
);
1144 // Test that the RenderView::OnSetTextDirection() function can change the text
1145 // direction of the selected input element.
1146 TEST_F(RenderViewImplTest
, OnSetTextDirection
) {
1147 // Load an HTML page consisting of a <textarea> element and a <div> element.
1148 // This test changes the text direction of the <textarea> element, and
1149 // writes the values of its 'dir' attribute and its 'direction' property to
1150 // verify that the text direction is changed.
1151 view()->set_send_content_state_immediately(true);
1156 "<textarea id=\"test\"></textarea>"
1157 "<div id=\"result\" contenteditable=\"true\"></div>"
1160 render_thread_
->sink().ClearMessages();
1162 static const struct {
1163 WebTextDirection direction
;
1164 const wchar_t* expected_result
;
1165 } kTextDirection
[] = {
1166 { blink::WebTextDirectionRightToLeft
, L
"\x000A" L
"rtl,rtl" },
1167 { blink::WebTextDirectionLeftToRight
, L
"\x000A" L
"ltr,ltr" },
1169 for (size_t i
= 0; i
< arraysize(kTextDirection
); ++i
) {
1170 // Set the text direction of the <textarea> element.
1171 ExecuteJavaScript("document.getElementById('test').focus();");
1172 view()->OnSetTextDirection(kTextDirection
[i
].direction
);
1174 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1175 // property to the <div> element.
1176 ExecuteJavaScript("var result = document.getElementById('result');"
1177 "var node = document.getElementById('test');"
1178 "var style = getComputedStyle(node, null);"
1179 "result.innerText ="
1180 " node.getAttribute('dir') + ',' +"
1181 " style.getPropertyValue('direction');");
1183 // Copy the document content to std::wstring and compare with the
1185 const int kMaxOutputCharacters
= 16;
1186 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1187 EXPECT_EQ(base::WideToUTF16(kTextDirection
[i
].expected_result
), output
);
1191 // see http://crbug.com/238750
1193 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent
1195 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent
1198 // Test that we can receive correct DOM events when we send input events
1199 // through the RenderWidget::OnHandleInputEvent() function.
1200 TEST_F(RenderViewImplTest
, MAYBE_OnHandleKeyboardEvent
) {
1201 #if !defined(OS_MACOSX)
1202 // Load an HTML page consisting of one <input> element and three
1203 // contentediable <div> elements.
1204 // The <input> element is used for sending keyboard events, and the <div>
1205 // elements are used for writing DOM events in the following format:
1206 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1207 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1208 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1209 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1210 view()->set_send_content_state_immediately(true);
1214 "<script type='text/javascript' language='javascript'>"
1215 "function OnKeyEvent(ev) {"
1216 " var result = document.getElementById(ev.type);"
1217 " result.innerText ="
1218 " (ev.which || ev.keyCode) + ',' +"
1219 " ev.shiftKey + ',' +"
1220 " ev.ctrlKey + ',' +"
1227 "<input id='test' type='text'"
1228 " onkeydown='return OnKeyEvent(event);'"
1229 " onkeypress='return OnKeyEvent(event);'"
1230 " onkeyup='return OnKeyEvent(event);'>"
1232 "<div id='keydown' contenteditable='true'>"
1234 "<div id='keypress' contenteditable='true'>"
1236 "<div id='keyup' contenteditable='true'>"
1240 ExecuteJavaScript("document.getElementById('test').focus();");
1241 render_thread_
->sink().ClearMessages();
1243 static const MockKeyboard::Layout kLayouts
[] = {
1245 // Since we ignore the mock keyboard layout on Linux and instead just use
1246 // the screen's keyboard layout, these trivially pass. They are commented
1247 // out to avoid the illusion that they work.
1248 MockKeyboard::LAYOUT_ARABIC
,
1249 MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1250 MockKeyboard::LAYOUT_FRENCH
,
1251 MockKeyboard::LAYOUT_HEBREW
,
1252 MockKeyboard::LAYOUT_RUSSIAN
,
1254 MockKeyboard::LAYOUT_UNITED_STATES
,
1257 for (size_t i
= 0; i
< arraysize(kLayouts
); ++i
) {
1258 // For each key code, we send three keyboard events.
1259 // * we press only the key;
1260 // * we press the key and a left-shift key, and;
1261 // * we press the key and a right-alt (AltGr) key.
1262 // For each modifiers, we need a string used for formatting its expected
1263 // result. (See the above comment for its format.)
1264 static const struct {
1265 MockKeyboard::Modifiers modifiers
;
1266 const char* expected_result
;
1267 } kModifierData
[] = {
1268 {MockKeyboard::NONE
, "false,false,false"},
1269 {MockKeyboard::LEFT_SHIFT
, "true,false,false"},
1271 {MockKeyboard::RIGHT_ALT
, "false,false,true"},
1275 MockKeyboard::Layout layout
= kLayouts
[i
];
1276 for (size_t j
= 0; j
< arraysize(kModifierData
); ++j
) {
1277 // Virtual key codes used for this test.
1278 static const int kKeyCodes
[] = {
1279 '0', '1', '2', '3', '4', '5', '6', '7',
1280 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1281 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1282 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1288 ui::VKEY_OEM_PERIOD
,
1296 // Not sure how to handle this key on Linux.
1301 MockKeyboard::Modifiers modifiers
= kModifierData
[j
].modifiers
;
1302 for (size_t k
= 0; k
< arraysize(kKeyCodes
); ++k
) {
1303 // Send a keyboard event to the RenderView object.
1304 // We should test a keyboard event only when the given keyboard-layout
1305 // driver is installed in a PC and the driver can assign a Unicode
1306 // charcter for the given tuple (key-code and modifiers).
1307 int key_code
= kKeyCodes
[k
];
1308 base::string16 char_code
;
1309 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1312 // Create an expected result from the virtual-key code, the character
1313 // code, and the modifier-key status.
1314 // We format a string that emulates a DOM-event string produced hy
1315 // our JavaScript function. (See the above comment for the format.)
1316 static char expected_result
[1024];
1317 expected_result
[0] = 0;
1318 base::snprintf(&expected_result
[0],
1319 sizeof(expected_result
),
1320 "\n" // texts in the <input> element
1321 "%d,%s\n" // texts in the first <div> element
1322 "%d,%s\n" // texts in the second <div> element
1323 "%d,%s", // texts in the third <div> element
1324 key_code
, kModifierData
[j
].expected_result
,
1325 static_cast<int>(char_code
[0]),
1326 kModifierData
[j
].expected_result
,
1327 key_code
, kModifierData
[j
].expected_result
);
1329 // Retrieve the text in the test page and compare it with the expected
1330 // text created from a virtual-key code, a character code, and the
1331 // modifier-key status.
1332 const int kMaxOutputCharacters
= 1024;
1333 std::string output
= base::UTF16ToUTF8(
1334 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
1335 EXPECT_EQ(expected_result
, output
);
1344 // Test that our EditorClientImpl class can insert characters when we send
1345 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1346 // This test is for preventing regressions caused only when we use non-US
1347 // keyboards, such as Issue 10846.
1348 // see http://crbug.com/244562
1350 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1352 #define MAYBE_InsertCharacters InsertCharacters
1354 TEST_F(RenderViewImplTest
, MAYBE_InsertCharacters
) {
1355 #if !defined(OS_MACOSX)
1356 static const struct {
1357 MockKeyboard::Layout layout
;
1358 const wchar_t* expected_result
;
1361 // Disabled these keyboard layouts because buildbots do not have their
1362 // keyboard-layout drivers installed.
1363 {MockKeyboard::LAYOUT_ARABIC
,
1364 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1365 L
"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1366 L
"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1367 L
"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1368 L
"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1369 L
"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1370 L
"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1371 L
"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1372 L
"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1373 L
"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1374 L
"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1375 L
"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1376 L
"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1377 L
"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1378 L
"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1379 L
"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1380 L
"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1382 {MockKeyboard::LAYOUT_HEBREW
,
1383 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1384 L
"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1385 L
"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1386 L
"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1387 L
"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1388 L
"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1389 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1390 L
"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1391 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1392 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1393 L
"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1394 L
"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1395 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1396 L
"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1397 L
"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1398 L
"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1399 L
"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1400 L
"\x003b\x005d\x005c\x005b\x002c"
1404 // On Linux, the only way to test alternate keyboard layouts is to change
1405 // the keyboard layout of the whole screen. I'm worried about the side
1406 // effects this may have on the buildbots.
1407 {MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1408 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1409 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1410 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1411 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1412 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1413 L
"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1414 L
"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1415 L
"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1416 L
"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1417 L
"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1418 L
"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1419 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1420 L
"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1421 L
"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1422 L
"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1423 L
"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1426 {MockKeyboard::LAYOUT_FRENCH
,
1427 L
"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1428 L
"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1429 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1430 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1431 L
"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1432 L
"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1433 L
"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1434 L
"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1435 L
"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1436 L
"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1437 L
"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1438 L
"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1439 L
"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1440 L
"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1441 L
"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1442 L
"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1443 L
"\x003b\x003a\x00f9\x0029\x002a\x0021"
1445 {MockKeyboard::LAYOUT_RUSSIAN
,
1446 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1447 L
"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1448 L
"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1449 L
"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1450 L
"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1451 L
"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1452 L
"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1453 L
"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1454 L
"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1455 L
"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1456 L
"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1457 L
"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1458 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1459 L
"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1460 L
"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1461 L
"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1462 L
"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1463 L
"\x0451\x0445\x005c\x044a\x044d"
1465 #endif // defined(OS_WIN)
1466 {MockKeyboard::LAYOUT_UNITED_STATES
,
1467 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1468 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1469 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1470 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1471 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1472 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1473 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1474 L
"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1475 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1476 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1477 L
"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1478 L
"\x003f\x007e\x007b\x007c\x007d\x0022"
1480 // This is ifdefed out for Linux to correspond to the fact that we don't
1481 // test alt+keystroke for now.
1482 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1483 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1484 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1485 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1486 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1487 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1492 for (size_t i
= 0; i
< arraysize(kLayouts
); ++i
) {
1493 // Load an HTML page consisting of one <div> element.
1494 // This <div> element is used by the EditorClientImpl class to insert
1495 // characters received through the RenderWidget::OnHandleInputEvent()
1497 view()->set_send_content_state_immediately(true);
1503 "<div id='test' contenteditable='true'>"
1507 ExecuteJavaScript("document.getElementById('test').focus();");
1508 render_thread_
->sink().ClearMessages();
1510 // For each key code, we send three keyboard events.
1511 // * Pressing only the key;
1512 // * Pressing the key and a left-shift key, and;
1513 // * Pressing the key and a right-alt (AltGr) key.
1514 static const MockKeyboard::Modifiers kModifiers
[] = {
1516 MockKeyboard::LEFT_SHIFT
,
1518 MockKeyboard::RIGHT_ALT
,
1522 MockKeyboard::Layout layout
= kLayouts
[i
].layout
;
1523 for (size_t j
= 0; j
< arraysize(kModifiers
); ++j
) {
1524 // Virtual key codes used for this test.
1525 static const int kKeyCodes
[] = {
1526 '0', '1', '2', '3', '4', '5', '6', '7',
1527 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1528 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1529 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1535 ui::VKEY_OEM_PERIOD
,
1543 // Unclear how to handle this on Linux.
1548 MockKeyboard::Modifiers modifiers
= kModifiers
[j
];
1549 for (size_t k
= 0; k
< arraysize(kKeyCodes
); ++k
) {
1550 // Send a keyboard event to the RenderView object.
1551 // We should test a keyboard event only when the given keyboard-layout
1552 // driver is installed in a PC and the driver can assign a Unicode
1553 // charcter for the given tuple (layout, key-code, and modifiers).
1554 int key_code
= kKeyCodes
[k
];
1555 base::string16 char_code
;
1556 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1561 // Retrieve the text in the test page and compare it with the expected
1562 // text created from a virtual-key code, a character code, and the
1563 // modifier-key status.
1564 const int kMaxOutputCharacters
= 4096;
1565 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1566 EXPECT_EQ(base::WideToUTF16(kLayouts
[i
].expected_result
), output
);
1573 // Crashy, http://crbug.com/53247.
1574 TEST_F(RenderViewImplTest
, DISABLED_DidFailProvisionalLoadWithErrorForError
) {
1575 GetMainFrame()->enableViewSourceMode(true);
1577 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1578 error
.reason
= net::ERR_FILE_NOT_FOUND
;
1579 error
.unreachableURL
= GURL("http://foo");
1580 WebLocalFrame
* web_frame
= GetMainFrame();
1582 // Start a load that will reach provisional state synchronously,
1583 // but won't complete synchronously.
1584 FrameMsg_Navigate_Params params
;
1585 params
.page_id
= -1;
1586 params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1587 params
.common_params
.url
= GURL("data:text/html,test data");
1588 params
.commit_params
.browser_navigation_start
=
1589 base::TimeTicks::FromInternalValue(1);
1590 frame()->OnNavigate(params
);
1592 // An error occurred.
1593 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame
, error
);
1594 // Frame should exit view-source mode.
1595 EXPECT_FALSE(web_frame
->isViewSourceModeEnabled());
1598 TEST_F(RenderViewImplTest
, DidFailProvisionalLoadWithErrorForCancellation
) {
1599 GetMainFrame()->enableViewSourceMode(true);
1601 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1602 error
.reason
= net::ERR_ABORTED
;
1603 error
.unreachableURL
= GURL("http://foo");
1604 WebLocalFrame
* web_frame
= GetMainFrame();
1606 // Start a load that will reach provisional state synchronously,
1607 // but won't complete synchronously.
1608 FrameMsg_Navigate_Params params
;
1609 params
.page_id
= -1;
1610 params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1611 params
.common_params
.url
= GURL("data:text/html,test data");
1612 params
.commit_params
.browser_navigation_start
=
1613 base::TimeTicks::FromInternalValue(1);
1614 frame()->OnNavigate(params
);
1616 // A cancellation occurred.
1617 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame
, error
);
1618 // Frame should stay in view-source mode.
1619 EXPECT_TRUE(web_frame
->isViewSourceModeEnabled());
1622 // Regression test for http://crbug.com/41562
1623 TEST_F(RenderViewImplTest
, UpdateTargetURLWithInvalidURL
) {
1624 const GURL
invalid_gurl("http://");
1625 view()->setMouseOverURL(blink::WebURL(invalid_gurl
));
1626 EXPECT_EQ(invalid_gurl
, view()->target_url_
);
1629 TEST_F(RenderViewImplTest
, SetHistoryLengthAndOffset
) {
1630 // No history to merge; one committed page.
1631 view()->OnSetHistoryOffsetAndLength(0, 1);
1632 EXPECT_EQ(1, view()->history_list_length_
);
1633 EXPECT_EQ(0, view()->history_list_offset_
);
1635 // History of length 1 to merge; one committed page.
1636 view()->OnSetHistoryOffsetAndLength(1, 2);
1637 EXPECT_EQ(2, view()->history_list_length_
);
1638 EXPECT_EQ(1, view()->history_list_offset_
);
1641 TEST_F(RenderViewImplTest
, ContextMenu
) {
1642 LoadHTML("<div>Page A</div>");
1644 // Create a right click in the center of the iframe. (I'm hoping this will
1645 // make this a bit more robust in case of some other formatting or other bug.)
1646 WebMouseEvent mouse_event
;
1647 mouse_event
.type
= WebInputEvent::MouseDown
;
1648 mouse_event
.button
= WebMouseEvent::ButtonRight
;
1649 mouse_event
.x
= 250;
1650 mouse_event
.y
= 250;
1651 mouse_event
.globalX
= 250;
1652 mouse_event
.globalY
= 250;
1654 SendWebMouseEvent(mouse_event
);
1656 // Now simulate the corresponding up event which should display the menu
1657 mouse_event
.type
= WebInputEvent::MouseUp
;
1658 SendWebMouseEvent(mouse_event
);
1660 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
1661 FrameHostMsg_ContextMenu::ID
));
1664 TEST_F(RenderViewImplTest
, TestBackForward
) {
1665 LoadHTML("<div id=pagename>Page A</div>");
1666 PageState page_a_state
=
1667 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1668 int was_page_a
= -1;
1669 base::string16 check_page_a
=
1671 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1672 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1673 EXPECT_EQ(1, was_page_a
);
1675 LoadHTML("<div id=pagename>Page B</div>");
1676 int was_page_b
= -1;
1677 base::string16 check_page_b
=
1679 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1680 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1681 EXPECT_EQ(1, was_page_b
);
1683 PageState back_state
=
1684 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1686 LoadHTML("<div id=pagename>Page C</div>");
1687 int was_page_c
= -1;
1688 base::string16 check_page_c
=
1690 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1691 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1692 EXPECT_EQ(1, was_page_b
);
1694 PageState forward_state
=
1695 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1697 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1698 EXPECT_EQ(1, was_page_b
);
1700 PageState back_state2
=
1701 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1703 GoForward(forward_state
);
1704 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1705 EXPECT_EQ(1, was_page_c
);
1707 GoBack(back_state2
);
1708 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1709 EXPECT_EQ(1, was_page_b
);
1712 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1713 GoBack(page_a_state
);
1714 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1715 EXPECT_EQ(1, was_page_a
);
1717 GoForward(forward_state
);
1718 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1719 EXPECT_EQ(1, was_page_b
);
1722 #if defined(OS_MACOSX) || defined(USE_AURA)
1723 TEST_F(RenderViewImplTest
, GetCompositionCharacterBoundsTest
) {
1726 // http://crbug.com/304193
1727 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
1731 LoadHTML("<textarea id=\"test\"></textarea>");
1732 ExecuteJavaScript("document.getElementById('test').focus();");
1734 const base::string16 empty_string
;
1735 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1736 std::vector
<gfx::Rect
> bounds
;
1737 view()->OnSetFocus(true);
1738 view()->OnSetInputMethodActive(true);
1740 // ASCII composition
1741 const base::string16 ascii_composition
= base::UTF8ToUTF16("aiueo");
1742 view()->OnImeSetComposition(ascii_composition
, empty_underline
, 0, 0);
1743 view()->GetCompositionCharacterBounds(&bounds
);
1744 ASSERT_EQ(ascii_composition
.size(), bounds
.size());
1745 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1746 EXPECT_LT(0, bounds
[i
].width());
1747 view()->OnImeConfirmComposition(
1748 empty_string
, gfx::Range::InvalidRange(), false);
1750 // Non surrogate pair unicode character.
1751 const base::string16 unicode_composition
= base::UTF8ToUTF16(
1752 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1753 view()->OnImeSetComposition(unicode_composition
, empty_underline
, 0, 0);
1754 view()->GetCompositionCharacterBounds(&bounds
);
1755 ASSERT_EQ(unicode_composition
.size(), bounds
.size());
1756 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1757 EXPECT_LT(0, bounds
[i
].width());
1758 view()->OnImeConfirmComposition(
1759 empty_string
, gfx::Range::InvalidRange(), false);
1761 // Surrogate pair character.
1762 const base::string16 surrogate_pair_char
=
1763 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1764 view()->OnImeSetComposition(surrogate_pair_char
,
1768 view()->GetCompositionCharacterBounds(&bounds
);
1769 ASSERT_EQ(surrogate_pair_char
.size(), bounds
.size());
1770 EXPECT_LT(0, bounds
[0].width());
1771 EXPECT_EQ(0, bounds
[1].width());
1772 view()->OnImeConfirmComposition(
1773 empty_string
, gfx::Range::InvalidRange(), false);
1776 const base::string16 surrogate_pair_mixed_composition
=
1777 surrogate_pair_char
+ base::UTF8ToUTF16("\xE3\x81\x82") +
1778 surrogate_pair_char
+ base::UTF8ToUTF16("b") + surrogate_pair_char
;
1779 const size_t utf16_length
= 8UL;
1780 const bool is_surrogate_pair_empty_rect
[8] = {
1781 false, true, false, false, true, false, false, true };
1782 view()->OnImeSetComposition(surrogate_pair_mixed_composition
,
1786 view()->GetCompositionCharacterBounds(&bounds
);
1787 ASSERT_EQ(utf16_length
, bounds
.size());
1788 for (size_t i
= 0; i
< utf16_length
; ++i
) {
1789 if (is_surrogate_pair_empty_rect
[i
]) {
1790 EXPECT_EQ(0, bounds
[i
].width());
1792 EXPECT_LT(0, bounds
[i
].width());
1795 view()->OnImeConfirmComposition(
1796 empty_string
, gfx::Range::InvalidRange(), false);
1800 TEST_F(RenderViewImplTest
, ZoomLimit
) {
1801 const double kMinZoomLevel
= ZoomFactorToZoomLevel(kMinimumZoomFactor
);
1802 const double kMaxZoomLevel
= ZoomFactorToZoomLevel(kMaximumZoomFactor
);
1804 FrameMsg_Navigate_Params params
;
1805 params
.page_id
= -1;
1806 params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1807 params
.commit_params
.browser_navigation_start
=
1808 base::TimeTicks::FromInternalValue(1);
1810 // Verifies navigation to a URL with preset zoom level indeed sets the level.
1811 // Regression test for http://crbug.com/139559, where the level was not
1812 // properly set when it is out of the default zoom limits of WebView.
1813 params
.common_params
.url
= GURL("data:text/html,min_zoomlimit_test");
1814 view()->OnSetZoomLevelForLoadingURL(params
.common_params
.url
, kMinZoomLevel
);
1815 frame()->OnNavigate(params
);
1816 ProcessPendingMessages();
1817 EXPECT_DOUBLE_EQ(kMinZoomLevel
, view()->GetWebView()->zoomLevel());
1819 // It should work even when the zoom limit is temporarily changed in the page.
1820 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
1821 ZoomFactorToZoomLevel(1.0));
1822 params
.common_params
.url
= GURL("data:text/html,max_zoomlimit_test");
1823 view()->OnSetZoomLevelForLoadingURL(params
.common_params
.url
, kMaxZoomLevel
);
1824 frame()->OnNavigate(params
);
1825 ProcessPendingMessages();
1826 EXPECT_DOUBLE_EQ(kMaxZoomLevel
, view()->GetWebView()->zoomLevel());
1829 TEST_F(RenderViewImplTest
, SetEditableSelectionAndComposition
) {
1830 // Load an HTML page consisting of an input field.
1835 "<input id=\"test1\" value=\"some test text hello\"></input>"
1838 ExecuteJavaScript("document.getElementById('test1').focus();");
1839 frame()->OnSetEditableSelectionOffsets(4, 8);
1840 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1841 frame()->OnSetCompositionFromExistingText(7, 10, empty_underline
);
1842 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1843 EXPECT_EQ(4, info
.selectionStart
);
1844 EXPECT_EQ(8, info
.selectionEnd
);
1845 EXPECT_EQ(7, info
.compositionStart
);
1846 EXPECT_EQ(10, info
.compositionEnd
);
1847 frame()->OnUnselect();
1848 info
= view()->webview()->textInputInfo();
1849 EXPECT_EQ(0, info
.selectionStart
);
1850 EXPECT_EQ(0, info
.selectionEnd
);
1854 TEST_F(RenderViewImplTest
, OnExtendSelectionAndDelete
) {
1855 // Load an HTML page consisting of an input field.
1860 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
1863 ExecuteJavaScript("document.getElementById('test1').focus();");
1864 frame()->OnSetEditableSelectionOffsets(10, 10);
1865 frame()->OnExtendSelectionAndDelete(3, 4);
1866 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1867 EXPECT_EQ("abcdefgopqrstuvwxyz", info
.value
);
1868 EXPECT_EQ(7, info
.selectionStart
);
1869 EXPECT_EQ(7, info
.selectionEnd
);
1870 frame()->OnSetEditableSelectionOffsets(4, 8);
1871 frame()->OnExtendSelectionAndDelete(2, 5);
1872 info
= view()->webview()->textInputInfo();
1873 EXPECT_EQ("abuvwxyz", info
.value
);
1874 EXPECT_EQ(2, info
.selectionStart
);
1875 EXPECT_EQ(2, info
.selectionEnd
);
1878 // Test that the navigating specific frames works correctly.
1879 TEST_F(RenderViewImplTest
, NavigateFrame
) {
1881 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
1883 // Navigate the frame only.
1884 FrameMsg_Navigate_Params nav_params
;
1885 nav_params
.common_params
.url
= GURL("data:text/html,world");
1886 nav_params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1887 nav_params
.common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
1888 nav_params
.current_history_list_length
= 1;
1889 nav_params
.current_history_list_offset
= 0;
1890 nav_params
.pending_history_list_offset
= 1;
1891 nav_params
.page_id
= -1;
1892 nav_params
.frame_to_navigate
= "frame";
1893 nav_params
.commit_params
.browser_navigation_start
=
1894 base::TimeTicks::FromInternalValue(1);
1895 frame()->OnNavigate(nav_params
);
1897 RenderFrame::FromWebFrame(frame()->GetWebFrame()->firstChild())).Wait();
1899 // Copy the document content to std::wstring and compare with the
1901 const int kMaxOutputCharacters
= 256;
1902 std::string output
= base::UTF16ToUTF8(
1903 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
1904 EXPECT_EQ(output
, "hello \n\nworld");
1907 // This test ensures that a RenderFrame object is created for the top level
1908 // frame in the RenderView.
1909 TEST_F(RenderViewImplTest
, BasicRenderFrame
) {
1910 EXPECT_TRUE(view()->main_render_frame_
.get());
1913 TEST_F(RenderViewImplTest
, GetSSLStatusOfFrame
) {
1914 LoadHTML("<!DOCTYPE html><html><body></body></html>");
1916 WebLocalFrame
* frame
= GetMainFrame();
1917 SSLStatus ssl_status
= view()->GetSSLStatusOfFrame(frame
);
1918 EXPECT_FALSE(net::IsCertStatusError(ssl_status
.cert_status
));
1920 const_cast<blink::WebURLResponse
&>(frame
->dataSource()->response()).
1922 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS
, 0, 0,
1923 SignedCertificateTimestampIDStatusList()));
1924 ssl_status
= view()->GetSSLStatusOfFrame(frame
);
1925 EXPECT_TRUE(net::IsCertStatusError(ssl_status
.cert_status
));
1928 TEST_F(RenderViewImplTest
, MessageOrderInDidChangeSelection
) {
1929 view()->OnSetInputMethodActive(true);
1930 view()->set_send_content_state_immediately(true);
1931 LoadHTML("<textarea id=\"test\"></textarea>");
1933 view()->handling_input_event_
= true;
1934 ExecuteJavaScript("document.getElementById('test').focus();");
1936 bool is_input_type_called
= false;
1937 bool is_selection_called
= false;
1938 size_t last_input_type
= 0;
1939 size_t last_selection
= 0;
1941 for (size_t i
= 0; i
< render_thread_
->sink().message_count(); ++i
) {
1942 const uint32 type
= render_thread_
->sink().GetMessageAt(i
)->type();
1943 if (type
== ViewHostMsg_TextInputTypeChanged::ID
) {
1944 is_input_type_called
= true;
1945 last_input_type
= i
;
1946 } else if (type
== ViewHostMsg_SelectionChanged::ID
) {
1947 is_selection_called
= true;
1952 EXPECT_TRUE(is_input_type_called
);
1953 EXPECT_TRUE(is_selection_called
);
1955 // InputTypeChange shold be called earlier than SelectionChanged.
1956 EXPECT_LT(last_input_type
, last_selection
);
1959 class SuppressErrorPageTest
: public RenderViewTest
{
1961 ContentRendererClient
* CreateContentRendererClient() override
{
1962 return new TestContentRendererClient
;
1965 RenderViewImpl
* view() {
1966 return static_cast<RenderViewImpl
*>(view_
);
1969 RenderFrameImpl
* frame() {
1970 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
1974 class TestContentRendererClient
: public ContentRendererClient
{
1976 bool ShouldSuppressErrorPage(RenderFrame
* render_frame
,
1977 const GURL
& url
) override
{
1978 return url
== GURL("http://example.com/suppress");
1981 void GetNavigationErrorStrings(content::RenderView
* render_view
,
1982 blink::WebFrame
* frame
,
1983 const blink::WebURLRequest
& failed_request
,
1984 const blink::WebURLError
& error
,
1985 std::string
* error_html
,
1986 base::string16
* error_description
) override
{
1988 *error_html
= "A suffusion of yellow.";
1993 #if defined(OS_ANDROID)
1994 // Crashing on Android: http://crbug.com/311341
1995 #define MAYBE_Suppresses DISABLED_Suppresses
1997 #define MAYBE_Suppresses Suppresses
2000 TEST_F(SuppressErrorPageTest
, MAYBE_Suppresses
) {
2002 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2003 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2004 error
.unreachableURL
= GURL("http://example.com/suppress");
2005 WebLocalFrame
* web_frame
= GetMainFrame();
2007 // Start a load that will reach provisional state synchronously,
2008 // but won't complete synchronously.
2009 FrameMsg_Navigate_Params params
;
2010 params
.page_id
= -1;
2011 params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2012 params
.common_params
.url
= GURL("data:text/html,test data");
2013 params
.commit_params
.browser_navigation_start
=
2014 base::TimeTicks::FromInternalValue(1);
2015 frame()->OnNavigate(params
);
2017 // An error occurred.
2018 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame
, error
);
2019 const int kMaxOutputCharacters
= 22;
2021 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2024 #if defined(OS_ANDROID)
2025 // Crashing on Android: http://crbug.com/311341
2026 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2028 #define MAYBE_DoesNotSuppress DoesNotSuppress
2031 TEST_F(SuppressErrorPageTest
, MAYBE_DoesNotSuppress
) {
2033 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2034 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2035 error
.unreachableURL
= GURL("http://example.com/dont-suppress");
2036 WebLocalFrame
* web_frame
= GetMainFrame();
2038 // Start a load that will reach provisional state synchronously,
2039 // but won't complete synchronously.
2040 FrameMsg_Navigate_Params params
;
2041 params
.page_id
= -1;
2042 params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2043 params
.common_params
.url
= GURL("data:text/html,test data");
2044 params
.commit_params
.browser_navigation_start
=
2045 base::TimeTicks::FromInternalValue(1);
2046 frame()->OnNavigate(params
);
2048 // An error occurred.
2049 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame
, error
);
2050 // The error page itself is loaded asynchronously.
2051 FrameLoadWaiter(frame()).Wait();
2052 const int kMaxOutputCharacters
= 22;
2053 EXPECT_EQ("A suffusion of yellow.",
2054 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2057 // Tests if IME API's candidatewindow* events sent from browser are handled
2059 TEST_F(RenderViewImplTest
, SendCandidateWindowEvents
) {
2060 // Sends an HTML with an <input> element and scripts to the renderer.
2061 // The script handles all 3 of candidatewindow* events for an
2062 // InputMethodContext object and once it received 'show', 'update', 'hide'
2063 // should appear in the result div.
2064 LoadHTML("<input id='test'>"
2065 "<div id='result'>Result: </div>"
2067 "window.onload = function() {"
2068 " var result = document.getElementById('result');"
2069 " var test = document.getElementById('test');"
2071 " var context = test.inputMethodContext;"
2073 " context.oncandidatewindowshow = function() {"
2074 " result.innerText += 'show'; };"
2075 " context.oncandidatewindowupdate = function(){"
2076 " result.innerText += 'update'; };"
2077 " context.oncandidatewindowhide = function(){"
2078 " result.innerText += 'hide'; };"
2083 // Fire candidatewindow events.
2084 view()->OnCandidateWindowShown();
2085 view()->OnCandidateWindowUpdated();
2086 view()->OnCandidateWindowHidden();
2088 // Retrieve the content and check if it is expected.
2089 const int kMaxOutputCharacters
= 50;
2090 std::string output
= base::UTF16ToUTF8(
2091 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
2092 EXPECT_EQ(output
, "\nResult:showupdatehide");
2095 // Ensure the render view sends favicon url update events correctly.
2096 TEST_F(RenderViewImplTest
, SendFaviconURLUpdateEvent
) {
2097 // An event should be sent when a favicon url exists.
2100 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2103 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
2104 ViewHostMsg_UpdateFaviconURL::ID
));
2105 render_thread_
->sink().ClearMessages();
2107 // An event should not be sent if no favicon url exists. This is an assumption
2108 // made by some of Chrome's favicon handling.
2113 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
2114 ViewHostMsg_UpdateFaviconURL::ID
));
2117 TEST_F(RenderViewImplTest
, FocusElementCallsFocusedNodeChanged
) {
2118 LoadHTML("<input id='test1' value='hello1'></input>"
2119 "<input id='test2' value='hello2'></input>");
2121 ExecuteJavaScript("document.getElementById('test1').focus();");
2122 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
2123 ViewHostMsg_FocusedNodeChanged::ID
);
2126 ViewHostMsg_FocusedNodeChanged::Param params
;
2127 ViewHostMsg_FocusedNodeChanged::Read(msg1
, ¶ms
);
2128 EXPECT_TRUE(get
<0>(params
));
2129 render_thread_
->sink().ClearMessages();
2131 ExecuteJavaScript("document.getElementById('test2').focus();");
2132 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
2133 ViewHostMsg_FocusedNodeChanged::ID
);
2135 ViewHostMsg_FocusedNodeChanged::Read(msg2
, ¶ms
);
2136 EXPECT_TRUE(get
<0>(params
));
2137 render_thread_
->sink().ClearMessages();
2139 view()->webview()->clearFocusedElement();
2140 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
2141 ViewHostMsg_FocusedNodeChanged::ID
);
2143 ViewHostMsg_FocusedNodeChanged::Read(msg3
, ¶ms
);
2144 EXPECT_FALSE(get
<0>(params
));
2145 render_thread_
->sink().ClearMessages();
2148 TEST_F(RenderViewImplTest
, ServiceWorkerNetworkProviderSetup
) {
2149 ServiceWorkerNetworkProvider
* provider
= NULL
;
2150 RequestExtraData
* extra_data
= NULL
;
2152 // Make sure each new document has a new provider and
2153 // that the main request is tagged with the provider's id.
2154 LoadHTML("<b>A Document</b>");
2155 ASSERT_TRUE(GetMainFrame()->dataSource());
2156 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2157 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2158 ASSERT_TRUE(provider
);
2159 extra_data
= static_cast<RequestExtraData
*>(
2160 GetMainFrame()->dataSource()->request().extraData());
2161 ASSERT_TRUE(extra_data
);
2162 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2163 provider
->provider_id());
2164 int provider1_id
= provider
->provider_id();
2166 LoadHTML("<b>New Document B Goes Here</b>");
2167 ASSERT_TRUE(GetMainFrame()->dataSource());
2168 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2169 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2170 ASSERT_TRUE(provider
);
2171 EXPECT_NE(provider1_id
, provider
->provider_id());
2172 extra_data
= static_cast<RequestExtraData
*>(
2173 GetMainFrame()->dataSource()->request().extraData());
2174 ASSERT_TRUE(extra_data
);
2175 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2176 provider
->provider_id());
2178 // See that subresource requests are also tagged with the provider's id.
2179 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2180 blink::WebURLRequest
request(GURL("http://foo.com"));
2181 request
.setRequestContext(blink::WebURLRequest::RequestContextSubresource
);
2182 blink::WebURLResponse redirect_response
;
2183 frame()->willSendRequest(GetMainFrame(), 0, request
, redirect_response
);
2184 extra_data
= static_cast<RequestExtraData
*>(request
.extraData());
2185 ASSERT_TRUE(extra_data
);
2186 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2187 provider
->provider_id());
2190 TEST_F(RenderViewImplTest
, OnSetAccessibilityMode
) {
2191 ASSERT_EQ(AccessibilityModeOff
, frame()->accessibility_mode());
2192 ASSERT_EQ((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2194 frame()->OnSetAccessibilityMode(AccessibilityModeTreeOnly
);
2195 ASSERT_EQ(AccessibilityModeTreeOnly
, frame()->accessibility_mode());
2196 ASSERT_NE((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2198 frame()->OnSetAccessibilityMode(AccessibilityModeOff
);
2199 ASSERT_EQ(AccessibilityModeOff
, frame()->accessibility_mode());
2200 ASSERT_EQ((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2202 frame()->OnSetAccessibilityMode(AccessibilityModeComplete
);
2203 ASSERT_EQ(AccessibilityModeComplete
, frame()->accessibility_mode());
2204 ASSERT_NE((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2207 TEST_F(RenderViewImplTest
, ScreenMetricsEmulation
) {
2208 LoadHTML("<body style='min-height:1000px;'></body>");
2210 blink::WebDeviceEmulationParams params
;
2211 base::string16 get_width
= base::ASCIIToUTF16("Number(window.innerWidth)");
2212 base::string16 get_height
= base::ASCIIToUTF16("Number(window.innerHeight)");
2215 params
.viewSize
.width
= 327;
2216 params
.viewSize
.height
= 415;
2217 view()->EnableScreenMetricsEmulation(params
);
2218 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width
, &width
));
2219 EXPECT_EQ(params
.viewSize
.width
, width
);
2220 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height
, &height
));
2221 EXPECT_EQ(params
.viewSize
.height
, height
);
2223 params
.viewSize
.width
= 1005;
2224 params
.viewSize
.height
= 1102;
2225 view()->EnableScreenMetricsEmulation(params
);
2226 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width
, &width
));
2227 EXPECT_EQ(params
.viewSize
.width
, width
);
2228 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height
, &height
));
2229 EXPECT_EQ(params
.viewSize
.height
, height
);
2231 view()->DisableScreenMetricsEmulation();
2233 view()->EnableScreenMetricsEmulation(params
);
2234 // Don't disable here to test that emulation is being shutdown properly.
2237 // Sanity checks for the Navigation Timing API |navigationStart| override. We
2238 // are asserting only most basic constraints, as TimeTicks (passed as the
2239 // override) are not comparable with the wall time (returned by the Blink API).
2240 TEST_F(RenderViewImplTest
, NavigationStartOverride
) {
2241 // Verify that a navigation that claims to have started at the earliest
2242 // possible TimeTicks is indeed reported as one that started before
2243 // OnNavigate() is called.
2244 base::Time before_navigation
= base::Time::Now();
2245 FrameMsg_Navigate_Params early_nav_params
;
2246 early_nav_params
.common_params
.url
= GURL("data:text/html,<div>Page</div>");
2247 early_nav_params
.common_params
.navigation_type
=
2248 FrameMsg_Navigate_Type::NORMAL
;
2249 early_nav_params
.common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
2250 early_nav_params
.page_id
= -1;
2251 early_nav_params
.is_post
= true;
2252 early_nav_params
.commit_params
.browser_navigation_start
=
2253 base::TimeTicks::FromInternalValue(1);
2255 frame()->OnNavigate(early_nav_params
);
2256 ProcessPendingMessages();
2258 base::Time early_nav_reported_start
=
2259 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2260 EXPECT_LT(early_nav_reported_start
, before_navigation
);
2262 // Verify that a navigation that claims to have started in the future - 42
2263 // days from now is *not* reported as one that starts in the future; as we
2264 // sanitize the override allowing a maximum of ::Now().
2265 FrameMsg_Navigate_Params late_nav_params
;
2266 late_nav_params
.common_params
.url
=
2267 GURL("data:text/html,<div>Another page</div>");
2268 late_nav_params
.common_params
.navigation_type
=
2269 FrameMsg_Navigate_Type::NORMAL
;
2270 late_nav_params
.common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
2271 late_nav_params
.page_id
= -1;
2272 late_nav_params
.is_post
= true;
2273 late_nav_params
.commit_params
.browser_navigation_start
=
2274 base::TimeTicks::Now() + base::TimeDelta::FromDays(42);
2276 frame()->OnNavigate(late_nav_params
);
2277 ProcessPendingMessages();
2278 base::Time after_navigation
=
2279 base::Time::Now() + base::TimeDelta::FromDays(1);
2281 base::Time late_nav_reported_start
=
2282 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2283 EXPECT_LE(late_nav_reported_start
, after_navigation
);
2286 class RenderViewImplInitialSizeTest
: public RenderViewImplTest
{
2288 RenderViewImplInitialSizeTest()
2289 : RenderViewImplTest(), initial_size_(200, 100) {}
2292 scoped_ptr
<ViewMsg_Resize_Params
> InitialSizeParams() override
{
2293 scoped_ptr
<ViewMsg_Resize_Params
> initial_size_params(
2294 new ViewMsg_Resize_Params());
2295 initial_size_params
->new_size
= initial_size_
;
2296 return initial_size_params
.Pass();
2299 gfx::Size initial_size_
;
2302 TEST_F(RenderViewImplInitialSizeTest
, InitialSize
) {
2303 ASSERT_EQ(initial_size_
, view_
->GetSize());
2304 ASSERT_EQ(initial_size_
, gfx::Size(view_
->GetWebView()->size()));
2307 TEST_F(RenderViewImplTest
, PreferredSizeZoomed
) {
2308 LoadHTML("<body style='margin:0;'><div style='display:inline-block; "
2309 "width:400px; height:400px;'/></body>");
2310 view()->webview()->mainFrame()->setCanHaveScrollbars(false);
2311 EnablePreferredSizeMode();
2313 gfx::Size size
= GetPreferredSize();
2314 EXPECT_EQ(gfx::Size(400, 400), size
);
2316 SetZoomLevel(ZoomFactorToZoomLevel(2.0));
2317 size
= GetPreferredSize();
2318 EXPECT_EQ(gfx::Size(800, 800), size
);
2321 } // namespace content