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/mock_keyboard.h"
39 #include "net/base/net_errors.h"
40 #include "net/cert/cert_status_flags.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "third_party/WebKit/public/platform/WebData.h"
43 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
44 #include "third_party/WebKit/public/platform/WebString.h"
45 #include "third_party/WebKit/public/platform/WebURLResponse.h"
46 #include "third_party/WebKit/public/web/WebDataSource.h"
47 #include "third_party/WebKit/public/web/WebHistoryItem.h"
48 #include "third_party/WebKit/public/web/WebLocalFrame.h"
49 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
50 #include "third_party/WebKit/public/web/WebView.h"
51 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
52 #include "ui/events/keycodes/keyboard_codes.h"
53 #include "ui/gfx/codec/jpeg_codec.h"
54 #include "ui/gfx/range/range.h"
57 #include "ui/events/event.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_x11.h"
67 #if defined(USE_OZONE)
68 #include "ui/events/keycodes/keyboard_code_conversion.h"
71 using blink::WebFrame
;
72 using blink::WebInputEvent
;
73 using blink::WebLocalFrame
;
74 using blink::WebMouseEvent
;
75 using blink::WebRuntimeFeatures
;
76 using blink::WebString
;
77 using blink::WebTextDirection
;
78 using blink::WebURLError
;
84 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
85 // Converts MockKeyboard::Modifiers to ui::EventFlags.
86 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers
) {
87 static struct ModifierMap
{
88 MockKeyboard::Modifiers src
;
91 { MockKeyboard::LEFT_SHIFT
, ui::EF_SHIFT_DOWN
},
92 { MockKeyboard::RIGHT_SHIFT
, ui::EF_SHIFT_DOWN
},
93 { MockKeyboard::LEFT_CONTROL
, ui::EF_CONTROL_DOWN
},
94 { MockKeyboard::RIGHT_CONTROL
, ui::EF_CONTROL_DOWN
},
95 { MockKeyboard::LEFT_ALT
, ui::EF_ALT_DOWN
},
96 { MockKeyboard::RIGHT_ALT
, ui::EF_ALT_DOWN
},
99 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kModifierMap
); ++i
) {
100 if (kModifierMap
[i
].src
& modifiers
) {
101 flags
|= kModifierMap
[i
].dst
;
108 class WebUITestWebUIControllerFactory
: public WebUIControllerFactory
{
110 virtual WebUIController
* CreateWebUIControllerForURL(
111 WebUI
* web_ui
, const GURL
& url
) const OVERRIDE
{
114 virtual WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
115 const GURL
& url
) const OVERRIDE
{
116 return WebUI::kNoWebUI
;
118 virtual bool UseWebUIForURL(BrowserContext
* browser_context
,
119 const GURL
& url
) const OVERRIDE
{
120 return HasWebUIScheme(url
);
122 virtual bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
123 const GURL
& url
) const OVERRIDE
{
124 return HasWebUIScheme(url
);
128 class RenderViewImplTest
: public RenderViewTest
{
130 RenderViewImplTest() {
131 // Attach a pseudo keyboard device to this object.
132 mock_keyboard_
.reset(new MockKeyboard());
135 virtual ~RenderViewImplTest() {}
137 virtual void SetUp() OVERRIDE
{
138 RenderViewTest::SetUp();
139 // Enable Blink's experimental and test only features so that test code
140 // does not have to bother enabling each feature.
141 WebRuntimeFeatures::enableExperimentalFeatures(true);
142 WebRuntimeFeatures::enableTestOnlyFeatures(true);
145 RenderViewImpl
* view() {
146 return static_cast<RenderViewImpl
*>(view_
);
149 RenderFrameImpl
* frame() {
150 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
153 // Sends IPC messages that emulates a key-press event.
154 int SendKeyEvent(MockKeyboard::Layout layout
,
156 MockKeyboard::Modifiers modifiers
,
157 base::string16
* output
) {
159 // Retrieve the Unicode character for the given tuple (keyboard-layout,
160 // key-code, and modifiers).
161 // Exit when a keyboard-layout driver cannot assign a Unicode character to
162 // the tuple to prevent sending an invalid key code to the RenderView
164 CHECK(mock_keyboard_
.get());
166 int length
= mock_keyboard_
->GetCharacters(layout
, key_code
, modifiers
,
171 // Create IPC messages from Windows messages and send them to our
173 // A keyboard event of Windows consists of three Windows messages:
174 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
175 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
176 // WM_CHAR sends a composed Unicode character.
177 MSG msg1
= { NULL
, WM_KEYDOWN
, key_code
, 0 };
178 #if defined(USE_AURA)
179 ui::KeyEvent
evt1(msg1
, false);
180 NativeWebKeyboardEvent
keydown_event(&evt1
);
182 NativeWebKeyboardEvent
keydown_event(msg1
);
184 SendNativeKeyEvent(keydown_event
);
186 MSG msg2
= { NULL
, WM_CHAR
, (*output
)[0], 0 };
187 #if defined(USE_AURA)
188 ui::KeyEvent
evt2(msg2
, true);
189 NativeWebKeyboardEvent
char_event(&evt2
);
191 NativeWebKeyboardEvent
char_event(msg2
);
193 SendNativeKeyEvent(char_event
);
195 MSG msg3
= { NULL
, WM_KEYUP
, key_code
, 0 };
196 #if defined(USE_AURA)
197 ui::KeyEvent
evt3(msg3
, false);
198 NativeWebKeyboardEvent
keyup_event(&evt3
);
200 NativeWebKeyboardEvent
keyup_event(msg3
);
202 SendNativeKeyEvent(keyup_event
);
205 #elif defined(USE_AURA) && defined(USE_X11)
206 // We ignore |layout|, which means we are only testing the layout of the
207 // current locale. TODO(mazda): fix this to respect |layout|.
209 const int flags
= ConvertMockKeyboardModifier(modifiers
);
211 ui::ScopedXI2Event xevent
;
212 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
213 static_cast<ui::KeyboardCode
>(key_code
),
215 ui::KeyEvent
event1(xevent
, false);
216 NativeWebKeyboardEvent
keydown_event(&event1
);
217 SendNativeKeyEvent(keydown_event
);
219 xevent
.InitKeyEvent(ui::ET_KEY_PRESSED
,
220 static_cast<ui::KeyboardCode
>(key_code
),
222 ui::KeyEvent
event2(xevent
, true);
223 NativeWebKeyboardEvent
char_event(&event2
);
224 SendNativeKeyEvent(char_event
);
226 xevent
.InitKeyEvent(ui::ET_KEY_RELEASED
,
227 static_cast<ui::KeyboardCode
>(key_code
),
229 ui::KeyEvent
event3(xevent
, false);
230 NativeWebKeyboardEvent
keyup_event(&event3
);
231 SendNativeKeyEvent(keyup_event
);
233 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
235 output
->assign(1, static_cast<base::char16
>(c
));
237 #elif defined(USE_OZONE)
238 const int flags
= ConvertMockKeyboardModifier(modifiers
);
240 // Ozone's native events are ui::Events. So first create the "native" event,
241 // then create the actual ui::KeyEvent with the native event.
242 ui::KeyEvent
keydown_native_event(ui::ET_KEY_PRESSED
,
243 static_cast<ui::KeyboardCode
>(key_code
),
246 ui::KeyEvent
keydown_event(&keydown_native_event
, false);
247 NativeWebKeyboardEvent
keydown_web_event(&keydown_event
);
248 SendNativeKeyEvent(keydown_web_event
);
250 ui::KeyEvent
char_native_event(ui::ET_KEY_PRESSED
,
251 static_cast<ui::KeyboardCode
>(key_code
),
254 ui::KeyEvent
char_event(&char_native_event
, true);
255 NativeWebKeyboardEvent
char_web_event(&char_event
);
256 SendNativeKeyEvent(char_web_event
);
258 ui::KeyEvent
keyup_native_event(ui::ET_KEY_RELEASED
,
259 static_cast<ui::KeyboardCode
>(key_code
),
262 ui::KeyEvent
keyup_event(&keyup_native_event
, false);
263 NativeWebKeyboardEvent
keyup_web_event(&keyup_event
);
264 SendNativeKeyEvent(keyup_web_event
);
266 long c
= GetCharacterFromKeyCode(static_cast<ui::KeyboardCode
>(key_code
),
268 output
->assign(1, static_cast<base::char16
>(c
));
277 scoped_ptr
<MockKeyboard
> mock_keyboard_
;
282 // Test that we get form state change notifications when input fields change.
283 TEST_F(RenderViewImplTest
, DISABLED_OnNavStateChanged
) {
284 // Don't want any delay for form state sync changes. This will still post a
285 // message so updates will get coalesced, but as soon as we spin the message
286 // loop, it will generate an update.
287 view()->set_send_content_state_immediately(true);
289 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
291 // We should NOT have gotten a form state change notification yet.
292 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
293 ViewHostMsg_UpdateState::ID
));
294 render_thread_
->sink().ClearMessages();
296 // Change the value of the input. We should have gotten an update state
297 // notification. We need to spin the message loop to catch this update.
298 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';");
299 ProcessPendingMessages();
300 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
301 ViewHostMsg_UpdateState::ID
));
304 TEST_F(RenderViewImplTest
, OnNavigationHttpPost
) {
305 FrameMsg_Navigate_Params nav_params
;
307 // An http url will trigger a resource load so cannot be used here.
308 nav_params
.url
= GURL("data:text/html,<div>Page</div>");
309 nav_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
310 nav_params
.transition
= PAGE_TRANSITION_TYPED
;
311 nav_params
.page_id
= -1;
312 nav_params
.is_post
= true;
315 const unsigned char* raw_data
= reinterpret_cast<const unsigned char*>(
317 const unsigned int length
= 11;
318 const std::vector
<unsigned char> post_data(raw_data
, raw_data
+ length
);
319 nav_params
.browser_initiated_post_data
= post_data
;
321 frame()->OnNavigate(nav_params
);
322 ProcessPendingMessages();
324 const IPC::Message
* frame_navigate_msg
=
325 render_thread_
->sink().GetUniqueMessageMatching(
326 FrameHostMsg_DidCommitProvisionalLoad::ID
);
327 EXPECT_TRUE(frame_navigate_msg
);
329 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params
;
330 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
332 EXPECT_TRUE(host_nav_params
.a
.is_post
);
334 // Check post data sent to browser matches
335 EXPECT_TRUE(host_nav_params
.a
.page_state
.IsValid());
336 scoped_ptr
<HistoryEntry
> entry
=
337 PageStateToHistoryEntry(host_nav_params
.a
.page_state
);
338 blink::WebHTTPBody body
= entry
->root().httpBody();
339 blink::WebHTTPBody::Element element
;
340 bool successful
= body
.elementAt(0, element
);
341 EXPECT_TRUE(successful
);
342 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData
, element
.type
);
343 EXPECT_EQ(length
, element
.data
.size());
344 EXPECT_EQ(0, memcmp(raw_data
, element
.data
.data(), length
));
347 TEST_F(RenderViewImplTest
, DecideNavigationPolicy
) {
348 WebUITestWebUIControllerFactory factory
;
349 WebUIControllerFactory::RegisterFactory(&factory
);
352 state
.set_navigation_state(NavigationState::CreateContentInitiated());
354 // Navigations to normal HTTP URLs can be handled locally.
355 blink::WebURLRequest
request(GURL("http://foo.com"));
356 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
360 blink::WebNavigationTypeLinkClicked
,
361 blink::WebNavigationPolicyCurrentTab
,
363 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab
, policy
);
365 // Verify that form posts to WebUI URLs will be sent to the browser process.
366 blink::WebURLRequest
form_request(GURL("chrome://foo"));
367 form_request
.setHTTPMethod("POST");
368 policy
= frame()->decidePolicyForNavigation(
372 blink::WebNavigationTypeFormSubmitted
,
373 blink::WebNavigationPolicyCurrentTab
,
375 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
377 // Verify that popup links to WebUI URLs also are sent to browser.
378 blink::WebURLRequest
popup_request(GURL("chrome://foo"));
379 policy
= frame()->decidePolicyForNavigation(
383 blink::WebNavigationTypeLinkClicked
,
384 blink::WebNavigationPolicyNewForegroundTab
,
386 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
389 TEST_F(RenderViewImplTest
, DecideNavigationPolicyHandlesAllTopLevel
) {
391 state
.set_navigation_state(NavigationState::CreateContentInitiated());
393 RendererPreferences prefs
= view()->renderer_preferences();
394 prefs
.browser_handles_all_top_level_requests
= true;
395 view()->OnSetRendererPrefs(prefs
);
397 const blink::WebNavigationType kNavTypes
[] = {
398 blink::WebNavigationTypeLinkClicked
,
399 blink::WebNavigationTypeFormSubmitted
,
400 blink::WebNavigationTypeBackForward
,
401 blink::WebNavigationTypeReload
,
402 blink::WebNavigationTypeFormResubmitted
,
403 blink::WebNavigationTypeOther
,
406 blink::WebURLRequest
request(GURL("http://foo.com"));
407 for (size_t i
= 0; i
< arraysize(kNavTypes
); ++i
) {
408 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
413 blink::WebNavigationPolicyCurrentTab
,
415 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
419 TEST_F(RenderViewImplTest
, DecideNavigationPolicyForWebUI
) {
420 // Enable bindings to simulate a WebUI view.
421 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI
);
424 state
.set_navigation_state(NavigationState::CreateContentInitiated());
426 // Navigations to normal HTTP URLs will be sent to browser process.
427 blink::WebURLRequest
request(GURL("http://foo.com"));
428 blink::WebNavigationPolicy policy
= frame()->decidePolicyForNavigation(
432 blink::WebNavigationTypeLinkClicked
,
433 blink::WebNavigationPolicyCurrentTab
,
435 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
437 // Navigations to WebUI URLs will also be sent to browser process.
438 blink::WebURLRequest
webui_request(GURL("chrome://foo"));
439 policy
= frame()->decidePolicyForNavigation(
443 blink::WebNavigationTypeLinkClicked
,
444 blink::WebNavigationPolicyCurrentTab
,
446 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
448 // Verify that form posts to data URLs will be sent to the browser process.
449 blink::WebURLRequest
data_request(GURL("data:text/html,foo"));
450 data_request
.setHTTPMethod("POST");
451 policy
= frame()->decidePolicyForNavigation(
455 blink::WebNavigationTypeFormSubmitted
,
456 blink::WebNavigationPolicyCurrentTab
,
458 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
460 // Verify that a popup that creates a view first and then navigates to a
461 // normal HTTP URL will be sent to the browser process, even though the
462 // new view does not have any enabled_bindings_.
463 blink::WebURLRequest
popup_request(GURL("http://foo.com"));
464 blink::WebView
* new_web_view
= view()->createView(
465 GetMainFrame(), popup_request
, blink::WebWindowFeatures(), "foo",
466 blink::WebNavigationPolicyNewForegroundTab
, false);
467 RenderViewImpl
* new_view
= RenderViewImpl::FromWebView(new_web_view
);
468 policy
= static_cast<RenderFrameImpl
*>(new_view
->GetMainRenderFrame())->
469 decidePolicyForNavigation(
470 new_web_view
->mainFrame()->toWebLocalFrame(),
473 blink::WebNavigationTypeLinkClicked
,
474 blink::WebNavigationPolicyNewForegroundTab
,
476 EXPECT_EQ(blink::WebNavigationPolicyIgnore
, policy
);
478 // Clean up after the new view so we don't leak it.
483 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
484 // already swapped out. http://crbug.com/93427.
485 TEST_F(RenderViewImplTest
, SendSwapOutACK
) {
486 LoadHTML("<div>Page A</div>");
487 int initial_page_id
= view()->GetPageId();
489 // Respond to a swap out request.
490 view()->main_render_frame()->OnSwapOut();
492 // Ensure the swap out commits synchronously.
493 EXPECT_NE(initial_page_id
, view()->GetPageId());
495 // Check for a valid OnSwapOutACK.
496 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
497 FrameHostMsg_SwapOut_ACK::ID
);
500 // It is possible to get another swap out request. Ensure that we send
501 // an ACK, even if we don't have to do anything else.
502 render_thread_
->sink().ClearMessages();
503 view()->main_render_frame()->OnSwapOut();
504 const IPC::Message
* msg2
= render_thread_
->sink().GetUniqueMessageMatching(
505 FrameHostMsg_SwapOut_ACK::ID
);
508 // If we navigate back to this RenderView, ensure we don't send a state
509 // update for the swapped out URL. (http://crbug.com/72235)
510 FrameMsg_Navigate_Params nav_params
;
511 nav_params
.url
= GURL("data:text/html,<div>Page B</div>");
512 nav_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
513 nav_params
.transition
= PAGE_TRANSITION_TYPED
;
514 nav_params
.current_history_list_length
= 1;
515 nav_params
.current_history_list_offset
= 0;
516 nav_params
.pending_history_list_offset
= 1;
517 nav_params
.page_id
= -1;
518 frame()->OnNavigate(nav_params
);
519 ProcessPendingMessages();
520 const IPC::Message
* msg3
= render_thread_
->sink().GetUniqueMessageMatching(
521 ViewHostMsg_UpdateState::ID
);
525 // Ensure the RenderViewImpl reloads the previous page if a reload request
526 // arrives while it is showing swappedout://. http://crbug.com/143155.
527 TEST_F(RenderViewImplTest
, ReloadWhileSwappedOut
) {
529 LoadHTML("<div>Page A</div>");
531 // Load page B, which will trigger an UpdateState message for page A.
532 LoadHTML("<div>Page B</div>");
534 // Check for a valid UpdateState message for page A.
535 ProcessPendingMessages();
536 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
537 ViewHostMsg_UpdateState::ID
);
541 ViewHostMsg_UpdateState::Read(msg_A
, &page_id_A
, &state_A
);
542 EXPECT_EQ(1, page_id_A
);
543 render_thread_
->sink().ClearMessages();
545 // Back to page A (page_id 1) and commit.
546 FrameMsg_Navigate_Params params_A
;
547 params_A
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
548 params_A
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
549 params_A
.current_history_list_length
= 2;
550 params_A
.current_history_list_offset
= 1;
551 params_A
.pending_history_list_offset
= 0;
552 params_A
.page_id
= 1;
553 params_A
.page_state
= state_A
;
554 frame()->OnNavigate(params_A
);
555 ProcessPendingMessages();
557 // Respond to a swap out request.
558 view()->main_render_frame()->OnSwapOut();
560 // Check for a OnSwapOutACK.
561 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
562 FrameHostMsg_SwapOut_ACK::ID
);
564 render_thread_
->sink().ClearMessages();
566 // It is possible to get a reload request at this point, containing the
567 // params.page_state of the initial page (e.g., if the new page fails the
568 // provisional load in the renderer process, after we unload the old page).
569 // Ensure the old page gets reloaded, not swappedout://.
570 FrameMsg_Navigate_Params nav_params
;
571 nav_params
.url
= GURL("data:text/html,<div>Page A</div>");
572 nav_params
.navigation_type
= FrameMsg_Navigate_Type::RELOAD
;
573 nav_params
.transition
= PAGE_TRANSITION_RELOAD
;
574 nav_params
.current_history_list_length
= 2;
575 nav_params
.current_history_list_offset
= 0;
576 nav_params
.pending_history_list_offset
= 0;
577 nav_params
.page_id
= 1;
578 nav_params
.page_state
= state_A
;
579 frame()->OnNavigate(nav_params
);
580 ProcessPendingMessages();
582 // Verify page A committed, not swappedout://.
583 const IPC::Message
* frame_navigate_msg
=
584 render_thread_
->sink().GetUniqueMessageMatching(
585 FrameHostMsg_DidCommitProvisionalLoad::ID
);
586 EXPECT_TRUE(frame_navigate_msg
);
588 // Read URL out of the parent trait of the params object.
589 FrameHostMsg_DidCommitProvisionalLoad::Param commit_params
;
590 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg
,
592 EXPECT_NE(GURL("swappedout://"), commit_params
.a
.url
);
596 // Test that we get the correct UpdateState message when we go back twice
597 // quickly without committing. Regression test for http://crbug.com/58082.
598 // Disabled: http://crbug.com/157357 .
599 TEST_F(RenderViewImplTest
, DISABLED_LastCommittedUpdateState
) {
601 LoadHTML("<div>Page A</div>");
603 // Load page B, which will trigger an UpdateState message for page A.
604 LoadHTML("<div>Page B</div>");
606 // Check for a valid UpdateState message for page A.
607 ProcessPendingMessages();
608 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
609 ViewHostMsg_UpdateState::ID
);
613 ViewHostMsg_UpdateState::Read(msg_A
, &page_id_A
, &state_A
);
614 EXPECT_EQ(1, page_id_A
);
615 render_thread_
->sink().ClearMessages();
617 // Load page C, which will trigger an UpdateState message for page B.
618 LoadHTML("<div>Page C</div>");
620 // Check for a valid UpdateState for page B.
621 ProcessPendingMessages();
622 const IPC::Message
* msg_B
= render_thread_
->sink().GetUniqueMessageMatching(
623 ViewHostMsg_UpdateState::ID
);
627 ViewHostMsg_UpdateState::Read(msg_B
, &page_id_B
, &state_B
);
628 EXPECT_EQ(2, page_id_B
);
629 EXPECT_NE(state_A
, state_B
);
630 render_thread_
->sink().ClearMessages();
632 // Load page D, which will trigger an UpdateState message for page C.
633 LoadHTML("<div>Page D</div>");
635 // Check for a valid UpdateState for page C.
636 ProcessPendingMessages();
637 const IPC::Message
* msg_C
= render_thread_
->sink().GetUniqueMessageMatching(
638 ViewHostMsg_UpdateState::ID
);
642 ViewHostMsg_UpdateState::Read(msg_C
, &page_id_C
, &state_C
);
643 EXPECT_EQ(3, page_id_C
);
644 EXPECT_NE(state_B
, state_C
);
645 render_thread_
->sink().ClearMessages();
647 // Go back to C and commit, preparing for our real test.
648 FrameMsg_Navigate_Params params_C
;
649 params_C
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
650 params_C
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
651 params_C
.current_history_list_length
= 4;
652 params_C
.current_history_list_offset
= 3;
653 params_C
.pending_history_list_offset
= 2;
654 params_C
.page_id
= 3;
655 params_C
.page_state
= state_C
;
656 frame()->OnNavigate(params_C
);
657 ProcessPendingMessages();
658 render_thread_
->sink().ClearMessages();
660 // Go back twice quickly, such that page B does not have a chance to commit.
661 // This leads to two changes to the back/forward list but only one change to
662 // the RenderView's page ID.
664 // Back to page B (page_id 2), without committing.
665 FrameMsg_Navigate_Params params_B
;
666 params_B
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
667 params_B
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
668 params_B
.current_history_list_length
= 4;
669 params_B
.current_history_list_offset
= 2;
670 params_B
.pending_history_list_offset
= 1;
671 params_B
.page_id
= 2;
672 params_B
.page_state
= state_B
;
673 frame()->OnNavigate(params_B
);
675 // Back to page A (page_id 1) and commit.
676 FrameMsg_Navigate_Params params
;
677 params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
678 params
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
679 params_B
.current_history_list_length
= 4;
680 params_B
.current_history_list_offset
= 2;
681 params_B
.pending_history_list_offset
= 0;
683 params
.page_state
= state_A
;
684 frame()->OnNavigate(params
);
685 ProcessPendingMessages();
687 // Now ensure that the UpdateState message we receive is consistent
688 // and represents page C in both page_id and state.
689 const IPC::Message
* msg
= render_thread_
->sink().GetUniqueMessageMatching(
690 ViewHostMsg_UpdateState::ID
);
694 ViewHostMsg_UpdateState::Read(msg
, &page_id
, &state
);
695 EXPECT_EQ(page_id_C
, page_id
);
696 EXPECT_NE(state_A
, state
);
697 EXPECT_NE(state_B
, state
);
698 EXPECT_EQ(state_C
, state
);
701 // Test that the history_page_ids_ list can reveal when a stale back/forward
702 // navigation arrives from the browser and can be ignored. See
703 // http://crbug.com/86758.
704 TEST_F(RenderViewImplTest
, StaleNavigationsIgnored
) {
706 LoadHTML("<div>Page A</div>");
707 EXPECT_EQ(1, view()->history_list_length_
);
708 EXPECT_EQ(0, view()->history_list_offset_
);
709 EXPECT_EQ(1, view()->history_page_ids_
[0]);
711 // Load page B, which will trigger an UpdateState message for page A.
712 LoadHTML("<div>Page B</div>");
713 EXPECT_EQ(2, view()->history_list_length_
);
714 EXPECT_EQ(1, view()->history_list_offset_
);
715 EXPECT_EQ(2, view()->history_page_ids_
[1]);
717 // Check for a valid UpdateState message for page A.
718 ProcessPendingMessages();
719 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
720 ViewHostMsg_UpdateState::ID
);
724 ViewHostMsg_UpdateState::Read(msg_A
, &page_id_A
, &state_A
);
725 EXPECT_EQ(1, page_id_A
);
726 render_thread_
->sink().ClearMessages();
728 // Back to page A (page_id 1) and commit.
729 FrameMsg_Navigate_Params params_A
;
730 params_A
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
731 params_A
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
732 params_A
.current_history_list_length
= 2;
733 params_A
.current_history_list_offset
= 1;
734 params_A
.pending_history_list_offset
= 0;
735 params_A
.page_id
= 1;
736 params_A
.page_state
= state_A
;
737 frame()->OnNavigate(params_A
);
738 ProcessPendingMessages();
740 // A new navigation commits, clearing the forward history.
741 LoadHTML("<div>Page C</div>");
742 EXPECT_EQ(2, view()->history_list_length_
);
743 EXPECT_EQ(1, view()->history_list_offset_
);
744 EXPECT_EQ(3, view()->history_page_ids_
[1]);
746 // The browser then sends a stale navigation to B, which should be ignored.
747 FrameMsg_Navigate_Params params_B
;
748 params_B
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
749 params_B
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
750 params_B
.current_history_list_length
= 2;
751 params_B
.current_history_list_offset
= 0;
752 params_B
.pending_history_list_offset
= 1;
753 params_B
.page_id
= 2;
754 params_B
.page_state
= state_A
; // Doesn't matter, just has to be present.
755 frame()->OnNavigate(params_B
);
757 // State should be unchanged.
758 EXPECT_EQ(2, view()->history_list_length_
);
759 EXPECT_EQ(1, view()->history_list_offset_
);
760 EXPECT_EQ(3, view()->history_page_ids_
[1]);
763 // Test that we do not ignore navigations after the entry limit is reached,
764 // in which case the browser starts dropping entries from the front. In this
765 // case, we'll see a page_id mismatch but the RenderView's id will be older,
766 // not newer, than params.page_id. Use this as a cue that we should update the
767 // state and not treat it like a navigation to a cropped forward history item.
768 // See http://crbug.com/89798.
769 TEST_F(RenderViewImplTest
, DontIgnoreBackAfterNavEntryLimit
) {
771 LoadHTML("<div>Page A</div>");
772 EXPECT_EQ(1, view()->history_list_length_
);
773 EXPECT_EQ(0, view()->history_list_offset_
);
774 EXPECT_EQ(1, view()->history_page_ids_
[0]);
776 // Load page B, which will trigger an UpdateState message for page A.
777 LoadHTML("<div>Page B</div>");
778 EXPECT_EQ(2, view()->history_list_length_
);
779 EXPECT_EQ(1, view()->history_list_offset_
);
780 EXPECT_EQ(2, view()->history_page_ids_
[1]);
782 // Check for a valid UpdateState message for page A.
783 ProcessPendingMessages();
784 const IPC::Message
* msg_A
= render_thread_
->sink().GetUniqueMessageMatching(
785 ViewHostMsg_UpdateState::ID
);
789 ViewHostMsg_UpdateState::Read(msg_A
, &page_id_A
, &state_A
);
790 EXPECT_EQ(1, page_id_A
);
791 render_thread_
->sink().ClearMessages();
793 // Load page C, which will trigger an UpdateState message for page B.
794 LoadHTML("<div>Page C</div>");
795 EXPECT_EQ(3, view()->history_list_length_
);
796 EXPECT_EQ(2, view()->history_list_offset_
);
797 EXPECT_EQ(3, view()->history_page_ids_
[2]);
799 // Check for a valid UpdateState message for page B.
800 ProcessPendingMessages();
801 const IPC::Message
* msg_B
= render_thread_
->sink().GetUniqueMessageMatching(
802 ViewHostMsg_UpdateState::ID
);
806 ViewHostMsg_UpdateState::Read(msg_B
, &page_id_B
, &state_B
);
807 EXPECT_EQ(2, page_id_B
);
808 render_thread_
->sink().ClearMessages();
810 // Suppose the browser has limited the number of NavigationEntries to 2.
811 // It has now dropped the first entry, but the renderer isn't notified.
812 // Ensure that going back to page B (page_id 2) at offset 0 is successful.
813 FrameMsg_Navigate_Params params_B
;
814 params_B
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
815 params_B
.transition
= PAGE_TRANSITION_FORWARD_BACK
;
816 params_B
.current_history_list_length
= 2;
817 params_B
.current_history_list_offset
= 1;
818 params_B
.pending_history_list_offset
= 0;
819 params_B
.page_id
= 2;
820 params_B
.page_state
= state_B
;
821 frame()->OnNavigate(params_B
);
822 ProcessPendingMessages();
824 EXPECT_EQ(2, view()->history_list_length_
);
825 EXPECT_EQ(0, view()->history_list_offset_
);
826 EXPECT_EQ(2, view()->history_page_ids_
[0]);
829 // Test that our IME backend sends a notification message when the input focus
831 TEST_F(RenderViewImplTest
, OnImeTypeChanged
) {
832 // Enable our IME backend code.
833 view()->OnSetInputMethodActive(true);
835 // Load an HTML page consisting of two input fields.
836 view()->set_send_content_state_immediately(true);
841 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
842 "<input id=\"test2\" type=\"password\"></input>"
843 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
844 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
845 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
846 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
848 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
850 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
851 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
852 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
853 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
854 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
855 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
856 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
857 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
860 render_thread_
->sink().ClearMessages();
862 struct InputModeTestCase
{
863 const char* input_id
;
864 ui::TextInputMode expected_mode
;
866 static const InputModeTestCase kInputModeTestCases
[] = {
867 {"test1", ui::TEXT_INPUT_MODE_DEFAULT
},
868 {"test3", ui::TEXT_INPUT_MODE_VERBATIM
},
869 {"test4", ui::TEXT_INPUT_MODE_LATIN
},
870 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME
},
871 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE
},
872 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN
},
873 {"test8", ui::TEXT_INPUT_MODE_KANA
},
874 {"test9", ui::TEXT_INPUT_MODE_KATAKANA
},
875 {"test10", ui::TEXT_INPUT_MODE_NUMERIC
},
876 {"test11", ui::TEXT_INPUT_MODE_TEL
},
877 {"test12", ui::TEXT_INPUT_MODE_EMAIL
},
878 {"test13", ui::TEXT_INPUT_MODE_URL
},
879 {"test14", ui::TEXT_INPUT_MODE_DEFAULT
},
880 {"test15", ui::TEXT_INPUT_MODE_VERBATIM
},
883 const int kRepeatCount
= 10;
884 for (int i
= 0; i
< kRepeatCount
; i
++) {
885 // Move the input focus to the first <input> element, where we should
887 ExecuteJavaScript("document.getElementById('test1').focus();");
888 ProcessPendingMessages();
889 render_thread_
->sink().ClearMessages();
891 // Update the IME status and verify if our IME backend sends an IPC message
893 view()->UpdateTextInputType();
894 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
895 EXPECT_TRUE(msg
!= NULL
);
896 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
897 ui::TextInputType type
;
898 bool can_compose_inline
= false;
899 ui::TextInputMode input_mode
= ui::TEXT_INPUT_MODE_DEFAULT
;
900 ViewHostMsg_TextInputTypeChanged::Read(msg
,
903 &can_compose_inline
);
904 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT
, type
);
905 EXPECT_EQ(true, can_compose_inline
);
907 // Move the input focus to the second <input> element, where we should
909 ExecuteJavaScript("document.getElementById('test2').focus();");
910 ProcessPendingMessages();
911 render_thread_
->sink().ClearMessages();
913 // Update the IME status and verify if our IME backend sends an IPC message
914 // to de-activate IMEs.
915 view()->UpdateTextInputType();
916 msg
= render_thread_
->sink().GetMessageAt(0);
917 EXPECT_TRUE(msg
!= NULL
);
918 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
919 ViewHostMsg_TextInputTypeChanged::Read(msg
,
922 &can_compose_inline
);
923 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD
, type
);
925 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kInputModeTestCases
); i
++) {
926 const InputModeTestCase
* test_case
= &kInputModeTestCases
[i
];
927 std::string javascript
=
928 base::StringPrintf("document.getElementById('%s').focus();",
929 test_case
->input_id
);
930 // Move the input focus to the target <input> element, where we should
932 ExecuteJavaScriptAndReturnIntValue(base::ASCIIToUTF16(javascript
), NULL
);
933 ProcessPendingMessages();
934 render_thread_
->sink().ClearMessages();
936 // Update the IME status and verify if our IME backend sends an IPC
937 // message to activate IMEs.
938 view()->UpdateTextInputType();
939 const IPC::Message
* msg
= render_thread_
->sink().GetMessageAt(0);
940 EXPECT_TRUE(msg
!= NULL
);
941 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID
, msg
->type());
942 ViewHostMsg_TextInputTypeChanged::Read(msg
,
945 &can_compose_inline
);
946 EXPECT_EQ(test_case
->expected_mode
, input_mode
);
951 // Test that our IME backend can compose CJK words.
952 // Our IME front-end sends many platform-independent messages to the IME backend
953 // while it composes CJK words. This test sends the minimal messages captured
954 // on my local environment directly to the IME backend to verify if the backend
955 // can compose CJK words without any problems.
956 // This test uses an array of command sets because an IME composotion does not
957 // only depends on IME events, but also depends on window events, e.g. moving
958 // the window focus while composing a CJK text. To handle such complicated
959 // cases, this test should not only call IME-related functions in the
960 // RenderWidget class, but also call some RenderWidget members, e.g.
961 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc.
962 TEST_F(RenderViewImplTest
, ImeComposition
) {
968 IME_CONFIRMCOMPOSITION
,
969 IME_CANCELCOMPOSITION
976 const wchar_t* ime_string
;
977 const wchar_t* result
;
979 static const ImeMessage kImeMessages
[] = {
980 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
981 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
982 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
983 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
984 {IME_SETCOMPOSITION
, false, 1, 1, L
"n", L
"n"},
985 {IME_SETCOMPOSITION
, false, 2, 2, L
"ni", L
"ni"},
986 {IME_SETCOMPOSITION
, false, 3, 3, L
"nih", L
"nih"},
987 {IME_SETCOMPOSITION
, false, 4, 4, L
"niha", L
"niha"},
988 {IME_SETCOMPOSITION
, false, 5, 5, L
"nihao", L
"nihao"},
989 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"\x4F60\x597D", L
"\x4F60\x597D"},
990 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
991 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
992 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
993 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
994 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xFF4B", L
"\xFF4B"},
995 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x304B", L
"\x304B"},
996 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x304B\xFF4E", L
"\x304B\xFF4E"},
997 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\xFF4A",
998 L
"\x304B\x3093\xFF4A"},
999 {IME_SETCOMPOSITION
, false, 0, 3, L
"\x304B\x3093\x3058",
1000 L
"\x304B\x3093\x3058"},
1001 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x611F\x3058", L
"\x611F\x3058"},
1002 {IME_SETCOMPOSITION
, false, 0, 2, L
"\x6F22\x5B57", L
"\x6F22\x5B57"},
1003 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1004 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\x6F22\x5B57"},
1005 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1006 {IME_INITIALIZE
, true, 0, 0, NULL
, NULL
},
1007 {IME_SETINPUTMODE
, true, 0, 0, NULL
, NULL
},
1008 {IME_SETFOCUS
, true, 0, 0, NULL
, NULL
},
1009 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3147", L
"\x3147"},
1010 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC544", L
"\xC544"},
1011 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xC548", L
"\xC548"},
1012 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1013 {IME_SETCOMPOSITION
, false, 0, 1, L
"\x3134", L
"\xC548\x3134"},
1014 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB140", L
"\xC548\xB140"},
1015 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1016 {IME_CANCELCOMPOSITION
, false, -1, -1, L
"", L
"\xC548"},
1017 {IME_SETCOMPOSITION
, false, 0, 1, L
"\xB155", L
"\xC548\xB155"},
1018 {IME_CONFIRMCOMPOSITION
, false, -1, -1, L
"", L
"\xC548\xB155"},
1021 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kImeMessages
); i
++) {
1022 const ImeMessage
* ime_message
= &kImeMessages
[i
];
1023 switch (ime_message
->command
) {
1024 case IME_INITIALIZE
:
1025 // Load an HTML page consisting of a content-editable <div> element,
1026 // and move the input focus to the <div> element, where we can use
1028 view()->OnSetInputMethodActive(ime_message
->enable
);
1029 view()->set_send_content_state_immediately(true);
1034 "<div id=\"test1\" contenteditable=\"true\"></div>"
1037 ExecuteJavaScript("document.getElementById('test1').focus();");
1040 case IME_SETINPUTMODE
:
1041 // Activate (or deactivate) our IME back-end.
1042 view()->OnSetInputMethodActive(ime_message
->enable
);
1046 // Update the window focus.
1047 view()->OnSetFocus(ime_message
->enable
);
1050 case IME_SETCOMPOSITION
:
1051 view()->OnImeSetComposition(
1052 base::WideToUTF16(ime_message
->ime_string
),
1053 std::vector
<blink::WebCompositionUnderline
>(),
1054 ime_message
->selection_start
,
1055 ime_message
->selection_end
);
1058 case IME_CONFIRMCOMPOSITION
:
1059 view()->OnImeConfirmComposition(
1060 base::WideToUTF16(ime_message
->ime_string
),
1061 gfx::Range::InvalidRange(),
1065 case IME_CANCELCOMPOSITION
:
1066 view()->OnImeSetComposition(
1068 std::vector
<blink::WebCompositionUnderline
>(),
1073 // Update the status of our IME back-end.
1074 // TODO(hbono): we should verify messages to be sent from the back-end.
1075 view()->UpdateTextInputType();
1076 ProcessPendingMessages();
1077 render_thread_
->sink().ClearMessages();
1079 if (ime_message
->result
) {
1080 // Retrieve the content of this page and compare it with the expected
1082 const int kMaxOutputCharacters
= 128;
1083 base::string16 output
=
1084 GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1085 EXPECT_EQ(base::WideToUTF16(ime_message
->result
), output
);
1090 // Test that the RenderView::OnSetTextDirection() function can change the text
1091 // direction of the selected input element.
1092 TEST_F(RenderViewImplTest
, OnSetTextDirection
) {
1093 // Load an HTML page consisting of a <textarea> element and a <div> element.
1094 // This test changes the text direction of the <textarea> element, and
1095 // writes the values of its 'dir' attribute and its 'direction' property to
1096 // verify that the text direction is changed.
1097 view()->set_send_content_state_immediately(true);
1102 "<textarea id=\"test\"></textarea>"
1103 "<div id=\"result\" contenteditable=\"true\"></div>"
1106 render_thread_
->sink().ClearMessages();
1108 static const struct {
1109 WebTextDirection direction
;
1110 const wchar_t* expected_result
;
1111 } kTextDirection
[] = {
1112 { blink::WebTextDirectionRightToLeft
, L
"\x000A" L
"rtl,rtl" },
1113 { blink::WebTextDirectionLeftToRight
, L
"\x000A" L
"ltr,ltr" },
1115 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kTextDirection
); ++i
) {
1116 // Set the text direction of the <textarea> element.
1117 ExecuteJavaScript("document.getElementById('test').focus();");
1118 view()->OnSetTextDirection(kTextDirection
[i
].direction
);
1120 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1121 // property to the <div> element.
1122 ExecuteJavaScript("var result = document.getElementById('result');"
1123 "var node = document.getElementById('test');"
1124 "var style = getComputedStyle(node, null);"
1125 "result.innerText ="
1126 " node.getAttribute('dir') + ',' +"
1127 " style.getPropertyValue('direction');");
1129 // Copy the document content to std::wstring and compare with the
1131 const int kMaxOutputCharacters
= 16;
1132 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1133 EXPECT_EQ(base::WideToUTF16(kTextDirection
[i
].expected_result
), output
);
1137 // see http://crbug.com/238750
1139 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent
1141 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent
1144 // Test that we can receive correct DOM events when we send input events
1145 // through the RenderWidget::OnHandleInputEvent() function.
1146 TEST_F(RenderViewImplTest
, MAYBE_OnHandleKeyboardEvent
) {
1147 #if !defined(OS_MACOSX)
1148 // Load an HTML page consisting of one <input> element and three
1149 // contentediable <div> elements.
1150 // The <input> element is used for sending keyboard events, and the <div>
1151 // elements are used for writing DOM events in the following format:
1152 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1153 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1154 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1155 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1156 view()->set_send_content_state_immediately(true);
1160 "<script type='text/javascript' language='javascript'>"
1161 "function OnKeyEvent(ev) {"
1162 " var result = document.getElementById(ev.type);"
1163 " result.innerText ="
1164 " (ev.which || ev.keyCode) + ',' +"
1165 " ev.shiftKey + ',' +"
1166 " ev.ctrlKey + ',' +"
1173 "<input id='test' type='text'"
1174 " onkeydown='return OnKeyEvent(event);'"
1175 " onkeypress='return OnKeyEvent(event);'"
1176 " onkeyup='return OnKeyEvent(event);'>"
1178 "<div id='keydown' contenteditable='true'>"
1180 "<div id='keypress' contenteditable='true'>"
1182 "<div id='keyup' contenteditable='true'>"
1186 ExecuteJavaScript("document.getElementById('test').focus();");
1187 render_thread_
->sink().ClearMessages();
1189 static const MockKeyboard::Layout kLayouts
[] = {
1191 // Since we ignore the mock keyboard layout on Linux and instead just use
1192 // the screen's keyboard layout, these trivially pass. They are commented
1193 // out to avoid the illusion that they work.
1194 MockKeyboard::LAYOUT_ARABIC
,
1195 MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1196 MockKeyboard::LAYOUT_FRENCH
,
1197 MockKeyboard::LAYOUT_HEBREW
,
1198 MockKeyboard::LAYOUT_RUSSIAN
,
1200 MockKeyboard::LAYOUT_UNITED_STATES
,
1203 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kLayouts
); ++i
) {
1204 // For each key code, we send three keyboard events.
1205 // * we press only the key;
1206 // * we press the key and a left-shift key, and;
1207 // * we press the key and a right-alt (AltGr) key.
1208 // For each modifiers, we need a string used for formatting its expected
1209 // result. (See the above comment for its format.)
1210 static const struct {
1211 MockKeyboard::Modifiers modifiers
;
1212 const char* expected_result
;
1213 } kModifierData
[] = {
1214 {MockKeyboard::NONE
, "false,false,false"},
1215 {MockKeyboard::LEFT_SHIFT
, "true,false,false"},
1217 {MockKeyboard::RIGHT_ALT
, "false,false,true"},
1221 MockKeyboard::Layout layout
= kLayouts
[i
];
1222 for (size_t j
= 0; j
< ARRAYSIZE_UNSAFE(kModifierData
); ++j
) {
1223 // Virtual key codes used for this test.
1224 static const int kKeyCodes
[] = {
1225 '0', '1', '2', '3', '4', '5', '6', '7',
1226 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1227 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1228 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1234 ui::VKEY_OEM_PERIOD
,
1242 // Not sure how to handle this key on Linux.
1247 MockKeyboard::Modifiers modifiers
= kModifierData
[j
].modifiers
;
1248 for (size_t k
= 0; k
< ARRAYSIZE_UNSAFE(kKeyCodes
); ++k
) {
1249 // Send a keyboard event to the RenderView object.
1250 // We should test a keyboard event only when the given keyboard-layout
1251 // driver is installed in a PC and the driver can assign a Unicode
1252 // charcter for the given tuple (key-code and modifiers).
1253 int key_code
= kKeyCodes
[k
];
1254 base::string16 char_code
;
1255 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1258 // Create an expected result from the virtual-key code, the character
1259 // code, and the modifier-key status.
1260 // We format a string that emulates a DOM-event string produced hy
1261 // our JavaScript function. (See the above comment for the format.)
1262 static char expected_result
[1024];
1263 expected_result
[0] = 0;
1264 base::snprintf(&expected_result
[0],
1265 sizeof(expected_result
),
1266 "\n" // texts in the <input> element
1267 "%d,%s\n" // texts in the first <div> element
1268 "%d,%s\n" // texts in the second <div> element
1269 "%d,%s", // texts in the third <div> element
1270 key_code
, kModifierData
[j
].expected_result
,
1271 static_cast<int>(char_code
[0]),
1272 kModifierData
[j
].expected_result
,
1273 key_code
, kModifierData
[j
].expected_result
);
1275 // Retrieve the text in the test page and compare it with the expected
1276 // text created from a virtual-key code, a character code, and the
1277 // modifier-key status.
1278 const int kMaxOutputCharacters
= 1024;
1279 std::string output
= base::UTF16ToUTF8(
1280 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
1281 EXPECT_EQ(expected_result
, output
);
1290 // Test that our EditorClientImpl class can insert characters when we send
1291 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1292 // This test is for preventing regressions caused only when we use non-US
1293 // keyboards, such as Issue 10846.
1294 // see http://crbug.com/244562
1296 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1298 #define MAYBE_InsertCharacters InsertCharacters
1300 TEST_F(RenderViewImplTest
, MAYBE_InsertCharacters
) {
1301 #if !defined(OS_MACOSX)
1302 static const struct {
1303 MockKeyboard::Layout layout
;
1304 const wchar_t* expected_result
;
1307 // Disabled these keyboard layouts because buildbots do not have their
1308 // keyboard-layout drivers installed.
1309 {MockKeyboard::LAYOUT_ARABIC
,
1310 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1311 L
"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1312 L
"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1313 L
"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1314 L
"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1315 L
"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1316 L
"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1317 L
"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1318 L
"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1319 L
"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1320 L
"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1321 L
"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1322 L
"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1323 L
"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1324 L
"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1325 L
"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1326 L
"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1328 {MockKeyboard::LAYOUT_HEBREW
,
1329 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1330 L
"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1331 L
"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1332 L
"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1333 L
"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1334 L
"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1335 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1336 L
"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1337 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1338 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1339 L
"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1340 L
"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1341 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1342 L
"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1343 L
"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1344 L
"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1345 L
"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1346 L
"\x003b\x005d\x005c\x005b\x002c"
1350 // On Linux, the only way to test alternate keyboard layouts is to change
1351 // the keyboard layout of the whole screen. I'm worried about the side
1352 // effects this may have on the buildbots.
1353 {MockKeyboard::LAYOUT_CANADIAN_FRENCH
,
1354 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1355 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1356 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1357 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1358 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1359 L
"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1360 L
"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1361 L
"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1362 L
"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1363 L
"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1364 L
"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1365 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1366 L
"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1367 L
"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1368 L
"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1369 L
"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1372 {MockKeyboard::LAYOUT_FRENCH
,
1373 L
"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1374 L
"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1375 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1376 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1377 L
"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1378 L
"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1379 L
"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1380 L
"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1381 L
"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1382 L
"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1383 L
"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1384 L
"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1385 L
"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1386 L
"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1387 L
"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1388 L
"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1389 L
"\x003b\x003a\x00f9\x0029\x002a\x0021"
1391 {MockKeyboard::LAYOUT_RUSSIAN
,
1392 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1393 L
"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1394 L
"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1395 L
"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1396 L
"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1397 L
"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1398 L
"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1399 L
"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1400 L
"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1401 L
"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1402 L
"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1403 L
"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1404 L
"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1405 L
"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1406 L
"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1407 L
"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1408 L
"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1409 L
"\x0451\x0445\x005c\x044a\x044d"
1411 #endif // defined(OS_WIN)
1412 {MockKeyboard::LAYOUT_UNITED_STATES
,
1413 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1414 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1415 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1416 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1417 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1418 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1419 L
"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1420 L
"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1421 L
"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1422 L
"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1423 L
"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1424 L
"\x003f\x007e\x007b\x007c\x007d\x0022"
1426 // This is ifdefed out for Linux to correspond to the fact that we don't
1427 // test alt+keystroke for now.
1428 L
"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1429 L
"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1430 L
"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1431 L
"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1432 L
"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1433 L
"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1438 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kLayouts
); ++i
) {
1439 // Load an HTML page consisting of one <div> element.
1440 // This <div> element is used by the EditorClientImpl class to insert
1441 // characters received through the RenderWidget::OnHandleInputEvent()
1443 view()->set_send_content_state_immediately(true);
1449 "<div id='test' contenteditable='true'>"
1453 ExecuteJavaScript("document.getElementById('test').focus();");
1454 render_thread_
->sink().ClearMessages();
1456 // For each key code, we send three keyboard events.
1457 // * Pressing only the key;
1458 // * Pressing the key and a left-shift key, and;
1459 // * Pressing the key and a right-alt (AltGr) key.
1460 static const MockKeyboard::Modifiers kModifiers
[] = {
1462 MockKeyboard::LEFT_SHIFT
,
1464 MockKeyboard::RIGHT_ALT
,
1468 MockKeyboard::Layout layout
= kLayouts
[i
].layout
;
1469 for (size_t j
= 0; j
< ARRAYSIZE_UNSAFE(kModifiers
); ++j
) {
1470 // Virtual key codes used for this test.
1471 static const int kKeyCodes
[] = {
1472 '0', '1', '2', '3', '4', '5', '6', '7',
1473 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1474 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1475 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1481 ui::VKEY_OEM_PERIOD
,
1489 // Unclear how to handle this on Linux.
1494 MockKeyboard::Modifiers modifiers
= kModifiers
[j
];
1495 for (size_t k
= 0; k
< ARRAYSIZE_UNSAFE(kKeyCodes
); ++k
) {
1496 // Send a keyboard event to the RenderView object.
1497 // We should test a keyboard event only when the given keyboard-layout
1498 // driver is installed in a PC and the driver can assign a Unicode
1499 // charcter for the given tuple (layout, key-code, and modifiers).
1500 int key_code
= kKeyCodes
[k
];
1501 base::string16 char_code
;
1502 if (SendKeyEvent(layout
, key_code
, modifiers
, &char_code
) < 0)
1507 // Retrieve the text in the test page and compare it with the expected
1508 // text created from a virtual-key code, a character code, and the
1509 // modifier-key status.
1510 const int kMaxOutputCharacters
= 4096;
1511 base::string16 output
= GetMainFrame()->contentAsText(kMaxOutputCharacters
);
1512 EXPECT_EQ(base::WideToUTF16(kLayouts
[i
].expected_result
), output
);
1519 // Crashy, http://crbug.com/53247.
1520 TEST_F(RenderViewImplTest
, DISABLED_DidFailProvisionalLoadWithErrorForError
) {
1521 GetMainFrame()->enableViewSourceMode(true);
1523 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1524 error
.reason
= net::ERR_FILE_NOT_FOUND
;
1525 error
.unreachableURL
= GURL("http://foo");
1526 WebLocalFrame
* web_frame
= GetMainFrame();
1528 // Start a load that will reach provisional state synchronously,
1529 // but won't complete synchronously.
1530 FrameMsg_Navigate_Params params
;
1531 params
.page_id
= -1;
1532 params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1533 params
.url
= GURL("data:text/html,test data");
1534 frame()->OnNavigate(params
);
1536 // An error occurred.
1537 view()->main_render_frame()->didFailProvisionalLoad(web_frame
, error
);
1538 // Frame should exit view-source mode.
1539 EXPECT_FALSE(web_frame
->isViewSourceModeEnabled());
1542 TEST_F(RenderViewImplTest
, DidFailProvisionalLoadWithErrorForCancellation
) {
1543 GetMainFrame()->enableViewSourceMode(true);
1545 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
1546 error
.reason
= net::ERR_ABORTED
;
1547 error
.unreachableURL
= GURL("http://foo");
1548 WebLocalFrame
* web_frame
= GetMainFrame();
1550 // Start a load that will reach provisional state synchronously,
1551 // but won't complete synchronously.
1552 FrameMsg_Navigate_Params params
;
1553 params
.page_id
= -1;
1554 params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1555 params
.url
= GURL("data:text/html,test data");
1556 frame()->OnNavigate(params
);
1558 // A cancellation occurred.
1559 view()->main_render_frame()->didFailProvisionalLoad(web_frame
, error
);
1560 // Frame should stay in view-source mode.
1561 EXPECT_TRUE(web_frame
->isViewSourceModeEnabled());
1564 // Regression test for http://crbug.com/41562
1565 TEST_F(RenderViewImplTest
, UpdateTargetURLWithInvalidURL
) {
1566 const GURL
invalid_gurl("http://");
1567 view()->setMouseOverURL(blink::WebURL(invalid_gurl
));
1568 EXPECT_EQ(invalid_gurl
, view()->target_url_
);
1571 TEST_F(RenderViewImplTest
, SetHistoryLengthAndPrune
) {
1572 int expected_page_id
= -1;
1574 // No history to merge and no committed pages.
1575 view()->OnSetHistoryLengthAndPrune(0, -1);
1576 EXPECT_EQ(0, view()->history_list_length_
);
1577 EXPECT_EQ(-1, view()->history_list_offset_
);
1579 // History to merge and no committed pages.
1580 view()->OnSetHistoryLengthAndPrune(2, -1);
1581 EXPECT_EQ(2, view()->history_list_length_
);
1582 EXPECT_EQ(1, view()->history_list_offset_
);
1583 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1584 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1587 blink::WebHistoryItem item
;
1590 // No history to merge and a committed page to be kept.
1591 frame()->didCommitProvisionalLoad(GetMainFrame(),
1593 blink::WebStandardCommit
);
1594 expected_page_id
= view()->page_id_
;
1595 view()->OnSetHistoryLengthAndPrune(0, expected_page_id
);
1596 EXPECT_EQ(1, view()->history_list_length_
);
1597 EXPECT_EQ(0, view()->history_list_offset_
);
1598 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[0]);
1601 // No history to merge and a committed page to be pruned.
1602 frame()->didCommitProvisionalLoad(GetMainFrame(),
1604 blink::WebStandardCommit
);
1605 expected_page_id
= view()->page_id_
;
1606 view()->OnSetHistoryLengthAndPrune(0, expected_page_id
+ 1);
1607 EXPECT_EQ(0, view()->history_list_length_
);
1608 EXPECT_EQ(-1, view()->history_list_offset_
);
1611 // No history to merge and a committed page that the browser was unaware of.
1612 frame()->didCommitProvisionalLoad(GetMainFrame(),
1614 blink::WebStandardCommit
);
1615 expected_page_id
= view()->page_id_
;
1616 view()->OnSetHistoryLengthAndPrune(0, -1);
1617 EXPECT_EQ(1, view()->history_list_length_
);
1618 EXPECT_EQ(0, view()->history_list_offset_
);
1619 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[0]);
1622 // History to merge and a committed page to be kept.
1623 frame()->didCommitProvisionalLoad(GetMainFrame(),
1625 blink::WebStandardCommit
);
1626 expected_page_id
= view()->page_id_
;
1627 view()->OnSetHistoryLengthAndPrune(2, expected_page_id
);
1628 EXPECT_EQ(3, view()->history_list_length_
);
1629 EXPECT_EQ(2, view()->history_list_offset_
);
1630 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1631 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1632 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[2]);
1635 // History to merge and a committed page to be pruned.
1636 frame()->didCommitProvisionalLoad(GetMainFrame(),
1638 blink::WebStandardCommit
);
1639 expected_page_id
= view()->page_id_
;
1640 view()->OnSetHistoryLengthAndPrune(2, expected_page_id
+ 1);
1641 EXPECT_EQ(2, view()->history_list_length_
);
1642 EXPECT_EQ(1, view()->history_list_offset_
);
1643 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1644 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1647 // History to merge and a committed page that the browser was unaware of.
1648 frame()->didCommitProvisionalLoad(GetMainFrame(),
1650 blink::WebStandardCommit
);
1651 expected_page_id
= view()->page_id_
;
1652 view()->OnSetHistoryLengthAndPrune(2, -1);
1653 EXPECT_EQ(3, view()->history_list_length_
);
1654 EXPECT_EQ(2, view()->history_list_offset_
);
1655 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1656 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1657 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[2]);
1660 int expected_page_id_2
= -1;
1662 // No history to merge and two committed pages, both to be kept.
1663 frame()->didCommitProvisionalLoad(GetMainFrame(),
1665 blink::WebStandardCommit
);
1666 expected_page_id
= view()->page_id_
;
1667 frame()->didCommitProvisionalLoad(GetMainFrame(),
1669 blink::WebStandardCommit
);
1670 expected_page_id_2
= view()->page_id_
;
1671 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1672 view()->OnSetHistoryLengthAndPrune(0, expected_page_id
);
1673 EXPECT_EQ(2, view()->history_list_length_
);
1674 EXPECT_EQ(1, view()->history_list_offset_
);
1675 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[0]);
1676 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[1]);
1679 // No history to merge and two committed pages, and only the second is kept.
1680 frame()->didCommitProvisionalLoad(GetMainFrame(),
1682 blink::WebStandardCommit
);
1683 expected_page_id
= view()->page_id_
;
1684 frame()->didCommitProvisionalLoad(GetMainFrame(),
1686 blink::WebStandardCommit
);
1687 expected_page_id_2
= view()->page_id_
;
1688 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1689 view()->OnSetHistoryLengthAndPrune(0, expected_page_id_2
);
1690 EXPECT_EQ(1, view()->history_list_length_
);
1691 EXPECT_EQ(0, view()->history_list_offset_
);
1692 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[0]);
1695 // No history to merge and two committed pages, both of which the browser was
1697 frame()->didCommitProvisionalLoad(GetMainFrame(),
1699 blink::WebStandardCommit
);
1700 expected_page_id
= view()->page_id_
;
1701 frame()->didCommitProvisionalLoad(GetMainFrame(),
1703 blink::WebStandardCommit
);
1704 expected_page_id_2
= view()->page_id_
;
1705 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1706 view()->OnSetHistoryLengthAndPrune(0, -1);
1707 EXPECT_EQ(2, view()->history_list_length_
);
1708 EXPECT_EQ(1, view()->history_list_offset_
);
1709 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[0]);
1710 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[1]);
1713 // History to merge and two committed pages, both to be kept.
1714 frame()->didCommitProvisionalLoad(GetMainFrame(),
1716 blink::WebStandardCommit
);
1717 expected_page_id
= view()->page_id_
;
1718 frame()->didCommitProvisionalLoad(GetMainFrame(),
1720 blink::WebStandardCommit
);
1721 expected_page_id_2
= view()->page_id_
;
1722 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1723 view()->OnSetHistoryLengthAndPrune(2, expected_page_id
);
1724 EXPECT_EQ(4, view()->history_list_length_
);
1725 EXPECT_EQ(3, view()->history_list_offset_
);
1726 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1727 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1728 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[2]);
1729 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[3]);
1732 // History to merge and two committed pages, and only the second is kept.
1733 frame()->didCommitProvisionalLoad(GetMainFrame(),
1735 blink::WebStandardCommit
);
1736 expected_page_id
= view()->page_id_
;
1737 frame()->didCommitProvisionalLoad(GetMainFrame(),
1739 blink::WebStandardCommit
);
1740 expected_page_id_2
= view()->page_id_
;
1741 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1742 view()->OnSetHistoryLengthAndPrune(2, expected_page_id_2
);
1743 EXPECT_EQ(3, view()->history_list_length_
);
1744 EXPECT_EQ(2, view()->history_list_offset_
);
1745 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1746 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1747 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[2]);
1750 // History to merge and two committed pages, both of which the browser was
1752 frame()->didCommitProvisionalLoad(GetMainFrame(),
1754 blink::WebStandardCommit
);
1755 expected_page_id
= view()->page_id_
;
1756 frame()->didCommitProvisionalLoad(GetMainFrame(),
1758 blink::WebStandardCommit
);
1759 expected_page_id_2
= view()->page_id_
;
1760 EXPECT_GT(expected_page_id_2
, expected_page_id
);
1761 view()->OnSetHistoryLengthAndPrune(2, -1);
1762 EXPECT_EQ(4, view()->history_list_length_
);
1763 EXPECT_EQ(3, view()->history_list_offset_
);
1764 EXPECT_EQ(-1, view()->history_page_ids_
[0]);
1765 EXPECT_EQ(-1, view()->history_page_ids_
[1]);
1766 EXPECT_EQ(expected_page_id
, view()->history_page_ids_
[2]);
1767 EXPECT_EQ(expected_page_id_2
, view()->history_page_ids_
[3]);
1770 TEST_F(RenderViewImplTest
, ContextMenu
) {
1771 LoadHTML("<div>Page A</div>");
1773 // Create a right click in the center of the iframe. (I'm hoping this will
1774 // make this a bit more robust in case of some other formatting or other bug.)
1775 WebMouseEvent mouse_event
;
1776 mouse_event
.type
= WebInputEvent::MouseDown
;
1777 mouse_event
.button
= WebMouseEvent::ButtonRight
;
1778 mouse_event
.x
= 250;
1779 mouse_event
.y
= 250;
1780 mouse_event
.globalX
= 250;
1781 mouse_event
.globalY
= 250;
1783 SendWebMouseEvent(mouse_event
);
1785 // Now simulate the corresponding up event which should display the menu
1786 mouse_event
.type
= WebInputEvent::MouseUp
;
1787 SendWebMouseEvent(mouse_event
);
1789 EXPECT_TRUE(render_thread_
->sink().GetUniqueMessageMatching(
1790 FrameHostMsg_ContextMenu::ID
));
1793 TEST_F(RenderViewImplTest
, TestBackForward
) {
1794 LoadHTML("<div id=pagename>Page A</div>");
1795 PageState page_a_state
=
1796 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1797 int was_page_a
= -1;
1798 base::string16 check_page_a
=
1800 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1801 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1802 EXPECT_EQ(1, was_page_a
);
1804 LoadHTML("<div id=pagename>Page B</div>");
1805 int was_page_b
= -1;
1806 base::string16 check_page_b
=
1808 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1809 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1810 EXPECT_EQ(1, was_page_b
);
1812 LoadHTML("<div id=pagename>Page C</div>");
1813 int was_page_c
= -1;
1814 base::string16 check_page_c
=
1816 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1817 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1818 EXPECT_EQ(1, was_page_b
);
1820 PageState forward_state
=
1821 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1822 GoBack(HistoryEntryToPageState(
1823 view()->history_controller()->GetPreviousEntry()));
1824 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1825 EXPECT_EQ(1, was_page_b
);
1827 GoForward(forward_state
);
1828 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c
, &was_page_c
));
1829 EXPECT_EQ(1, was_page_c
);
1831 GoBack(HistoryEntryToPageState(
1832 view()->history_controller()->GetPreviousEntry()));
1833 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1834 EXPECT_EQ(1, was_page_b
);
1837 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1838 GoBack(page_a_state
);
1839 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a
, &was_page_a
));
1840 EXPECT_EQ(1, was_page_a
);
1842 GoForward(forward_state
);
1843 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b
, &was_page_b
));
1844 EXPECT_EQ(1, was_page_b
);
1847 #if defined(OS_MACOSX) || defined(USE_AURA)
1848 TEST_F(RenderViewImplTest
, GetCompositionCharacterBoundsTest
) {
1851 // http://crbug.com/304193
1852 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
1856 LoadHTML("<textarea id=\"test\"></textarea>");
1857 ExecuteJavaScript("document.getElementById('test').focus();");
1859 const base::string16 empty_string
;
1860 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1861 std::vector
<gfx::Rect
> bounds
;
1862 view()->OnSetFocus(true);
1863 view()->OnSetInputMethodActive(true);
1865 // ASCII composition
1866 const base::string16 ascii_composition
= base::UTF8ToUTF16("aiueo");
1867 view()->OnImeSetComposition(ascii_composition
, empty_underline
, 0, 0);
1868 view()->GetCompositionCharacterBounds(&bounds
);
1869 ASSERT_EQ(ascii_composition
.size(), bounds
.size());
1870 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1871 EXPECT_LT(0, bounds
[i
].width());
1872 view()->OnImeConfirmComposition(
1873 empty_string
, gfx::Range::InvalidRange(), false);
1875 // Non surrogate pair unicode character.
1876 const base::string16 unicode_composition
= base::UTF8ToUTF16(
1877 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1878 view()->OnImeSetComposition(unicode_composition
, empty_underline
, 0, 0);
1879 view()->GetCompositionCharacterBounds(&bounds
);
1880 ASSERT_EQ(unicode_composition
.size(), bounds
.size());
1881 for (size_t i
= 0; i
< bounds
.size(); ++i
)
1882 EXPECT_LT(0, bounds
[i
].width());
1883 view()->OnImeConfirmComposition(
1884 empty_string
, gfx::Range::InvalidRange(), false);
1886 // Surrogate pair character.
1887 const base::string16 surrogate_pair_char
=
1888 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1889 view()->OnImeSetComposition(surrogate_pair_char
,
1893 view()->GetCompositionCharacterBounds(&bounds
);
1894 ASSERT_EQ(surrogate_pair_char
.size(), bounds
.size());
1895 EXPECT_LT(0, bounds
[0].width());
1896 EXPECT_EQ(0, bounds
[1].width());
1897 view()->OnImeConfirmComposition(
1898 empty_string
, gfx::Range::InvalidRange(), false);
1901 const base::string16 surrogate_pair_mixed_composition
=
1902 surrogate_pair_char
+ base::UTF8ToUTF16("\xE3\x81\x82") +
1903 surrogate_pair_char
+ base::UTF8ToUTF16("b") + surrogate_pair_char
;
1904 const size_t utf16_length
= 8UL;
1905 const bool is_surrogate_pair_empty_rect
[8] = {
1906 false, true, false, false, true, false, false, true };
1907 view()->OnImeSetComposition(surrogate_pair_mixed_composition
,
1911 view()->GetCompositionCharacterBounds(&bounds
);
1912 ASSERT_EQ(utf16_length
, bounds
.size());
1913 for (size_t i
= 0; i
< utf16_length
; ++i
) {
1914 if (is_surrogate_pair_empty_rect
[i
]) {
1915 EXPECT_EQ(0, bounds
[i
].width());
1917 EXPECT_LT(0, bounds
[i
].width());
1920 view()->OnImeConfirmComposition(
1921 empty_string
, gfx::Range::InvalidRange(), false);
1925 TEST_F(RenderViewImplTest
, ZoomLimit
) {
1926 const double kMinZoomLevel
= ZoomFactorToZoomLevel(kMinimumZoomFactor
);
1927 const double kMaxZoomLevel
= ZoomFactorToZoomLevel(kMaximumZoomFactor
);
1929 FrameMsg_Navigate_Params params
;
1930 params
.page_id
= -1;
1931 params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
1933 // Verifies navigation to a URL with preset zoom level indeed sets the level.
1934 // Regression test for http://crbug.com/139559, where the level was not
1935 // properly set when it is out of the default zoom limits of WebView.
1936 params
.url
= GURL("data:text/html,min_zoomlimit_test");
1937 view()->OnSetZoomLevelForLoadingURL(params
.url
, kMinZoomLevel
);
1938 frame()->OnNavigate(params
);
1939 ProcessPendingMessages();
1940 EXPECT_DOUBLE_EQ(kMinZoomLevel
, view()->GetWebView()->zoomLevel());
1942 // It should work even when the zoom limit is temporarily changed in the page.
1943 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
1944 ZoomFactorToZoomLevel(1.0));
1945 params
.url
= GURL("data:text/html,max_zoomlimit_test");
1946 view()->OnSetZoomLevelForLoadingURL(params
.url
, kMaxZoomLevel
);
1947 frame()->OnNavigate(params
);
1948 ProcessPendingMessages();
1949 EXPECT_DOUBLE_EQ(kMaxZoomLevel
, view()->GetWebView()->zoomLevel());
1952 TEST_F(RenderViewImplTest
, SetEditableSelectionAndComposition
) {
1953 // Load an HTML page consisting of an input field.
1958 "<input id=\"test1\" value=\"some test text hello\"></input>"
1961 ExecuteJavaScript("document.getElementById('test1').focus();");
1962 frame()->OnSetEditableSelectionOffsets(4, 8);
1963 const std::vector
<blink::WebCompositionUnderline
> empty_underline
;
1964 frame()->OnSetCompositionFromExistingText(7, 10, empty_underline
);
1965 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1966 EXPECT_EQ(4, info
.selectionStart
);
1967 EXPECT_EQ(8, info
.selectionEnd
);
1968 EXPECT_EQ(7, info
.compositionStart
);
1969 EXPECT_EQ(10, info
.compositionEnd
);
1970 frame()->OnUnselect();
1971 info
= view()->webview()->textInputInfo();
1972 EXPECT_EQ(0, info
.selectionStart
);
1973 EXPECT_EQ(0, info
.selectionEnd
);
1977 TEST_F(RenderViewImplTest
, OnExtendSelectionAndDelete
) {
1978 // Load an HTML page consisting of an input field.
1983 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
1986 ExecuteJavaScript("document.getElementById('test1').focus();");
1987 frame()->OnSetEditableSelectionOffsets(10, 10);
1988 frame()->OnExtendSelectionAndDelete(3, 4);
1989 blink::WebTextInputInfo info
= view()->webview()->textInputInfo();
1990 EXPECT_EQ("abcdefgopqrstuvwxyz", info
.value
);
1991 EXPECT_EQ(7, info
.selectionStart
);
1992 EXPECT_EQ(7, info
.selectionEnd
);
1993 frame()->OnSetEditableSelectionOffsets(4, 8);
1994 frame()->OnExtendSelectionAndDelete(2, 5);
1995 info
= view()->webview()->textInputInfo();
1996 EXPECT_EQ("abuvwxyz", info
.value
);
1997 EXPECT_EQ(2, info
.selectionStart
);
1998 EXPECT_EQ(2, info
.selectionEnd
);
2001 // Test that the navigating specific frames works correctly.
2002 TEST_F(RenderViewImplTest
, NavigateFrame
) {
2004 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
2006 // Navigate the frame only.
2007 FrameMsg_Navigate_Params nav_params
;
2008 nav_params
.url
= GURL("data:text/html,world");
2009 nav_params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2010 nav_params
.transition
= PAGE_TRANSITION_TYPED
;
2011 nav_params
.current_history_list_length
= 1;
2012 nav_params
.current_history_list_offset
= 0;
2013 nav_params
.pending_history_list_offset
= 1;
2014 nav_params
.page_id
= -1;
2015 nav_params
.frame_to_navigate
= "frame";
2016 frame()->OnNavigate(nav_params
);
2017 ProcessPendingMessages();
2019 // Copy the document content to std::wstring and compare with the
2021 const int kMaxOutputCharacters
= 256;
2022 std::string output
= base::UTF16ToUTF8(
2023 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
2024 EXPECT_EQ(output
, "hello \n\nworld");
2027 // This test ensures that a RenderFrame object is created for the top level
2028 // frame in the RenderView.
2029 TEST_F(RenderViewImplTest
, BasicRenderFrame
) {
2030 EXPECT_TRUE(view()->main_render_frame_
.get());
2033 TEST_F(RenderViewImplTest
, GetSSLStatusOfFrame
) {
2034 LoadHTML("<!DOCTYPE html><html><body></body></html>");
2036 WebLocalFrame
* frame
= GetMainFrame();
2037 SSLStatus ssl_status
= view()->GetSSLStatusOfFrame(frame
);
2038 EXPECT_FALSE(net::IsCertStatusError(ssl_status
.cert_status
));
2040 const_cast<blink::WebURLResponse
&>(frame
->dataSource()->response()).
2042 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS
, 0, 0,
2043 SignedCertificateTimestampIDStatusList()));
2044 ssl_status
= view()->GetSSLStatusOfFrame(frame
);
2045 EXPECT_TRUE(net::IsCertStatusError(ssl_status
.cert_status
));
2048 TEST_F(RenderViewImplTest
, MessageOrderInDidChangeSelection
) {
2049 view()->OnSetInputMethodActive(true);
2050 view()->set_send_content_state_immediately(true);
2051 LoadHTML("<textarea id=\"test\"></textarea>");
2053 view()->handling_input_event_
= true;
2054 ExecuteJavaScript("document.getElementById('test').focus();");
2056 bool is_input_type_called
= false;
2057 bool is_selection_called
= false;
2058 size_t last_input_type
= 0;
2059 size_t last_selection
= 0;
2061 for (size_t i
= 0; i
< render_thread_
->sink().message_count(); ++i
) {
2062 const uint32 type
= render_thread_
->sink().GetMessageAt(i
)->type();
2063 if (type
== ViewHostMsg_TextInputTypeChanged::ID
) {
2064 is_input_type_called
= true;
2065 last_input_type
= i
;
2066 } else if (type
== ViewHostMsg_SelectionChanged::ID
) {
2067 is_selection_called
= true;
2072 EXPECT_TRUE(is_input_type_called
);
2073 EXPECT_TRUE(is_selection_called
);
2075 // InputTypeChange shold be called earlier than SelectionChanged.
2076 EXPECT_LT(last_input_type
, last_selection
);
2079 class SuppressErrorPageTest
: public RenderViewTest
{
2081 virtual ContentRendererClient
* CreateContentRendererClient() OVERRIDE
{
2082 return new TestContentRendererClient
;
2085 RenderViewImpl
* view() {
2086 return static_cast<RenderViewImpl
*>(view_
);
2089 RenderFrameImpl
* frame() {
2090 return static_cast<RenderFrameImpl
*>(view()->GetMainRenderFrame());
2094 class TestContentRendererClient
: public ContentRendererClient
{
2096 virtual bool ShouldSuppressErrorPage(RenderFrame
* render_frame
,
2097 const GURL
& url
) OVERRIDE
{
2098 return url
== GURL("http://example.com/suppress");
2101 virtual void GetNavigationErrorStrings(
2102 content::RenderView
* render_view
,
2103 blink::WebFrame
* frame
,
2104 const blink::WebURLRequest
& failed_request
,
2105 const blink::WebURLError
& error
,
2106 std::string
* error_html
,
2107 base::string16
* error_description
) OVERRIDE
{
2109 *error_html
= "A suffusion of yellow.";
2114 #if defined(OS_ANDROID)
2115 // Crashing on Android: http://crbug.com/311341
2116 #define MAYBE_Suppresses DISABLED_Suppresses
2118 #define MAYBE_Suppresses Suppresses
2121 TEST_F(SuppressErrorPageTest
, MAYBE_Suppresses
) {
2123 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2124 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2125 error
.unreachableURL
= GURL("http://example.com/suppress");
2126 WebLocalFrame
* web_frame
= GetMainFrame();
2128 // Start a load that will reach provisional state synchronously,
2129 // but won't complete synchronously.
2130 FrameMsg_Navigate_Params params
;
2131 params
.page_id
= -1;
2132 params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2133 params
.url
= GURL("data:text/html,test data");
2134 frame()->OnNavigate(params
);
2136 // An error occurred.
2137 view()->main_render_frame()->didFailProvisionalLoad(web_frame
, error
);
2138 const int kMaxOutputCharacters
= 22;
2140 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2143 #if defined(OS_ANDROID)
2144 // Crashing on Android: http://crbug.com/311341
2145 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2147 #define MAYBE_DoesNotSuppress DoesNotSuppress
2150 TEST_F(SuppressErrorPageTest
, MAYBE_DoesNotSuppress
) {
2152 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
2153 error
.reason
= net::ERR_FILE_NOT_FOUND
;
2154 error
.unreachableURL
= GURL("http://example.com/dont-suppress");
2155 WebLocalFrame
* web_frame
= GetMainFrame();
2157 // Start a load that will reach provisional state synchronously,
2158 // but won't complete synchronously.
2159 FrameMsg_Navigate_Params params
;
2160 params
.page_id
= -1;
2161 params
.navigation_type
= FrameMsg_Navigate_Type::NORMAL
;
2162 params
.url
= GURL("data:text/html,test data");
2163 frame()->OnNavigate(params
);
2165 // An error occurred.
2166 view()->main_render_frame()->didFailProvisionalLoad(web_frame
, error
);
2167 ProcessPendingMessages();
2168 const int kMaxOutputCharacters
= 22;
2169 EXPECT_EQ("A suffusion of yellow.",
2170 base::UTF16ToASCII(web_frame
->contentAsText(kMaxOutputCharacters
)));
2173 // Tests if IME API's candidatewindow* events sent from browser are handled
2175 TEST_F(RenderViewImplTest
, SendCandidateWindowEvents
) {
2176 // Sends an HTML with an <input> element and scripts to the renderer.
2177 // The script handles all 3 of candidatewindow* events for an
2178 // InputMethodContext object and once it received 'show', 'update', 'hide'
2179 // should appear in the result div.
2180 LoadHTML("<input id='test'>"
2181 "<div id='result'>Result: </div>"
2183 "window.onload = function() {"
2184 " var result = document.getElementById('result');"
2185 " var test = document.getElementById('test');"
2187 " var context = test.inputMethodContext;"
2189 " context.oncandidatewindowshow = function() {"
2190 " result.innerText += 'show'; };"
2191 " context.oncandidatewindowupdate = function(){"
2192 " result.innerText += 'update'; };"
2193 " context.oncandidatewindowhide = function(){"
2194 " result.innerText += 'hide'; };"
2199 // Fire candidatewindow events.
2200 view()->OnCandidateWindowShown();
2201 view()->OnCandidateWindowUpdated();
2202 view()->OnCandidateWindowHidden();
2204 // Retrieve the content and check if it is expected.
2205 const int kMaxOutputCharacters
= 50;
2206 std::string output
= base::UTF16ToUTF8(
2207 GetMainFrame()->contentAsText(kMaxOutputCharacters
));
2208 EXPECT_EQ(output
, "\nResult:showupdatehide");
2211 // Ensure the render view sends favicon url update events correctly.
2212 TEST_F(RenderViewImplTest
, SendFaviconURLUpdateEvent
) {
2213 // An event should be sent when a favicon url exists.
2216 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2219 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
2220 ViewHostMsg_UpdateFaviconURL::ID
));
2221 render_thread_
->sink().ClearMessages();
2223 // An event should not be sent if no favicon url exists. This is an assumption
2224 // made by some of Chrome's favicon handling.
2229 EXPECT_FALSE(render_thread_
->sink().GetFirstMessageMatching(
2230 ViewHostMsg_UpdateFaviconURL::ID
));
2233 // Test progress tracker messages.
2234 TEST_F(RenderViewImplTest
, SendProgressCompletionUpdates
) {
2235 std::string data_url_string
= "data:text/html,<body>placeholder</body>";
2236 GURL
url(data_url_string
);
2237 GetMainFrame()->loadRequest(blink::WebURLRequest(url
));
2239 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
2240 FrameHostMsg_DidStartLoading::ID
));
2242 // The load started, we should receive a start notification and a progress
2243 // update with the minimum progress.
2244 const IPC::Message
* message
= render_thread_
->sink().GetFirstMessageMatching(
2245 ViewHostMsg_DidChangeLoadProgress::ID
);
2246 EXPECT_TRUE(message
);
2247 Tuple1
<double> progress_value
;
2248 ViewHostMsg_DidChangeLoadProgress::Read(message
, &progress_value
);
2249 EXPECT_EQ(0.1, progress_value
.a
);
2250 render_thread_
->sink().ClearMessages();
2252 ProcessPendingMessages();
2254 // The data url has loaded, so we should see a progress change to 1.0 (done)
2255 // and a stop notification.
2256 message
= render_thread_
->sink().GetFirstMessageMatching(
2257 ViewHostMsg_DidChangeLoadProgress::ID
);
2258 EXPECT_TRUE(message
);
2259 ViewHostMsg_DidChangeLoadProgress::Read(message
, &progress_value
);
2260 EXPECT_EQ(1.0, progress_value
.a
);
2262 EXPECT_TRUE(render_thread_
->sink().GetFirstMessageMatching(
2263 FrameHostMsg_DidStopLoading::ID
));
2264 render_thread_
->sink().ClearMessages();
2267 TEST_F(RenderViewImplTest
, FocusElementCallsFocusedNodeChanged
) {
2268 LoadHTML("<input id='test1' value='hello1'></input>"
2269 "<input id='test2' value='hello2'></input>");
2271 ExecuteJavaScript("document.getElementById('test1').focus();");
2272 const IPC::Message
* msg1
= render_thread_
->sink().GetFirstMessageMatching(
2273 ViewHostMsg_FocusedNodeChanged::ID
);
2276 ViewHostMsg_FocusedNodeChanged::Param params
;
2277 ViewHostMsg_FocusedNodeChanged::Read(msg1
, ¶ms
);
2278 EXPECT_TRUE(params
.a
);
2279 render_thread_
->sink().ClearMessages();
2281 ExecuteJavaScript("document.getElementById('test2').focus();");
2282 const IPC::Message
* msg2
= render_thread_
->sink().GetFirstMessageMatching(
2283 ViewHostMsg_FocusedNodeChanged::ID
);
2285 ViewHostMsg_FocusedNodeChanged::Read(msg2
, ¶ms
);
2286 EXPECT_TRUE(params
.a
);
2287 render_thread_
->sink().ClearMessages();
2289 view()->webview()->clearFocusedElement();
2290 const IPC::Message
* msg3
= render_thread_
->sink().GetFirstMessageMatching(
2291 ViewHostMsg_FocusedNodeChanged::ID
);
2293 ViewHostMsg_FocusedNodeChanged::Read(msg3
, ¶ms
);
2294 EXPECT_FALSE(params
.a
);
2295 render_thread_
->sink().ClearMessages();
2298 TEST_F(RenderViewImplTest
, ServiceWorkerNetworkProviderSetup
) {
2299 ServiceWorkerNetworkProvider
* provider
= NULL
;
2300 RequestExtraData
* extra_data
= NULL
;
2302 // Make sure each new document has a new provider and
2303 // that the main request is tagged with the provider's id.
2304 LoadHTML("<b>A Document</b>");
2305 ASSERT_TRUE(GetMainFrame()->dataSource());
2306 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2307 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2308 ASSERT_TRUE(provider
);
2309 extra_data
= static_cast<RequestExtraData
*>(
2310 GetMainFrame()->dataSource()->request().extraData());
2311 ASSERT_TRUE(extra_data
);
2312 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2313 provider
->provider_id());
2314 int provider1_id
= provider
->provider_id();
2316 LoadHTML("<b>New Document B Goes Here</b>");
2317 ASSERT_TRUE(GetMainFrame()->dataSource());
2318 provider
= ServiceWorkerNetworkProvider::FromDocumentState(
2319 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2320 ASSERT_TRUE(provider
);
2321 EXPECT_NE(provider1_id
, provider
->provider_id());
2322 extra_data
= static_cast<RequestExtraData
*>(
2323 GetMainFrame()->dataSource()->request().extraData());
2324 ASSERT_TRUE(extra_data
);
2325 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2326 provider
->provider_id());
2328 // See that subresource requests are also tagged with the provider's id.
2329 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2330 blink::WebURLRequest
request(GURL("http://foo.com"));
2331 request
.setTargetType(blink::WebURLRequest::TargetIsSubresource
);
2332 blink::WebURLResponse redirect_response
;
2333 frame()->willSendRequest(GetMainFrame(), 0, request
, redirect_response
);
2334 extra_data
= static_cast<RequestExtraData
*>(request
.extraData());
2335 ASSERT_TRUE(extra_data
);
2336 EXPECT_EQ(extra_data
->service_worker_provider_id(),
2337 provider
->provider_id());
2340 TEST_F(RenderViewImplTest
, OnSetAccessibilityMode
) {
2341 ASSERT_EQ(AccessibilityModeOff
, view()->accessibility_mode());
2342 ASSERT_EQ((RendererAccessibility
*) NULL
, view()->renderer_accessibility());
2344 view()->OnSetAccessibilityMode(AccessibilityModeTreeOnly
);
2345 ASSERT_EQ(AccessibilityModeTreeOnly
, view()->accessibility_mode());
2346 ASSERT_NE((RendererAccessibility
*) NULL
, view()->renderer_accessibility());
2347 ASSERT_EQ(RendererAccessibilityTypeComplete
,
2348 view()->renderer_accessibility()->GetType());
2350 view()->OnSetAccessibilityMode(AccessibilityModeOff
);
2351 ASSERT_EQ(AccessibilityModeOff
, view()->accessibility_mode());
2352 ASSERT_EQ((RendererAccessibility
*) NULL
, view()->renderer_accessibility());
2354 view()->OnSetAccessibilityMode(AccessibilityModeComplete
);
2355 ASSERT_EQ(AccessibilityModeComplete
, view()->accessibility_mode());
2356 ASSERT_NE((RendererAccessibility
*) NULL
, view()->renderer_accessibility());
2357 ASSERT_EQ(RendererAccessibilityTypeComplete
,
2358 view()->renderer_accessibility()->GetType());
2360 view()->OnSetAccessibilityMode(AccessibilityModeEditableTextOnly
);
2361 ASSERT_EQ(AccessibilityModeEditableTextOnly
, view()->accessibility_mode());
2362 ASSERT_NE((RendererAccessibility
*) NULL
, view()->renderer_accessibility());
2363 ASSERT_EQ(RendererAccessibilityTypeFocusOnly
,
2364 view()->renderer_accessibility()->GetType());
2367 } // namespace content