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/win/windows_version.h"
12 #include "content/child/request_extra_data.h"
13 #include "content/child/service_worker/service_worker_network_provider.h"
14 #include "content/common/frame_messages.h"
15 #include "content/common/ssl_status_serialization.h"
16 #include "content/common/view_messages.h"
17 #include "content/public/browser/browser_context.h"
18 #include "content/public/browser/native_web_keyboard_event.h"
19 #include "content/public/browser/web_ui_controller_factory.h"
20 #include "content/public/common/bindings_policy.h"
21 #include "content/public/common/page_zoom.h"
22 #include "content/public/common/url_constants.h"
23 #include "content/public/common/url_utils.h"
24 #include "content/public/renderer/content_renderer_client.h"
25 #include "content/public/renderer/document_state.h"
26 #include "content/public/renderer/navigation_state.h"
27 #include "content/public/test/browser_test_utils.h"
28 #include "content/public/test/render_view_test.h"
29 #include "content/public/test/test_utils.h"
30 #include "content/renderer/accessibility/renderer_accessibility.h"
31 #include "content/renderer/accessibility/renderer_accessibility_complete.h"
32 #include "content/renderer/accessibility/renderer_accessibility_focus_only.h"
33 #include "content/renderer/history_controller.h"
34 #include "content/renderer/history_serialization.h"
35 #include "content/renderer/render_view_impl.h"
36 #include "content/shell/browser/shell.h"
37 #include "content/shell/browser/shell_browser_context.h"
38 #include "content/test/frame_load_waiter.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/WebHistoryItem.h"
49 #include "third_party/WebKit/public/web/WebLocalFrame.h"
50 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
51 #include "third_party/WebKit/public/web/WebView.h"
52 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
53 #include "ui/events/keycodes/keyboard_codes.h"
54 #include "ui/gfx/codec/jpeg_codec.h"
55 #include "ui/gfx/range/range.h"
58 #include "ui/events/event.h"
61 #if defined(USE_AURA) && defined(USE_X11)
63 #include "ui/events/event_constants.h"
64 #include "ui/events/keycodes/keyboard_code_conversion.h"
65 #include "ui/events/test/events_test_utils_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 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
86 // Converts MockKeyboard::Modifiers to ui::EventFlags.
87 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers
) {
88 static struct ModifierMap
{
89 MockKeyboard::Modifiers src
;
92 { MockKeyboard::LEFT_SHIFT
, ui::EF_SHIFT_DOWN
},
93 { MockKeyboard::RIGHT_SHIFT
, ui::EF_SHIFT_DOWN
},
94 { MockKeyboard::LEFT_CONTROL
, ui::EF_CONTROL_DOWN
},
95 { MockKeyboard::RIGHT_CONTROL
, ui::EF_CONTROL_DOWN
},
96 { MockKeyboard::LEFT_ALT
, ui::EF_ALT_DOWN
},
97 { MockKeyboard::RIGHT_ALT
, ui::EF_ALT_DOWN
},
100 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kModifierMap
); ++i
) {
101 if (kModifierMap
[i
].src
& modifiers
) {
102 flags
|= kModifierMap
[i
].dst
;
109 class WebUITestWebUIControllerFactory
: public WebUIControllerFactory
{
111 virtual WebUIController
* CreateWebUIControllerForURL(
112 WebUI
* web_ui
, const GURL
& url
) const OVERRIDE
{
115 virtual WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
116 const GURL
& url
) const OVERRIDE
{
117 return WebUI::kNoWebUI
;
119 virtual bool UseWebUIForURL(BrowserContext
* browser_context
,
120 const GURL
& url
) const OVERRIDE
{
121 return HasWebUIScheme(url
);
123 virtual bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
124 const GURL
& url
) const OVERRIDE
{
125 return HasWebUIScheme(url
);
129 class RenderViewImplTest
: public RenderViewTest
{
131 RenderViewImplTest() {
132 // Attach a pseudo keyboard device to this object.
133 mock_keyboard_
.reset(new MockKeyboard());
136 virtual ~RenderViewImplTest() {}
138 virtual void SetUp() OVERRIDE
{
139 RenderViewTest::SetUp();
140 // Enable Blink's experimental and test only features so that test code
141 // does not have to bother enabling each feature.
142 WebRuntimeFeatures::enableExperimentalFeatures(true);
143 WebRuntimeFeatures::enableTestOnlyFeatures(true);
146 RenderViewImpl
* view() {
147 return static_cast<RenderViewImpl
*>(view_
);
150 RenderFrameImpl
* frame() {
151 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
154 // Sends IPC messages that emulates a key-press event.
155 int SendKeyEvent(MockKeyboard::Layout layout
,
157 MockKeyboard::Modifiers modifiers
,
158 base::string16
* output
) {
160 // Retrieve the Unicode character for the given tuple (keyboard-layout,
161 // key-code, and modifiers).
162 // Exit when a keyboard-layout driver cannot assign a Unicode character to
163 // the tuple to prevent sending an invalid key code to the RenderView
165 CHECK(mock_keyboard_
.get());
167 int length
= mock_keyboard_
->GetCharacters(layout
, key_code
, modifiers
,
172 // Create IPC messages from Windows messages and send them to our
174 // A keyboard event of Windows consists of three Windows messages:
175 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
176 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
177 // WM_CHAR sends a composed Unicode character.
178 MSG msg1
= { NULL
, WM_KEYDOWN
, key_code
, 0 };
179 #if defined(USE_AURA)
180 ui::KeyEvent
evt1(msg1
, false);
181 NativeWebKeyboardEvent
keydown_event(&evt1
);
183 NativeWebKeyboardEvent
keydown_event(msg1
);
185 SendNativeKeyEvent(keydown_event
);
187 MSG msg2
= { NULL
, WM_CHAR
, (*output
)[0], 0 };
188 #if defined(USE_AURA)
189 ui::KeyEvent
evt2(msg2
, true);
190 NativeWebKeyboardEvent
char_event(&evt2
);
192 NativeWebKeyboardEvent
char_event(msg2
);
194 SendNativeKeyEvent(char_event
);
196 MSG msg3
= { NULL
, WM_KEYUP
, key_code
, 0 };
197 #if defined(USE_AURA)
198 ui::KeyEvent
evt3(msg3
, false);
199 NativeWebKeyboardEvent
keyup_event(&evt3
);
201 NativeWebKeyboardEvent
keyup_event(msg3
);
203 SendNativeKeyEvent(keyup_event
);
206 #elif defined(USE_AURA) && defined(USE_X11)
207 // We ignore |layout|, which means we are only testing the layout of the
208 // current locale. TODO(mazda): fix this to respect |layout|.
210 const int flags
= ConvertMockKeyboardModifier(modifiers
);
212 ui::ScopedXI2Event xevent
;
213 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
214 static_cast<ui::KeyboardCode
>(key_code
),
216 ui::KeyEvent
event1(xevent
, false);
217 NativeWebKeyboardEvent
keydown_event(&event1
);
218 SendNativeKeyEvent(keydown_event
);
220 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
221 static_cast<ui::KeyboardCode
>(key_code
),
223 ui::KeyEvent
event2(xevent
, true);
224 NativeWebKeyboardEvent
char_event(&event2
);
225 SendNativeKeyEvent(char_event
);
227 xevent
.InitKeyEvent(ui::ET_KEY_RELEASED
,
228 static_cast<ui::KeyboardCode
>(key_code
),
230 ui::KeyEvent
event3(xevent
, false);
231 NativeWebKeyboardEvent
keyup_event(&event3
);
232 SendNativeKeyEvent(keyup_event
);
234 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
236 output
->assign(1, static_cast<base::char16
>(c
));
238 #elif defined(USE_OZONE)
239 const int flags
= ConvertMockKeyboardModifier(modifiers
);
241 // Ozone's native events are ui::Events. So first create the "native" event,
242 // then create the actual ui::KeyEvent with the native event.
243 ui::KeyEvent
keydown_native_event(ui::ET_KEY_PRESSED
,
244 static_cast<ui::KeyboardCode
>(key_code
),
247 ui::KeyEvent
keydown_event(&keydown_native_event
, false);
248 NativeWebKeyboardEvent
keydown_web_event(&keydown_event
);
249 SendNativeKeyEvent(keydown_web_event
);
251 ui::KeyEvent
char_native_event(ui::ET_KEY_PRESSED
,
252 static_cast<ui::KeyboardCode
>(key_code
),
255 ui::KeyEvent
char_event(&char_native_event
, true);
256 NativeWebKeyboardEvent
char_web_event(&char_event
);
257 SendNativeKeyEvent(char_web_event
);
259 ui::KeyEvent
keyup_native_event(ui::ET_KEY_RELEASED
,
260 static_cast<ui::KeyboardCode
>(key_code
),
263 ui::KeyEvent
keyup_event(&keyup_native_event
, false);
264 NativeWebKeyboardEvent
keyup_web_event(&keyup_event
);
265 SendNativeKeyEvent(keyup_web_event
);
267 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
269 output
->assign(1, static_cast<base::char16
>(c
));
278 scoped_ptr
<MockKeyboard
> mock_keyboard_
;
283 // Test that we get form state change notifications when input fields change.
284 TEST_F(RenderViewImplTest
, DISABLED_OnNavStateChanged
) {
285 // Don't want any delay for form state sync changes. This will still post a
286 // message so updates will get coalesced, but as soon as we spin the message
287 // loop, it will generate an update.
288 view()->set_send_content_state_immediately(true);
290 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
292 // We should NOT have gotten a form state change notification yet.
293 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
294 ViewHostMsg_UpdateState::ID
));
295 render_thread_
->sink().ClearMessages();
297 // Change the value of the input. We should have gotten an update state
298 // notification. We need to spin the message loop to catch this update.
299 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';");
300 ProcessPendingMessages();
301 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
302 ViewHostMsg_UpdateState::ID
));
305 TEST_F(RenderViewImplTest
, OnNavigationHttpPost
) {
306 FrameMsg_Navigate_Params nav_params
;
308 // An http url will trigger a resource load so cannot be used here.
309 nav_params
.url
= GURL("data:text/html,<div>Page</div>");
310 nav_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
311 nav_params
.transition
= PAGE_TRANSITION_TYPED
;
312 nav_params
.page_id
= -1;
313 nav_params
.is_post
= true;
316 const unsigned char* raw_data
= reinterpret_cast<const unsigned char*>(
318 const unsigned int length
= 11;
319 const std::vector
<unsigned char> post_data(raw_data
, raw_data
+ length
);
320 nav_params
.browser_initiated_post_data
= post_data
;
322 frame()->OnNavigate(nav_params
);
323 ProcessPendingMessages();
325 const IPC::Message
* frame_navigate_msg
=
326 render_thread_
->sink().GetUniqueMessageMatching(
327 FrameHostMsg_DidCommitProvisionalLoad::ID
);
328 EXPECT_TRUE(frame_navigate_msg
);
330 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params
;
331 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
333 EXPECT_TRUE(host_nav_params
.a
.is_post
);
335 // Check post data sent to browser matches
336 EXPECT_TRUE(host_nav_params
.a
.page_state
.IsValid());
337 scoped_ptr
<HistoryEntry
> entry
=
338 PageStateToHistoryEntry(host_nav_params
.a
.page_state
);
339 blink::WebHTTPBody body
= entry
->root().httpBody();
340 blink::WebHTTPBody::Element element
;
341 bool successful
= body
.elementAt(0, element
);
342 EXPECT_TRUE(successful
);
343 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData
, element
.type
);
344 EXPECT_EQ(length
, element
.data
.size());
345 EXPECT_EQ(0, memcmp(raw_data
, element
.data
.data(), length
));
348 TEST_F(RenderViewImplTest
, DecideNavigationPolicy
) {
349 WebUITestWebUIControllerFactory factory
;
350 WebUIControllerFactory::RegisterFactory(&factory
);
353 state
.set_navigation_state(NavigationState::CreateContentInitiated());
355 // Navigations to normal HTTP URLs can be handled locally.
356 blink::WebURLRequest
request(GURL("http://foo.com"));
357 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
361 blink::WebNavigationTypeLinkClicked
,
362 blink::WebNavigationPolicyCurrentTab
,
364 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab
, policy
);
366 // Verify that form posts to WebUI URLs will be sent to the browser process.
367 blink::WebURLRequest
form_request(GURL("chrome://foo"));
368 form_request
.setHTTPMethod("POST");
369 policy
= frame()->decidePolicyForNavigation(
373 blink::WebNavigationTypeFormSubmitted
,
374 blink::WebNavigationPolicyCurrentTab
,
376 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
378 // Verify that popup links to WebUI URLs also are sent to browser.
379 blink::WebURLRequest
popup_request(GURL("chrome://foo"));
380 policy
= frame()->decidePolicyForNavigation(
384 blink::WebNavigationTypeLinkClicked
,
385 blink::WebNavigationPolicyNewForegroundTab
,
387 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
390 TEST_F(RenderViewImplTest
, DecideNavigationPolicyHandlesAllTopLevel
) {
392 state
.set_navigation_state(NavigationState::CreateContentInitiated());
394 RendererPreferences prefs
= view()->renderer_preferences();
395 prefs
.browser_handles_all_top_level_requests
= true;
396 view()->OnSetRendererPrefs(prefs
);
398 const blink::WebNavigationType kNavTypes
[] = {
399 blink::WebNavigationTypeLinkClicked
,
400 blink::WebNavigationTypeFormSubmitted
,
401 blink::WebNavigationTypeBackForward
,
402 blink::WebNavigationTypeReload
,
403 blink::WebNavigationTypeFormResubmitted
,
404 blink::WebNavigationTypeOther
,
407 blink::WebURLRequest
request(GURL("http://foo.com"));
408 for (size_t i
= 0; i
< arraysize(kNavTypes
); ++i
) {
409 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
414 blink::WebNavigationPolicyCurrentTab
,
416 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
420 TEST_F(RenderViewImplTest
, DecideNavigationPolicyForWebUI
) {
421 // Enable bindings to simulate a WebUI view.
422 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI
);
425 state
.set_navigation_state(NavigationState::CreateContentInitiated());
427 // Navigations to normal HTTP URLs will be sent to browser process.
428 blink::WebURLRequest
request(GURL("http://foo.com"));
429 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
433 blink::WebNavigationTypeLinkClicked
,
434 blink::WebNavigationPolicyCurrentTab
,
436 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
438 // Navigations to WebUI URLs will also be sent to browser process.
439 blink::WebURLRequest
webui_request(GURL("chrome://foo"));
440 policy
= frame()->decidePolicyForNavigation(
444 blink::WebNavigationTypeLinkClicked
,
445 blink::WebNavigationPolicyCurrentTab
,
447 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
449 // Verify that form posts to data URLs will be sent to the browser process.
450 blink::WebURLRequest
data_request(GURL("data:text/html,foo"));
451 data_request
.setHTTPMethod("POST");
452 policy
= frame()->decidePolicyForNavigation(
456 blink::WebNavigationTypeFormSubmitted
,
457 blink::WebNavigationPolicyCurrentTab
,
459 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
461 // Verify that a popup that creates a view first and then navigates to a
462 // normal HTTP URL will be sent to the browser process, even though the
463 // new view does not have any enabled_bindings_.
464 blink::WebURLRequest
popup_request(GURL("http://foo.com"));
465 blink::WebView
* new_web_view
= view()->createView(
466 GetMainFrame(), popup_request
, blink::WebWindowFeatures(), "foo",
467 blink::WebNavigationPolicyNewForegroundTab
, false);
468 RenderViewImpl
* new_view
= RenderViewImpl::FromWebView(new_web_view
);
469 policy
= static_cast<RenderFrameImpl
*>(new_view
->GetMainRenderFrame())->
470 decidePolicyForNavigation(
471 new_web_view
->mainFrame()->toWebLocalFrame(),
474 blink::WebNavigationTypeLinkClicked
,
475 blink::WebNavigationPolicyNewForegroundTab
,
477 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
479 // Clean up after the new view so we don't leak it.
484 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
485 // already swapped out. http://crbug.com/93427.
486 TEST_F(RenderViewImplTest
, SendSwapOutACK
) {
487 LoadHTML("<div>Page A</div>");
488 int initial_page_id
= view()->GetPageId();
490 // Respond to a swap out request.
491 view()->main_render_frame()->OnSwapOut();
493 // Ensure the swap out commits synchronously.
494 EXPECT_NE(initial_page_id
, view()->GetPageId());
496 // Check for a valid OnSwapOutACK.
497 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
498 FrameHostMsg_SwapOut_ACK::ID
);
501 // It is possible to get another swap out request. Ensure that we send
502 // an ACK, even if we don't have to do anything else.
503 render_thread_
->sink().ClearMessages();
504 view()->main_render_frame()->OnSwapOut();
505 const IPC::Message
* msg2
= render_thread_
->sink().GetUniqueMessageMatching(
506 FrameHostMsg_SwapOut_ACK::ID
);
509 // If we navigate back to this RenderView, ensure we don't send a state
510 // update for the swapped out URL. (http://crbug.com/72235)
511 FrameMsg_Navigate_Params nav_params
;
512 nav_params
.url
= GURL("data:text/html,<div>Page B</div>");
513 nav_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
514 nav_params
.transition
= PAGE_TRANSITION_TYPED
;
515 nav_params
.current_history_list_length
= 1;
516 nav_params
.current_history_list_offset
= 0;
517 nav_params
.pending_history_list_offset
= 1;
518 nav_params
.page_id
= -1;
519 frame()->OnNavigate(nav_params
);
520 ProcessPendingMessages();
521 const IPC::Message
* msg3
= render_thread_
->sink().GetUniqueMessageMatching(
522 ViewHostMsg_UpdateState::ID
);
526 // Ensure the RenderViewImpl reloads the previous page if a reload request
527 // arrives while it is showing swappedout://. http://crbug.com/143155.
528 TEST_F(RenderViewImplTest
, ReloadWhileSwappedOut
) {
530 LoadHTML("<div>Page A</div>");
532 // Load page B, which will trigger an UpdateState message for page A.
533 LoadHTML("<div>Page B</div>");
535 // Check for a valid UpdateState message for page A.
536 ProcessPendingMessages();
537 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
538 ViewHostMsg_UpdateState::ID
);
542 ViewHostMsg_UpdateState::Read(msg_A
, &page_id_A
, &state_A
);
543 EXPECT_EQ(1, page_id_A
);
544 render_thread_
->sink().ClearMessages();
546 // Back to page A (page_id 1) and commit.
547 FrameMsg_Navigate_Params params_A
;
548 params_A
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
549 params_A
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
550 params_A
.current_history_list_length
= 2;
551 params_A
.current_history_list_offset
= 1;
552 params_A
.pending_history_list_offset
= 0;
553 params_A
.page_id
= 1;
554 params_A
.page_state
= state_A
;
555 frame()->OnNavigate(params_A
);
556 ProcessPendingMessages();
558 // Respond to a swap out request.
559 view()->main_render_frame()->OnSwapOut();
561 // Check for a OnSwapOutACK.
562 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
563 FrameHostMsg_SwapOut_ACK::ID
);
565 render_thread_
->sink().ClearMessages();
567 // It is possible to get a reload request at this point, containing the
568 // params.page_state of the initial page (e.g., if the new page fails the
569 // provisional load in the renderer process, after we unload the old page).
570 // Ensure the old page gets reloaded, not swappedout://.
571 FrameMsg_Navigate_Params nav_params
;
572 nav_params
.url
= GURL("data:text/html,<div>Page A</div>");
573 nav_params
.navigation_type
= FrameMsg_Navigate_Type::RELOAD
;
574 nav_params
.transition
= PAGE_TRANSITION_RELOAD
;
575 nav_params
.current_history_list_length
= 2;
576 nav_params
.current_history_list_offset
= 0;
577 nav_params
.pending_history_list_offset
= 0;
578 nav_params
.page_id
= 1;
579 nav_params
.page_state
= state_A
;
580 frame()->OnNavigate(nav_params
);
581 ProcessPendingMessages();
583 // Verify page A committed, not swappedout://.
584 const IPC::Message
* frame_navigate_msg
=
585 render_thread_
->sink().GetUniqueMessageMatching(
586 FrameHostMsg_DidCommitProvisionalLoad::ID
);
587 EXPECT_TRUE(frame_navigate_msg
);
589 // Read URL out of the parent trait of the params object.
590 FrameHostMsg_DidCommitProvisionalLoad::Param commit_params
;
591 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
593 EXPECT_NE(GURL("swappedout://"), commit_params
.a
.url
);
597 // Test that we get the correct UpdateState message when we go back twice
598 // quickly without committing. Regression test for http://crbug.com/58082.
599 // Disabled: http://crbug.com/157357 .
600 TEST_F(RenderViewImplTest
, DISABLED_LastCommittedUpdateState
) {
602 LoadHTML("<div>Page A</div>");
604 // Load page B, which will trigger an UpdateState message for page A.
605 LoadHTML("<div>Page B</div>");
607 // Check for a valid UpdateState message for page A.
608 ProcessPendingMessages();
609 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
610 ViewHostMsg_UpdateState::ID
);
614 ViewHostMsg_UpdateState::Read(msg_A
, &page_id_A
, &state_A
);
615 EXPECT_EQ(1, page_id_A
);
616 render_thread_
->sink().ClearMessages();
618 // Load page C, which will trigger an UpdateState message for page B.
619 LoadHTML("<div>Page C</div>");
621 // Check for a valid UpdateState for page B.
622 ProcessPendingMessages();
623 const IPC::Message
* msg_B
= render_thread_
->sink().GetUniqueMessageMatching(
624 ViewHostMsg_UpdateState::ID
);
628 ViewHostMsg_UpdateState::Read(msg_B
, &page_id_B
, &state_B
);
629 EXPECT_EQ(2, page_id_B
);
630 EXPECT_NE(state_A
, state_B
);
631 render_thread_
->sink().ClearMessages();
633 // Load page D, which will trigger an UpdateState message for page C.
634 LoadHTML("<div>Page D</div>");
636 // Check for a valid UpdateState for page C.
637 ProcessPendingMessages();
638 const IPC::Message
* msg_C
= render_thread_
->sink().GetUniqueMessageMatching(
639 ViewHostMsg_UpdateState::ID
);
643 ViewHostMsg_UpdateState::Read(msg_C
, &page_id_C
, &state_C
);
644 EXPECT_EQ(3, page_id_C
);
645 EXPECT_NE(state_B
, state_C
);
646 render_thread_
->sink().ClearMessages();
648 // Go back to C and commit, preparing for our real test.
649 FrameMsg_Navigate_Params params_C
;
650 params_C
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
651 params_C
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
652 params_C
.current_history_list_length
= 4;
653 params_C
.current_history_list_offset
= 3;
654 params_C
.pending_history_list_offset
= 2;
655 params_C
.page_id
= 3;
656 params_C
.page_state
= state_C
;
657 frame()->OnNavigate(params_C
);
658 ProcessPendingMessages();
659 render_thread_
->sink().ClearMessages();
661 // Go back twice quickly, such that page B does not have a chance to commit.
662 // This leads to two changes to the back/forward list but only one change to
663 // the RenderView's page ID.
665 // Back to page B (page_id 2), without committing.
666 FrameMsg_Navigate_Params params_B
;
667 params_B
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
668 params_B
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
669 params_B
.current_history_list_length
= 4;
670 params_B
.current_history_list_offset
= 2;
671 params_B
.pending_history_list_offset
= 1;
672 params_B
.page_id
= 2;
673 params_B
.page_state
= state_B
;
674 frame()->OnNavigate(params_B
);
676 // Back to page A (page_id 1) and commit.
677 FrameMsg_Navigate_Params params
;
678 params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
679 params
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
680 params_B
.current_history_list_length
= 4;
681 params_B
.current_history_list_offset
= 2;
682 params_B
.pending_history_list_offset
= 0;
684 params
.page_state
= state_A
;
685 frame()->OnNavigate(params
);
686 ProcessPendingMessages();
688 // Now ensure that the UpdateState message we receive is consistent
689 // and represents page C in both page_id and state.
690 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
691 ViewHostMsg_UpdateState::ID
);
695 ViewHostMsg_UpdateState::Read(msg
, &page_id
, &state
);
696 EXPECT_EQ(page_id_C
, page_id
);
697 EXPECT_NE(state_A
, state
);
698 EXPECT_NE(state_B
, state
);
699 EXPECT_EQ(state_C
, state
);
702 // Test that the history_page_ids_ list can reveal when a stale back/forward
703 // navigation arrives from the browser and can be ignored. See
704 // http://crbug.com/86758.
705 TEST_F(RenderViewImplTest
, StaleNavigationsIgnored
) {
707 LoadHTML("<div>Page A</div>");
708 EXPECT_EQ(1, view()->history_list_length_
);
709 EXPECT_EQ(0, view()->history_list_offset_
);
710 EXPECT_EQ(1, view()->history_page_ids_
[0]);
712 // Load page B, which will trigger an UpdateState message for page A.
713 LoadHTML("<div>Page B</div>");
714 EXPECT_EQ(2, view()->history_list_length_
);
715 EXPECT_EQ(1, view()->history_list_offset_
);
716 EXPECT_EQ(2, view()->history_page_ids_
[1]);
718 // Check for a valid UpdateState message for page A.
719 ProcessPendingMessages();
720 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
721 ViewHostMsg_UpdateState::ID
);
725 ViewHostMsg_UpdateState::Read(msg_A
, &page_id_A
, &state_A
);
726 EXPECT_EQ(1, page_id_A
);
727 render_thread_
->sink().ClearMessages();
729 // Back to page A (page_id 1) and commit.
730 FrameMsg_Navigate_Params params_A
;
731 params_A
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
732 params_A
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
733 params_A
.current_history_list_length
= 2;
734 params_A
.current_history_list_offset
= 1;
735 params_A
.pending_history_list_offset
= 0;
736 params_A
.page_id
= 1;
737 params_A
.page_state
= state_A
;
738 frame()->OnNavigate(params_A
);
739 ProcessPendingMessages();
741 // A new navigation commits, clearing the forward history.
742 LoadHTML("<div>Page C</div>");
743 EXPECT_EQ(2, view()->history_list_length_
);
744 EXPECT_EQ(1, view()->history_list_offset_
);
745 EXPECT_EQ(3, view()->history_page_ids_
[1]);
747 // The browser then sends a stale navigation to B, which should be ignored.
748 FrameMsg_Navigate_Params params_B
;
749 params_B
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
750 params_B
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
751 params_B
.current_history_list_length
= 2;
752 params_B
.current_history_list_offset
= 0;
753 params_B
.pending_history_list_offset
= 1;
754 params_B
.page_id
= 2;
755 params_B
.page_state
= state_A
; // Doesn't matter, just has to be present.
756 frame()->OnNavigate(params_B
);
758 // State should be unchanged.
759 EXPECT_EQ(2, view()->history_list_length_
);
760 EXPECT_EQ(1, view()->history_list_offset_
);
761 EXPECT_EQ(3, view()->history_page_ids_
[1]);
764 // Test that we do not ignore navigations after the entry limit is reached,
765 // in which case the browser starts dropping entries from the front. In this
766 // case, we'll see a page_id mismatch but the RenderView's id will be older,
767 // not newer, than params.page_id. Use this as a cue that we should update the
768 // state and not treat it like a navigation to a cropped forward history item.
769 // See http://crbug.com/89798.
770 TEST_F(RenderViewImplTest
, DontIgnoreBackAfterNavEntryLimit
) {
772 LoadHTML("<div>Page A</div>");
773 EXPECT_EQ(1, view()->history_list_length_
);
774 EXPECT_EQ(0, view()->history_list_offset_
);
775 EXPECT_EQ(1, view()->history_page_ids_
[0]);
777 // Load page B, which will trigger an UpdateState message for page A.
778 LoadHTML("<div>Page B</div>");
779 EXPECT_EQ(2, view()->history_list_length_
);
780 EXPECT_EQ(1, view()->history_list_offset_
);
781 EXPECT_EQ(2, view()->history_page_ids_
[1]);
783 // Check for a valid UpdateState message for page A.
784 ProcessPendingMessages();
785 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
786 ViewHostMsg_UpdateState::ID
);
790 ViewHostMsg_UpdateState::Read(msg_A
, &page_id_A
, &state_A
);
791 EXPECT_EQ(1, page_id_A
);
792 render_thread_
->sink().ClearMessages();
794 // Load page C, which will trigger an UpdateState message for page B.
795 LoadHTML("<div>Page C</div>");
796 EXPECT_EQ(3, view()->history_list_length_
);
797 EXPECT_EQ(2, view()->history_list_offset_
);
798 EXPECT_EQ(3, view()->history_page_ids_
[2]);
800 // Check for a valid UpdateState message for page B.
801 ProcessPendingMessages();
802 const IPC::Message
* msg_B
= render_thread_
->sink().GetUniqueMessageMatching(
803 ViewHostMsg_UpdateState::ID
);
807 ViewHostMsg_UpdateState::Read(msg_B
, &page_id_B
, &state_B
);
808 EXPECT_EQ(2, page_id_B
);
809 render_thread_
->sink().ClearMessages();
811 // Suppose the browser has limited the number of NavigationEntries to 2.
812 // It has now dropped the first entry, but the renderer isn't notified.
813 // Ensure that going back to page B (page_id 2) at offset 0 is successful.
814 FrameMsg_Navigate_Params params_B
;
815 params_B
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
816 params_B
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
817 params_B
.current_history_list_length
= 2;
818 params_B
.current_history_list_offset
= 1;
819 params_B
.pending_history_list_offset
= 0;
820 params_B
.page_id
= 2;
821 params_B
.page_state
= state_B
;
822 frame()->OnNavigate(params_B
);
823 ProcessPendingMessages();
825 EXPECT_EQ(2, view()->history_list_length_
);
826 EXPECT_EQ(0, view()->history_list_offset_
);
827 EXPECT_EQ(2, view()->history_page_ids_
[0]);
830 // Test that our IME backend sends a notification message when the input focus
832 TEST_F(RenderViewImplTest
, OnImeTypeChanged
) {
833 // Enable our IME backend code.
834 view()->OnSetInputMethodActive(true);
836 // Load an HTML page consisting of two input fields.
837 view()->set_send_content_state_immediately(true);
842 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
843 "<input id=\"test2\" type=\"password\"></input>"
844 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
845 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
846 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
847 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
849 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
851 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
852 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
853 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
854 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
855 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
856 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
857 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
858 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
861 render_thread_
->sink().ClearMessages();
863 struct InputModeTestCase
{
864 const char* input_id
;
865 ui::TextInputMode expected_mode
;
867 static const InputModeTestCase kInputModeTestCases
[] = {
868 {"test1", ui::TEXT_INPUT_MODE_DEFAULT
},
869 {"test3", ui::TEXT_INPUT_MODE_VERBATIM
},
870 {"test4", ui::TEXT_INPUT_MODE_LATIN
},
871 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME
},
872 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE
},
873 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN
},
874 {"test8", ui::TEXT_INPUT_MODE_KANA
},
875 {"test9", ui::TEXT_INPUT_MODE_KATAKANA
},
876 {"test10", ui::TEXT_INPUT_MODE_NUMERIC
},
877 {"test11", ui::TEXT_INPUT_MODE_TEL
},
878 {"test12", ui::TEXT_INPUT_MODE_EMAIL
},
879 {"test13", ui::TEXT_INPUT_MODE_URL
},
880 {"test14", ui::TEXT_INPUT_MODE_DEFAULT
},
881 {"test15", ui::TEXT_INPUT_MODE_VERBATIM
},
884 const int kRepeatCount
= 10;
885 for (int i
= 0; i
< kRepeatCount
; i
++) {
886 // Move the input focus to the first <input> element, where we should
888 ExecuteJavaScript("document.getElementById('test1').focus();");
889 ProcessPendingMessages();
890 render_thread_
->sink().ClearMessages();
892 // Update the IME status and verify if our IME backend sends an IPC message
894 view()->UpdateTextInputType();
895 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
896 EXPECT_TRUE(msg
!= NULL
);
897 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
898 ui::TextInputType type
;
899 bool can_compose_inline
= false;
900 ui::TextInputMode input_mode
= ui::TEXT_INPUT_MODE_DEFAULT
;
901 ViewHostMsg_TextInputTypeChanged::Read(msg
,
904 &can_compose_inline
);
905 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT
, type
);
906 EXPECT_EQ(true, can_compose_inline
);
908 // Move the input focus to the second <input> element, where we should
910 ExecuteJavaScript("document.getElementById('test2').focus();");
911 ProcessPendingMessages();
912 render_thread_
->sink().ClearMessages();
914 // Update the IME status and verify if our IME backend sends an IPC message
915 // to de-activate IMEs.
916 view()->UpdateTextInputType();
917 msg
= render_thread_
->sink().GetMessageAt(0);
918 EXPECT_TRUE(msg
!= NULL
);
919 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
920 ViewHostMsg_TextInputTypeChanged::Read(msg
,
923 &can_compose_inline
);
924 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD
, type
);
926 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kInputModeTestCases
); i
++) {
927 const InputModeTestCase
* test_case
= &kInputModeTestCases
[i
];
928 std::string javascript
=
929 base::StringPrintf("document.getElementById('%s').focus();",
930 test_case
->input_id
);
931 // Move the input focus to the target <input> element, where we should
933 ExecuteJavaScriptAndReturnIntValue(base::ASCIIToUTF16(javascript
), NULL
);
934 ProcessPendingMessages();
935 render_thread_
->sink().ClearMessages();
937 // Update the IME status and verify if our IME backend sends an IPC
938 // message to activate IMEs.
939 view()->UpdateTextInputType();
940 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
941 EXPECT_TRUE(msg
!= NULL
);
942 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
943 ViewHostMsg_TextInputTypeChanged::Read(msg
,
946 &can_compose_inline
);
947 EXPECT_EQ(test_case
->expected_mode
, input_mode
);
952 // Test that our IME backend can compose CJK words.
953 // Our IME front-end sends many platform-independent messages to the IME backend
954 // while it composes CJK words. This test sends the minimal messages captured
955 // on my local environment directly to the IME backend to verify if the backend
956 // can compose CJK words without any problems.
957 // This test uses an array of command sets because an IME composotion does not
958 // only depends on IME events, but also depends on window events, e.g. moving
959 // the window focus while composing a CJK text. To handle such complicated
960 // cases, this test should not only call IME-related functions in the
961 // RenderWidget class, but also call some RenderWidget members, e.g.
962 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc.
963 TEST_F(RenderViewImplTest
, ImeComposition
) {
969 IME_CONFIRMCOMPOSITION
,
970 IME_CANCELCOMPOSITION
977 const wchar_t* ime_string
;
978 const wchar_t* result
;
980 static const ImeMessage kImeMessages
[] = {
981 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
982 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
983 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
984 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
985 {IME_SETCOMPOSITION
, false, 1, 1, L
"n", L
"n"},
986 {IME_SETCOMPOSITION
, false, 2, 2, L
"ni", L
"ni"},
987 {IME_SETCOMPOSITION
, false, 3, 3, L
"nih", L
"nih"},
988 {IME_SETCOMPOSITION
, false, 4, 4, L
"niha", L
"niha"},
989 {IME_SETCOMPOSITION
, false, 5, 5, L
"nihao", L
"nihao"},
990 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"\x4F60\x597D", L
"\x4F60\x597D"},
991 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
992 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
993 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
994 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
995 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xFF4B", L
"\xFF4B"},
996 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x304B", L
"\x304B"},
997 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x304B\xFF4E", L
"\x304B\xFF4E"},
998 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\xFF4A",
999 L
"\x304B\x3093\xFF4A"},
1000 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\x3058",
1001 L
"\x304B\x3093\x3058"},
1002 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x611F\x3058", L
"\x611F\x3058"},
1003 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x6F22\x5B57", L
"\x6F22\x5B57"},
1004 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1005 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1006 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1007 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1008 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1009 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1010 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3147", L
"\x3147"},
1011 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC544", L
"\xC544"},
1012 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC548", L
"\xC548"},
1013 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1014 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3134", L
"\xC548\x3134"},
1015 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB140", L
"\xC548\xB140"},
1016 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1017 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1018 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1019 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548\xB155"},
1022 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kImeMessages
); i
++) {
1023 const ImeMessage
* ime_message
= &kImeMessages
[i
];
1024 switch (ime_message
->command
) {
1025 case IME_INITIALIZE
:
1026 // Load an HTML page consisting of a content-editable <div> element,
1027 // and move the input focus to the <div> element, where we can use
1029 view()->OnSetInputMethodActive(ime_message
->enable
);
1030 view()->set_send_content_state_immediately(true);
1035 "<div id=\"test1\" contenteditable=\"true\"></div>"
1038 ExecuteJavaScript("document.getElementById('test1').focus();");
1041 case IME_SETINPUTMODE
:
1042 // Activate (or deactivate) our IME back-end.
1043 view()->OnSetInputMethodActive(ime_message
->enable
);
1047 // Update the window focus.
1048 view()->OnSetFocus(ime_message
->enable
);
1051 case IME_SETCOMPOSITION
:
1052 view()->OnImeSetComposition(
1053 base::WideToUTF16(ime_message
->ime_string
),
1054 std::vector
<blink::WebCompositionUnderline
>(),
1055 ime_message
->selection_start
,
1056 ime_message
->selection_end
);
1059 case IME_CONFIRMCOMPOSITION
:
1060 view()->OnImeConfirmComposition(
1061 base::WideToUTF16(ime_message
->ime_string
),
1062 gfx::Range::InvalidRange(),
1066 case IME_CANCELCOMPOSITION
:
1067 view()->OnImeSetComposition(
1069 std::vector
<blink::WebCompositionUnderline
>(),
1074 // Update the status of our IME back-end.
1075 // TODO(hbono): we should verify messages to be sent from the back-end.
1076 view()->UpdateTextInputType();
1077 ProcessPendingMessages();
1078 render_thread_
->sink().ClearMessages();
1080 if (ime_message
->result
) {
1081 // Retrieve the content of this page and compare it with the expected
1083 const int kMaxOutputCharacters
= 128;
1084 base::string16 output
=
1085 GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1086 EXPECT_EQ(base::WideToUTF16(ime_message
->result
), output
);
1091 // Test that the RenderView::OnSetTextDirection() function can change the text
1092 // direction of the selected input element.
1093 TEST_F(RenderViewImplTest
, OnSetTextDirection
) {
1094 // Load an HTML page consisting of a <textarea> element and a <div> element.
1095 // This test changes the text direction of the <textarea> element, and
1096 // writes the values of its 'dir' attribute and its 'direction' property to
1097 // verify that the text direction is changed.
1098 view()->set_send_content_state_immediately(true);
1103 "<textarea id=\"test\"></textarea>"
1104 "<div id=\"result\" contenteditable=\"true\"></div>"
1107 render_thread_
->sink().ClearMessages();
1109 static const struct {
1110 WebTextDirection direction
;
1111 const wchar_t* expected_result
;
1112 } kTextDirection
[] = {
1113 { blink::WebTextDirectionRightToLeft
, L
"\x000A" L
"rtl,rtl" },
1114 { blink::WebTextDirectionLeftToRight
, L
"\x000A" L
"ltr,ltr" },
1116 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kTextDirection
); ++i
) {
1117 // Set the text direction of the <textarea> element.
1118 ExecuteJavaScript("document.getElementById('test').focus();");
1119 view()->OnSetTextDirection(kTextDirection
[i
].direction
);
1121 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1122 // property to the <div> element.
1123 ExecuteJavaScript("var result = document.getElementById('result');"
1124 "var node = document.getElementById('test');"
1125 "var style = getComputedStyle(node, null);"
1126 "result.innerText ="
1127 " node.getAttribute('dir') + ',' +"
1128 " style.getPropertyValue('direction');");
1130 // Copy the document content to std::wstring and compare with the
1132 const int kMaxOutputCharacters
= 16;
1133 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1134 EXPECT_EQ(base::WideToUTF16(kTextDirection
[i
].expected_result
), output
);
1138 // see http://crbug.com/238750
1140 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent
1142 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent
1145 // Test that we can receive correct DOM events when we send input events
1146 // through the RenderWidget::OnHandleInputEvent() function.
1147 TEST_F(RenderViewImplTest
, MAYBE_OnHandleKeyboardEvent
) {
1148 #if !defined(OS_MACOSX)
1149 // Load an HTML page consisting of one <input> element and three
1150 // contentediable <div> elements.
1151 // The <input> element is used for sending keyboard events, and the <div>
1152 // elements are used for writing DOM events in the following format:
1153 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1154 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1155 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1156 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1157 view()->set_send_content_state_immediately(true);
1161 "<script type='text/javascript' language='javascript'>"
1162 "function OnKeyEvent(ev) {"
1163 " var result = document.getElementById(ev.type);"
1164 " result.innerText ="
1165 " (ev.which || ev.keyCode) + ',' +"
1166 " ev.shiftKey + ',' +"
1167 " ev.ctrlKey + ',' +"
1174 "<input id='test' type='text'"
1175 " onkeydown='return OnKeyEvent(event);'"
1176 " onkeypress='return OnKeyEvent(event);'"
1177 " onkeyup='return OnKeyEvent(event);'>"
1179 "<div id='keydown' contenteditable='true'>"
1181 "<div id='keypress' contenteditable='true'>"
1183 "<div id='keyup' contenteditable='true'>"
1187 ExecuteJavaScript("document.getElementById('test').focus();");
1188 render_thread_
->sink().ClearMessages();
1190 static const MockKeyboard::Layout kLayouts
[] = {
1192 // Since we ignore the mock keyboard layout on Linux and instead just use
1193 // the screen's keyboard layout, these trivially pass. They are commented
1194 // out to avoid the illusion that they work.
1195 MockKeyboard::LAYOUT_ARABIC
,
1196 MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1197 MockKeyboard::LAYOUT_FRENCH
,
1198 MockKeyboard::LAYOUT_HEBREW
,
1199 MockKeyboard::LAYOUT_RUSSIAN
,
1201 MockKeyboard::LAYOUT_UNITED_STATES
,
1204 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kLayouts
); ++i
) {
1205 // For each key code, we send three keyboard events.
1206 // * we press only the key;
1207 // * we press the key and a left-shift key, and;
1208 // * we press the key and a right-alt (AltGr) key.
1209 // For each modifiers, we need a string used for formatting its expected
1210 // result. (See the above comment for its format.)
1211 static const struct {
1212 MockKeyboard::Modifiers modifiers
;
1213 const char* expected_result
;
1214 } kModifierData
[] = {
1215 {MockKeyboard::NONE
, "false,false,false"},
1216 {MockKeyboard::LEFT_SHIFT
, "true,false,false"},
1218 {MockKeyboard::RIGHT_ALT
, "false,false,true"},
1222 MockKeyboard::Layout layout
= kLayouts
[i
];
1223 for (size_t j
= 0; j
< ARRAYSIZE_UNSAFE(kModifierData
); ++j
) {
1224 // Virtual key codes used for this test.
1225 static const int kKeyCodes
[] = {
1226 '0', '1', '2', '3', '4', '5', '6', '7',
1227 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1228 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1229 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1235 ui::VKEY_OEM_PERIOD
,
1243 // Not sure how to handle this key on Linux.
1248 MockKeyboard::Modifiers modifiers
= kModifierData
[j
].modifiers
;
1249 for (size_t k
= 0; k
< ARRAYSIZE_UNSAFE(kKeyCodes
); ++k
) {
1250 // Send a keyboard event to the RenderView object.
1251 // We should test a keyboard event only when the given keyboard-layout
1252 // driver is installed in a PC and the driver can assign a Unicode
1253 // charcter for the given tuple (key-code and modifiers).
1254 int key_code
= kKeyCodes
[k
];
1255 base::string16 char_code
;
1256 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1259 // Create an expected result from the virtual-key code, the character
1260 // code, and the modifier-key status.
1261 // We format a string that emulates a DOM-event string produced hy
1262 // our JavaScript function. (See the above comment for the format.)
1263 static char expected_result
[1024];
1264 expected_result
[0] = 0;
1265 base::snprintf(&expected_result
[0],
1266 sizeof(expected_result
),
1267 "\n" // texts in the <input> element
1268 "%d,%s\n" // texts in the first <div> element
1269 "%d,%s\n" // texts in the second <div> element
1270 "%d,%s", // texts in the third <div> element
1271 key_code
, kModifierData
[j
].expected_result
,
1272 static_cast<int>(char_code
[0]),
1273 kModifierData
[j
].expected_result
,
1274 key_code
, kModifierData
[j
].expected_result
);
1276 // Retrieve the text in the test page and compare it with the expected
1277 // text created from a virtual-key code, a character code, and the
1278 // modifier-key status.
1279 const int kMaxOutputCharacters
= 1024;
1280 std::string output
= base::UTF16ToUTF8(
1281 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
1282 EXPECT_EQ(expected_result
, output
);
1291 // Test that our EditorClientImpl class can insert characters when we send
1292 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1293 // This test is for preventing regressions caused only when we use non-US
1294 // keyboards, such as Issue 10846.
1295 // see http://crbug.com/244562
1297 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1299 #define MAYBE_InsertCharacters InsertCharacters
1301 TEST_F(RenderViewImplTest
, MAYBE_InsertCharacters
) {
1302 #if !defined(OS_MACOSX)
1303 static const struct {
1304 MockKeyboard::Layout layout
;
1305 const wchar_t* expected_result
;
1308 // Disabled these keyboard layouts because buildbots do not have their
1309 // keyboard-layout drivers installed.
1310 {MockKeyboard::LAYOUT_ARABIC
,
1311 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1312 L
"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1313 L
"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1314 L
"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1315 L
"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1316 L
"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1317 L
"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1318 L
"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1319 L
"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1320 L
"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1321 L
"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1322 L
"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1323 L
"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1324 L
"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1325 L
"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1326 L
"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1327 L
"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1329 {MockKeyboard::LAYOUT_HEBREW
,
1330 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1331 L
"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1332 L
"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1333 L
"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1334 L
"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1335 L
"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1336 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1337 L
"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1338 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1339 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1340 L
"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1341 L
"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1342 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1343 L
"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1344 L
"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1345 L
"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1346 L
"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1347 L
"\x003b\x005d\x005c\x005b\x002c"
1351 // On Linux, the only way to test alternate keyboard layouts is to change
1352 // the keyboard layout of the whole screen. I'm worried about the side
1353 // effects this may have on the buildbots.
1354 {MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1355 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1356 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1357 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1358 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1359 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1360 L
"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1361 L
"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1362 L
"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1363 L
"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1364 L
"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1365 L
"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1366 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1367 L
"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1368 L
"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1369 L
"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1370 L
"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1373 {MockKeyboard::LAYOUT_FRENCH
,
1374 L
"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1375 L
"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1376 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1377 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1378 L
"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1379 L
"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1380 L
"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1381 L
"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1382 L
"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1383 L
"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1384 L
"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1385 L
"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1386 L
"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1387 L
"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1388 L
"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1389 L
"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1390 L
"\x003b\x003a\x00f9\x0029\x002a\x0021"
1392 {MockKeyboard::LAYOUT_RUSSIAN
,
1393 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1394 L
"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1395 L
"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1396 L
"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1397 L
"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1398 L
"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1399 L
"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1400 L
"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1401 L
"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1402 L
"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1403 L
"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1404 L
"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1405 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1406 L
"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1407 L
"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1408 L
"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1409 L
"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1410 L
"\x0451\x0445\x005c\x044a\x044d"
1412 #endif // defined(OS_WIN)
1413 {MockKeyboard::LAYOUT_UNITED_STATES
,
1414 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1415 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1416 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1417 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1418 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1419 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1420 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1421 L
"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1422 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1423 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1424 L
"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1425 L
"\x003f\x007e\x007b\x007c\x007d\x0022"
1427 // This is ifdefed out for Linux to correspond to the fact that we don't
1428 // test alt+keystroke for now.
1429 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1430 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1431 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1432 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1433 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1434 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1439 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kLayouts
); ++i
) {
1440 // Load an HTML page consisting of one <div> element.
1441 // This <div> element is used by the EditorClientImpl class to insert
1442 // characters received through the RenderWidget::OnHandleInputEvent()
1444 view()->set_send_content_state_immediately(true);
1450 "<div id='test' contenteditable='true'>"
1454 ExecuteJavaScript("document.getElementById('test').focus();");
1455 render_thread_
->sink().ClearMessages();
1457 // For each key code, we send three keyboard events.
1458 // * Pressing only the key;
1459 // * Pressing the key and a left-shift key, and;
1460 // * Pressing the key and a right-alt (AltGr) key.
1461 static const MockKeyboard::Modifiers kModifiers
[] = {
1463 MockKeyboard::LEFT_SHIFT
,
1465 MockKeyboard::RIGHT_ALT
,
1469 MockKeyboard::Layout layout
= kLayouts
[i
].layout
;
1470 for (size_t j
= 0; j
< ARRAYSIZE_UNSAFE(kModifiers
); ++j
) {
1471 // Virtual key codes used for this test.
1472 static const int kKeyCodes
[] = {
1473 '0', '1', '2', '3', '4', '5', '6', '7',
1474 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1475 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1476 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1482 ui::VKEY_OEM_PERIOD
,
1490 // Unclear how to handle this on Linux.
1495 MockKeyboard::Modifiers modifiers
= kModifiers
[j
];
1496 for (size_t k
= 0; k
< ARRAYSIZE_UNSAFE(kKeyCodes
); ++k
) {
1497 // Send a keyboard event to the RenderView object.
1498 // We should test a keyboard event only when the given keyboard-layout
1499 // driver is installed in a PC and the driver can assign a Unicode
1500 // charcter for the given tuple (layout, key-code, and modifiers).
1501 int key_code
= kKeyCodes
[k
];
1502 base::string16 char_code
;
1503 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1508 // Retrieve the text in the test page and compare it with the expected
1509 // text created from a virtual-key code, a character code, and the
1510 // modifier-key status.
1511 const int kMaxOutputCharacters
= 4096;
1512 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1513 EXPECT_EQ(base::WideToUTF16(kLayouts
[i
].expected_result
), output
);
1520 // Crashy, http://crbug.com/53247.
1521 TEST_F(RenderViewImplTest
, DISABLED_DidFailProvisionalLoadWithErrorForError
) {
1522 GetMainFrame()->enableViewSourceMode(true);
1524 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1525 error
.reason
= net::ERR_FILE_NOT_FOUND
;
1526 error
.unreachableURL
= GURL("http://foo");
1527 WebLocalFrame
* web_frame
= GetMainFrame();
1529 // Start a load that will reach provisional state synchronously,
1530 // but won't complete synchronously.
1531 FrameMsg_Navigate_Params params
;
1532 params
.page_id
= -1;
1533 params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1534 params
.url
= GURL("data:text/html,test data");
1535 frame()->OnNavigate(params
);
1537 // An error occurred.
1538 view()->main_render_frame()->didFailProvisionalLoad(web_frame
, error
);
1539 // Frame should exit view-source mode.
1540 EXPECT_FALSE(web_frame
->isViewSourceModeEnabled());
1543 TEST_F(RenderViewImplTest
, DidFailProvisionalLoadWithErrorForCancellation
) {
1544 GetMainFrame()->enableViewSourceMode(true);
1546 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1547 error
.reason
= net::ERR_ABORTED
;
1548 error
.unreachableURL
= GURL("http://foo");
1549 WebLocalFrame
* web_frame
= GetMainFrame();
1551 // Start a load that will reach provisional state synchronously,
1552 // but won't complete synchronously.
1553 FrameMsg_Navigate_Params params
;
1554 params
.page_id
= -1;
1555 params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1556 params
.url
= GURL("data:text/html,test data");
1557 frame()->OnNavigate(params
);
1559 // A cancellation occurred.
1560 view()->main_render_frame()->didFailProvisionalLoad(web_frame
, error
);
1561 // Frame should stay in view-source mode.
1562 EXPECT_TRUE(web_frame
->isViewSourceModeEnabled());
1565 // Regression test for http://crbug.com/41562
1566 TEST_F(RenderViewImplTest
, UpdateTargetURLWithInvalidURL
) {
1567 const GURL
invalid_gurl("http://");
1568 view()->setMouseOverURL(blink::WebURL(invalid_gurl
));
1569 EXPECT_EQ(invalid_gurl
, view()->target_url_
);
1572 TEST_F(RenderViewImplTest
, SetHistoryLengthAndPrune
) {
1573 int expected_page_id
= -1;
1575 // No history to merge and no committed pages.
1576 view()->OnSetHistoryLengthAndPrune(0, -1);
1577 EXPECT_EQ(0, view()->history_list_length_
);
1578 EXPECT_EQ(-1, view()->history_list_offset_
);
1580 // History to merge and no committed pages.
1581 view()->OnSetHistoryLengthAndPrune(2, -1);
1582 EXPECT_EQ(2, view()->history_list_length_
);
1583 EXPECT_EQ(1, view()->history_list_offset_
);
1584 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1585 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1588 blink::WebHistoryItem item
;
1591 // No history to merge and a committed page to be kept.
1592 frame()->didCommitProvisionalLoad(GetMainFrame(),
1594 blink::WebStandardCommit
);
1595 expected_page_id
= view()->page_id_
;
1596 view()->OnSetHistoryLengthAndPrune(0, expected_page_id
);
1597 EXPECT_EQ(1, view()->history_list_length_
);
1598 EXPECT_EQ(0, view()->history_list_offset_
);
1599 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[0]);
1602 // No history to merge and a committed page to be pruned.
1603 frame()->didCommitProvisionalLoad(GetMainFrame(),
1605 blink::WebStandardCommit
);
1606 expected_page_id
= view()->page_id_
;
1607 view()->OnSetHistoryLengthAndPrune(0, expected_page_id
+ 1);
1608 EXPECT_EQ(0, view()->history_list_length_
);
1609 EXPECT_EQ(-1, view()->history_list_offset_
);
1612 // No history to merge and a committed page that the browser was unaware of.
1613 frame()->didCommitProvisionalLoad(GetMainFrame(),
1615 blink::WebStandardCommit
);
1616 expected_page_id
= view()->page_id_
;
1617 view()->OnSetHistoryLengthAndPrune(0, -1);
1618 EXPECT_EQ(1, view()->history_list_length_
);
1619 EXPECT_EQ(0, view()->history_list_offset_
);
1620 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[0]);
1623 // History to merge and a committed page to be kept.
1624 frame()->didCommitProvisionalLoad(GetMainFrame(),
1626 blink::WebStandardCommit
);
1627 expected_page_id
= view()->page_id_
;
1628 view()->OnSetHistoryLengthAndPrune(2, expected_page_id
);
1629 EXPECT_EQ(3, view()->history_list_length_
);
1630 EXPECT_EQ(2, view()->history_list_offset_
);
1631 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1632 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1633 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[2]);
1636 // History to merge and a committed page to be pruned.
1637 frame()->didCommitProvisionalLoad(GetMainFrame(),
1639 blink::WebStandardCommit
);
1640 expected_page_id
= view()->page_id_
;
1641 view()->OnSetHistoryLengthAndPrune(2, expected_page_id
+ 1);
1642 EXPECT_EQ(2, view()->history_list_length_
);
1643 EXPECT_EQ(1, view()->history_list_offset_
);
1644 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1645 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1648 // History to merge and a committed page that the browser was unaware of.
1649 frame()->didCommitProvisionalLoad(GetMainFrame(),
1651 blink::WebStandardCommit
);
1652 expected_page_id
= view()->page_id_
;
1653 view()->OnSetHistoryLengthAndPrune(2, -1);
1654 EXPECT_EQ(3, view()->history_list_length_
);
1655 EXPECT_EQ(2, view()->history_list_offset_
);
1656 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1657 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1658 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[2]);
1661 int expected_page_id_2
= -1;
1663 // No history to merge and two committed pages, both to be kept.
1664 frame()->didCommitProvisionalLoad(GetMainFrame(),
1666 blink::WebStandardCommit
);
1667 expected_page_id
= view()->page_id_
;
1668 frame()->didCommitProvisionalLoad(GetMainFrame(),
1670 blink::WebStandardCommit
);
1671 expected_page_id_2
= view()->page_id_
;
1672 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1673 view()->OnSetHistoryLengthAndPrune(0, expected_page_id
);
1674 EXPECT_EQ(2, view()->history_list_length_
);
1675 EXPECT_EQ(1, view()->history_list_offset_
);
1676 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[0]);
1677 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[1]);
1680 // No history to merge and two committed pages, and only the second is kept.
1681 frame()->didCommitProvisionalLoad(GetMainFrame(),
1683 blink::WebStandardCommit
);
1684 expected_page_id
= view()->page_id_
;
1685 frame()->didCommitProvisionalLoad(GetMainFrame(),
1687 blink::WebStandardCommit
);
1688 expected_page_id_2
= view()->page_id_
;
1689 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1690 view()->OnSetHistoryLengthAndPrune(0, expected_page_id_2
);
1691 EXPECT_EQ(1, view()->history_list_length_
);
1692 EXPECT_EQ(0, view()->history_list_offset_
);
1693 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[0]);
1696 // No history to merge and two committed pages, both of which the browser was
1698 frame()->didCommitProvisionalLoad(GetMainFrame(),
1700 blink::WebStandardCommit
);
1701 expected_page_id
= view()->page_id_
;
1702 frame()->didCommitProvisionalLoad(GetMainFrame(),
1704 blink::WebStandardCommit
);
1705 expected_page_id_2
= view()->page_id_
;
1706 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1707 view()->OnSetHistoryLengthAndPrune(0, -1);
1708 EXPECT_EQ(2, view()->history_list_length_
);
1709 EXPECT_EQ(1, view()->history_list_offset_
);
1710 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[0]);
1711 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[1]);
1714 // History to merge and two committed pages, both to be kept.
1715 frame()->didCommitProvisionalLoad(GetMainFrame(),
1717 blink::WebStandardCommit
);
1718 expected_page_id
= view()->page_id_
;
1719 frame()->didCommitProvisionalLoad(GetMainFrame(),
1721 blink::WebStandardCommit
);
1722 expected_page_id_2
= view()->page_id_
;
1723 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1724 view()->OnSetHistoryLengthAndPrune(2, expected_page_id
);
1725 EXPECT_EQ(4, view()->history_list_length_
);
1726 EXPECT_EQ(3, view()->history_list_offset_
);
1727 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1728 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1729 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[2]);
1730 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[3]);
1733 // History to merge and two committed pages, and only the second is kept.
1734 frame()->didCommitProvisionalLoad(GetMainFrame(),
1736 blink::WebStandardCommit
);
1737 expected_page_id
= view()->page_id_
;
1738 frame()->didCommitProvisionalLoad(GetMainFrame(),
1740 blink::WebStandardCommit
);
1741 expected_page_id_2
= view()->page_id_
;
1742 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1743 view()->OnSetHistoryLengthAndPrune(2, expected_page_id_2
);
1744 EXPECT_EQ(3, view()->history_list_length_
);
1745 EXPECT_EQ(2, view()->history_list_offset_
);
1746 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1747 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1748 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[2]);
1751 // History to merge and two committed pages, both of which the browser was
1753 frame()->didCommitProvisionalLoad(GetMainFrame(),
1755 blink::WebStandardCommit
);
1756 expected_page_id
= view()->page_id_
;
1757 frame()->didCommitProvisionalLoad(GetMainFrame(),
1759 blink::WebStandardCommit
);
1760 expected_page_id_2
= view()->page_id_
;
1761 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1762 view()->OnSetHistoryLengthAndPrune(2, -1);
1763 EXPECT_EQ(4, view()->history_list_length_
);
1764 EXPECT_EQ(3, view()->history_list_offset_
);
1765 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1766 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1767 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[2]);
1768 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[3]);
1771 TEST_F(RenderViewImplTest
, ContextMenu
) {
1772 LoadHTML("<div>Page A</div>");
1774 // Create a right click in the center of the iframe. (I'm hoping this will
1775 // make this a bit more robust in case of some other formatting or other bug.)
1776 WebMouseEvent mouse_event
;
1777 mouse_event
.type
= WebInputEvent::MouseDown
;
1778 mouse_event
.button
= WebMouseEvent::ButtonRight
;
1779 mouse_event
.x
= 250;
1780 mouse_event
.y
= 250;
1781 mouse_event
.globalX
= 250;
1782 mouse_event
.globalY
= 250;
1784 SendWebMouseEvent(mouse_event
);
1786 // Now simulate the corresponding up event which should display the menu
1787 mouse_event
.type
= WebInputEvent::MouseUp
;
1788 SendWebMouseEvent(mouse_event
);
1790 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
1791 FrameHostMsg_ContextMenu::ID
));
1794 TEST_F(RenderViewImplTest
, TestBackForward
) {
1795 LoadHTML("<div id=pagename>Page A</div>");
1796 PageState page_a_state
=
1797 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1798 int was_page_a
= -1;
1799 base::string16 check_page_a
=
1801 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1802 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1803 EXPECT_EQ(1, was_page_a
);
1805 LoadHTML("<div id=pagename>Page B</div>");
1806 int was_page_b
= -1;
1807 base::string16 check_page_b
=
1809 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1810 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1811 EXPECT_EQ(1, was_page_b
);
1813 LoadHTML("<div id=pagename>Page C</div>");
1814 int was_page_c
= -1;
1815 base::string16 check_page_c
=
1817 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1818 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1819 EXPECT_EQ(1, was_page_b
);
1821 PageState forward_state
=
1822 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1823 GoBack(HistoryEntryToPageState(
1824 view()->history_controller()->GetPreviousEntry()));
1825 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1826 EXPECT_EQ(1, was_page_b
);
1828 GoForward(forward_state
);
1829 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1830 EXPECT_EQ(1, was_page_c
);
1832 GoBack(HistoryEntryToPageState(
1833 view()->history_controller()->GetPreviousEntry()));
1834 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1835 EXPECT_EQ(1, was_page_b
);
1838 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1839 GoBack(page_a_state
);
1840 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1841 EXPECT_EQ(1, was_page_a
);
1843 GoForward(forward_state
);
1844 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1845 EXPECT_EQ(1, was_page_b
);
1848 #if defined(OS_MACOSX) || defined(USE_AURA)
1849 TEST_F(RenderViewImplTest
, GetCompositionCharacterBoundsTest
) {
1852 // http://crbug.com/304193
1853 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
1857 LoadHTML("<textarea id=\"test\"></textarea>");
1858 ExecuteJavaScript("document.getElementById('test').focus();");
1860 const base::string16 empty_string
;
1861 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1862 std::vector
<gfx::Rect
> bounds
;
1863 view()->OnSetFocus(true);
1864 view()->OnSetInputMethodActive(true);
1866 // ASCII composition
1867 const base::string16 ascii_composition
= base::UTF8ToUTF16("aiueo");
1868 view()->OnImeSetComposition(ascii_composition
, empty_underline
, 0, 0);
1869 view()->GetCompositionCharacterBounds(&bounds
);
1870 ASSERT_EQ(ascii_composition
.size(), bounds
.size());
1871 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1872 EXPECT_LT(0, bounds
[i
].width());
1873 view()->OnImeConfirmComposition(
1874 empty_string
, gfx::Range::InvalidRange(), false);
1876 // Non surrogate pair unicode character.
1877 const base::string16 unicode_composition
= base::UTF8ToUTF16(
1878 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1879 view()->OnImeSetComposition(unicode_composition
, empty_underline
, 0, 0);
1880 view()->GetCompositionCharacterBounds(&bounds
);
1881 ASSERT_EQ(unicode_composition
.size(), bounds
.size());
1882 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1883 EXPECT_LT(0, bounds
[i
].width());
1884 view()->OnImeConfirmComposition(
1885 empty_string
, gfx::Range::InvalidRange(), false);
1887 // Surrogate pair character.
1888 const base::string16 surrogate_pair_char
=
1889 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1890 view()->OnImeSetComposition(surrogate_pair_char
,
1894 view()->GetCompositionCharacterBounds(&bounds
);
1895 ASSERT_EQ(surrogate_pair_char
.size(), bounds
.size());
1896 EXPECT_LT(0, bounds
[0].width());
1897 EXPECT_EQ(0, bounds
[1].width());
1898 view()->OnImeConfirmComposition(
1899 empty_string
, gfx::Range::InvalidRange(), false);
1902 const base::string16 surrogate_pair_mixed_composition
=
1903 surrogate_pair_char
+ base::UTF8ToUTF16("\xE3\x81\x82") +
1904 surrogate_pair_char
+ base::UTF8ToUTF16("b") + surrogate_pair_char
;
1905 const size_t utf16_length
= 8UL;
1906 const bool is_surrogate_pair_empty_rect
[8] = {
1907 false, true, false, false, true, false, false, true };
1908 view()->OnImeSetComposition(surrogate_pair_mixed_composition
,
1912 view()->GetCompositionCharacterBounds(&bounds
);
1913 ASSERT_EQ(utf16_length
, bounds
.size());
1914 for (size_t i
= 0; i
< utf16_length
; ++i
) {
1915 if (is_surrogate_pair_empty_rect
[i
]) {
1916 EXPECT_EQ(0, bounds
[i
].width());
1918 EXPECT_LT(0, bounds
[i
].width());
1921 view()->OnImeConfirmComposition(
1922 empty_string
, gfx::Range::InvalidRange(), false);
1926 TEST_F(RenderViewImplTest
, ZoomLimit
) {
1927 const double kMinZoomLevel
= ZoomFactorToZoomLevel(kMinimumZoomFactor
);
1928 const double kMaxZoomLevel
= ZoomFactorToZoomLevel(kMaximumZoomFactor
);
1930 FrameMsg_Navigate_Params params
;
1931 params
.page_id
= -1;
1932 params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1934 // Verifies navigation to a URL with preset zoom level indeed sets the level.
1935 // Regression test for http://crbug.com/139559, where the level was not
1936 // properly set when it is out of the default zoom limits of WebView.
1937 params
.url
= GURL("data:text/html,min_zoomlimit_test");
1938 view()->OnSetZoomLevelForLoadingURL(params
.url
, kMinZoomLevel
);
1939 frame()->OnNavigate(params
);
1940 ProcessPendingMessages();
1941 EXPECT_DOUBLE_EQ(kMinZoomLevel
, view()->GetWebView()->zoomLevel());
1943 // It should work even when the zoom limit is temporarily changed in the page.
1944 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
1945 ZoomFactorToZoomLevel(1.0));
1946 params
.url
= GURL("data:text/html,max_zoomlimit_test");
1947 view()->OnSetZoomLevelForLoadingURL(params
.url
, kMaxZoomLevel
);
1948 frame()->OnNavigate(params
);
1949 ProcessPendingMessages();
1950 EXPECT_DOUBLE_EQ(kMaxZoomLevel
, view()->GetWebView()->zoomLevel());
1953 TEST_F(RenderViewImplTest
, SetEditableSelectionAndComposition
) {
1954 // Load an HTML page consisting of an input field.
1959 "<input id=\"test1\" value=\"some test text hello\"></input>"
1962 ExecuteJavaScript("document.getElementById('test1').focus();");
1963 frame()->OnSetEditableSelectionOffsets(4, 8);
1964 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1965 frame()->OnSetCompositionFromExistingText(7, 10, empty_underline
);
1966 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1967 EXPECT_EQ(4, info
.selectionStart
);
1968 EXPECT_EQ(8, info
.selectionEnd
);
1969 EXPECT_EQ(7, info
.compositionStart
);
1970 EXPECT_EQ(10, info
.compositionEnd
);
1971 frame()->OnUnselect();
1972 info
= view()->webview()->textInputInfo();
1973 EXPECT_EQ(0, info
.selectionStart
);
1974 EXPECT_EQ(0, info
.selectionEnd
);
1978 TEST_F(RenderViewImplTest
, OnExtendSelectionAndDelete
) {
1979 // Load an HTML page consisting of an input field.
1984 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
1987 ExecuteJavaScript("document.getElementById('test1').focus();");
1988 frame()->OnSetEditableSelectionOffsets(10, 10);
1989 frame()->OnExtendSelectionAndDelete(3, 4);
1990 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1991 EXPECT_EQ("abcdefgopqrstuvwxyz", info
.value
);
1992 EXPECT_EQ(7, info
.selectionStart
);
1993 EXPECT_EQ(7, info
.selectionEnd
);
1994 frame()->OnSetEditableSelectionOffsets(4, 8);
1995 frame()->OnExtendSelectionAndDelete(2, 5);
1996 info
= view()->webview()->textInputInfo();
1997 EXPECT_EQ("abuvwxyz", info
.value
);
1998 EXPECT_EQ(2, info
.selectionStart
);
1999 EXPECT_EQ(2, info
.selectionEnd
);
2002 // Test that the navigating specific frames works correctly.
2003 TEST_F(RenderViewImplTest
, NavigateFrame
) {
2005 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
2007 // Navigate the frame only.
2008 FrameMsg_Navigate_Params nav_params
;
2009 nav_params
.url
= GURL("data:text/html,world");
2010 nav_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2011 nav_params
.transition
= PAGE_TRANSITION_TYPED
;
2012 nav_params
.current_history_list_length
= 1;
2013 nav_params
.current_history_list_offset
= 0;
2014 nav_params
.pending_history_list_offset
= 1;
2015 nav_params
.page_id
= -1;
2016 nav_params
.frame_to_navigate
= "frame";
2017 frame()->OnNavigate(nav_params
);
2019 RenderFrame::FromWebFrame(frame()->GetWebFrame()->firstChild())).Wait();
2021 // Copy the document content to std::wstring and compare with the
2023 const int kMaxOutputCharacters
= 256;
2024 std::string output
= base::UTF16ToUTF8(
2025 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
2026 EXPECT_EQ(output
, "hello \n\nworld");
2029 // This test ensures that a RenderFrame object is created for the top level
2030 // frame in the RenderView.
2031 TEST_F(RenderViewImplTest
, BasicRenderFrame
) {
2032 EXPECT_TRUE(view()->main_render_frame_
.get());
2035 TEST_F(RenderViewImplTest
, GetSSLStatusOfFrame
) {
2036 LoadHTML("<!DOCTYPE html><html><body></body></html>");
2038 WebLocalFrame
* frame
= GetMainFrame();
2039 SSLStatus ssl_status
= view()->GetSSLStatusOfFrame(frame
);
2040 EXPECT_FALSE(net::IsCertStatusError(ssl_status
.cert_status
));
2042 const_cast<blink::WebURLResponse
&>(frame
->dataSource()->response()).
2044 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS
, 0, 0,
2045 SignedCertificateTimestampIDStatusList()));
2046 ssl_status
= view()->GetSSLStatusOfFrame(frame
);
2047 EXPECT_TRUE(net::IsCertStatusError(ssl_status
.cert_status
));
2050 TEST_F(RenderViewImplTest
, MessageOrderInDidChangeSelection
) {
2051 view()->OnSetInputMethodActive(true);
2052 view()->set_send_content_state_immediately(true);
2053 LoadHTML("<textarea id=\"test\"></textarea>");
2055 view()->handling_input_event_
= true;
2056 ExecuteJavaScript("document.getElementById('test').focus();");
2058 bool is_input_type_called
= false;
2059 bool is_selection_called
= false;
2060 size_t last_input_type
= 0;
2061 size_t last_selection
= 0;
2063 for (size_t i
= 0; i
< render_thread_
->sink().message_count(); ++i
) {
2064 const uint32 type
= render_thread_
->sink().GetMessageAt(i
)->type();
2065 if (type
== ViewHostMsg_TextInputTypeChanged::ID
) {
2066 is_input_type_called
= true;
2067 last_input_type
= i
;
2068 } else if (type
== ViewHostMsg_SelectionChanged::ID
) {
2069 is_selection_called
= true;
2074 EXPECT_TRUE(is_input_type_called
);
2075 EXPECT_TRUE(is_selection_called
);
2077 // InputTypeChange shold be called earlier than SelectionChanged.
2078 EXPECT_LT(last_input_type
, last_selection
);
2081 class SuppressErrorPageTest
: public RenderViewTest
{
2083 virtual ContentRendererClient
* CreateContentRendererClient() OVERRIDE
{
2084 return new TestContentRendererClient
;
2087 RenderViewImpl
* view() {
2088 return static_cast<RenderViewImpl
*>(view_
);
2091 RenderFrameImpl
* frame() {
2092 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
2096 class TestContentRendererClient
: public ContentRendererClient
{
2098 virtual bool ShouldSuppressErrorPage(RenderFrame
* render_frame
,
2099 const GURL
& url
) OVERRIDE
{
2100 return url
== GURL("http://example.com/suppress");
2103 virtual void GetNavigationErrorStrings(
2104 content::RenderView
* render_view
,
2105 blink::WebFrame
* frame
,
2106 const blink::WebURLRequest
& failed_request
,
2107 const blink::WebURLError
& error
,
2108 std::string
* error_html
,
2109 base::string16
* error_description
) OVERRIDE
{
2111 *error_html
= "A suffusion of yellow.";
2116 #if defined(OS_ANDROID)
2117 // Crashing on Android: http://crbug.com/311341
2118 #define MAYBE_Suppresses DISABLED_Suppresses
2120 #define MAYBE_Suppresses Suppresses
2123 TEST_F(SuppressErrorPageTest
, MAYBE_Suppresses
) {
2125 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2126 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2127 error
.unreachableURL
= GURL("http://example.com/suppress");
2128 WebLocalFrame
* web_frame
= GetMainFrame();
2130 // Start a load that will reach provisional state synchronously,
2131 // but won't complete synchronously.
2132 FrameMsg_Navigate_Params params
;
2133 params
.page_id
= -1;
2134 params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2135 params
.url
= GURL("data:text/html,test data");
2136 frame()->OnNavigate(params
);
2138 // An error occurred.
2139 view()->main_render_frame()->didFailProvisionalLoad(web_frame
, error
);
2140 const int kMaxOutputCharacters
= 22;
2142 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2145 #if defined(OS_ANDROID)
2146 // Crashing on Android: http://crbug.com/311341
2147 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2149 #define MAYBE_DoesNotSuppress DoesNotSuppress
2152 TEST_F(SuppressErrorPageTest
, MAYBE_DoesNotSuppress
) {
2154 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2155 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2156 error
.unreachableURL
= GURL("http://example.com/dont-suppress");
2157 WebLocalFrame
* web_frame
= GetMainFrame();
2159 // Start a load that will reach provisional state synchronously,
2160 // but won't complete synchronously.
2161 FrameMsg_Navigate_Params params
;
2162 params
.page_id
= -1;
2163 params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2164 params
.url
= GURL("data:text/html,test data");
2165 frame()->OnNavigate(params
);
2167 // An error occurred.
2168 view()->main_render_frame()->didFailProvisionalLoad(web_frame
, error
);
2169 // The error page itself is loaded asynchronously.
2170 FrameLoadWaiter(frame()).Wait();
2171 const int kMaxOutputCharacters
= 22;
2172 EXPECT_EQ("A suffusion of yellow.",
2173 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2176 // Tests if IME API's candidatewindow* events sent from browser are handled
2178 TEST_F(RenderViewImplTest
, SendCandidateWindowEvents
) {
2179 // Sends an HTML with an <input> element and scripts to the renderer.
2180 // The script handles all 3 of candidatewindow* events for an
2181 // InputMethodContext object and once it received 'show', 'update', 'hide'
2182 // should appear in the result div.
2183 LoadHTML("<input id='test'>"
2184 "<div id='result'>Result: </div>"
2186 "window.onload = function() {"
2187 " var result = document.getElementById('result');"
2188 " var test = document.getElementById('test');"
2190 " var context = test.inputMethodContext;"
2192 " context.oncandidatewindowshow = function() {"
2193 " result.innerText += 'show'; };"
2194 " context.oncandidatewindowupdate = function(){"
2195 " result.innerText += 'update'; };"
2196 " context.oncandidatewindowhide = function(){"
2197 " result.innerText += 'hide'; };"
2202 // Fire candidatewindow events.
2203 view()->OnCandidateWindowShown();
2204 view()->OnCandidateWindowUpdated();
2205 view()->OnCandidateWindowHidden();
2207 // Retrieve the content and check if it is expected.
2208 const int kMaxOutputCharacters
= 50;
2209 std::string output
= base::UTF16ToUTF8(
2210 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
2211 EXPECT_EQ(output
, "\nResult:showupdatehide");
2214 // Ensure the render view sends favicon url update events correctly.
2215 TEST_F(RenderViewImplTest
, SendFaviconURLUpdateEvent
) {
2216 // An event should be sent when a favicon url exists.
2219 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2222 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
2223 ViewHostMsg_UpdateFaviconURL::ID
));
2224 render_thread_
->sink().ClearMessages();
2226 // An event should not be sent if no favicon url exists. This is an assumption
2227 // made by some of Chrome's favicon handling.
2232 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
2233 ViewHostMsg_UpdateFaviconURL::ID
));
2236 // Test progress tracker messages.
2237 TEST_F(RenderViewImplTest
, SendProgressCompletionUpdates
) {
2238 std::string data_url_string
= "data:text/html,<body>placeholder</body>";
2239 GURL
url(data_url_string
);
2240 GetMainFrame()->loadRequest(blink::WebURLRequest(url
));
2242 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
2243 FrameHostMsg_DidStartLoading::ID
));
2245 // The load started, we should receive a start notification and a progress
2246 // update with the minimum progress.
2247 const IPC::Message
* message
= render_thread_
->sink().GetFirstMessageMatching(
2248 ViewHostMsg_DidChangeLoadProgress::ID
);
2249 EXPECT_TRUE(message
);
2250 Tuple1
<double> progress_value
;
2251 ViewHostMsg_DidChangeLoadProgress::Read(message
, &progress_value
);
2252 EXPECT_EQ(0.1, progress_value
.a
);
2253 render_thread_
->sink().ClearMessages();
2255 FrameLoadWaiter(frame()).Wait();
2257 // The data url has loaded, so we should see a progress change to 1.0 (done)
2258 // and a stop notification.
2259 message
= render_thread_
->sink().GetFirstMessageMatching(
2260 ViewHostMsg_DidChangeLoadProgress::ID
);
2261 EXPECT_TRUE(message
);
2262 ViewHostMsg_DidChangeLoadProgress::Read(message
, &progress_value
);
2263 EXPECT_EQ(1.0, progress_value
.a
);
2265 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
2266 FrameHostMsg_DidStopLoading::ID
));
2267 render_thread_
->sink().ClearMessages();
2270 TEST_F(RenderViewImplTest
, FocusElementCallsFocusedNodeChanged
) {
2271 LoadHTML("<input id='test1' value='hello1'></input>"
2272 "<input id='test2' value='hello2'></input>");
2274 ExecuteJavaScript("document.getElementById('test1').focus();");
2275 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
2276 ViewHostMsg_FocusedNodeChanged::ID
);
2279 ViewHostMsg_FocusedNodeChanged::Param params
;
2280 ViewHostMsg_FocusedNodeChanged::Read(msg1
, ¶ms
);
2281 EXPECT_TRUE(params
.a
);
2282 render_thread_
->sink().ClearMessages();
2284 ExecuteJavaScript("document.getElementById('test2').focus();");
2285 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
2286 ViewHostMsg_FocusedNodeChanged::ID
);
2288 ViewHostMsg_FocusedNodeChanged::Read(msg2
, ¶ms
);
2289 EXPECT_TRUE(params
.a
);
2290 render_thread_
->sink().ClearMessages();
2292 view()->webview()->clearFocusedElement();
2293 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
2294 ViewHostMsg_FocusedNodeChanged::ID
);
2296 ViewHostMsg_FocusedNodeChanged::Read(msg3
, ¶ms
);
2297 EXPECT_FALSE(params
.a
);
2298 render_thread_
->sink().ClearMessages();
2301 TEST_F(RenderViewImplTest
, ServiceWorkerNetworkProviderSetup
) {
2302 ServiceWorkerNetworkProvider
* provider
= NULL
;
2303 RequestExtraData
* extra_data
= NULL
;
2305 // Make sure each new document has a new provider and
2306 // that the main request is tagged with the provider's id.
2307 LoadHTML("<b>A Document</b>");
2308 ASSERT_TRUE(GetMainFrame()->dataSource());
2309 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2310 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2311 ASSERT_TRUE(provider
);
2312 extra_data
= static_cast<RequestExtraData
*>(
2313 GetMainFrame()->dataSource()->request().extraData());
2314 ASSERT_TRUE(extra_data
);
2315 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2316 provider
->provider_id());
2317 int provider1_id
= provider
->provider_id();
2319 LoadHTML("<b>New Document B Goes Here</b>");
2320 ASSERT_TRUE(GetMainFrame()->dataSource());
2321 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2322 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2323 ASSERT_TRUE(provider
);
2324 EXPECT_NE(provider1_id
, provider
->provider_id());
2325 extra_data
= static_cast<RequestExtraData
*>(
2326 GetMainFrame()->dataSource()->request().extraData());
2327 ASSERT_TRUE(extra_data
);
2328 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2329 provider
->provider_id());
2331 // See that subresource requests are also tagged with the provider's id.
2332 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2333 blink::WebURLRequest
request(GURL("http://foo.com"));
2334 request
.setTargetType(blink::WebURLRequest::TargetIsSubresource
);
2335 blink::WebURLResponse redirect_response
;
2336 frame()->willSendRequest(GetMainFrame(), 0, request
, redirect_response
);
2337 extra_data
= static_cast<RequestExtraData
*>(request
.extraData());
2338 ASSERT_TRUE(extra_data
);
2339 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2340 provider
->provider_id());
2343 TEST_F(RenderViewImplTest
, OnSetAccessibilityMode
) {
2344 ASSERT_EQ(AccessibilityModeOff
, view()->accessibility_mode());
2345 ASSERT_EQ((RendererAccessibility
*) NULL
, view()->renderer_accessibility());
2347 view()->OnSetAccessibilityMode(AccessibilityModeTreeOnly
);
2348 ASSERT_EQ(AccessibilityModeTreeOnly
, view()->accessibility_mode());
2349 ASSERT_NE((RendererAccessibility
*) NULL
, view()->renderer_accessibility());
2350 ASSERT_EQ(RendererAccessibilityTypeComplete
,
2351 view()->renderer_accessibility()->GetType());
2353 view()->OnSetAccessibilityMode(AccessibilityModeOff
);
2354 ASSERT_EQ(AccessibilityModeOff
, view()->accessibility_mode());
2355 ASSERT_EQ((RendererAccessibility
*) NULL
, view()->renderer_accessibility());
2357 view()->OnSetAccessibilityMode(AccessibilityModeComplete
);
2358 ASSERT_EQ(AccessibilityModeComplete
, view()->accessibility_mode());
2359 ASSERT_NE((RendererAccessibility
*) NULL
, view()->renderer_accessibility());
2360 ASSERT_EQ(RendererAccessibilityTypeComplete
,
2361 view()->renderer_accessibility()->GetType());
2363 view()->OnSetAccessibilityMode(AccessibilityModeEditableTextOnly
);
2364 ASSERT_EQ(AccessibilityModeEditableTextOnly
, view()->accessibility_mode());
2365 ASSERT_NE((RendererAccessibility
*) NULL
, view()->renderer_accessibility());
2366 ASSERT_EQ(RendererAccessibilityTypeFocusOnly
,
2367 view()->renderer_accessibility()->GetType());
2370 } // namespace content