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/page_zoom.h"
23 #include "content/public/common/url_constants.h"
24 #include "content/public/common/url_utils.h"
25 #include "content/public/renderer/content_renderer_client.h"
26 #include "content/public/renderer/document_state.h"
27 #include "content/public/renderer/navigation_state.h"
28 #include "content/public/test/browser_test_utils.h"
29 #include "content/public/test/frame_load_waiter.h"
30 #include "content/public/test/render_view_test.h"
31 #include "content/public/test/test_utils.h"
32 #include "content/renderer/accessibility/renderer_accessibility.h"
33 #include "content/renderer/history_controller.h"
34 #include "content/renderer/history_serialization.h"
35 #include "content/renderer/render_process.h"
36 #include "content/renderer/render_view_impl.h"
37 #include "content/shell/browser/shell.h"
38 #include "content/shell/browser/shell_browser_context.h"
39 #include "content/test/mock_keyboard.h"
40 #include "net/base/net_errors.h"
41 #include "net/cert/cert_status_flags.h"
42 #include "testing/gtest/include/gtest/gtest.h"
43 #include "third_party/WebKit/public/platform/WebData.h"
44 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
45 #include "third_party/WebKit/public/platform/WebString.h"
46 #include "third_party/WebKit/public/platform/WebURLResponse.h"
47 #include "third_party/WebKit/public/web/WebDataSource.h"
48 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
49 #include "third_party/WebKit/public/web/WebHistoryItem.h"
50 #include "third_party/WebKit/public/web/WebLocalFrame.h"
51 #include "third_party/WebKit/public/web/WebPerformance.h"
52 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
53 #include "third_party/WebKit/public/web/WebView.h"
54 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
55 #include "ui/events/event.h"
56 #include "ui/events/keycodes/keyboard_codes.h"
57 #include "ui/gfx/codec/jpeg_codec.h"
58 #include "ui/gfx/range/range.h"
60 #if defined(USE_AURA) && defined(USE_X11)
62 #include "ui/events/event_constants.h"
63 #include "ui/events/keycodes/keyboard_code_conversion.h"
64 #include "ui/events/test/events_test_utils.h"
65 #include "ui/events/test/events_test_utils_x11.h"
68 #if defined(USE_OZONE)
69 #include "ui/events/keycodes/keyboard_code_conversion.h"
72 using blink::WebFrame
;
73 using blink::WebInputEvent
;
74 using blink::WebLocalFrame
;
75 using blink::WebMouseEvent
;
76 using blink::WebRuntimeFeatures
;
77 using blink::WebString
;
78 using blink::WebTextDirection
;
79 using blink::WebURLError
;
85 static const int kProxyRoutingId
= 13;
87 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
88 // Converts MockKeyboard::Modifiers to ui::EventFlags.
89 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers
) {
90 static struct ModifierMap
{
91 MockKeyboard::Modifiers src
;
94 { MockKeyboard::LEFT_SHIFT
, ui::EF_SHIFT_DOWN
},
95 { MockKeyboard::RIGHT_SHIFT
, ui::EF_SHIFT_DOWN
},
96 { MockKeyboard::LEFT_CONTROL
, ui::EF_CONTROL_DOWN
},
97 { MockKeyboard::RIGHT_CONTROL
, ui::EF_CONTROL_DOWN
},
98 { MockKeyboard::LEFT_ALT
, ui::EF_ALT_DOWN
},
99 { MockKeyboard::RIGHT_ALT
, ui::EF_ALT_DOWN
},
102 for (size_t i
= 0; i
< arraysize(kModifierMap
); ++i
) {
103 if (kModifierMap
[i
].src
& modifiers
) {
104 flags
|= kModifierMap
[i
].dst
;
111 class WebUITestWebUIControllerFactory
: public WebUIControllerFactory
{
113 WebUIController
* CreateWebUIControllerForURL(WebUI
* web_ui
,
114 const GURL
& url
) const override
{
117 WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
118 const GURL
& url
) const override
{
119 return WebUI::kNoWebUI
;
121 bool UseWebUIForURL(BrowserContext
* browser_context
,
122 const GURL
& url
) const override
{
123 return HasWebUIScheme(url
);
125 bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
126 const GURL
& url
) const override
{
127 return HasWebUIScheme(url
);
133 class RenderViewImplTest
: public RenderViewTest
{
135 RenderViewImplTest() {
136 // Attach a pseudo keyboard device to this object.
137 mock_keyboard_
.reset(new MockKeyboard());
140 ~RenderViewImplTest() override
{}
142 void SetUp() override
{
143 RenderViewTest::SetUp();
144 // Enable Blink's experimental and test only features so that test code
145 // does not have to bother enabling each feature.
146 WebRuntimeFeatures::enableExperimentalFeatures(true);
147 WebRuntimeFeatures::enableTestOnlyFeatures(true);
150 RenderViewImpl
* view() {
151 return static_cast<RenderViewImpl
*>(view_
);
155 return view()->page_id_
;
158 RenderFrameImpl
* frame() {
159 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
162 // Sends IPC messages that emulates a key-press event.
163 int SendKeyEvent(MockKeyboard::Layout layout
,
165 MockKeyboard::Modifiers modifiers
,
166 base::string16
* output
) {
168 // Retrieve the Unicode character for the given tuple (keyboard-layout,
169 // key-code, and modifiers).
170 // Exit when a keyboard-layout driver cannot assign a Unicode character to
171 // the tuple to prevent sending an invalid key code to the RenderView
173 CHECK(mock_keyboard_
.get());
175 int length
= mock_keyboard_
->GetCharacters(layout
, key_code
, modifiers
,
180 // Create IPC messages from Windows messages and send them to our
182 // A keyboard event of Windows consists of three Windows messages:
183 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
184 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
185 // WM_CHAR sends a composed Unicode character.
186 MSG msg1
= { NULL
, WM_KEYDOWN
, key_code
, 0 };
187 ui::KeyEvent
evt1(msg1
);
188 NativeWebKeyboardEvent
keydown_event(evt1
);
189 SendNativeKeyEvent(keydown_event
);
191 MSG msg2
= { NULL
, WM_CHAR
, (*output
)[0], 0 };
192 ui::KeyEvent
evt2(msg2
);
193 NativeWebKeyboardEvent
char_event(evt2
);
194 SendNativeKeyEvent(char_event
);
196 MSG msg3
= { NULL
, WM_KEYUP
, key_code
, 0 };
197 ui::KeyEvent
evt3(msg3
);
198 NativeWebKeyboardEvent
keyup_event(evt3
);
199 SendNativeKeyEvent(keyup_event
);
202 #elif defined(USE_AURA) && defined(USE_X11)
203 // We ignore |layout|, which means we are only testing the layout of the
204 // current locale. TODO(mazda): fix this to respect |layout|.
206 const int flags
= ConvertMockKeyboardModifier(modifiers
);
208 ui::ScopedXI2Event xevent
;
209 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
210 static_cast<ui::KeyboardCode
>(key_code
),
212 ui::KeyEvent
event1(xevent
);
213 NativeWebKeyboardEvent
keydown_event(event1
);
214 SendNativeKeyEvent(keydown_event
);
216 // X11 doesn't actually have native character events, but give the test
218 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
219 static_cast<ui::KeyboardCode
>(key_code
),
221 ui::KeyEvent
event2(xevent
);
222 event2
.set_character(GetCharacterFromKeyCode(event2
.key_code(),
224 ui::KeyEventTestApi
test_event2(&event2
);
225 test_event2
.set_is_char(true);
226 NativeWebKeyboardEvent
char_event(event2
);
227 SendNativeKeyEvent(char_event
);
229 xevent
.InitKeyEvent(ui::ET_KEY_RELEASED
,
230 static_cast<ui::KeyboardCode
>(key_code
),
232 ui::KeyEvent
event3(xevent
);
233 NativeWebKeyboardEvent
keyup_event(event3
);
234 SendNativeKeyEvent(keyup_event
);
236 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
238 output
->assign(1, static_cast<base::char16
>(c
));
240 #elif defined(USE_OZONE)
241 const int flags
= ConvertMockKeyboardModifier(modifiers
);
243 ui::KeyEvent
keydown_event(ui::ET_KEY_PRESSED
,
244 static_cast<ui::KeyboardCode
>(key_code
),
246 NativeWebKeyboardEvent
keydown_web_event(keydown_event
);
247 SendNativeKeyEvent(keydown_web_event
);
249 ui::KeyEvent
char_event(keydown_event
.GetCharacter(),
250 static_cast<ui::KeyboardCode
>(key_code
),
252 NativeWebKeyboardEvent
char_web_event(char_event
);
253 SendNativeKeyEvent(char_web_event
);
255 ui::KeyEvent
keyup_event(ui::ET_KEY_RELEASED
,
256 static_cast<ui::KeyboardCode
>(key_code
),
258 NativeWebKeyboardEvent
keyup_web_event(keyup_event
);
259 SendNativeKeyEvent(keyup_web_event
);
261 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
263 output
->assign(1, static_cast<base::char16
>(c
));
272 scoped_ptr
<MockKeyboard
> mock_keyboard_
;
275 TEST_F(RenderViewImplTest
, SaveImageFromDataURL
) {
276 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
277 ViewHostMsg_SaveImageFromDataURL::ID
);
279 render_thread_
->sink().ClearMessages();
281 const std::string image_data_url
=
282 "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
284 view()->saveImageFromDataURL(WebString::fromUTF8(image_data_url
));
285 ProcessPendingMessages();
286 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
287 ViewHostMsg_SaveImageFromDataURL::ID
);
290 ViewHostMsg_SaveImageFromDataURL::Param param1
;
291 ViewHostMsg_SaveImageFromDataURL::Read(msg2
, ¶m1
);
292 EXPECT_EQ(param1
.b
.length(), image_data_url
.length());
293 EXPECT_EQ(param1
.b
, image_data_url
);
295 ProcessPendingMessages();
296 render_thread_
->sink().ClearMessages();
298 const std::string
large_data_url(1024 * 1024 * 10 - 1, 'd');
300 view()->saveImageFromDataURL(WebString::fromUTF8(large_data_url
));
301 ProcessPendingMessages();
302 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
303 ViewHostMsg_SaveImageFromDataURL::ID
);
306 ViewHostMsg_SaveImageFromDataURL::Param param2
;
307 ViewHostMsg_SaveImageFromDataURL::Read(msg3
, ¶m2
);
308 EXPECT_EQ(param2
.b
.length(), large_data_url
.length());
309 EXPECT_EQ(param2
.b
, large_data_url
);
311 ProcessPendingMessages();
312 render_thread_
->sink().ClearMessages();
314 const std::string
exceeded_data_url(1024 * 1024 * 10 + 1, 'd');
316 view()->saveImageFromDataURL(WebString::fromUTF8(exceeded_data_url
));
317 ProcessPendingMessages();
318 const IPC::Message
* msg4
= render_thread_
->sink().GetFirstMessageMatching(
319 ViewHostMsg_SaveImageFromDataURL::ID
);
323 // Test that we get form state change notifications when input fields change.
324 TEST_F(RenderViewImplTest
, DISABLED_OnNavStateChanged
) {
325 // Don't want any delay for form state sync changes. This will still post a
326 // message so updates will get coalesced, but as soon as we spin the message
327 // loop, it will generate an update.
328 view()->set_send_content_state_immediately(true);
330 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
332 // We should NOT have gotten a form state change notification yet.
333 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
334 ViewHostMsg_UpdateState::ID
));
335 render_thread_
->sink().ClearMessages();
337 // Change the value of the input. We should have gotten an update state
338 // notification. We need to spin the message loop to catch this update.
339 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';");
340 ProcessPendingMessages();
341 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
342 ViewHostMsg_UpdateState::ID
));
345 TEST_F(RenderViewImplTest
, OnNavigationHttpPost
) {
346 FrameMsg_Navigate_Params nav_params
;
348 // An http url will trigger a resource load so cannot be used here.
349 nav_params
.common_params
.url
= GURL("data:text/html,<div>Page</div>");
350 nav_params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
351 nav_params
.common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
352 nav_params
.page_id
= -1;
353 nav_params
.request_params
.is_post
= true;
354 nav_params
.commit_params
.browser_navigation_start
=
355 base::TimeTicks::FromInternalValue(1);
358 const unsigned char* raw_data
= reinterpret_cast<const unsigned char*>(
360 const unsigned int length
= 11;
361 const std::vector
<unsigned char> post_data(raw_data
, raw_data
+ length
);
362 nav_params
.request_params
.browser_initiated_post_data
= post_data
;
364 frame()->OnNavigate(nav_params
);
365 ProcessPendingMessages();
367 const IPC::Message
* frame_navigate_msg
=
368 render_thread_
->sink().GetUniqueMessageMatching(
369 FrameHostMsg_DidCommitProvisionalLoad::ID
);
370 EXPECT_TRUE(frame_navigate_msg
);
372 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params
;
373 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
375 EXPECT_TRUE(host_nav_params
.a
.is_post
);
377 // Check post data sent to browser matches
378 EXPECT_TRUE(host_nav_params
.a
.page_state
.IsValid());
379 scoped_ptr
<HistoryEntry
> entry
=
380 PageStateToHistoryEntry(host_nav_params
.a
.page_state
);
381 blink::WebHTTPBody body
= entry
->root().httpBody();
382 blink::WebHTTPBody::Element element
;
383 bool successful
= body
.elementAt(0, element
);
384 EXPECT_TRUE(successful
);
385 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData
, element
.type
);
386 EXPECT_EQ(length
, element
.data
.size());
387 EXPECT_EQ(0, memcmp(raw_data
, element
.data
.data(), length
));
390 TEST_F(RenderViewImplTest
, DecideNavigationPolicy
) {
391 WebUITestWebUIControllerFactory factory
;
392 WebUIControllerFactory::RegisterFactory(&factory
);
395 state
.set_navigation_state(NavigationState::CreateContentInitiated());
397 // Navigations to normal HTTP URLs can be handled locally.
398 blink::WebURLRequest
request(GURL("http://foo.com"));
399 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
400 policy_info
.frame
= GetMainFrame();
401 policy_info
.extraData
= &state
;
402 policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
403 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
404 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
406 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab
, policy
);
408 // Verify that form posts to WebUI URLs will be sent to the browser process.
409 blink::WebURLRequest
form_request(GURL("chrome://foo"));
410 blink::WebFrameClient::NavigationPolicyInfo
form_policy_info(form_request
);
411 form_policy_info
.frame
= GetMainFrame();
412 form_policy_info
.extraData
= &state
;
413 form_policy_info
.navigationType
= blink::WebNavigationTypeFormSubmitted
;
414 form_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
415 form_request
.setHTTPMethod("POST");
416 policy
= frame()->decidePolicyForNavigation(form_policy_info
);
417 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
419 // Verify that popup links to WebUI URLs also are sent to browser.
420 blink::WebURLRequest
popup_request(GURL("chrome://foo"));
421 blink::WebFrameClient::NavigationPolicyInfo
popup_policy_info(popup_request
);
422 popup_policy_info
.frame
= GetMainFrame();
423 popup_policy_info
.extraData
= &state
;
424 popup_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
425 popup_policy_info
.defaultPolicy
= blink::WebNavigationPolicyNewForegroundTab
;
426 policy
= frame()->decidePolicyForNavigation(popup_policy_info
);
427 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
430 TEST_F(RenderViewImplTest
, DecideNavigationPolicyHandlesAllTopLevel
) {
432 state
.set_navigation_state(NavigationState::CreateContentInitiated());
434 RendererPreferences prefs
= view()->renderer_preferences();
435 prefs
.browser_handles_all_top_level_requests
= true;
436 view()->OnSetRendererPrefs(prefs
);
438 const blink::WebNavigationType kNavTypes
[] = {
439 blink::WebNavigationTypeLinkClicked
,
440 blink::WebNavigationTypeFormSubmitted
,
441 blink::WebNavigationTypeBackForward
,
442 blink::WebNavigationTypeReload
,
443 blink::WebNavigationTypeFormResubmitted
,
444 blink::WebNavigationTypeOther
,
447 blink::WebURLRequest
request(GURL("http://foo.com"));
448 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
449 policy_info
.frame
= GetMainFrame();
450 policy_info
.extraData
= &state
;
451 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
453 for (size_t i
= 0; i
< arraysize(kNavTypes
); ++i
) {
454 policy_info
.navigationType
= kNavTypes
[i
];
456 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
458 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
462 TEST_F(RenderViewImplTest
, DecideNavigationPolicyForWebUI
) {
463 // Enable bindings to simulate a WebUI view.
464 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI
);
467 state
.set_navigation_state(NavigationState::CreateContentInitiated());
469 // Navigations to normal HTTP URLs will be sent to browser process.
470 blink::WebURLRequest
request(GURL("http://foo.com"));
471 blink::WebFrameClient::NavigationPolicyInfo
policy_info(request
);
472 policy_info
.frame
= GetMainFrame();
473 policy_info
.extraData
= &state
;
474 policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
475 policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
477 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
479 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
481 // Navigations to WebUI URLs will also be sent to browser process.
482 blink::WebURLRequest
webui_request(GURL("chrome://foo"));
483 blink::WebFrameClient::NavigationPolicyInfo
webui_policy_info(webui_request
);
484 webui_policy_info
.frame
= GetMainFrame();
485 webui_policy_info
.extraData
= &state
;
486 webui_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
487 webui_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
488 policy
= frame()->decidePolicyForNavigation(webui_policy_info
);
489 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
491 // Verify that form posts to data URLs will be sent to the browser process.
492 blink::WebURLRequest
data_request(GURL("data:text/html,foo"));
493 blink::WebFrameClient::NavigationPolicyInfo
data_policy_info(data_request
);
494 data_policy_info
.frame
= GetMainFrame();
495 data_policy_info
.extraData
= &state
;
496 data_policy_info
.navigationType
= blink::WebNavigationTypeFormSubmitted
;
497 data_policy_info
.defaultPolicy
= blink::WebNavigationPolicyCurrentTab
;
498 data_request
.setHTTPMethod("POST");
499 policy
= frame()->decidePolicyForNavigation(data_policy_info
);
500 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
502 // Verify that a popup that creates a view first and then navigates to a
503 // normal HTTP URL will be sent to the browser process, even though the
504 // new view does not have any enabled_bindings_.
505 blink::WebURLRequest
popup_request(GURL("http://foo.com"));
506 blink::WebView
* new_web_view
= view()->createView(
507 GetMainFrame(), popup_request
, blink::WebWindowFeatures(), "foo",
508 blink::WebNavigationPolicyNewForegroundTab
, false);
509 RenderViewImpl
* new_view
= RenderViewImpl::FromWebView(new_web_view
);
510 blink::WebFrameClient::NavigationPolicyInfo
popup_policy_info(popup_request
);
511 popup_policy_info
.frame
= new_web_view
->mainFrame()->toWebLocalFrame();
512 popup_policy_info
.extraData
= &state
;
513 popup_policy_info
.navigationType
= blink::WebNavigationTypeLinkClicked
;
514 popup_policy_info
.defaultPolicy
= blink::WebNavigationPolicyNewForegroundTab
;
515 policy
= static_cast<RenderFrameImpl
*>(new_view
->GetMainRenderFrame())->
516 decidePolicyForNavigation(popup_policy_info
);
517 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
519 // Clean up after the new view so we don't leak it.
524 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
525 // already swapped out. http://crbug.com/93427.
526 TEST_F(RenderViewImplTest
, SendSwapOutACK
) {
527 LoadHTML("<div>Page A</div>");
528 int initial_page_id
= view_page_id();
530 // Increment the ref count so that we don't exit when swapping out.
531 RenderProcess::current()->AddRefProcess();
533 // Respond to a swap out request.
534 view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId
);
536 // Ensure the swap out commits synchronously.
537 EXPECT_NE(initial_page_id
, view_page_id());
539 // Check for a valid OnSwapOutACK.
540 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
541 FrameHostMsg_SwapOut_ACK::ID
);
544 // It is possible to get another swap out request. Ensure that we send
545 // an ACK, even if we don't have to do anything else.
546 render_thread_
->sink().ClearMessages();
547 view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId
);
548 const IPC::Message
* msg2
= render_thread_
->sink().GetUniqueMessageMatching(
549 FrameHostMsg_SwapOut_ACK::ID
);
552 // If we navigate back to this RenderView, ensure we don't send a state
553 // update for the swapped out URL. (http://crbug.com/72235)
554 FrameMsg_Navigate_Params nav_params
;
555 nav_params
.common_params
.url
= GURL("data:text/html,<div>Page B</div>");
556 nav_params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
557 nav_params
.common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
558 nav_params
.current_history_list_length
= 1;
559 nav_params
.current_history_list_offset
= 0;
560 nav_params
.pending_history_list_offset
= 1;
561 nav_params
.page_id
= -1;
562 nav_params
.commit_params
.browser_navigation_start
=
563 base::TimeTicks::FromInternalValue(1);
564 frame()->OnNavigate(nav_params
);
565 ProcessPendingMessages();
566 const IPC::Message
* msg3
= render_thread_
->sink().GetUniqueMessageMatching(
567 ViewHostMsg_UpdateState::ID
);
571 // Ensure the RenderViewImpl reloads the previous page if a reload request
572 // arrives while it is showing swappedout://. http://crbug.com/143155.
573 TEST_F(RenderViewImplTest
, ReloadWhileSwappedOut
) {
575 LoadHTML("<div>Page A</div>");
577 // Load page B, which will trigger an UpdateState message for page A.
578 LoadHTML("<div>Page B</div>");
580 // Check for a valid UpdateState message for page A.
581 ProcessPendingMessages();
582 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
583 ViewHostMsg_UpdateState::ID
);
585 ViewHostMsg_UpdateState::Param params
;
586 ViewHostMsg_UpdateState::Read(msg_A
, ¶ms
);
587 int page_id_A
= params
.a
;
588 PageState state_A
= params
.b
;
589 EXPECT_EQ(1, page_id_A
);
590 render_thread_
->sink().ClearMessages();
592 // Back to page A (page_id 1) and commit.
593 FrameMsg_Navigate_Params params_A
;
594 params_A
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
595 params_A
.common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
596 params_A
.current_history_list_length
= 2;
597 params_A
.current_history_list_offset
= 1;
598 params_A
.pending_history_list_offset
= 0;
599 params_A
.page_id
= 1;
600 params_A
.commit_params
.page_state
= state_A
;
601 params_A
.commit_params
.browser_navigation_start
=
602 base::TimeTicks::FromInternalValue(1);
603 frame()->OnNavigate(params_A
);
604 ProcessPendingMessages();
606 // Respond to a swap out request.
607 view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId
);
609 // Check for a OnSwapOutACK.
610 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
611 FrameHostMsg_SwapOut_ACK::ID
);
613 render_thread_
->sink().ClearMessages();
615 // It is possible to get a reload request at this point, containing the
616 // params.page_state of the initial page (e.g., if the new page fails the
617 // provisional load in the renderer process, after we unload the old page).
618 // Ensure the old page gets reloaded, not swappedout://.
619 FrameMsg_Navigate_Params nav_params
;
620 nav_params
.common_params
.url
= GURL("data:text/html,<div>Page A</div>");
621 nav_params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::RELOAD
;
622 nav_params
.common_params
.transition
= ui::PAGE_TRANSITION_RELOAD
;
623 nav_params
.current_history_list_length
= 2;
624 nav_params
.current_history_list_offset
= 0;
625 nav_params
.pending_history_list_offset
= 0;
626 nav_params
.page_id
= 1;
627 nav_params
.commit_params
.page_state
= state_A
;
628 nav_params
.commit_params
.browser_navigation_start
=
629 base::TimeTicks::FromInternalValue(1);
630 frame()->OnNavigate(nav_params
);
631 ProcessPendingMessages();
633 // Verify page A committed, not swappedout://.
634 const IPC::Message
* frame_navigate_msg
=
635 render_thread_
->sink().GetUniqueMessageMatching(
636 FrameHostMsg_DidCommitProvisionalLoad::ID
);
637 EXPECT_TRUE(frame_navigate_msg
);
639 // Read URL out of the parent trait of the params object.
640 FrameHostMsg_DidCommitProvisionalLoad::Param commit_params
;
641 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
643 EXPECT_NE(GURL("swappedout://"), commit_params
.a
.url
);
647 // Test that we get the correct UpdateState message when we go back twice
648 // quickly without committing. Regression test for http://crbug.com/58082.
649 // Disabled: http://crbug.com/157357 .
650 TEST_F(RenderViewImplTest
, DISABLED_LastCommittedUpdateState
) {
652 LoadHTML("<div>Page A</div>");
654 // Load page B, which will trigger an UpdateState message for page A.
655 LoadHTML("<div>Page B</div>");
657 // Check for a valid UpdateState message for page A.
658 ProcessPendingMessages();
659 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
660 ViewHostMsg_UpdateState::ID
);
662 ViewHostMsg_UpdateState::Param param
;
663 ViewHostMsg_UpdateState::Read(msg_A
, ¶m
);
664 int page_id_A
= param
.a
;
665 PageState state_A
= param
.b
;
666 EXPECT_EQ(1, page_id_A
);
667 render_thread_
->sink().ClearMessages();
669 // Load page C, which will trigger an UpdateState message for page B.
670 LoadHTML("<div>Page C</div>");
672 // Check for a valid UpdateState for page B.
673 ProcessPendingMessages();
674 const IPC::Message
* msg_B
= render_thread_
->sink().GetUniqueMessageMatching(
675 ViewHostMsg_UpdateState::ID
);
677 ViewHostMsg_UpdateState::Read(msg_B
, ¶m
);
678 int page_id_B
= param
.a
;
679 PageState state_B
= param
.b
;
680 EXPECT_EQ(2, page_id_B
);
681 EXPECT_NE(state_A
, state_B
);
682 render_thread_
->sink().ClearMessages();
684 // Load page D, which will trigger an UpdateState message for page C.
685 LoadHTML("<div>Page D</div>");
687 // Check for a valid UpdateState for page C.
688 ProcessPendingMessages();
689 const IPC::Message
* msg_C
= render_thread_
->sink().GetUniqueMessageMatching(
690 ViewHostMsg_UpdateState::ID
);
692 ViewHostMsg_UpdateState::Read(msg_C
, ¶m
);
693 int page_id_C
= param
.a
;
694 PageState state_C
= param
.b
;
695 EXPECT_EQ(3, page_id_C
);
696 EXPECT_NE(state_B
, state_C
);
697 render_thread_
->sink().ClearMessages();
699 // Go back to C and commit, preparing for our real test.
700 FrameMsg_Navigate_Params params_C
;
701 params_C
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
702 params_C
.common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
703 params_C
.current_history_list_length
= 4;
704 params_C
.current_history_list_offset
= 3;
705 params_C
.pending_history_list_offset
= 2;
706 params_C
.page_id
= 3;
707 params_C
.commit_params
.page_state
= state_C
;
708 params_C
.commit_params
.browser_navigation_start
=
709 base::TimeTicks::FromInternalValue(1);
710 frame()->OnNavigate(params_C
);
711 ProcessPendingMessages();
712 render_thread_
->sink().ClearMessages();
714 // Go back twice quickly, such that page B does not have a chance to commit.
715 // This leads to two changes to the back/forward list but only one change to
716 // the RenderView's page ID.
718 // Back to page B (page_id 2), without committing.
719 FrameMsg_Navigate_Params params_B
;
720 params_B
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
721 params_B
.common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
722 params_B
.current_history_list_length
= 4;
723 params_B
.current_history_list_offset
= 2;
724 params_B
.pending_history_list_offset
= 1;
725 params_B
.page_id
= 2;
726 params_B
.commit_params
.page_state
= state_B
;
727 params_B
.commit_params
.browser_navigation_start
=
728 base::TimeTicks::FromInternalValue(1);
729 frame()->OnNavigate(params_B
);
731 // Back to page A (page_id 1) and commit.
732 FrameMsg_Navigate_Params params
;
733 params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
734 params
.common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
735 params_B
.current_history_list_length
= 4;
736 params_B
.current_history_list_offset
= 2;
737 params_B
.pending_history_list_offset
= 0;
739 params
.commit_params
.page_state
= state_A
;
740 params
.commit_params
.browser_navigation_start
=
741 base::TimeTicks::FromInternalValue(1);
742 frame()->OnNavigate(params
);
743 ProcessPendingMessages();
745 // Now ensure that the UpdateState message we receive is consistent
746 // and represents page C in both page_id and state.
747 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
748 ViewHostMsg_UpdateState::ID
);
750 ViewHostMsg_UpdateState::Read(msg
, ¶m
);
751 int page_id
= param
.a
;
752 PageState state
= param
.b
;
753 EXPECT_EQ(page_id_C
, page_id
);
754 EXPECT_NE(state_A
, state
);
755 EXPECT_NE(state_B
, state
);
756 EXPECT_EQ(state_C
, state
);
759 // Test that the history_page_ids_ list can reveal when a stale back/forward
760 // navigation arrives from the browser and can be ignored. See
761 // http://crbug.com/86758.
762 TEST_F(RenderViewImplTest
, StaleNavigationsIgnored
) {
764 LoadHTML("<div>Page A</div>");
765 EXPECT_EQ(1, view()->history_list_length_
);
766 EXPECT_EQ(0, view()->history_list_offset_
);
767 EXPECT_EQ(1, view()->history_page_ids_
[0]);
769 // Load page B, which will trigger an UpdateState message for page A.
770 LoadHTML("<div>Page B</div>");
771 EXPECT_EQ(2, view()->history_list_length_
);
772 EXPECT_EQ(1, view()->history_list_offset_
);
773 EXPECT_EQ(2, view()->history_page_ids_
[1]);
775 // Check for a valid UpdateState message for page A.
776 ProcessPendingMessages();
777 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
778 ViewHostMsg_UpdateState::ID
);
780 ViewHostMsg_UpdateState::Param param
;
781 ViewHostMsg_UpdateState::Read(msg_A
, ¶m
);
782 int page_id_A
= param
.a
;
783 PageState state_A
= param
.b
;
784 EXPECT_EQ(1, page_id_A
);
785 render_thread_
->sink().ClearMessages();
787 // Back to page A (page_id 1) and commit.
788 FrameMsg_Navigate_Params params_A
;
789 params_A
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
790 params_A
.common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
791 params_A
.current_history_list_length
= 2;
792 params_A
.current_history_list_offset
= 1;
793 params_A
.pending_history_list_offset
= 0;
794 params_A
.page_id
= 1;
795 params_A
.commit_params
.page_state
= state_A
;
796 params_A
.commit_params
.browser_navigation_start
=
797 base::TimeTicks::FromInternalValue(1);
798 frame()->OnNavigate(params_A
);
799 ProcessPendingMessages();
801 // A new navigation commits, clearing the forward history.
802 LoadHTML("<div>Page C</div>");
803 EXPECT_EQ(2, view()->history_list_length_
);
804 EXPECT_EQ(1, view()->history_list_offset_
);
805 EXPECT_EQ(3, view()->history_page_ids_
[1]);
807 // The browser then sends a stale navigation to B, which should be ignored.
808 FrameMsg_Navigate_Params params_B
;
809 params_B
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
810 params_B
.common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
811 params_B
.current_history_list_length
= 2;
812 params_B
.current_history_list_offset
= 0;
813 params_B
.pending_history_list_offset
= 1;
814 params_B
.page_id
= 2;
815 params_B
.commit_params
.page_state
=
816 state_A
; // Doesn't matter, just has to be present.
817 params_B
.commit_params
.browser_navigation_start
=
818 base::TimeTicks::FromInternalValue(1);
819 frame()->OnNavigate(params_B
);
821 // State should be unchanged.
822 EXPECT_EQ(2, view()->history_list_length_
);
823 EXPECT_EQ(1, view()->history_list_offset_
);
824 EXPECT_EQ(3, view()->history_page_ids_
[1]);
827 // Test that we do not ignore navigations after the entry limit is reached,
828 // in which case the browser starts dropping entries from the front. In this
829 // case, we'll see a page_id mismatch but the RenderView's id will be older,
830 // not newer, than params.page_id. Use this as a cue that we should update the
831 // state and not treat it like a navigation to a cropped forward history item.
832 // See http://crbug.com/89798.
833 TEST_F(RenderViewImplTest
, DontIgnoreBackAfterNavEntryLimit
) {
835 LoadHTML("<div>Page A</div>");
836 EXPECT_EQ(1, view()->history_list_length_
);
837 EXPECT_EQ(0, view()->history_list_offset_
);
838 EXPECT_EQ(1, view()->history_page_ids_
[0]);
840 // Load page B, which will trigger an UpdateState message for page A.
841 LoadHTML("<div>Page B</div>");
842 EXPECT_EQ(2, view()->history_list_length_
);
843 EXPECT_EQ(1, view()->history_list_offset_
);
844 EXPECT_EQ(2, view()->history_page_ids_
[1]);
846 // Check for a valid UpdateState message for page A.
847 ProcessPendingMessages();
848 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
849 ViewHostMsg_UpdateState::ID
);
851 ViewHostMsg_UpdateState::Param param
;
852 ViewHostMsg_UpdateState::Read(msg_A
, ¶m
);
853 int page_id_A
= param
.a
;
854 PageState state_A
= param
.b
;
855 EXPECT_EQ(1, page_id_A
);
856 render_thread_
->sink().ClearMessages();
858 // Load page C, which will trigger an UpdateState message for page B.
859 LoadHTML("<div>Page C</div>");
860 EXPECT_EQ(3, view()->history_list_length_
);
861 EXPECT_EQ(2, view()->history_list_offset_
);
862 EXPECT_EQ(3, view()->history_page_ids_
[2]);
864 // Check for a valid UpdateState message for page B.
865 ProcessPendingMessages();
866 const IPC::Message
* msg_B
= render_thread_
->sink().GetUniqueMessageMatching(
867 ViewHostMsg_UpdateState::ID
);
869 ViewHostMsg_UpdateState::Read(msg_B
, ¶m
);
870 int page_id_B
= param
.a
;
871 PageState state_B
= param
.b
;
872 EXPECT_EQ(2, page_id_B
);
873 render_thread_
->sink().ClearMessages();
875 // Suppose the browser has limited the number of NavigationEntries to 2.
876 // It has now dropped the first entry, but the renderer isn't notified.
877 // Ensure that going back to page B (page_id 2) at offset 0 is successful.
878 FrameMsg_Navigate_Params params_B
;
879 params_B
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
880 params_B
.common_params
.transition
= ui::PAGE_TRANSITION_FORWARD_BACK
;
881 params_B
.current_history_list_length
= 2;
882 params_B
.current_history_list_offset
= 1;
883 params_B
.pending_history_list_offset
= 0;
884 params_B
.page_id
= 2;
885 params_B
.commit_params
.page_state
= state_B
;
886 params_B
.commit_params
.browser_navigation_start
=
887 base::TimeTicks::FromInternalValue(1);
888 frame()->OnNavigate(params_B
);
889 ProcessPendingMessages();
891 EXPECT_EQ(2, view()->history_list_length_
);
892 EXPECT_EQ(0, view()->history_list_offset_
);
893 EXPECT_EQ(2, view()->history_page_ids_
[0]);
896 // Test that our IME backend sends a notification message when the input focus
898 TEST_F(RenderViewImplTest
, OnImeTypeChanged
) {
899 // Enable our IME backend code.
900 view()->OnSetInputMethodActive(true);
902 // Load an HTML page consisting of two input fields.
903 view()->set_send_content_state_immediately(true);
908 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
909 "<input id=\"test2\" type=\"password\"></input>"
910 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
911 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
912 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
913 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
915 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
917 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
918 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
919 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
920 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
921 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
922 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
923 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
924 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
927 render_thread_
->sink().ClearMessages();
929 struct InputModeTestCase
{
930 const char* input_id
;
931 ui::TextInputMode expected_mode
;
933 static const InputModeTestCase kInputModeTestCases
[] = {
934 {"test1", ui::TEXT_INPUT_MODE_DEFAULT
},
935 {"test3", ui::TEXT_INPUT_MODE_VERBATIM
},
936 {"test4", ui::TEXT_INPUT_MODE_LATIN
},
937 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME
},
938 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE
},
939 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN
},
940 {"test8", ui::TEXT_INPUT_MODE_KANA
},
941 {"test9", ui::TEXT_INPUT_MODE_KATAKANA
},
942 {"test10", ui::TEXT_INPUT_MODE_NUMERIC
},
943 {"test11", ui::TEXT_INPUT_MODE_TEL
},
944 {"test12", ui::TEXT_INPUT_MODE_EMAIL
},
945 {"test13", ui::TEXT_INPUT_MODE_URL
},
946 {"test14", ui::TEXT_INPUT_MODE_DEFAULT
},
947 {"test15", ui::TEXT_INPUT_MODE_VERBATIM
},
950 const int kRepeatCount
= 10;
951 for (int i
= 0; i
< kRepeatCount
; i
++) {
952 // Move the input focus to the first <input> element, where we should
954 ExecuteJavaScript("document.getElementById('test1').focus();");
955 ProcessPendingMessages();
956 render_thread_
->sink().ClearMessages();
958 // Update the IME status and verify if our IME backend sends an IPC message
960 view()->UpdateTextInputType();
961 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
962 EXPECT_TRUE(msg
!= NULL
);
963 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
964 ViewHostMsg_TextInputTypeChanged::Param params
;
965 ViewHostMsg_TextInputTypeChanged::Read(msg
, ¶ms
);
966 ui::TextInputType type
= params
.a
;
967 ui::TextInputMode input_mode
= params
.b
;
968 bool can_compose_inline
= params
.c
;
969 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT
, type
);
970 EXPECT_EQ(true, can_compose_inline
);
972 // Move the input focus to the second <input> element, where we should
974 ExecuteJavaScript("document.getElementById('test2').focus();");
975 ProcessPendingMessages();
976 render_thread_
->sink().ClearMessages();
978 // Update the IME status and verify if our IME backend sends an IPC message
979 // to de-activate IMEs.
980 view()->UpdateTextInputType();
981 msg
= render_thread_
->sink().GetMessageAt(0);
982 EXPECT_TRUE(msg
!= NULL
);
983 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
984 ViewHostMsg_TextInputTypeChanged::Read(msg
, & params
);
986 input_mode
= params
.b
;
987 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD
, type
);
989 for (size_t i
= 0; i
< arraysize(kInputModeTestCases
); i
++) {
990 const InputModeTestCase
* test_case
= &kInputModeTestCases
[i
];
991 std::string javascript
=
992 base::StringPrintf("document.getElementById('%s').focus();",
993 test_case
->input_id
);
994 // Move the input focus to the target <input> element, where we should
996 ExecuteJavaScriptAndReturnIntValue(base::ASCIIToUTF16(javascript
), NULL
);
997 ProcessPendingMessages();
998 render_thread_
->sink().ClearMessages();
1000 // Update the IME status and verify if our IME backend sends an IPC
1001 // message to activate IMEs.
1002 view()->UpdateTextInputType();
1003 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
1004 EXPECT_TRUE(msg
!= NULL
);
1005 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
1006 ViewHostMsg_TextInputTypeChanged::Read(msg
, & params
);
1008 input_mode
= params
.b
;
1009 EXPECT_EQ(test_case
->expected_mode
, input_mode
);
1014 // Test that our IME backend can compose CJK words.
1015 // Our IME front-end sends many platform-independent messages to the IME backend
1016 // while it composes CJK words. This test sends the minimal messages captured
1017 // on my local environment directly to the IME backend to verify if the backend
1018 // can compose CJK words without any problems.
1019 // This test uses an array of command sets because an IME composotion does not
1020 // only depends on IME events, but also depends on window events, e.g. moving
1021 // the window focus while composing a CJK text. To handle such complicated
1022 // cases, this test should not only call IME-related functions in the
1023 // RenderWidget class, but also call some RenderWidget members, e.g.
1024 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc.
1025 TEST_F(RenderViewImplTest
, ImeComposition
) {
1031 IME_CONFIRMCOMPOSITION
,
1032 IME_CANCELCOMPOSITION
1037 int selection_start
;
1039 const wchar_t* ime_string
;
1040 const wchar_t* result
;
1042 static const ImeMessage kImeMessages
[] = {
1043 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
1044 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1045 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1046 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1047 {IME_SETCOMPOSITION
, false, 1, 1, L
"n", L
"n"},
1048 {IME_SETCOMPOSITION
, false, 2, 2, L
"ni", L
"ni"},
1049 {IME_SETCOMPOSITION
, false, 3, 3, L
"nih", L
"nih"},
1050 {IME_SETCOMPOSITION
, false, 4, 4, L
"niha", L
"niha"},
1051 {IME_SETCOMPOSITION
, false, 5, 5, L
"nihao", L
"nihao"},
1052 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"\x4F60\x597D", L
"\x4F60\x597D"},
1053 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
1054 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1055 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1056 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1057 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xFF4B", L
"\xFF4B"},
1058 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x304B", L
"\x304B"},
1059 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x304B\xFF4E", L
"\x304B\xFF4E"},
1060 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\xFF4A",
1061 L
"\x304B\x3093\xFF4A"},
1062 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\x3058",
1063 L
"\x304B\x3093\x3058"},
1064 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x611F\x3058", L
"\x611F\x3058"},
1065 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x6F22\x5B57", L
"\x6F22\x5B57"},
1066 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1067 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1068 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1069 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1070 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1071 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1072 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3147", L
"\x3147"},
1073 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC544", L
"\xC544"},
1074 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC548", L
"\xC548"},
1075 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1076 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3134", L
"\xC548\x3134"},
1077 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB140", L
"\xC548\xB140"},
1078 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1079 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1080 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1081 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548\xB155"},
1084 for (size_t i
= 0; i
< arraysize(kImeMessages
); i
++) {
1085 const ImeMessage
* ime_message
= &kImeMessages
[i
];
1086 switch (ime_message
->command
) {
1087 case IME_INITIALIZE
:
1088 // Load an HTML page consisting of a content-editable <div> element,
1089 // and move the input focus to the <div> element, where we can use
1091 view()->OnSetInputMethodActive(ime_message
->enable
);
1092 view()->set_send_content_state_immediately(true);
1097 "<div id=\"test1\" contenteditable=\"true\"></div>"
1100 ExecuteJavaScript("document.getElementById('test1').focus();");
1103 case IME_SETINPUTMODE
:
1104 // Activate (or deactivate) our IME back-end.
1105 view()->OnSetInputMethodActive(ime_message
->enable
);
1109 // Update the window focus.
1110 view()->OnSetFocus(ime_message
->enable
);
1113 case IME_SETCOMPOSITION
:
1114 view()->OnImeSetComposition(
1115 base::WideToUTF16(ime_message
->ime_string
),
1116 std::vector
<blink::WebCompositionUnderline
>(),
1117 ime_message
->selection_start
,
1118 ime_message
->selection_end
);
1121 case IME_CONFIRMCOMPOSITION
:
1122 view()->OnImeConfirmComposition(
1123 base::WideToUTF16(ime_message
->ime_string
),
1124 gfx::Range::InvalidRange(),
1128 case IME_CANCELCOMPOSITION
:
1129 view()->OnImeSetComposition(
1131 std::vector
<blink::WebCompositionUnderline
>(),
1136 // Update the status of our IME back-end.
1137 // TODO(hbono): we should verify messages to be sent from the back-end.
1138 view()->UpdateTextInputType();
1139 ProcessPendingMessages();
1140 render_thread_
->sink().ClearMessages();
1142 if (ime_message
->result
) {
1143 // Retrieve the content of this page and compare it with the expected
1145 const int kMaxOutputCharacters
= 128;
1146 base::string16 output
=
1147 GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1148 EXPECT_EQ(base::WideToUTF16(ime_message
->result
), output
);
1153 // Test that the RenderView::OnSetTextDirection() function can change the text
1154 // direction of the selected input element.
1155 TEST_F(RenderViewImplTest
, OnSetTextDirection
) {
1156 // Load an HTML page consisting of a <textarea> element and a <div> element.
1157 // This test changes the text direction of the <textarea> element, and
1158 // writes the values of its 'dir' attribute and its 'direction' property to
1159 // verify that the text direction is changed.
1160 view()->set_send_content_state_immediately(true);
1165 "<textarea id=\"test\"></textarea>"
1166 "<div id=\"result\" contenteditable=\"true\"></div>"
1169 render_thread_
->sink().ClearMessages();
1171 static const struct {
1172 WebTextDirection direction
;
1173 const wchar_t* expected_result
;
1174 } kTextDirection
[] = {
1175 { blink::WebTextDirectionRightToLeft
, L
"\x000A" L
"rtl,rtl" },
1176 { blink::WebTextDirectionLeftToRight
, L
"\x000A" L
"ltr,ltr" },
1178 for (size_t i
= 0; i
< arraysize(kTextDirection
); ++i
) {
1179 // Set the text direction of the <textarea> element.
1180 ExecuteJavaScript("document.getElementById('test').focus();");
1181 view()->OnSetTextDirection(kTextDirection
[i
].direction
);
1183 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1184 // property to the <div> element.
1185 ExecuteJavaScript("var result = document.getElementById('result');"
1186 "var node = document.getElementById('test');"
1187 "var style = getComputedStyle(node, null);"
1188 "result.innerText ="
1189 " node.getAttribute('dir') + ',' +"
1190 " style.getPropertyValue('direction');");
1192 // Copy the document content to std::wstring and compare with the
1194 const int kMaxOutputCharacters
= 16;
1195 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1196 EXPECT_EQ(base::WideToUTF16(kTextDirection
[i
].expected_result
), output
);
1200 // see http://crbug.com/238750
1202 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent
1204 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent
1207 // Test that we can receive correct DOM events when we send input events
1208 // through the RenderWidget::OnHandleInputEvent() function.
1209 TEST_F(RenderViewImplTest
, MAYBE_OnHandleKeyboardEvent
) {
1210 #if !defined(OS_MACOSX)
1211 // Load an HTML page consisting of one <input> element and three
1212 // contentediable <div> elements.
1213 // The <input> element is used for sending keyboard events, and the <div>
1214 // elements are used for writing DOM events in the following format:
1215 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1216 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1217 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1218 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1219 view()->set_send_content_state_immediately(true);
1223 "<script type='text/javascript' language='javascript'>"
1224 "function OnKeyEvent(ev) {"
1225 " var result = document.getElementById(ev.type);"
1226 " result.innerText ="
1227 " (ev.which || ev.keyCode) + ',' +"
1228 " ev.shiftKey + ',' +"
1229 " ev.ctrlKey + ',' +"
1236 "<input id='test' type='text'"
1237 " onkeydown='return OnKeyEvent(event);'"
1238 " onkeypress='return OnKeyEvent(event);'"
1239 " onkeyup='return OnKeyEvent(event);'>"
1241 "<div id='keydown' contenteditable='true'>"
1243 "<div id='keypress' contenteditable='true'>"
1245 "<div id='keyup' contenteditable='true'>"
1249 ExecuteJavaScript("document.getElementById('test').focus();");
1250 render_thread_
->sink().ClearMessages();
1252 static const MockKeyboard::Layout kLayouts
[] = {
1254 // Since we ignore the mock keyboard layout on Linux and instead just use
1255 // the screen's keyboard layout, these trivially pass. They are commented
1256 // out to avoid the illusion that they work.
1257 MockKeyboard::LAYOUT_ARABIC
,
1258 MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1259 MockKeyboard::LAYOUT_FRENCH
,
1260 MockKeyboard::LAYOUT_HEBREW
,
1261 MockKeyboard::LAYOUT_RUSSIAN
,
1263 MockKeyboard::LAYOUT_UNITED_STATES
,
1266 for (size_t i
= 0; i
< arraysize(kLayouts
); ++i
) {
1267 // For each key code, we send three keyboard events.
1268 // * we press only the key;
1269 // * we press the key and a left-shift key, and;
1270 // * we press the key and a right-alt (AltGr) key.
1271 // For each modifiers, we need a string used for formatting its expected
1272 // result. (See the above comment for its format.)
1273 static const struct {
1274 MockKeyboard::Modifiers modifiers
;
1275 const char* expected_result
;
1276 } kModifierData
[] = {
1277 {MockKeyboard::NONE
, "false,false,false"},
1278 {MockKeyboard::LEFT_SHIFT
, "true,false,false"},
1280 {MockKeyboard::RIGHT_ALT
, "false,false,true"},
1284 MockKeyboard::Layout layout
= kLayouts
[i
];
1285 for (size_t j
= 0; j
< arraysize(kModifierData
); ++j
) {
1286 // Virtual key codes used for this test.
1287 static const int kKeyCodes
[] = {
1288 '0', '1', '2', '3', '4', '5', '6', '7',
1289 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1290 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1291 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1297 ui::VKEY_OEM_PERIOD
,
1305 // Not sure how to handle this key on Linux.
1310 MockKeyboard::Modifiers modifiers
= kModifierData
[j
].modifiers
;
1311 for (size_t k
= 0; k
< arraysize(kKeyCodes
); ++k
) {
1312 // Send a keyboard event to the RenderView object.
1313 // We should test a keyboard event only when the given keyboard-layout
1314 // driver is installed in a PC and the driver can assign a Unicode
1315 // charcter for the given tuple (key-code and modifiers).
1316 int key_code
= kKeyCodes
[k
];
1317 base::string16 char_code
;
1318 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1321 // Create an expected result from the virtual-key code, the character
1322 // code, and the modifier-key status.
1323 // We format a string that emulates a DOM-event string produced hy
1324 // our JavaScript function. (See the above comment for the format.)
1325 static char expected_result
[1024];
1326 expected_result
[0] = 0;
1327 base::snprintf(&expected_result
[0],
1328 sizeof(expected_result
),
1329 "\n" // texts in the <input> element
1330 "%d,%s\n" // texts in the first <div> element
1331 "%d,%s\n" // texts in the second <div> element
1332 "%d,%s", // texts in the third <div> element
1333 key_code
, kModifierData
[j
].expected_result
,
1334 static_cast<int>(char_code
[0]),
1335 kModifierData
[j
].expected_result
,
1336 key_code
, kModifierData
[j
].expected_result
);
1338 // Retrieve the text in the test page and compare it with the expected
1339 // text created from a virtual-key code, a character code, and the
1340 // modifier-key status.
1341 const int kMaxOutputCharacters
= 1024;
1342 std::string output
= base::UTF16ToUTF8(
1343 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
1344 EXPECT_EQ(expected_result
, output
);
1353 // Test that our EditorClientImpl class can insert characters when we send
1354 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1355 // This test is for preventing regressions caused only when we use non-US
1356 // keyboards, such as Issue 10846.
1357 // see http://crbug.com/244562
1359 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1361 #define MAYBE_InsertCharacters InsertCharacters
1363 TEST_F(RenderViewImplTest
, MAYBE_InsertCharacters
) {
1364 #if !defined(OS_MACOSX)
1365 static const struct {
1366 MockKeyboard::Layout layout
;
1367 const wchar_t* expected_result
;
1370 // Disabled these keyboard layouts because buildbots do not have their
1371 // keyboard-layout drivers installed.
1372 {MockKeyboard::LAYOUT_ARABIC
,
1373 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1374 L
"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1375 L
"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1376 L
"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1377 L
"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1378 L
"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1379 L
"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1380 L
"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1381 L
"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1382 L
"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1383 L
"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1384 L
"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1385 L
"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1386 L
"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1387 L
"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1388 L
"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1389 L
"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1391 {MockKeyboard::LAYOUT_HEBREW
,
1392 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1393 L
"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1394 L
"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1395 L
"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1396 L
"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1397 L
"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1398 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1399 L
"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1400 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1401 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1402 L
"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1403 L
"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1404 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1405 L
"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1406 L
"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1407 L
"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1408 L
"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1409 L
"\x003b\x005d\x005c\x005b\x002c"
1413 // On Linux, the only way to test alternate keyboard layouts is to change
1414 // the keyboard layout of the whole screen. I'm worried about the side
1415 // effects this may have on the buildbots.
1416 {MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1417 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1418 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1419 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1420 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1421 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1422 L
"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1423 L
"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1424 L
"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1425 L
"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1426 L
"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1427 L
"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1428 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1429 L
"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1430 L
"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1431 L
"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1432 L
"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1435 {MockKeyboard::LAYOUT_FRENCH
,
1436 L
"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1437 L
"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1438 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1439 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1440 L
"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1441 L
"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1442 L
"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1443 L
"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1444 L
"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1445 L
"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1446 L
"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1447 L
"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1448 L
"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1449 L
"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1450 L
"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1451 L
"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1452 L
"\x003b\x003a\x00f9\x0029\x002a\x0021"
1454 {MockKeyboard::LAYOUT_RUSSIAN
,
1455 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1456 L
"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1457 L
"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1458 L
"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1459 L
"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1460 L
"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1461 L
"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1462 L
"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1463 L
"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1464 L
"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1465 L
"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1466 L
"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1467 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1468 L
"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1469 L
"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1470 L
"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1471 L
"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1472 L
"\x0451\x0445\x005c\x044a\x044d"
1474 #endif // defined(OS_WIN)
1475 {MockKeyboard::LAYOUT_UNITED_STATES
,
1476 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1477 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1478 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1479 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1480 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1481 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1482 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1483 L
"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1484 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1485 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1486 L
"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1487 L
"\x003f\x007e\x007b\x007c\x007d\x0022"
1489 // This is ifdefed out for Linux to correspond to the fact that we don't
1490 // test alt+keystroke for now.
1491 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1492 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1493 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1494 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1495 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1496 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1501 for (size_t i
= 0; i
< arraysize(kLayouts
); ++i
) {
1502 // Load an HTML page consisting of one <div> element.
1503 // This <div> element is used by the EditorClientImpl class to insert
1504 // characters received through the RenderWidget::OnHandleInputEvent()
1506 view()->set_send_content_state_immediately(true);
1512 "<div id='test' contenteditable='true'>"
1516 ExecuteJavaScript("document.getElementById('test').focus();");
1517 render_thread_
->sink().ClearMessages();
1519 // For each key code, we send three keyboard events.
1520 // * Pressing only the key;
1521 // * Pressing the key and a left-shift key, and;
1522 // * Pressing the key and a right-alt (AltGr) key.
1523 static const MockKeyboard::Modifiers kModifiers
[] = {
1525 MockKeyboard::LEFT_SHIFT
,
1527 MockKeyboard::RIGHT_ALT
,
1531 MockKeyboard::Layout layout
= kLayouts
[i
].layout
;
1532 for (size_t j
= 0; j
< arraysize(kModifiers
); ++j
) {
1533 // Virtual key codes used for this test.
1534 static const int kKeyCodes
[] = {
1535 '0', '1', '2', '3', '4', '5', '6', '7',
1536 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1537 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1538 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1544 ui::VKEY_OEM_PERIOD
,
1552 // Unclear how to handle this on Linux.
1557 MockKeyboard::Modifiers modifiers
= kModifiers
[j
];
1558 for (size_t k
= 0; k
< arraysize(kKeyCodes
); ++k
) {
1559 // Send a keyboard event to the RenderView object.
1560 // We should test a keyboard event only when the given keyboard-layout
1561 // driver is installed in a PC and the driver can assign a Unicode
1562 // charcter for the given tuple (layout, key-code, and modifiers).
1563 int key_code
= kKeyCodes
[k
];
1564 base::string16 char_code
;
1565 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1570 // Retrieve the text in the test page and compare it with the expected
1571 // text created from a virtual-key code, a character code, and the
1572 // modifier-key status.
1573 const int kMaxOutputCharacters
= 4096;
1574 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1575 EXPECT_EQ(base::WideToUTF16(kLayouts
[i
].expected_result
), output
);
1582 // Crashy, http://crbug.com/53247.
1583 TEST_F(RenderViewImplTest
, DISABLED_DidFailProvisionalLoadWithErrorForError
) {
1584 GetMainFrame()->enableViewSourceMode(true);
1586 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1587 error
.reason
= net::ERR_FILE_NOT_FOUND
;
1588 error
.unreachableURL
= GURL("http://foo");
1589 WebLocalFrame
* web_frame
= GetMainFrame();
1591 // Start a load that will reach provisional state synchronously,
1592 // but won't complete synchronously.
1593 FrameMsg_Navigate_Params params
;
1594 params
.page_id
= -1;
1595 params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1596 params
.common_params
.url
= GURL("data:text/html,test data");
1597 params
.commit_params
.browser_navigation_start
=
1598 base::TimeTicks::FromInternalValue(1);
1599 frame()->OnNavigate(params
);
1601 // An error occurred.
1602 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame
, error
);
1603 // Frame should exit view-source mode.
1604 EXPECT_FALSE(web_frame
->isViewSourceModeEnabled());
1607 TEST_F(RenderViewImplTest
, DidFailProvisionalLoadWithErrorForCancellation
) {
1608 GetMainFrame()->enableViewSourceMode(true);
1610 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1611 error
.reason
= net::ERR_ABORTED
;
1612 error
.unreachableURL
= GURL("http://foo");
1613 WebLocalFrame
* web_frame
= GetMainFrame();
1615 // Start a load that will reach provisional state synchronously,
1616 // but won't complete synchronously.
1617 FrameMsg_Navigate_Params params
;
1618 params
.page_id
= -1;
1619 params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1620 params
.common_params
.url
= GURL("data:text/html,test data");
1621 params
.commit_params
.browser_navigation_start
=
1622 base::TimeTicks::FromInternalValue(1);
1623 frame()->OnNavigate(params
);
1625 // A cancellation occurred.
1626 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame
, error
);
1627 // Frame should stay in view-source mode.
1628 EXPECT_TRUE(web_frame
->isViewSourceModeEnabled());
1631 // Regression test for http://crbug.com/41562
1632 TEST_F(RenderViewImplTest
, UpdateTargetURLWithInvalidURL
) {
1633 const GURL
invalid_gurl("http://");
1634 view()->setMouseOverURL(blink::WebURL(invalid_gurl
));
1635 EXPECT_EQ(invalid_gurl
, view()->target_url_
);
1638 TEST_F(RenderViewImplTest
, SetHistoryLengthAndPrune
) {
1639 int expected_page_id
= -1;
1641 // No history to merge and no committed pages.
1642 view()->OnSetHistoryLengthAndPrune(0, -1);
1643 EXPECT_EQ(0, view()->history_list_length_
);
1644 EXPECT_EQ(-1, view()->history_list_offset_
);
1646 // History to merge and no committed pages.
1647 view()->OnSetHistoryLengthAndPrune(2, -1);
1648 EXPECT_EQ(2, view()->history_list_length_
);
1649 EXPECT_EQ(1, view()->history_list_offset_
);
1650 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1651 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1654 blink::WebHistoryItem item
;
1657 // No history to merge and a committed page to be kept.
1658 frame()->didCommitProvisionalLoad(GetMainFrame(),
1660 blink::WebStandardCommit
);
1661 expected_page_id
= view()->page_id_
;
1662 view()->OnSetHistoryLengthAndPrune(0, expected_page_id
);
1663 EXPECT_EQ(1, view()->history_list_length_
);
1664 EXPECT_EQ(0, view()->history_list_offset_
);
1665 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[0]);
1668 // No history to merge and a committed page to be pruned.
1669 frame()->didCommitProvisionalLoad(GetMainFrame(),
1671 blink::WebStandardCommit
);
1672 expected_page_id
= view()->page_id_
;
1673 view()->OnSetHistoryLengthAndPrune(0, expected_page_id
+ 1);
1674 EXPECT_EQ(0, view()->history_list_length_
);
1675 EXPECT_EQ(-1, view()->history_list_offset_
);
1678 // No history to merge and a committed page that the browser was unaware of.
1679 frame()->didCommitProvisionalLoad(GetMainFrame(),
1681 blink::WebStandardCommit
);
1682 expected_page_id
= view()->page_id_
;
1683 view()->OnSetHistoryLengthAndPrune(0, -1);
1684 EXPECT_EQ(1, view()->history_list_length_
);
1685 EXPECT_EQ(0, view()->history_list_offset_
);
1686 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[0]);
1689 // History to merge and a committed page to be kept.
1690 frame()->didCommitProvisionalLoad(GetMainFrame(),
1692 blink::WebStandardCommit
);
1693 expected_page_id
= view()->page_id_
;
1694 view()->OnSetHistoryLengthAndPrune(2, expected_page_id
);
1695 EXPECT_EQ(3, view()->history_list_length_
);
1696 EXPECT_EQ(2, view()->history_list_offset_
);
1697 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1698 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1699 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[2]);
1702 // History to merge and a committed page to be pruned.
1703 frame()->didCommitProvisionalLoad(GetMainFrame(),
1705 blink::WebStandardCommit
);
1706 expected_page_id
= view()->page_id_
;
1707 view()->OnSetHistoryLengthAndPrune(2, expected_page_id
+ 1);
1708 EXPECT_EQ(2, view()->history_list_length_
);
1709 EXPECT_EQ(1, view()->history_list_offset_
);
1710 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1711 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1714 // History to merge and a committed page that the browser was unaware of.
1715 frame()->didCommitProvisionalLoad(GetMainFrame(),
1717 blink::WebStandardCommit
);
1718 expected_page_id
= view()->page_id_
;
1719 view()->OnSetHistoryLengthAndPrune(2, -1);
1720 EXPECT_EQ(3, view()->history_list_length_
);
1721 EXPECT_EQ(2, view()->history_list_offset_
);
1722 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1723 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1724 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[2]);
1727 int expected_page_id_2
= -1;
1729 // No history to merge and two committed pages, both to be kept.
1730 frame()->didCommitProvisionalLoad(GetMainFrame(),
1732 blink::WebStandardCommit
);
1733 expected_page_id
= view()->page_id_
;
1734 frame()->didCommitProvisionalLoad(GetMainFrame(),
1736 blink::WebStandardCommit
);
1737 expected_page_id_2
= view()->page_id_
;
1738 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1739 view()->OnSetHistoryLengthAndPrune(0, expected_page_id
);
1740 EXPECT_EQ(2, view()->history_list_length_
);
1741 EXPECT_EQ(1, view()->history_list_offset_
);
1742 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[0]);
1743 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[1]);
1746 // No history to merge and two committed pages, and only the second is kept.
1747 frame()->didCommitProvisionalLoad(GetMainFrame(),
1749 blink::WebStandardCommit
);
1750 expected_page_id
= view()->page_id_
;
1751 frame()->didCommitProvisionalLoad(GetMainFrame(),
1753 blink::WebStandardCommit
);
1754 expected_page_id_2
= view()->page_id_
;
1755 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1756 view()->OnSetHistoryLengthAndPrune(0, expected_page_id_2
);
1757 EXPECT_EQ(1, view()->history_list_length_
);
1758 EXPECT_EQ(0, view()->history_list_offset_
);
1759 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[0]);
1762 // No history to merge and two committed pages, both of which the browser was
1764 frame()->didCommitProvisionalLoad(GetMainFrame(),
1766 blink::WebStandardCommit
);
1767 expected_page_id
= view()->page_id_
;
1768 frame()->didCommitProvisionalLoad(GetMainFrame(),
1770 blink::WebStandardCommit
);
1771 expected_page_id_2
= view()->page_id_
;
1772 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1773 view()->OnSetHistoryLengthAndPrune(0, -1);
1774 EXPECT_EQ(2, view()->history_list_length_
);
1775 EXPECT_EQ(1, view()->history_list_offset_
);
1776 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[0]);
1777 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[1]);
1780 // History to merge and two committed pages, both to be kept.
1781 frame()->didCommitProvisionalLoad(GetMainFrame(),
1783 blink::WebStandardCommit
);
1784 expected_page_id
= view()->page_id_
;
1785 frame()->didCommitProvisionalLoad(GetMainFrame(),
1787 blink::WebStandardCommit
);
1788 expected_page_id_2
= view()->page_id_
;
1789 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1790 view()->OnSetHistoryLengthAndPrune(2, expected_page_id
);
1791 EXPECT_EQ(4, view()->history_list_length_
);
1792 EXPECT_EQ(3, view()->history_list_offset_
);
1793 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1794 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1795 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[2]);
1796 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[3]);
1799 // History to merge and two committed pages, and only the second is kept.
1800 frame()->didCommitProvisionalLoad(GetMainFrame(),
1802 blink::WebStandardCommit
);
1803 expected_page_id
= view()->page_id_
;
1804 frame()->didCommitProvisionalLoad(GetMainFrame(),
1806 blink::WebStandardCommit
);
1807 expected_page_id_2
= view()->page_id_
;
1808 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1809 view()->OnSetHistoryLengthAndPrune(2, expected_page_id_2
);
1810 EXPECT_EQ(3, view()->history_list_length_
);
1811 EXPECT_EQ(2, view()->history_list_offset_
);
1812 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1813 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1814 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[2]);
1817 // History to merge and two committed pages, both of which the browser was
1819 frame()->didCommitProvisionalLoad(GetMainFrame(),
1821 blink::WebStandardCommit
);
1822 expected_page_id
= view()->page_id_
;
1823 frame()->didCommitProvisionalLoad(GetMainFrame(),
1825 blink::WebStandardCommit
);
1826 expected_page_id_2
= view()->page_id_
;
1827 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1828 view()->OnSetHistoryLengthAndPrune(2, -1);
1829 EXPECT_EQ(4, view()->history_list_length_
);
1830 EXPECT_EQ(3, view()->history_list_offset_
);
1831 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1832 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1833 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[2]);
1834 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[3]);
1837 TEST_F(RenderViewImplTest
, ContextMenu
) {
1838 LoadHTML("<div>Page A</div>");
1840 // Create a right click in the center of the iframe. (I'm hoping this will
1841 // make this a bit more robust in case of some other formatting or other bug.)
1842 WebMouseEvent mouse_event
;
1843 mouse_event
.type
= WebInputEvent::MouseDown
;
1844 mouse_event
.button
= WebMouseEvent::ButtonRight
;
1845 mouse_event
.x
= 250;
1846 mouse_event
.y
= 250;
1847 mouse_event
.globalX
= 250;
1848 mouse_event
.globalY
= 250;
1850 SendWebMouseEvent(mouse_event
);
1852 // Now simulate the corresponding up event which should display the menu
1853 mouse_event
.type
= WebInputEvent::MouseUp
;
1854 SendWebMouseEvent(mouse_event
);
1856 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
1857 FrameHostMsg_ContextMenu::ID
));
1860 TEST_F(RenderViewImplTest
, TestBackForward
) {
1861 LoadHTML("<div id=pagename>Page A</div>");
1862 PageState page_a_state
=
1863 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1864 int was_page_a
= -1;
1865 base::string16 check_page_a
=
1867 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1868 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1869 EXPECT_EQ(1, was_page_a
);
1871 LoadHTML("<div id=pagename>Page B</div>");
1872 int was_page_b
= -1;
1873 base::string16 check_page_b
=
1875 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1876 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1877 EXPECT_EQ(1, was_page_b
);
1879 PageState back_state
=
1880 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1882 LoadHTML("<div id=pagename>Page C</div>");
1883 int was_page_c
= -1;
1884 base::string16 check_page_c
=
1886 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1887 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1888 EXPECT_EQ(1, was_page_b
);
1890 PageState forward_state
=
1891 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1893 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1894 EXPECT_EQ(1, was_page_b
);
1896 PageState back_state2
=
1897 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1899 GoForward(forward_state
);
1900 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1901 EXPECT_EQ(1, was_page_c
);
1903 GoBack(back_state2
);
1904 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1905 EXPECT_EQ(1, was_page_b
);
1908 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1909 GoBack(page_a_state
);
1910 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1911 EXPECT_EQ(1, was_page_a
);
1913 GoForward(forward_state
);
1914 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1915 EXPECT_EQ(1, was_page_b
);
1918 #if defined(OS_MACOSX) || defined(USE_AURA)
1919 TEST_F(RenderViewImplTest
, GetCompositionCharacterBoundsTest
) {
1922 // http://crbug.com/304193
1923 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
1927 LoadHTML("<textarea id=\"test\"></textarea>");
1928 ExecuteJavaScript("document.getElementById('test').focus();");
1930 const base::string16 empty_string
;
1931 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1932 std::vector
<gfx::Rect
> bounds
;
1933 view()->OnSetFocus(true);
1934 view()->OnSetInputMethodActive(true);
1936 // ASCII composition
1937 const base::string16 ascii_composition
= base::UTF8ToUTF16("aiueo");
1938 view()->OnImeSetComposition(ascii_composition
, empty_underline
, 0, 0);
1939 view()->GetCompositionCharacterBounds(&bounds
);
1940 ASSERT_EQ(ascii_composition
.size(), bounds
.size());
1941 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1942 EXPECT_LT(0, bounds
[i
].width());
1943 view()->OnImeConfirmComposition(
1944 empty_string
, gfx::Range::InvalidRange(), false);
1946 // Non surrogate pair unicode character.
1947 const base::string16 unicode_composition
= base::UTF8ToUTF16(
1948 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1949 view()->OnImeSetComposition(unicode_composition
, empty_underline
, 0, 0);
1950 view()->GetCompositionCharacterBounds(&bounds
);
1951 ASSERT_EQ(unicode_composition
.size(), bounds
.size());
1952 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1953 EXPECT_LT(0, bounds
[i
].width());
1954 view()->OnImeConfirmComposition(
1955 empty_string
, gfx::Range::InvalidRange(), false);
1957 // Surrogate pair character.
1958 const base::string16 surrogate_pair_char
=
1959 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1960 view()->OnImeSetComposition(surrogate_pair_char
,
1964 view()->GetCompositionCharacterBounds(&bounds
);
1965 ASSERT_EQ(surrogate_pair_char
.size(), bounds
.size());
1966 EXPECT_LT(0, bounds
[0].width());
1967 EXPECT_EQ(0, bounds
[1].width());
1968 view()->OnImeConfirmComposition(
1969 empty_string
, gfx::Range::InvalidRange(), false);
1972 const base::string16 surrogate_pair_mixed_composition
=
1973 surrogate_pair_char
+ base::UTF8ToUTF16("\xE3\x81\x82") +
1974 surrogate_pair_char
+ base::UTF8ToUTF16("b") + surrogate_pair_char
;
1975 const size_t utf16_length
= 8UL;
1976 const bool is_surrogate_pair_empty_rect
[8] = {
1977 false, true, false, false, true, false, false, true };
1978 view()->OnImeSetComposition(surrogate_pair_mixed_composition
,
1982 view()->GetCompositionCharacterBounds(&bounds
);
1983 ASSERT_EQ(utf16_length
, bounds
.size());
1984 for (size_t i
= 0; i
< utf16_length
; ++i
) {
1985 if (is_surrogate_pair_empty_rect
[i
]) {
1986 EXPECT_EQ(0, bounds
[i
].width());
1988 EXPECT_LT(0, bounds
[i
].width());
1991 view()->OnImeConfirmComposition(
1992 empty_string
, gfx::Range::InvalidRange(), false);
1996 TEST_F(RenderViewImplTest
, ZoomLimit
) {
1997 const double kMinZoomLevel
= ZoomFactorToZoomLevel(kMinimumZoomFactor
);
1998 const double kMaxZoomLevel
= ZoomFactorToZoomLevel(kMaximumZoomFactor
);
2000 FrameMsg_Navigate_Params params
;
2001 params
.page_id
= -1;
2002 params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2003 params
.commit_params
.browser_navigation_start
=
2004 base::TimeTicks::FromInternalValue(1);
2006 // Verifies navigation to a URL with preset zoom level indeed sets the level.
2007 // Regression test for http://crbug.com/139559, where the level was not
2008 // properly set when it is out of the default zoom limits of WebView.
2009 params
.common_params
.url
= GURL("data:text/html,min_zoomlimit_test");
2010 view()->OnSetZoomLevelForLoadingURL(params
.common_params
.url
, kMinZoomLevel
);
2011 frame()->OnNavigate(params
);
2012 ProcessPendingMessages();
2013 EXPECT_DOUBLE_EQ(kMinZoomLevel
, view()->GetWebView()->zoomLevel());
2015 // It should work even when the zoom limit is temporarily changed in the page.
2016 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
2017 ZoomFactorToZoomLevel(1.0));
2018 params
.common_params
.url
= GURL("data:text/html,max_zoomlimit_test");
2019 view()->OnSetZoomLevelForLoadingURL(params
.common_params
.url
, kMaxZoomLevel
);
2020 frame()->OnNavigate(params
);
2021 ProcessPendingMessages();
2022 EXPECT_DOUBLE_EQ(kMaxZoomLevel
, view()->GetWebView()->zoomLevel());
2025 TEST_F(RenderViewImplTest
, SetEditableSelectionAndComposition
) {
2026 // Load an HTML page consisting of an input field.
2031 "<input id=\"test1\" value=\"some test text hello\"></input>"
2034 ExecuteJavaScript("document.getElementById('test1').focus();");
2035 frame()->OnSetEditableSelectionOffsets(4, 8);
2036 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
2037 frame()->OnSetCompositionFromExistingText(7, 10, empty_underline
);
2038 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
2039 EXPECT_EQ(4, info
.selectionStart
);
2040 EXPECT_EQ(8, info
.selectionEnd
);
2041 EXPECT_EQ(7, info
.compositionStart
);
2042 EXPECT_EQ(10, info
.compositionEnd
);
2043 frame()->OnUnselect();
2044 info
= view()->webview()->textInputInfo();
2045 EXPECT_EQ(0, info
.selectionStart
);
2046 EXPECT_EQ(0, info
.selectionEnd
);
2050 TEST_F(RenderViewImplTest
, OnExtendSelectionAndDelete
) {
2051 // Load an HTML page consisting of an input field.
2056 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
2059 ExecuteJavaScript("document.getElementById('test1').focus();");
2060 frame()->OnSetEditableSelectionOffsets(10, 10);
2061 frame()->OnExtendSelectionAndDelete(3, 4);
2062 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
2063 EXPECT_EQ("abcdefgopqrstuvwxyz", info
.value
);
2064 EXPECT_EQ(7, info
.selectionStart
);
2065 EXPECT_EQ(7, info
.selectionEnd
);
2066 frame()->OnSetEditableSelectionOffsets(4, 8);
2067 frame()->OnExtendSelectionAndDelete(2, 5);
2068 info
= view()->webview()->textInputInfo();
2069 EXPECT_EQ("abuvwxyz", info
.value
);
2070 EXPECT_EQ(2, info
.selectionStart
);
2071 EXPECT_EQ(2, info
.selectionEnd
);
2074 // Test that the navigating specific frames works correctly.
2075 TEST_F(RenderViewImplTest
, NavigateFrame
) {
2077 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
2079 // Navigate the frame only.
2080 FrameMsg_Navigate_Params nav_params
;
2081 nav_params
.common_params
.url
= GURL("data:text/html,world");
2082 nav_params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2083 nav_params
.common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
2084 nav_params
.current_history_list_length
= 1;
2085 nav_params
.current_history_list_offset
= 0;
2086 nav_params
.pending_history_list_offset
= 1;
2087 nav_params
.page_id
= -1;
2088 nav_params
.frame_to_navigate
= "frame";
2089 nav_params
.commit_params
.browser_navigation_start
=
2090 base::TimeTicks::FromInternalValue(1);
2091 frame()->OnNavigate(nav_params
);
2093 RenderFrame::FromWebFrame(frame()->GetWebFrame()->firstChild())).Wait();
2095 // Copy the document content to std::wstring and compare with the
2097 const int kMaxOutputCharacters
= 256;
2098 std::string output
= base::UTF16ToUTF8(
2099 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
2100 EXPECT_EQ(output
, "hello \n\nworld");
2103 // This test ensures that a RenderFrame object is created for the top level
2104 // frame in the RenderView.
2105 TEST_F(RenderViewImplTest
, BasicRenderFrame
) {
2106 EXPECT_TRUE(view()->main_render_frame_
.get());
2109 TEST_F(RenderViewImplTest
, GetSSLStatusOfFrame
) {
2110 LoadHTML("<!DOCTYPE html><html><body></body></html>");
2112 WebLocalFrame
* frame
= GetMainFrame();
2113 SSLStatus ssl_status
= view()->GetSSLStatusOfFrame(frame
);
2114 EXPECT_FALSE(net::IsCertStatusError(ssl_status
.cert_status
));
2116 const_cast<blink::WebURLResponse
&>(frame
->dataSource()->response()).
2118 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS
, 0, 0,
2119 SignedCertificateTimestampIDStatusList()));
2120 ssl_status
= view()->GetSSLStatusOfFrame(frame
);
2121 EXPECT_TRUE(net::IsCertStatusError(ssl_status
.cert_status
));
2124 TEST_F(RenderViewImplTest
, MessageOrderInDidChangeSelection
) {
2125 view()->OnSetInputMethodActive(true);
2126 view()->set_send_content_state_immediately(true);
2127 LoadHTML("<textarea id=\"test\"></textarea>");
2129 view()->handling_input_event_
= true;
2130 ExecuteJavaScript("document.getElementById('test').focus();");
2132 bool is_input_type_called
= false;
2133 bool is_selection_called
= false;
2134 size_t last_input_type
= 0;
2135 size_t last_selection
= 0;
2137 for (size_t i
= 0; i
< render_thread_
->sink().message_count(); ++i
) {
2138 const uint32 type
= render_thread_
->sink().GetMessageAt(i
)->type();
2139 if (type
== ViewHostMsg_TextInputTypeChanged::ID
) {
2140 is_input_type_called
= true;
2141 last_input_type
= i
;
2142 } else if (type
== ViewHostMsg_SelectionChanged::ID
) {
2143 is_selection_called
= true;
2148 EXPECT_TRUE(is_input_type_called
);
2149 EXPECT_TRUE(is_selection_called
);
2151 // InputTypeChange shold be called earlier than SelectionChanged.
2152 EXPECT_LT(last_input_type
, last_selection
);
2155 class SuppressErrorPageTest
: public RenderViewTest
{
2157 ContentRendererClient
* CreateContentRendererClient() override
{
2158 return new TestContentRendererClient
;
2161 RenderViewImpl
* view() {
2162 return static_cast<RenderViewImpl
*>(view_
);
2165 RenderFrameImpl
* frame() {
2166 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
2170 class TestContentRendererClient
: public ContentRendererClient
{
2172 bool ShouldSuppressErrorPage(RenderFrame
* render_frame
,
2173 const GURL
& url
) override
{
2174 return url
== GURL("http://example.com/suppress");
2177 void GetNavigationErrorStrings(content::RenderView
* render_view
,
2178 blink::WebFrame
* frame
,
2179 const blink::WebURLRequest
& failed_request
,
2180 const blink::WebURLError
& error
,
2181 std::string
* error_html
,
2182 base::string16
* error_description
) override
{
2184 *error_html
= "A suffusion of yellow.";
2189 #if defined(OS_ANDROID)
2190 // Crashing on Android: http://crbug.com/311341
2191 #define MAYBE_Suppresses DISABLED_Suppresses
2193 #define MAYBE_Suppresses Suppresses
2196 TEST_F(SuppressErrorPageTest
, MAYBE_Suppresses
) {
2198 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2199 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2200 error
.unreachableURL
= GURL("http://example.com/suppress");
2201 WebLocalFrame
* web_frame
= GetMainFrame();
2203 // Start a load that will reach provisional state synchronously,
2204 // but won't complete synchronously.
2205 FrameMsg_Navigate_Params params
;
2206 params
.page_id
= -1;
2207 params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2208 params
.common_params
.url
= GURL("data:text/html,test data");
2209 params
.commit_params
.browser_navigation_start
=
2210 base::TimeTicks::FromInternalValue(1);
2211 frame()->OnNavigate(params
);
2213 // An error occurred.
2214 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame
, error
);
2215 const int kMaxOutputCharacters
= 22;
2217 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2220 #if defined(OS_ANDROID)
2221 // Crashing on Android: http://crbug.com/311341
2222 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2224 #define MAYBE_DoesNotSuppress DoesNotSuppress
2227 TEST_F(SuppressErrorPageTest
, MAYBE_DoesNotSuppress
) {
2229 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2230 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2231 error
.unreachableURL
= GURL("http://example.com/dont-suppress");
2232 WebLocalFrame
* web_frame
= GetMainFrame();
2234 // Start a load that will reach provisional state synchronously,
2235 // but won't complete synchronously.
2236 FrameMsg_Navigate_Params params
;
2237 params
.page_id
= -1;
2238 params
.common_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2239 params
.common_params
.url
= GURL("data:text/html,test data");
2240 params
.commit_params
.browser_navigation_start
=
2241 base::TimeTicks::FromInternalValue(1);
2242 frame()->OnNavigate(params
);
2244 // An error occurred.
2245 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame
, error
);
2246 // The error page itself is loaded asynchronously.
2247 FrameLoadWaiter(frame()).Wait();
2248 const int kMaxOutputCharacters
= 22;
2249 EXPECT_EQ("A suffusion of yellow.",
2250 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2253 // Tests if IME API's candidatewindow* events sent from browser are handled
2255 TEST_F(RenderViewImplTest
, SendCandidateWindowEvents
) {
2256 // Sends an HTML with an <input> element and scripts to the renderer.
2257 // The script handles all 3 of candidatewindow* events for an
2258 // InputMethodContext object and once it received 'show', 'update', 'hide'
2259 // should appear in the result div.
2260 LoadHTML("<input id='test'>"
2261 "<div id='result'>Result: </div>"
2263 "window.onload = function() {"
2264 " var result = document.getElementById('result');"
2265 " var test = document.getElementById('test');"
2267 " var context = test.inputMethodContext;"
2269 " context.oncandidatewindowshow = function() {"
2270 " result.innerText += 'show'; };"
2271 " context.oncandidatewindowupdate = function(){"
2272 " result.innerText += 'update'; };"
2273 " context.oncandidatewindowhide = function(){"
2274 " result.innerText += 'hide'; };"
2279 // Fire candidatewindow events.
2280 view()->OnCandidateWindowShown();
2281 view()->OnCandidateWindowUpdated();
2282 view()->OnCandidateWindowHidden();
2284 // Retrieve the content and check if it is expected.
2285 const int kMaxOutputCharacters
= 50;
2286 std::string output
= base::UTF16ToUTF8(
2287 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
2288 EXPECT_EQ(output
, "\nResult:showupdatehide");
2291 // Ensure the render view sends favicon url update events correctly.
2292 TEST_F(RenderViewImplTest
, SendFaviconURLUpdateEvent
) {
2293 // An event should be sent when a favicon url exists.
2296 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2299 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
2300 ViewHostMsg_UpdateFaviconURL::ID
));
2301 render_thread_
->sink().ClearMessages();
2303 // An event should not be sent if no favicon url exists. This is an assumption
2304 // made by some of Chrome's favicon handling.
2309 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
2310 ViewHostMsg_UpdateFaviconURL::ID
));
2313 TEST_F(RenderViewImplTest
, FocusElementCallsFocusedNodeChanged
) {
2314 LoadHTML("<input id='test1' value='hello1'></input>"
2315 "<input id='test2' value='hello2'></input>");
2317 ExecuteJavaScript("document.getElementById('test1').focus();");
2318 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
2319 ViewHostMsg_FocusedNodeChanged::ID
);
2322 ViewHostMsg_FocusedNodeChanged::Param params
;
2323 ViewHostMsg_FocusedNodeChanged::Read(msg1
, ¶ms
);
2324 EXPECT_TRUE(params
.a
);
2325 render_thread_
->sink().ClearMessages();
2327 ExecuteJavaScript("document.getElementById('test2').focus();");
2328 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
2329 ViewHostMsg_FocusedNodeChanged::ID
);
2331 ViewHostMsg_FocusedNodeChanged::Read(msg2
, ¶ms
);
2332 EXPECT_TRUE(params
.a
);
2333 render_thread_
->sink().ClearMessages();
2335 view()->webview()->clearFocusedElement();
2336 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
2337 ViewHostMsg_FocusedNodeChanged::ID
);
2339 ViewHostMsg_FocusedNodeChanged::Read(msg3
, ¶ms
);
2340 EXPECT_FALSE(params
.a
);
2341 render_thread_
->sink().ClearMessages();
2344 TEST_F(RenderViewImplTest
, ServiceWorkerNetworkProviderSetup
) {
2345 ServiceWorkerNetworkProvider
* provider
= NULL
;
2346 RequestExtraData
* extra_data
= NULL
;
2348 // Make sure each new document has a new provider and
2349 // that the main request is tagged with the provider's id.
2350 LoadHTML("<b>A Document</b>");
2351 ASSERT_TRUE(GetMainFrame()->dataSource());
2352 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2353 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2354 ASSERT_TRUE(provider
);
2355 extra_data
= static_cast<RequestExtraData
*>(
2356 GetMainFrame()->dataSource()->request().extraData());
2357 ASSERT_TRUE(extra_data
);
2358 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2359 provider
->provider_id());
2360 int provider1_id
= provider
->provider_id();
2362 LoadHTML("<b>New Document B Goes Here</b>");
2363 ASSERT_TRUE(GetMainFrame()->dataSource());
2364 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2365 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2366 ASSERT_TRUE(provider
);
2367 EXPECT_NE(provider1_id
, provider
->provider_id());
2368 extra_data
= static_cast<RequestExtraData
*>(
2369 GetMainFrame()->dataSource()->request().extraData());
2370 ASSERT_TRUE(extra_data
);
2371 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2372 provider
->provider_id());
2374 // See that subresource requests are also tagged with the provider's id.
2375 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2376 blink::WebURLRequest
request(GURL("http://foo.com"));
2377 request
.setRequestContext(blink::WebURLRequest::RequestContextSubresource
);
2378 blink::WebURLResponse redirect_response
;
2379 frame()->willSendRequest(GetMainFrame(), 0, request
, redirect_response
);
2380 extra_data
= static_cast<RequestExtraData
*>(request
.extraData());
2381 ASSERT_TRUE(extra_data
);
2382 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2383 provider
->provider_id());
2386 TEST_F(RenderViewImplTest
, OnSetAccessibilityMode
) {
2387 ASSERT_EQ(AccessibilityModeOff
, frame()->accessibility_mode());
2388 ASSERT_EQ((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2390 frame()->OnSetAccessibilityMode(AccessibilityModeTreeOnly
);
2391 ASSERT_EQ(AccessibilityModeTreeOnly
, frame()->accessibility_mode());
2392 ASSERT_NE((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2394 frame()->OnSetAccessibilityMode(AccessibilityModeOff
);
2395 ASSERT_EQ(AccessibilityModeOff
, frame()->accessibility_mode());
2396 ASSERT_EQ((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2398 frame()->OnSetAccessibilityMode(AccessibilityModeComplete
);
2399 ASSERT_EQ(AccessibilityModeComplete
, frame()->accessibility_mode());
2400 ASSERT_NE((RendererAccessibility
*) NULL
, frame()->renderer_accessibility());
2403 TEST_F(RenderViewImplTest
, ScreenMetricsEmulation
) {
2404 LoadHTML("<body style='min-height:1000px;'></body>");
2406 blink::WebDeviceEmulationParams params
;
2407 base::string16 get_width
= base::ASCIIToUTF16("Number(window.innerWidth)");
2408 base::string16 get_height
= base::ASCIIToUTF16("Number(window.innerHeight)");
2411 params
.viewSize
.width
= 327;
2412 params
.viewSize
.height
= 415;
2413 view()->EnableScreenMetricsEmulation(params
);
2414 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width
, &width
));
2415 EXPECT_EQ(params
.viewSize
.width
, width
);
2416 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height
, &height
));
2417 EXPECT_EQ(params
.viewSize
.height
, height
);
2419 params
.viewSize
.width
= 1005;
2420 params
.viewSize
.height
= 1102;
2421 view()->EnableScreenMetricsEmulation(params
);
2422 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width
, &width
));
2423 EXPECT_EQ(params
.viewSize
.width
, width
);
2424 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height
, &height
));
2425 EXPECT_EQ(params
.viewSize
.height
, height
);
2427 view()->DisableScreenMetricsEmulation();
2429 view()->EnableScreenMetricsEmulation(params
);
2430 // Don't disable here to test that emulation is being shutdown properly.
2433 // Sanity checks for the Navigation Timing API |navigationStart| override. We
2434 // are asserting only most basic constraints, as TimeTicks (passed as the
2435 // override) are not comparable with the wall time (returned by the Blink API).
2436 TEST_F(RenderViewImplTest
, NavigationStartOverride
) {
2437 // Verify that a navigation that claims to have started at the earliest
2438 // possible TimeTicks is indeed reported as one that started before
2439 // OnNavigate() is called.
2440 base::Time before_navigation
= base::Time::Now();
2441 FrameMsg_Navigate_Params early_nav_params
;
2442 early_nav_params
.common_params
.url
= GURL("data:text/html,<div>Page</div>");
2443 early_nav_params
.common_params
.navigation_type
=
2444 FrameMsg_Navigate_Type::NORMAL
;
2445 early_nav_params
.common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
2446 early_nav_params
.page_id
= -1;
2447 early_nav_params
.request_params
.is_post
= true;
2448 early_nav_params
.commit_params
.browser_navigation_start
=
2449 base::TimeTicks::FromInternalValue(1);
2451 frame()->OnNavigate(early_nav_params
);
2452 ProcessPendingMessages();
2454 base::Time early_nav_reported_start
=
2455 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2456 EXPECT_LT(early_nav_reported_start
, before_navigation
);
2458 // Verify that a navigation that claims to have started in the future - 42
2459 // days from now is *not* reported as one that starts in the future; as we
2460 // sanitize the override allowing a maximum of ::Now().
2461 FrameMsg_Navigate_Params late_nav_params
;
2462 late_nav_params
.common_params
.url
=
2463 GURL("data:text/html,<div>Another page</div>");
2464 late_nav_params
.common_params
.navigation_type
=
2465 FrameMsg_Navigate_Type::NORMAL
;
2466 late_nav_params
.common_params
.transition
= ui::PAGE_TRANSITION_TYPED
;
2467 late_nav_params
.page_id
= -1;
2468 late_nav_params
.request_params
.is_post
= true;
2469 late_nav_params
.commit_params
.browser_navigation_start
=
2470 base::TimeTicks::Now() + base::TimeDelta::FromDays(42);
2472 frame()->OnNavigate(late_nav_params
);
2473 ProcessPendingMessages();
2474 base::Time after_navigation
=
2475 base::Time::Now() + base::TimeDelta::FromDays(1);
2477 base::Time late_nav_reported_start
=
2478 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2479 EXPECT_LE(late_nav_reported_start
, after_navigation
);
2482 class RenderViewImplInitialSizeTest
: public RenderViewImplTest
{
2484 RenderViewImplInitialSizeTest()
2485 : RenderViewImplTest(), initial_size_(200, 100) {}
2488 virtual scoped_ptr
<ViewMsg_Resize_Params
> InitialSizeParams() override
{
2489 scoped_ptr
<ViewMsg_Resize_Params
> initial_size_params(
2490 new ViewMsg_Resize_Params());
2491 initial_size_params
->new_size
= initial_size_
;
2492 return initial_size_params
.Pass();
2495 gfx::Size initial_size_
;
2498 TEST_F(RenderViewImplInitialSizeTest
, InitialSize
) {
2499 ASSERT_EQ(initial_size_
, view_
->GetSize());
2500 ASSERT_EQ(initial_size_
, gfx::Size(view_
->GetWebView()->size()));
2503 } // namespace content