Fix auto-uninstall of legacy multi-install Chrome Frame.
[chromium-blink-merge.git] / content / renderer / render_view_browsertest.cc
blobf0a880237ec5c94ca8dd74adb8b4878ed95efc91
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"
6 #include "base/bind.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"
56 #if defined(USE_AURA)
57 #include "ui/events/event.h"
58 #endif
60 #if defined(USE_AURA) && defined(USE_X11)
61 #include <X11/Xlib.h>
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"
65 #endif
67 #if defined(USE_OZONE)
68 #include "ui/events/keycodes/keyboard_code_conversion.h"
69 #endif
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;
80 namespace content {
82 namespace {
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;
89 int dst;
90 } kModifierMap[] = {
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 },
98 int flags = 0;
99 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kModifierMap); ++i) {
100 if (kModifierMap[i].src & modifiers) {
101 flags |= kModifierMap[i].dst;
104 return flags;
106 #endif
108 class WebUITestWebUIControllerFactory : public WebUIControllerFactory {
109 public:
110 virtual WebUIController* CreateWebUIControllerForURL(
111 WebUI* web_ui, const GURL& url) const OVERRIDE {
112 return NULL;
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 {
129 public:
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,
155 int key_code,
156 MockKeyboard::Modifiers modifiers,
157 base::string16* output) {
158 #if defined(OS_WIN)
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
163 // object.
164 CHECK(mock_keyboard_.get());
165 CHECK(output);
166 int length = mock_keyboard_->GetCharacters(layout, key_code, modifiers,
167 output);
168 if (length != 1)
169 return -1;
171 // Create IPC messages from Windows messages and send them to our
172 // back-end.
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);
181 #else
182 NativeWebKeyboardEvent keydown_event(msg1);
183 #endif
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);
190 #else
191 NativeWebKeyboardEvent char_event(msg2);
192 #endif
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);
199 #else
200 NativeWebKeyboardEvent keyup_event(msg3);
201 #endif
202 SendNativeKeyEvent(keyup_event);
204 return length;
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|.
208 CHECK(output);
209 const int flags = ConvertMockKeyboardModifier(modifiers);
211 ui::ScopedXI2Event xevent;
212 xevent.InitKeyEvent(ui::ET_KEY_PRESSED,
213 static_cast<ui::KeyboardCode>(key_code),
214 flags);
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),
221 flags);
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),
228 flags);
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),
234 flags);
235 output->assign(1, static_cast<base::char16>(c));
236 return 1;
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),
244 flags,
245 true);
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),
252 flags,
253 true);
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),
260 flags,
261 true);
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),
267 flags);
268 output->assign(1, static_cast<base::char16>(c));
269 return 1;
270 #else
271 NOTIMPLEMENTED();
272 return L'\0';
273 #endif
276 private:
277 scoped_ptr<MockKeyboard> mock_keyboard_;
280 } // namespace
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;
314 // Set up post data.
315 const unsigned char* raw_data = reinterpret_cast<const unsigned char*>(
316 "post \0\ndata");
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,
331 &host_nav_params);
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);
351 DocumentState state;
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(
357 GetMainFrame(),
358 &state,
359 request,
360 blink::WebNavigationTypeLinkClicked,
361 blink::WebNavigationPolicyCurrentTab,
362 false);
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(
369 GetMainFrame(),
370 &state,
371 form_request,
372 blink::WebNavigationTypeFormSubmitted,
373 blink::WebNavigationPolicyCurrentTab,
374 false);
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(
380 GetMainFrame(),
381 &state,
382 popup_request,
383 blink::WebNavigationTypeLinkClicked,
384 blink::WebNavigationPolicyNewForegroundTab,
385 false);
386 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
389 TEST_F(RenderViewImplTest, DecideNavigationPolicyHandlesAllTopLevel) {
390 DocumentState state;
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(
409 GetMainFrame(),
410 &state,
411 request,
412 kNavTypes[i],
413 blink::WebNavigationPolicyCurrentTab,
414 false);
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);
423 DocumentState state;
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(
429 GetMainFrame(),
430 &state,
431 request,
432 blink::WebNavigationTypeLinkClicked,
433 blink::WebNavigationPolicyCurrentTab,
434 false);
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(
440 GetMainFrame(),
441 &state,
442 webui_request,
443 blink::WebNavigationTypeLinkClicked,
444 blink::WebNavigationPolicyCurrentTab,
445 false);
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(
452 GetMainFrame(),
453 &state,
454 data_request,
455 blink::WebNavigationTypeFormSubmitted,
456 blink::WebNavigationPolicyCurrentTab,
457 false);
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(),
471 &state,
472 popup_request,
473 blink::WebNavigationTypeLinkClicked,
474 blink::WebNavigationPolicyNewForegroundTab,
475 false);
476 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
478 // Clean up after the new view so we don't leak it.
479 new_view->Close();
480 new_view->Release();
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);
498 ASSERT_TRUE(msg);
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);
506 ASSERT_TRUE(msg2);
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);
522 EXPECT_FALSE(msg3);
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) {
528 // Load page A.
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);
538 ASSERT_TRUE(msg_A);
539 int page_id_A;
540 PageState state_A;
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);
563 ASSERT_TRUE(msg);
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,
591 &commit_params);
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) {
600 // Load page A.
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);
610 ASSERT_TRUE(msg_A);
611 int page_id_A;
612 PageState state_A;
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);
624 ASSERT_TRUE(msg_B);
625 int page_id_B;
626 PageState state_B;
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);
639 ASSERT_TRUE(msg_C);
640 int page_id_C;
641 PageState state_C;
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;
682 params.page_id = 1;
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);
691 ASSERT_TRUE(msg);
692 int page_id;
693 PageState state;
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) {
705 // Load page A.
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);
721 ASSERT_TRUE(msg_A);
722 int page_id_A;
723 PageState state_A;
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) {
770 // Load page A.
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);
786 ASSERT_TRUE(msg_A);
787 int page_id_A;
788 PageState state_A;
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);
803 ASSERT_TRUE(msg_B);
804 int page_id_B;
805 PageState state_B;
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
830 // changes.
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);
837 LoadHTML("<html>"
838 "<head>"
839 "</head>"
840 "<body>"
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\">"
847 "</input>"
848 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
849 "</input>"
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>"
858 "</body>"
859 "</html>");
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
886 // activate IMEs.
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
892 // to activate IMEs.
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,
901 &type,
902 &input_mode,
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
908 // de-activate IMEs.
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,
920 &type,
921 &input_mode,
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
931 // activate IMEs.
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,
943 &type,
944 &input_mode,
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) {
963 enum ImeCommand {
964 IME_INITIALIZE,
965 IME_SETINPUTMODE,
966 IME_SETFOCUS,
967 IME_SETCOMPOSITION,
968 IME_CONFIRMCOMPOSITION,
969 IME_CANCELCOMPOSITION
971 struct ImeMessage {
972 ImeCommand command;
973 bool enable;
974 int selection_start;
975 int selection_end;
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
1027 // IMEs.
1028 view()->OnSetInputMethodActive(ime_message->enable);
1029 view()->set_send_content_state_immediately(true);
1030 LoadHTML("<html>"
1031 "<head>"
1032 "</head>"
1033 "<body>"
1034 "<div id=\"test1\" contenteditable=\"true\"></div>"
1035 "</body>"
1036 "</html>");
1037 ExecuteJavaScript("document.getElementById('test1').focus();");
1038 break;
1040 case IME_SETINPUTMODE:
1041 // Activate (or deactivate) our IME back-end.
1042 view()->OnSetInputMethodActive(ime_message->enable);
1043 break;
1045 case IME_SETFOCUS:
1046 // Update the window focus.
1047 view()->OnSetFocus(ime_message->enable);
1048 break;
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);
1056 break;
1058 case IME_CONFIRMCOMPOSITION:
1059 view()->OnImeConfirmComposition(
1060 base::WideToUTF16(ime_message->ime_string),
1061 gfx::Range::InvalidRange(),
1062 false);
1063 break;
1065 case IME_CANCELCOMPOSITION:
1066 view()->OnImeSetComposition(
1067 base::string16(),
1068 std::vector<blink::WebCompositionUnderline>(),
1069 0, 0);
1070 break;
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
1081 // result.
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);
1098 LoadHTML("<html>"
1099 "<head>"
1100 "</head>"
1101 "<body>"
1102 "<textarea id=\"test\"></textarea>"
1103 "<div id=\"result\" contenteditable=\"true\"></div>"
1104 "</body>"
1105 "</html>");
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
1130 // expected result.
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
1138 #if defined(OS_WIN)
1139 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent
1140 #else
1141 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent
1142 #endif
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);
1157 LoadHTML("<html>"
1158 "<head>"
1159 "<title></title>"
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 + ',' +"
1167 " ev.altKey;"
1168 " return true;"
1170 "</script>"
1171 "</head>"
1172 "<body>"
1173 "<input id='test' type='text'"
1174 " onkeydown='return OnKeyEvent(event);'"
1175 " onkeypress='return OnKeyEvent(event);'"
1176 " onkeyup='return OnKeyEvent(event);'>"
1177 "</input>"
1178 "<div id='keydown' contenteditable='true'>"
1179 "</div>"
1180 "<div id='keypress' contenteditable='true'>"
1181 "</div>"
1182 "<div id='keyup' contenteditable='true'>"
1183 "</div>"
1184 "</body>"
1185 "</html>");
1186 ExecuteJavaScript("document.getElementById('test').focus();");
1187 render_thread_->sink().ClearMessages();
1189 static const MockKeyboard::Layout kLayouts[] = {
1190 #if defined(OS_WIN)
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,
1199 #endif
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"},
1216 #if defined(OS_WIN)
1217 {MockKeyboard::RIGHT_ALT, "false,false,true"},
1218 #endif
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',
1229 'W', 'X', 'Y', 'Z',
1230 ui::VKEY_OEM_1,
1231 ui::VKEY_OEM_PLUS,
1232 ui::VKEY_OEM_COMMA,
1233 ui::VKEY_OEM_MINUS,
1234 ui::VKEY_OEM_PERIOD,
1235 ui::VKEY_OEM_2,
1236 ui::VKEY_OEM_3,
1237 ui::VKEY_OEM_4,
1238 ui::VKEY_OEM_5,
1239 ui::VKEY_OEM_6,
1240 ui::VKEY_OEM_7,
1241 #if defined(OS_WIN)
1242 // Not sure how to handle this key on Linux.
1243 ui::VKEY_OEM_8,
1244 #endif
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)
1256 continue;
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);
1285 #else
1286 NOTIMPLEMENTED();
1287 #endif
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
1295 #if defined(OS_WIN)
1296 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1297 #else
1298 #define MAYBE_InsertCharacters InsertCharacters
1299 #endif
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;
1305 } kLayouts[] = {
1306 #if 0
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"
1348 #endif
1349 #if defined(OS_WIN)
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"
1370 L"\x003c"
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"
1425 #if defined(OS_WIN)
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"
1434 #endif
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()
1442 // function.
1443 view()->set_send_content_state_immediately(true);
1444 LoadHTML("<html>"
1445 "<head>"
1446 "<title></title>"
1447 "</head>"
1448 "<body>"
1449 "<div id='test' contenteditable='true'>"
1450 "</div>"
1451 "</body>"
1452 "</html>");
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[] = {
1461 MockKeyboard::NONE,
1462 MockKeyboard::LEFT_SHIFT,
1463 #if defined(OS_WIN)
1464 MockKeyboard::RIGHT_ALT,
1465 #endif
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',
1476 'W', 'X', 'Y', 'Z',
1477 ui::VKEY_OEM_1,
1478 ui::VKEY_OEM_PLUS,
1479 ui::VKEY_OEM_COMMA,
1480 ui::VKEY_OEM_MINUS,
1481 ui::VKEY_OEM_PERIOD,
1482 ui::VKEY_OEM_2,
1483 ui::VKEY_OEM_3,
1484 ui::VKEY_OEM_4,
1485 ui::VKEY_OEM_5,
1486 ui::VKEY_OEM_6,
1487 ui::VKEY_OEM_7,
1488 #if defined(OS_WIN)
1489 // Unclear how to handle this on Linux.
1490 ui::VKEY_OEM_8,
1491 #endif
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)
1503 continue;
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);
1514 #else
1515 NOTIMPLEMENTED();
1516 #endif
1519 // Crashy, http://crbug.com/53247.
1520 TEST_F(RenderViewImplTest, DISABLED_DidFailProvisionalLoadWithErrorForError) {
1521 GetMainFrame()->enableViewSourceMode(true);
1522 WebURLError error;
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);
1544 WebURLError error;
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]);
1585 ClearHistory();
1587 blink::WebHistoryItem item;
1588 item.initialize();
1590 // No history to merge and a committed page to be kept.
1591 frame()->didCommitProvisionalLoad(GetMainFrame(),
1592 item,
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]);
1599 ClearHistory();
1601 // No history to merge and a committed page to be pruned.
1602 frame()->didCommitProvisionalLoad(GetMainFrame(),
1603 item,
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_);
1609 ClearHistory();
1611 // No history to merge and a committed page that the browser was unaware of.
1612 frame()->didCommitProvisionalLoad(GetMainFrame(),
1613 item,
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]);
1620 ClearHistory();
1622 // History to merge and a committed page to be kept.
1623 frame()->didCommitProvisionalLoad(GetMainFrame(),
1624 item,
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]);
1633 ClearHistory();
1635 // History to merge and a committed page to be pruned.
1636 frame()->didCommitProvisionalLoad(GetMainFrame(),
1637 item,
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]);
1645 ClearHistory();
1647 // History to merge and a committed page that the browser was unaware of.
1648 frame()->didCommitProvisionalLoad(GetMainFrame(),
1649 item,
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]);
1658 ClearHistory();
1660 int expected_page_id_2 = -1;
1662 // No history to merge and two committed pages, both to be kept.
1663 frame()->didCommitProvisionalLoad(GetMainFrame(),
1664 item,
1665 blink::WebStandardCommit);
1666 expected_page_id = view()->page_id_;
1667 frame()->didCommitProvisionalLoad(GetMainFrame(),
1668 item,
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]);
1677 ClearHistory();
1679 // No history to merge and two committed pages, and only the second is kept.
1680 frame()->didCommitProvisionalLoad(GetMainFrame(),
1681 item,
1682 blink::WebStandardCommit);
1683 expected_page_id = view()->page_id_;
1684 frame()->didCommitProvisionalLoad(GetMainFrame(),
1685 item,
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]);
1693 ClearHistory();
1695 // No history to merge and two committed pages, both of which the browser was
1696 // unaware of.
1697 frame()->didCommitProvisionalLoad(GetMainFrame(),
1698 item,
1699 blink::WebStandardCommit);
1700 expected_page_id = view()->page_id_;
1701 frame()->didCommitProvisionalLoad(GetMainFrame(),
1702 item,
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]);
1711 ClearHistory();
1713 // History to merge and two committed pages, both to be kept.
1714 frame()->didCommitProvisionalLoad(GetMainFrame(),
1715 item,
1716 blink::WebStandardCommit);
1717 expected_page_id = view()->page_id_;
1718 frame()->didCommitProvisionalLoad(GetMainFrame(),
1719 item,
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]);
1730 ClearHistory();
1732 // History to merge and two committed pages, and only the second is kept.
1733 frame()->didCommitProvisionalLoad(GetMainFrame(),
1734 item,
1735 blink::WebStandardCommit);
1736 expected_page_id = view()->page_id_;
1737 frame()->didCommitProvisionalLoad(GetMainFrame(),
1738 item,
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]);
1748 ClearHistory();
1750 // History to merge and two committed pages, both of which the browser was
1751 // unaware of.
1752 frame()->didCommitProvisionalLoad(GetMainFrame(),
1753 item,
1754 blink::WebStandardCommit);
1755 expected_page_id = view()->page_id_;
1756 frame()->didCommitProvisionalLoad(GetMainFrame(),
1757 item,
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 =
1799 base::ASCIIToUTF16(
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 =
1807 base::ASCIIToUTF16(
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 =
1815 base::ASCIIToUTF16(
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);
1836 forward_state =
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) {
1850 #if defined(OS_WIN)
1851 // http://crbug.com/304193
1852 if (base::win::GetVersion() < base::win::VERSION_VISTA)
1853 return;
1854 #endif
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,
1890 empty_underline,
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);
1900 // Mixed string.
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,
1908 empty_underline,
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());
1916 } else {
1917 EXPECT_LT(0, bounds[i].width());
1920 view()->OnImeConfirmComposition(
1921 empty_string, gfx::Range::InvalidRange(), false);
1923 #endif
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.
1954 LoadHTML("<html>"
1955 "<head>"
1956 "</head>"
1957 "<body>"
1958 "<input id=\"test1\" value=\"some test text hello\"></input>"
1959 "</body>"
1960 "</html>");
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.
1979 LoadHTML("<html>"
1980 "<head>"
1981 "</head>"
1982 "<body>"
1983 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
1984 "</body>"
1985 "</html>");
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) {
2003 // Load page A.
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
2020 // expected result.
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()).
2041 setSecurityInfo(
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;
2068 last_selection = i;
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 {
2080 public:
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());
2093 private:
2094 class TestContentRendererClient : public ContentRendererClient {
2095 public:
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 {
2108 if (error_html)
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
2117 #else
2118 #define MAYBE_Suppresses Suppresses
2119 #endif
2121 TEST_F(SuppressErrorPageTest, MAYBE_Suppresses) {
2122 WebURLError error;
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;
2139 EXPECT_EQ("",
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
2146 #else
2147 #define MAYBE_DoesNotSuppress DoesNotSuppress
2148 #endif
2150 TEST_F(SuppressErrorPageTest, MAYBE_DoesNotSuppress) {
2151 WebURLError error;
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
2174 // in renderer.
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>"
2182 "<script>"
2183 "window.onload = function() {"
2184 " var result = document.getElementById('result');"
2185 " var test = document.getElementById('test');"
2186 " test.focus();"
2187 " var context = test.inputMethodContext;"
2188 " if (context) {"
2189 " context.oncandidatewindowshow = function() {"
2190 " result.innerText += 'show'; };"
2191 " context.oncandidatewindowupdate = function(){"
2192 " result.innerText += 'update'; };"
2193 " context.oncandidatewindowhide = function(){"
2194 " result.innerText += 'hide'; };"
2195 " }"
2196 "};"
2197 "</script>");
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.
2214 LoadHTML("<html>"
2215 "<head>"
2216 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2217 "</head>"
2218 "</html>");
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.
2225 LoadHTML("<html>"
2226 "<head>"
2227 "</head>"
2228 "</html>");
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);
2274 EXPECT_TRUE(msg1);
2276 ViewHostMsg_FocusedNodeChanged::Param params;
2277 ViewHostMsg_FocusedNodeChanged::Read(msg1, &params);
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);
2284 EXPECT_TRUE(msg2);
2285 ViewHostMsg_FocusedNodeChanged::Read(msg2, &params);
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);
2292 EXPECT_TRUE(msg3);
2293 ViewHostMsg_FocusedNodeChanged::Read(msg3, &params);
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