Re-enable blink_perf.canvas on Windows
[chromium-blink-merge.git] / content / renderer / render_view_browsertest.cc
blobbf2f15de09cf9577a31992a30b6ec900fc5e0388
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/time/time.h"
12 #include "base/win/windows_version.h"
13 #include "content/child/request_extra_data.h"
14 #include "content/child/service_worker/service_worker_network_provider.h"
15 #include "content/common/frame_messages.h"
16 #include "content/common/ssl_status_serialization.h"
17 #include "content/common/view_messages.h"
18 #include "content/public/browser/browser_context.h"
19 #include "content/public/browser/native_web_keyboard_event.h"
20 #include "content/public/browser/web_ui_controller_factory.h"
21 #include "content/public/common/bindings_policy.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/page_zoom.h"
24 #include "content/public/common/url_constants.h"
25 #include "content/public/common/url_utils.h"
26 #include "content/public/renderer/content_renderer_client.h"
27 #include "content/public/renderer/document_state.h"
28 #include "content/public/renderer/navigation_state.h"
29 #include "content/public/test/browser_test_utils.h"
30 #include "content/public/test/frame_load_waiter.h"
31 #include "content/public/test/render_view_test.h"
32 #include "content/public/test/test_utils.h"
33 #include "content/renderer/accessibility/renderer_accessibility.h"
34 #include "content/renderer/devtools/devtools_agent.h"
35 #include "content/renderer/history_controller.h"
36 #include "content/renderer/history_serialization.h"
37 #include "content/renderer/navigation_state_impl.h"
38 #include "content/renderer/render_process.h"
39 #include "content/renderer/render_view_impl.h"
40 #include "content/shell/browser/shell.h"
41 #include "content/shell/browser/shell_browser_context.h"
42 #include "content/test/mock_keyboard.h"
43 #include "net/base/net_errors.h"
44 #include "net/cert/cert_status_flags.h"
45 #include "testing/gtest/include/gtest/gtest.h"
46 #include "third_party/WebKit/public/platform/WebData.h"
47 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
48 #include "third_party/WebKit/public/platform/WebString.h"
49 #include "third_party/WebKit/public/platform/WebURLResponse.h"
50 #include "third_party/WebKit/public/web/WebDataSource.h"
51 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
52 #include "third_party/WebKit/public/web/WebHistoryCommitType.h"
53 #include "third_party/WebKit/public/web/WebHistoryItem.h"
54 #include "third_party/WebKit/public/web/WebLocalFrame.h"
55 #include "third_party/WebKit/public/web/WebPerformance.h"
56 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
57 #include "third_party/WebKit/public/web/WebView.h"
58 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
59 #include "ui/events/event.h"
60 #include "ui/events/keycodes/keyboard_codes.h"
61 #include "ui/gfx/codec/jpeg_codec.h"
62 #include "ui/gfx/range/range.h"
64 #if defined(USE_AURA) && defined(USE_X11)
65 #include <X11/Xlib.h>
66 #include "ui/events/event_constants.h"
67 #include "ui/events/keycodes/keyboard_code_conversion.h"
68 #include "ui/events/test/events_test_utils.h"
69 #include "ui/events/test/events_test_utils_x11.h"
70 #endif
72 #if defined(USE_OZONE)
73 #include "ui/events/keycodes/keyboard_code_conversion.h"
74 #endif
76 using blink::WebFrame;
77 using blink::WebInputEvent;
78 using blink::WebLocalFrame;
79 using blink::WebMouseEvent;
80 using blink::WebRuntimeFeatures;
81 using blink::WebString;
82 using blink::WebTextDirection;
83 using blink::WebURLError;
85 namespace content {
87 namespace {
89 static const int kProxyRoutingId = 13;
91 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
92 // Converts MockKeyboard::Modifiers to ui::EventFlags.
93 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers) {
94 static struct ModifierMap {
95 MockKeyboard::Modifiers src;
96 int dst;
97 } kModifierMap[] = {
98 { MockKeyboard::LEFT_SHIFT, ui::EF_SHIFT_DOWN },
99 { MockKeyboard::RIGHT_SHIFT, ui::EF_SHIFT_DOWN },
100 { MockKeyboard::LEFT_CONTROL, ui::EF_CONTROL_DOWN },
101 { MockKeyboard::RIGHT_CONTROL, ui::EF_CONTROL_DOWN },
102 { MockKeyboard::LEFT_ALT, ui::EF_ALT_DOWN },
103 { MockKeyboard::RIGHT_ALT, ui::EF_ALT_DOWN },
105 int flags = 0;
106 for (size_t i = 0; i < arraysize(kModifierMap); ++i) {
107 if (kModifierMap[i].src & modifiers) {
108 flags |= kModifierMap[i].dst;
111 return flags;
113 #endif
115 class WebUITestWebUIControllerFactory : public WebUIControllerFactory {
116 public:
117 WebUIController* CreateWebUIControllerForURL(WebUI* web_ui,
118 const GURL& url) const override {
119 return NULL;
121 WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
122 const GURL& url) const override {
123 return WebUI::kNoWebUI;
125 bool UseWebUIForURL(BrowserContext* browser_context,
126 const GURL& url) const override {
127 return HasWebUIScheme(url);
129 bool UseWebUIBindingsForURL(BrowserContext* browser_context,
130 const GURL& url) const override {
131 return HasWebUIScheme(url);
135 } // namespace
137 class RenderViewImplTest : public RenderViewTest {
138 public:
139 RenderViewImplTest() {
140 // Attach a pseudo keyboard device to this object.
141 mock_keyboard_.reset(new MockKeyboard());
144 ~RenderViewImplTest() override {}
146 void SetUp() override {
147 RenderViewTest::SetUp();
148 // Enable Blink's experimental and test only features so that test code
149 // does not have to bother enabling each feature.
150 WebRuntimeFeatures::enableExperimentalFeatures(true);
151 WebRuntimeFeatures::enableTestOnlyFeatures(true);
154 RenderViewImpl* view() {
155 return static_cast<RenderViewImpl*>(view_);
158 int view_page_id() {
159 return view()->page_id_;
162 RenderFrameImpl* frame() {
163 return static_cast<RenderFrameImpl*>(view()->GetMainRenderFrame());
166 // Sends IPC messages that emulates a key-press event.
167 int SendKeyEvent(MockKeyboard::Layout layout,
168 int key_code,
169 MockKeyboard::Modifiers modifiers,
170 base::string16* output) {
171 #if defined(OS_WIN)
172 // Retrieve the Unicode character for the given tuple (keyboard-layout,
173 // key-code, and modifiers).
174 // Exit when a keyboard-layout driver cannot assign a Unicode character to
175 // the tuple to prevent sending an invalid key code to the RenderView
176 // object.
177 CHECK(mock_keyboard_.get());
178 CHECK(output);
179 int length = mock_keyboard_->GetCharacters(layout, key_code, modifiers,
180 output);
181 if (length != 1)
182 return -1;
184 // Create IPC messages from Windows messages and send them to our
185 // back-end.
186 // A keyboard event of Windows consists of three Windows messages:
187 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
188 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
189 // WM_CHAR sends a composed Unicode character.
190 MSG msg1 = { NULL, WM_KEYDOWN, key_code, 0 };
191 ui::KeyEvent evt1(msg1);
192 NativeWebKeyboardEvent keydown_event(evt1);
193 SendNativeKeyEvent(keydown_event);
195 MSG msg2 = { NULL, WM_CHAR, (*output)[0], 0 };
196 ui::KeyEvent evt2(msg2);
197 NativeWebKeyboardEvent char_event(evt2);
198 SendNativeKeyEvent(char_event);
200 MSG msg3 = { NULL, WM_KEYUP, key_code, 0 };
201 ui::KeyEvent evt3(msg3);
202 NativeWebKeyboardEvent keyup_event(evt3);
203 SendNativeKeyEvent(keyup_event);
205 return length;
206 #elif defined(USE_AURA) && defined(USE_X11)
207 // We ignore |layout|, which means we are only testing the layout of the
208 // current locale. TODO(mazda): fix this to respect |layout|.
209 CHECK(output);
210 const int flags = ConvertMockKeyboardModifier(modifiers);
212 ui::ScopedXI2Event xevent;
213 xevent.InitKeyEvent(ui::ET_KEY_PRESSED,
214 static_cast<ui::KeyboardCode>(key_code),
215 flags);
216 ui::KeyEvent event1(xevent);
217 NativeWebKeyboardEvent keydown_event(event1);
218 SendNativeKeyEvent(keydown_event);
220 // X11 doesn't actually have native character events, but give the test
221 // what it wants.
222 xevent.InitKeyEvent(ui::ET_KEY_PRESSED,
223 static_cast<ui::KeyboardCode>(key_code),
224 flags);
225 ui::KeyEvent event2(xevent);
226 event2.set_character(GetCharacterFromKeyCode(event2.key_code(),
227 event2.flags()));
228 ui::KeyEventTestApi test_event2(&event2);
229 test_event2.set_is_char(true);
230 NativeWebKeyboardEvent char_event(event2);
231 SendNativeKeyEvent(char_event);
233 xevent.InitKeyEvent(ui::ET_KEY_RELEASED,
234 static_cast<ui::KeyboardCode>(key_code),
235 flags);
236 ui::KeyEvent event3(xevent);
237 NativeWebKeyboardEvent keyup_event(event3);
238 SendNativeKeyEvent(keyup_event);
240 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
241 flags);
242 output->assign(1, static_cast<base::char16>(c));
243 return 1;
244 #elif defined(USE_OZONE)
245 const int flags = ConvertMockKeyboardModifier(modifiers);
247 ui::KeyEvent keydown_event(ui::ET_KEY_PRESSED,
248 static_cast<ui::KeyboardCode>(key_code),
249 flags);
250 NativeWebKeyboardEvent keydown_web_event(keydown_event);
251 SendNativeKeyEvent(keydown_web_event);
253 ui::KeyEvent char_event(keydown_event.GetCharacter(),
254 static_cast<ui::KeyboardCode>(key_code),
255 flags);
256 NativeWebKeyboardEvent char_web_event(char_event);
257 SendNativeKeyEvent(char_web_event);
259 ui::KeyEvent keyup_event(ui::ET_KEY_RELEASED,
260 static_cast<ui::KeyboardCode>(key_code),
261 flags);
262 NativeWebKeyboardEvent keyup_web_event(keyup_event);
263 SendNativeKeyEvent(keyup_web_event);
265 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
266 flags);
267 output->assign(1, static_cast<base::char16>(c));
268 return 1;
269 #else
270 NOTIMPLEMENTED();
271 return L'\0';
272 #endif
275 void EnablePreferredSizeMode() {
276 view()->OnEnablePreferredSizeChangedMode();
279 const gfx::Size& GetPreferredSize() {
280 view()->CheckPreferredSize();
281 return view()->preferred_size_;
284 void SetZoomLevel(double level) {
285 view()->OnSetZoomLevelForView(false, level);
288 void NavigateMainFrame(const CommonNavigationParams& common_params,
289 const StartNavigationParams& start_params,
290 const RequestNavigationParams& request_params) {
291 NavigateFrame(frame(), common_params, start_params, request_params);
294 void NavigateFrame(RenderFrameImpl* frame,
295 const CommonNavigationParams& common_params,
296 const StartNavigationParams& start_params,
297 const RequestNavigationParams& request_params) {
298 // PlzNavigate
299 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
300 switches::kEnableBrowserSideNavigation)) {
301 frame->OnCommitNavigation(ResourceResponseHead(), common_params.url,
302 common_params, request_params);
303 return;
305 frame->OnNavigate(common_params, start_params, request_params);
308 void SwapOut(RenderFrameImpl* frame,
309 int proxy_routing_id,
310 bool is_loading,
311 const FrameReplicationState& replicated_frame_state) {
312 frame->OnSwapOut(proxy_routing_id, is_loading, replicated_frame_state);
315 void SetEditableSelectionOffsets(int start, int end) {
316 frame()->OnSetEditableSelectionOffsets(start, end);
319 void ExtendSelectionAndDelete(int before, int after) {
320 frame()->OnExtendSelectionAndDelete(before, after);
323 void Unselect() { frame()->OnUnselect(); }
325 void SetAccessibilityMode(AccessibilityMode new_mode) {
326 frame()->OnSetAccessibilityMode(new_mode);
329 void SetCompositionFromExistingText(
330 int start,
331 int end,
332 const std::vector<blink::WebCompositionUnderline>& underlines) {
333 frame()->OnSetCompositionFromExistingText(start, end, underlines);
336 private:
337 scoped_ptr<MockKeyboard> mock_keyboard_;
340 class DevToolsAgentTest : public RenderViewImplTest {
341 public:
342 void Attach() {
343 std::string host_id = "host_id";
344 agent()->OnAttach(host_id);
347 void Detach() {
348 agent()->OnDetach();
351 bool IsPaused() {
352 return agent()->paused_;
355 void DispatchDevToolsMessage(const std::string& message) {
356 agent()->OnDispatchOnInspectorBackend(message);
359 void CloseWhilePaused() {
360 EXPECT_TRUE(IsPaused());
361 view()->NotifyOnClose();
364 private:
365 DevToolsAgent* agent() {
366 return frame()->devtools_agent();
370 // Ensure that the main RenderFrame is deleted and cleared from the RenderView
371 // after closing it.
372 TEST_F(RenderViewImplTest, RenderFrameClearedAfterClose) {
373 // Create a new main frame RenderFrame so that we don't interfere with the
374 // shutdown of frame() in RenderViewTest.TearDown.
375 blink::WebURLRequest popup_request(GURL("http://foo.com"));
376 blink::WebView* new_web_view = view()->createView(
377 GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
378 blink::WebNavigationPolicyNewForegroundTab, false);
379 RenderViewImpl* new_view = RenderViewImpl::FromWebView(new_web_view);
381 // Close the view, causing the main RenderFrame to be detached and deleted.
382 new_view->Close();
383 EXPECT_FALSE(new_view->GetMainRenderFrame());
385 // Clean up after the new view so we don't leak it.
386 new_view->Release();
389 TEST_F(RenderViewImplTest, SaveImageFromDataURL) {
390 const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
391 ViewHostMsg_SaveImageFromDataURL::ID);
392 EXPECT_FALSE(msg1);
393 render_thread_->sink().ClearMessages();
395 const std::string image_data_url =
396 "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
398 view()->saveImageFromDataURL(WebString::fromUTF8(image_data_url));
399 ProcessPendingMessages();
400 const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching(
401 ViewHostMsg_SaveImageFromDataURL::ID);
402 EXPECT_TRUE(msg2);
404 ViewHostMsg_SaveImageFromDataURL::Param param1;
405 ViewHostMsg_SaveImageFromDataURL::Read(msg2, &param1);
406 EXPECT_EQ(get<1>(param1).length(), image_data_url.length());
407 EXPECT_EQ(get<1>(param1), image_data_url);
409 ProcessPendingMessages();
410 render_thread_->sink().ClearMessages();
412 const std::string large_data_url(1024 * 1024 * 10 - 1, 'd');
414 view()->saveImageFromDataURL(WebString::fromUTF8(large_data_url));
415 ProcessPendingMessages();
416 const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching(
417 ViewHostMsg_SaveImageFromDataURL::ID);
418 EXPECT_TRUE(msg3);
420 ViewHostMsg_SaveImageFromDataURL::Param param2;
421 ViewHostMsg_SaveImageFromDataURL::Read(msg3, &param2);
422 EXPECT_EQ(get<1>(param2).length(), large_data_url.length());
423 EXPECT_EQ(get<1>(param2), large_data_url);
425 ProcessPendingMessages();
426 render_thread_->sink().ClearMessages();
428 const std::string exceeded_data_url(1024 * 1024 * 10 + 1, 'd');
430 view()->saveImageFromDataURL(WebString::fromUTF8(exceeded_data_url));
431 ProcessPendingMessages();
432 const IPC::Message* msg4 = render_thread_->sink().GetFirstMessageMatching(
433 ViewHostMsg_SaveImageFromDataURL::ID);
434 EXPECT_FALSE(msg4);
437 // Test that we get form state change notifications when input fields change.
438 TEST_F(RenderViewImplTest, DISABLED_OnNavStateChanged) {
439 // Don't want any delay for form state sync changes. This will still post a
440 // message so updates will get coalesced, but as soon as we spin the message
441 // loop, it will generate an update.
442 view()->set_send_content_state_immediately(true);
444 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
446 // We should NOT have gotten a form state change notification yet.
447 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
448 ViewHostMsg_UpdateState::ID));
449 render_thread_->sink().ClearMessages();
451 // Change the value of the input. We should have gotten an update state
452 // notification. We need to spin the message loop to catch this update.
453 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';");
454 ProcessPendingMessages();
455 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
456 ViewHostMsg_UpdateState::ID));
459 TEST_F(RenderViewImplTest, OnNavigationHttpPost) {
460 // An http url will trigger a resource load so cannot be used here.
461 CommonNavigationParams common_params;
462 StartNavigationParams start_params;
463 RequestNavigationParams request_params;
464 common_params.url = GURL("data:text/html,<div>Page</div>");
465 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
466 common_params.transition = ui::PAGE_TRANSITION_TYPED;
467 request_params.page_id = -1;
469 // Set up post data.
470 const unsigned char* raw_data = reinterpret_cast<const unsigned char*>(
471 "post \0\ndata");
472 const unsigned int length = 11;
473 const std::vector<unsigned char> post_data(raw_data, raw_data + length);
474 start_params.is_post = true;
475 start_params.browser_initiated_post_data = post_data;
477 NavigateMainFrame(common_params, start_params, request_params);
478 ProcessPendingMessages();
480 const IPC::Message* frame_navigate_msg =
481 render_thread_->sink().GetUniqueMessageMatching(
482 FrameHostMsg_DidCommitProvisionalLoad::ID);
483 EXPECT_TRUE(frame_navigate_msg);
485 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params;
486 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
487 &host_nav_params);
488 EXPECT_TRUE(get<0>(host_nav_params).is_post);
490 // Check post data sent to browser matches
491 EXPECT_TRUE(get<0>(host_nav_params).page_state.IsValid());
492 scoped_ptr<HistoryEntry> entry =
493 PageStateToHistoryEntry(get<0>(host_nav_params).page_state);
494 blink::WebHTTPBody body = entry->root().httpBody();
495 blink::WebHTTPBody::Element element;
496 bool successful = body.elementAt(0, element);
497 EXPECT_TRUE(successful);
498 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData, element.type);
499 EXPECT_EQ(length, element.data.size());
500 EXPECT_EQ(0, memcmp(raw_data, element.data.data(), length));
503 TEST_F(RenderViewImplTest, DecideNavigationPolicy) {
504 WebUITestWebUIControllerFactory factory;
505 WebUIControllerFactory::RegisterFactory(&factory);
507 DocumentState state;
508 state.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
510 // Navigations to normal HTTP URLs can be handled locally.
511 blink::WebURLRequest request(GURL("http://foo.com"));
512 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
513 policy_info.frame = GetMainFrame();
514 policy_info.extraData = &state;
515 policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
516 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
517 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
518 policy_info);
519 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab, policy);
521 // Verify that form posts to WebUI URLs will be sent to the browser process.
522 blink::WebURLRequest form_request(GURL("chrome://foo"));
523 blink::WebFrameClient::NavigationPolicyInfo form_policy_info(form_request);
524 form_policy_info.frame = GetMainFrame();
525 form_policy_info.extraData = &state;
526 form_policy_info.navigationType = blink::WebNavigationTypeFormSubmitted;
527 form_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
528 form_request.setHTTPMethod("POST");
529 policy = frame()->decidePolicyForNavigation(form_policy_info);
530 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
532 // Verify that popup links to WebUI URLs also are sent to browser.
533 blink::WebURLRequest popup_request(GURL("chrome://foo"));
534 blink::WebFrameClient::NavigationPolicyInfo popup_policy_info(popup_request);
535 popup_policy_info.frame = GetMainFrame();
536 popup_policy_info.extraData = &state;
537 popup_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
538 popup_policy_info.defaultPolicy = blink::WebNavigationPolicyNewForegroundTab;
539 policy = frame()->decidePolicyForNavigation(popup_policy_info);
540 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
543 TEST_F(RenderViewImplTest, DecideNavigationPolicyHandlesAllTopLevel) {
544 DocumentState state;
545 state.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
547 RendererPreferences prefs = view()->renderer_preferences();
548 prefs.browser_handles_all_top_level_requests = true;
549 view()->OnSetRendererPrefs(prefs);
551 const blink::WebNavigationType kNavTypes[] = {
552 blink::WebNavigationTypeLinkClicked,
553 blink::WebNavigationTypeFormSubmitted,
554 blink::WebNavigationTypeBackForward,
555 blink::WebNavigationTypeReload,
556 blink::WebNavigationTypeFormResubmitted,
557 blink::WebNavigationTypeOther,
560 blink::WebURLRequest request(GURL("http://foo.com"));
561 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
562 policy_info.frame = GetMainFrame();
563 policy_info.extraData = &state;
564 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
566 for (size_t i = 0; i < arraysize(kNavTypes); ++i) {
567 policy_info.navigationType = kNavTypes[i];
569 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
570 policy_info);
571 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
575 TEST_F(RenderViewImplTest, DecideNavigationPolicyForWebUI) {
576 // Enable bindings to simulate a WebUI view.
577 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI);
579 DocumentState state;
580 state.set_navigation_state(NavigationStateImpl::CreateContentInitiated());
582 // Navigations to normal HTTP URLs will be sent to browser process.
583 blink::WebURLRequest request(GURL("http://foo.com"));
584 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
585 policy_info.frame = GetMainFrame();
586 policy_info.extraData = &state;
587 policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
588 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
590 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
591 policy_info);
592 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
594 // Navigations to WebUI URLs will also be sent to browser process.
595 blink::WebURLRequest webui_request(GURL("chrome://foo"));
596 blink::WebFrameClient::NavigationPolicyInfo webui_policy_info(webui_request);
597 webui_policy_info.frame = GetMainFrame();
598 webui_policy_info.extraData = &state;
599 webui_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
600 webui_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
601 policy = frame()->decidePolicyForNavigation(webui_policy_info);
602 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
604 // Verify that form posts to data URLs will be sent to the browser process.
605 blink::WebURLRequest data_request(GURL("data:text/html,foo"));
606 blink::WebFrameClient::NavigationPolicyInfo data_policy_info(data_request);
607 data_policy_info.frame = GetMainFrame();
608 data_policy_info.extraData = &state;
609 data_policy_info.navigationType = blink::WebNavigationTypeFormSubmitted;
610 data_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
611 data_request.setHTTPMethod("POST");
612 policy = frame()->decidePolicyForNavigation(data_policy_info);
613 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
615 // Verify that a popup that creates a view first and then navigates to a
616 // normal HTTP URL will be sent to the browser process, even though the
617 // new view does not have any enabled_bindings_.
618 blink::WebURLRequest popup_request(GURL("http://foo.com"));
619 blink::WebView* new_web_view = view()->createView(
620 GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
621 blink::WebNavigationPolicyNewForegroundTab, false);
622 RenderViewImpl* new_view = RenderViewImpl::FromWebView(new_web_view);
623 blink::WebFrameClient::NavigationPolicyInfo popup_policy_info(popup_request);
624 popup_policy_info.frame = new_web_view->mainFrame()->toWebLocalFrame();
625 popup_policy_info.extraData = &state;
626 popup_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
627 popup_policy_info.defaultPolicy = blink::WebNavigationPolicyNewForegroundTab;
628 policy = static_cast<RenderFrameImpl*>(new_view->GetMainRenderFrame())->
629 decidePolicyForNavigation(popup_policy_info);
630 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
632 // Clean up after the new view so we don't leak it.
633 new_view->Close();
634 new_view->Release();
637 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
638 // already swapped out. http://crbug.com/93427.
639 TEST_F(RenderViewImplTest, SendSwapOutACK) {
640 LoadHTML("<div>Page A</div>");
641 int initial_page_id = view_page_id();
643 // Increment the ref count so that we don't exit when swapping out.
644 RenderProcess::current()->AddRefProcess();
646 // Respond to a swap out request.
647 SwapOut(frame(), kProxyRoutingId, true, content::FrameReplicationState());
649 // Ensure the swap out commits synchronously.
650 EXPECT_NE(initial_page_id, view_page_id());
652 // Check for a valid OnSwapOutACK.
653 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
654 FrameHostMsg_SwapOut_ACK::ID);
655 ASSERT_TRUE(msg);
657 // It is possible to get another swap out request. Ensure that we send
658 // an ACK, even if we don't have to do anything else.
659 render_thread_->sink().ClearMessages();
660 SwapOut(frame(), kProxyRoutingId, false, content::FrameReplicationState());
661 const IPC::Message* msg2 = render_thread_->sink().GetUniqueMessageMatching(
662 FrameHostMsg_SwapOut_ACK::ID);
663 ASSERT_TRUE(msg2);
665 // If we navigate back to this RenderView, ensure we don't send a state
666 // update for the swapped out URL. (http://crbug.com/72235)
667 CommonNavigationParams common_params;
668 RequestNavigationParams request_params;
669 common_params.url = GURL("data:text/html,<div>Page B</div>");
670 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
671 common_params.transition = ui::PAGE_TRANSITION_TYPED;
672 request_params.current_history_list_length = 1;
673 request_params.current_history_list_offset = 0;
674 request_params.pending_history_list_offset = 1;
675 request_params.page_id = -1;
676 NavigateMainFrame(common_params, StartNavigationParams(), request_params);
677 ProcessPendingMessages();
678 const IPC::Message* msg3 = render_thread_->sink().GetUniqueMessageMatching(
679 ViewHostMsg_UpdateState::ID);
680 EXPECT_FALSE(msg3);
683 // Ensure the RenderViewImpl reloads the previous page if a reload request
684 // arrives while it is showing swappedout://. http://crbug.com/143155.
685 TEST_F(RenderViewImplTest, ReloadWhileSwappedOut) {
686 // Load page A.
687 LoadHTML("<div>Page A</div>");
689 // Load page B, which will trigger an UpdateState message for page A.
690 LoadHTML("<div>Page B</div>");
692 // Check for a valid UpdateState message for page A.
693 ProcessPendingMessages();
694 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
695 ViewHostMsg_UpdateState::ID);
696 ASSERT_TRUE(msg_A);
697 ViewHostMsg_UpdateState::Param params;
698 ViewHostMsg_UpdateState::Read(msg_A, &params);
699 int page_id_A = get<0>(params);
700 PageState state_A = get<1>(params);
701 EXPECT_EQ(1, page_id_A);
702 render_thread_->sink().ClearMessages();
704 // Back to page A (page_id 1) and commit.
705 CommonNavigationParams common_params_A;
706 RequestNavigationParams request_params_A;
707 common_params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL;
708 common_params_A.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
709 request_params_A.current_history_list_length = 2;
710 request_params_A.current_history_list_offset = 1;
711 request_params_A.pending_history_list_offset = 0;
712 request_params_A.page_id = 1;
713 request_params_A.nav_entry_id = 1;
714 request_params_A.page_state = state_A;
715 NavigateMainFrame(common_params_A, StartNavigationParams(), request_params_A);
716 EXPECT_EQ(1, view()->historyBackListCount());
717 EXPECT_EQ(2, view()->historyBackListCount() +
718 view()->historyForwardListCount() + 1);
719 ProcessPendingMessages();
721 // Respond to a swap out request.
722 SwapOut(frame(), kProxyRoutingId, true, content::FrameReplicationState());
724 // Check for a OnSwapOutACK.
725 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
726 FrameHostMsg_SwapOut_ACK::ID);
727 ASSERT_TRUE(msg);
728 render_thread_->sink().ClearMessages();
730 // It is possible to get a reload request at this point, containing the
731 // params.page_state of the initial page (e.g., if the new page fails the
732 // provisional load in the renderer process, after we unload the old page).
733 // Ensure the old page gets reloaded, not swappedout://.
734 CommonNavigationParams common_params;
735 RequestNavigationParams request_params;
736 common_params.url = GURL("data:text/html,<div>Page A</div>");
737 common_params.navigation_type = FrameMsg_Navigate_Type::RELOAD;
738 common_params.transition = ui::PAGE_TRANSITION_RELOAD;
739 request_params.current_history_list_length = 2;
740 request_params.current_history_list_offset = 0;
741 request_params.pending_history_list_offset = 0;
742 request_params.page_id = 1;
743 request_params.nav_entry_id = 1;
744 request_params.page_state = state_A;
745 NavigateMainFrame(common_params, StartNavigationParams(), request_params);
746 ProcessPendingMessages();
748 // Verify page A committed, not swappedout://.
749 const IPC::Message* frame_navigate_msg =
750 render_thread_->sink().GetUniqueMessageMatching(
751 FrameHostMsg_DidCommitProvisionalLoad::ID);
752 EXPECT_TRUE(frame_navigate_msg);
754 // Read URL out of the parent trait of the params object.
755 FrameHostMsg_DidCommitProvisionalLoad::Param commit_load_params;
756 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
757 &commit_load_params);
758 EXPECT_NE(GURL("swappedout://"), get<0>(commit_load_params).url);
761 // Verify that security origins are replicated properly to RenderFrameProxies
762 // when swapping out.
763 TEST_F(RenderViewImplTest, OriginReplicationForSwapOut) {
764 // This test should only run with --site-per-process, since origin
765 // replication only happens in that mode.
766 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
767 switches::kSitePerProcess))
768 return;
770 LoadHTML(
771 "Hello <iframe src='data:text/html,frame 1'></iframe>"
772 "<iframe src='data:text/html,frame 2'></iframe>");
773 WebFrame* web_frame = frame()->GetWebFrame();
774 RenderFrameImpl* child_frame = static_cast<RenderFrameImpl*>(
775 RenderFrame::FromWebFrame(web_frame->firstChild()));
777 // Swap the child frame out and pass a serialized origin to be set for
778 // WebRemoteFrame.
779 content::FrameReplicationState replication_state;
780 replication_state.origin = url::Origin("http://foo.com");
781 SwapOut(child_frame, kProxyRoutingId, true, replication_state);
783 // The child frame should now be a WebRemoteFrame.
784 EXPECT_TRUE(web_frame->firstChild()->isWebRemoteFrame());
786 // Expect the origin to be updated properly.
787 blink::WebSecurityOrigin origin = web_frame->firstChild()->securityOrigin();
788 EXPECT_EQ(origin.toString(),
789 WebString::fromUTF8(replication_state.origin.string()));
791 // Now, swap out the second frame using a unique origin and verify that it is
792 // replicated correctly.
793 replication_state.origin = url::Origin();
794 RenderFrameImpl* child_frame2 = static_cast<RenderFrameImpl*>(
795 RenderFrame::FromWebFrame(web_frame->lastChild()));
796 SwapOut(child_frame2, kProxyRoutingId + 1, true, replication_state);
797 EXPECT_TRUE(web_frame->lastChild()->isWebRemoteFrame());
798 EXPECT_TRUE(web_frame->lastChild()->securityOrigin().isUnique());
801 // Test that we get the correct UpdateState message when we go back twice
802 // quickly without committing. Regression test for http://crbug.com/58082.
803 // Disabled: http://crbug.com/157357 .
804 TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) {
805 // Load page A.
806 LoadHTML("<div>Page A</div>");
808 // Load page B, which will trigger an UpdateState message for page A.
809 LoadHTML("<div>Page B</div>");
811 // Check for a valid UpdateState message for page A.
812 ProcessPendingMessages();
813 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
814 ViewHostMsg_UpdateState::ID);
815 ASSERT_TRUE(msg_A);
816 ViewHostMsg_UpdateState::Param param;
817 ViewHostMsg_UpdateState::Read(msg_A, &param);
818 int page_id_A = get<0>(param);
819 PageState state_A = get<1>(param);
820 EXPECT_EQ(1, page_id_A);
821 render_thread_->sink().ClearMessages();
823 // Load page C, which will trigger an UpdateState message for page B.
824 LoadHTML("<div>Page C</div>");
826 // Check for a valid UpdateState for page B.
827 ProcessPendingMessages();
828 const IPC::Message* msg_B = render_thread_->sink().GetUniqueMessageMatching(
829 ViewHostMsg_UpdateState::ID);
830 ASSERT_TRUE(msg_B);
831 ViewHostMsg_UpdateState::Read(msg_B, &param);
832 int page_id_B = get<0>(param);
833 PageState state_B = get<1>(param);
834 EXPECT_EQ(2, page_id_B);
835 EXPECT_NE(state_A, state_B);
836 render_thread_->sink().ClearMessages();
838 // Load page D, which will trigger an UpdateState message for page C.
839 LoadHTML("<div>Page D</div>");
841 // Check for a valid UpdateState for page C.
842 ProcessPendingMessages();
843 const IPC::Message* msg_C = render_thread_->sink().GetUniqueMessageMatching(
844 ViewHostMsg_UpdateState::ID);
845 ASSERT_TRUE(msg_C);
846 ViewHostMsg_UpdateState::Read(msg_C, &param);
847 int page_id_C = get<0>(param);
848 PageState state_C = get<1>(param);
849 EXPECT_EQ(3, page_id_C);
850 EXPECT_NE(state_B, state_C);
851 render_thread_->sink().ClearMessages();
853 // Go back to C and commit, preparing for our real test.
854 CommonNavigationParams common_params_C;
855 RequestNavigationParams request_params_C;
856 common_params_C.navigation_type = FrameMsg_Navigate_Type::NORMAL;
857 common_params_C.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
858 request_params_C.current_history_list_length = 4;
859 request_params_C.current_history_list_offset = 3;
860 request_params_C.pending_history_list_offset = 2;
861 request_params_C.page_id = 3;
862 request_params_C.page_state = state_C;
863 NavigateMainFrame(common_params_C, StartNavigationParams(), request_params_C);
864 ProcessPendingMessages();
865 render_thread_->sink().ClearMessages();
867 // Go back twice quickly, such that page B does not have a chance to commit.
868 // This leads to two changes to the back/forward list but only one change to
869 // the RenderView's page ID.
871 // Back to page B (page_id 2), without committing.
872 CommonNavigationParams common_params_B;
873 RequestNavigationParams request_params_B;
874 common_params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
875 common_params_B.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
876 request_params_B.current_history_list_length = 4;
877 request_params_B.current_history_list_offset = 2;
878 request_params_B.pending_history_list_offset = 1;
879 request_params_B.page_id = 2;
880 request_params_B.page_state = state_B;
881 NavigateMainFrame(common_params_B, StartNavigationParams(), request_params_B);
883 // Back to page A (page_id 1) and commit.
884 CommonNavigationParams common_params;
885 RequestNavigationParams request_params;
886 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
887 common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
888 request_params.current_history_list_length = 4;
889 request_params.current_history_list_offset = 2;
890 request_params.pending_history_list_offset = 0;
891 request_params.page_id = 1;
892 request_params.page_state = state_A;
893 NavigateMainFrame(common_params, StartNavigationParams(), request_params);
894 ProcessPendingMessages();
896 // Now ensure that the UpdateState message we receive is consistent
897 // and represents page C in both page_id and state.
898 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
899 ViewHostMsg_UpdateState::ID);
900 ASSERT_TRUE(msg);
901 ViewHostMsg_UpdateState::Read(msg, &param);
902 int page_id = get<0>(param);
903 PageState state = get<1>(param);
904 EXPECT_EQ(page_id_C, page_id);
905 EXPECT_NE(state_A, state);
906 EXPECT_NE(state_B, state);
907 EXPECT_EQ(state_C, state);
910 // Test that stale back/forward navigations arriving from the browser are
911 // ignored. See http://crbug.com/86758.
912 TEST_F(RenderViewImplTest, StaleNavigationsIgnored) {
913 // Load page A.
914 LoadHTML("<div id=pagename>Page A</div>");
915 EXPECT_EQ(1, view()->history_list_length_);
916 EXPECT_EQ(0, view()->history_list_offset_);
918 // Load page B, which will trigger an UpdateState message for page A.
919 LoadHTML("<div id=pagename>Page B</div>");
920 EXPECT_EQ(2, view()->history_list_length_);
921 EXPECT_EQ(1, view()->history_list_offset_);
923 // Check for a valid UpdateState message for page A.
924 ProcessPendingMessages();
925 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
926 ViewHostMsg_UpdateState::ID);
927 ASSERT_TRUE(msg_A);
928 ViewHostMsg_UpdateState::Param param;
929 ViewHostMsg_UpdateState::Read(msg_A, &param);
930 int page_id_A = get<0>(param);
931 PageState state_A = get<1>(param);
932 EXPECT_EQ(1, page_id_A);
933 render_thread_->sink().ClearMessages();
935 // Back to page A (nav_entry_id 1) and commit.
936 CommonNavigationParams common_params_A;
937 RequestNavigationParams request_params_A;
938 common_params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL;
939 common_params_A.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
940 request_params_A.current_history_list_length = 2;
941 request_params_A.current_history_list_offset = 1;
942 request_params_A.pending_history_list_offset = 0;
943 request_params_A.page_id = 1;
944 request_params_A.nav_entry_id = 1;
945 request_params_A.page_state = state_A;
946 NavigateMainFrame(common_params_A, StartNavigationParams(), request_params_A);
947 ProcessPendingMessages();
949 // A new navigation commits, clearing the forward history.
950 LoadHTML("<div id=pagename>Page C</div>");
951 EXPECT_EQ(2, view()->history_list_length_);
952 EXPECT_EQ(1, view()->history_list_offset_);
953 EXPECT_EQ(3, view()->page_id_); // page C is now page id 3
954 int was_page_c = -1;
955 base::string16 check_page_c = base::ASCIIToUTF16(
956 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
957 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
958 EXPECT_EQ(1, was_page_c);
960 // The browser then sends a stale navigation to B, which should be ignored.
961 CommonNavigationParams common_params_B;
962 RequestNavigationParams request_params_B;
963 common_params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
964 common_params_B.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
965 request_params_B.current_history_list_length = 2;
966 request_params_B.current_history_list_offset = 0;
967 request_params_B.pending_history_list_offset = 1;
968 request_params_B.page_id = 2;
969 request_params_B.nav_entry_id = 2;
970 request_params_B.page_state =
971 state_A; // Doesn't matter, just has to be present.
972 NavigateMainFrame(common_params_B, StartNavigationParams(), request_params_B);
974 // State should be unchanged.
975 EXPECT_EQ(2, view()->history_list_length_);
976 EXPECT_EQ(1, view()->history_list_offset_);
977 EXPECT_EQ(3, view()->page_id_); // page C, not page B
978 was_page_c = -1;
979 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
980 EXPECT_EQ(1, was_page_c);
982 // Check for a valid DidDropNavigation message.
983 ProcessPendingMessages();
984 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
985 FrameHostMsg_DidDropNavigation::ID);
986 ASSERT_TRUE(msg);
987 render_thread_->sink().ClearMessages();
990 // Test that our IME backend sends a notification message when the input focus
991 // changes.
992 TEST_F(RenderViewImplTest, OnImeTypeChanged) {
993 // Enable our IME backend code.
994 view()->OnSetInputMethodActive(true);
996 // Load an HTML page consisting of two input fields.
997 view()->set_send_content_state_immediately(true);
998 LoadHTML("<html>"
999 "<head>"
1000 "</head>"
1001 "<body>"
1002 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
1003 "<input id=\"test2\" type=\"password\"></input>"
1004 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
1005 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
1006 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
1007 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
1008 "</input>"
1009 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
1010 "</input>"
1011 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
1012 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
1013 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
1014 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
1015 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
1016 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
1017 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
1018 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
1019 "</body>"
1020 "</html>");
1021 render_thread_->sink().ClearMessages();
1023 struct InputModeTestCase {
1024 const char* input_id;
1025 ui::TextInputMode expected_mode;
1027 static const InputModeTestCase kInputModeTestCases[] = {
1028 {"test1", ui::TEXT_INPUT_MODE_DEFAULT},
1029 {"test3", ui::TEXT_INPUT_MODE_VERBATIM},
1030 {"test4", ui::TEXT_INPUT_MODE_LATIN},
1031 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME},
1032 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE},
1033 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN},
1034 {"test8", ui::TEXT_INPUT_MODE_KANA},
1035 {"test9", ui::TEXT_INPUT_MODE_KATAKANA},
1036 {"test10", ui::TEXT_INPUT_MODE_NUMERIC},
1037 {"test11", ui::TEXT_INPUT_MODE_TEL},
1038 {"test12", ui::TEXT_INPUT_MODE_EMAIL},
1039 {"test13", ui::TEXT_INPUT_MODE_URL},
1040 {"test14", ui::TEXT_INPUT_MODE_DEFAULT},
1041 {"test15", ui::TEXT_INPUT_MODE_VERBATIM},
1044 const int kRepeatCount = 10;
1045 for (int i = 0; i < kRepeatCount; i++) {
1046 // Move the input focus to the first <input> element, where we should
1047 // activate IMEs.
1048 ExecuteJavaScript("document.getElementById('test1').focus();");
1049 ProcessPendingMessages();
1050 render_thread_->sink().ClearMessages();
1052 // Update the IME status and verify if our IME backend sends an IPC message
1053 // to activate IMEs.
1054 view()->UpdateTextInputType();
1055 const IPC::Message* msg = render_thread_->sink().GetMessageAt(0);
1056 EXPECT_TRUE(msg != NULL);
1057 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
1058 ViewHostMsg_TextInputTypeChanged::Param params;
1059 ViewHostMsg_TextInputTypeChanged::Read(msg, &params);
1060 ui::TextInputType type = get<0>(params);
1061 ui::TextInputMode input_mode = get<1>(params);
1062 bool can_compose_inline = get<2>(params);
1063 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, type);
1064 EXPECT_EQ(true, can_compose_inline);
1066 // Move the input focus to the second <input> element, where we should
1067 // de-activate IMEs.
1068 ExecuteJavaScript("document.getElementById('test2').focus();");
1069 ProcessPendingMessages();
1070 render_thread_->sink().ClearMessages();
1072 // Update the IME status and verify if our IME backend sends an IPC message
1073 // to de-activate IMEs.
1074 view()->UpdateTextInputType();
1075 msg = render_thread_->sink().GetMessageAt(0);
1076 EXPECT_TRUE(msg != NULL);
1077 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
1078 ViewHostMsg_TextInputTypeChanged::Read(msg, & params);
1079 type = get<0>(params);
1080 input_mode = get<1>(params);
1081 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, type);
1083 for (size_t i = 0; i < arraysize(kInputModeTestCases); i++) {
1084 const InputModeTestCase* test_case = &kInputModeTestCases[i];
1085 std::string javascript =
1086 base::StringPrintf("document.getElementById('%s').focus();",
1087 test_case->input_id);
1088 // Move the input focus to the target <input> element, where we should
1089 // activate IMEs.
1090 ExecuteJavaScriptAndReturnIntValue(base::ASCIIToUTF16(javascript), NULL);
1091 ProcessPendingMessages();
1092 render_thread_->sink().ClearMessages();
1094 // Update the IME status and verify if our IME backend sends an IPC
1095 // message to activate IMEs.
1096 view()->UpdateTextInputType();
1097 const IPC::Message* msg = render_thread_->sink().GetMessageAt(0);
1098 EXPECT_TRUE(msg != NULL);
1099 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
1100 ViewHostMsg_TextInputTypeChanged::Read(msg, & params);
1101 type = get<0>(params);
1102 input_mode = get<1>(params);
1103 EXPECT_EQ(test_case->expected_mode, input_mode);
1108 // Test that our IME backend can compose CJK words.
1109 // Our IME front-end sends many platform-independent messages to the IME backend
1110 // while it composes CJK words. This test sends the minimal messages captured
1111 // on my local environment directly to the IME backend to verify if the backend
1112 // can compose CJK words without any problems.
1113 // This test uses an array of command sets because an IME composotion does not
1114 // only depends on IME events, but also depends on window events, e.g. moving
1115 // the window focus while composing a CJK text. To handle such complicated
1116 // cases, this test should not only call IME-related functions in the
1117 // RenderWidget class, but also call some RenderWidget members, e.g.
1118 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc.
1119 TEST_F(RenderViewImplTest, ImeComposition) {
1120 enum ImeCommand {
1121 IME_INITIALIZE,
1122 IME_SETINPUTMODE,
1123 IME_SETFOCUS,
1124 IME_SETCOMPOSITION,
1125 IME_CONFIRMCOMPOSITION,
1126 IME_CANCELCOMPOSITION
1128 struct ImeMessage {
1129 ImeCommand command;
1130 bool enable;
1131 int selection_start;
1132 int selection_end;
1133 const wchar_t* ime_string;
1134 const wchar_t* result;
1136 static const ImeMessage kImeMessages[] = {
1137 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
1138 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1139 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1140 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1141 {IME_SETCOMPOSITION, false, 1, 1, L"n", L"n"},
1142 {IME_SETCOMPOSITION, false, 2, 2, L"ni", L"ni"},
1143 {IME_SETCOMPOSITION, false, 3, 3, L"nih", L"nih"},
1144 {IME_SETCOMPOSITION, false, 4, 4, L"niha", L"niha"},
1145 {IME_SETCOMPOSITION, false, 5, 5, L"nihao", L"nihao"},
1146 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"\x4F60\x597D", L"\x4F60\x597D"},
1147 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
1148 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1149 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1150 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1151 {IME_SETCOMPOSITION, false, 0, 1, L"\xFF4B", L"\xFF4B"},
1152 {IME_SETCOMPOSITION, false, 0, 1, L"\x304B", L"\x304B"},
1153 {IME_SETCOMPOSITION, false, 0, 2, L"\x304B\xFF4E", L"\x304B\xFF4E"},
1154 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\xFF4A",
1155 L"\x304B\x3093\xFF4A"},
1156 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\x3058",
1157 L"\x304B\x3093\x3058"},
1158 {IME_SETCOMPOSITION, false, 0, 2, L"\x611F\x3058", L"\x611F\x3058"},
1159 {IME_SETCOMPOSITION, false, 0, 2, L"\x6F22\x5B57", L"\x6F22\x5B57"},
1160 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1161 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1162 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1163 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1164 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1165 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1166 {IME_SETCOMPOSITION, false, 0, 1, L"\x3147", L"\x3147"},
1167 {IME_SETCOMPOSITION, false, 0, 1, L"\xC544", L"\xC544"},
1168 {IME_SETCOMPOSITION, false, 0, 1, L"\xC548", L"\xC548"},
1169 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1170 {IME_SETCOMPOSITION, false, 0, 1, L"\x3134", L"\xC548\x3134"},
1171 {IME_SETCOMPOSITION, false, 0, 1, L"\xB140", L"\xC548\xB140"},
1172 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1173 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1174 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1175 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548\xB155"},
1178 for (size_t i = 0; i < arraysize(kImeMessages); i++) {
1179 const ImeMessage* ime_message = &kImeMessages[i];
1180 switch (ime_message->command) {
1181 case IME_INITIALIZE:
1182 // Load an HTML page consisting of a content-editable <div> element,
1183 // and move the input focus to the <div> element, where we can use
1184 // IMEs.
1185 view()->OnSetInputMethodActive(ime_message->enable);
1186 view()->set_send_content_state_immediately(true);
1187 LoadHTML("<html>"
1188 "<head>"
1189 "</head>"
1190 "<body>"
1191 "<div id=\"test1\" contenteditable=\"true\"></div>"
1192 "</body>"
1193 "</html>");
1194 ExecuteJavaScript("document.getElementById('test1').focus();");
1195 break;
1197 case IME_SETINPUTMODE:
1198 // Activate (or deactivate) our IME back-end.
1199 view()->OnSetInputMethodActive(ime_message->enable);
1200 break;
1202 case IME_SETFOCUS:
1203 // Update the window focus.
1204 view()->OnSetFocus(ime_message->enable);
1205 break;
1207 case IME_SETCOMPOSITION:
1208 view()->OnImeSetComposition(
1209 base::WideToUTF16(ime_message->ime_string),
1210 std::vector<blink::WebCompositionUnderline>(),
1211 ime_message->selection_start,
1212 ime_message->selection_end);
1213 break;
1215 case IME_CONFIRMCOMPOSITION:
1216 view()->OnImeConfirmComposition(
1217 base::WideToUTF16(ime_message->ime_string),
1218 gfx::Range::InvalidRange(),
1219 false);
1220 break;
1222 case IME_CANCELCOMPOSITION:
1223 view()->OnImeSetComposition(
1224 base::string16(),
1225 std::vector<blink::WebCompositionUnderline>(),
1226 0, 0);
1227 break;
1230 // Update the status of our IME back-end.
1231 // TODO(hbono): we should verify messages to be sent from the back-end.
1232 view()->UpdateTextInputType();
1233 ProcessPendingMessages();
1234 render_thread_->sink().ClearMessages();
1236 if (ime_message->result) {
1237 // Retrieve the content of this page and compare it with the expected
1238 // result.
1239 const int kMaxOutputCharacters = 128;
1240 base::string16 output =
1241 GetMainFrame()->contentAsText(kMaxOutputCharacters);
1242 EXPECT_EQ(base::WideToUTF16(ime_message->result), output);
1247 // Test that the RenderView::OnSetTextDirection() function can change the text
1248 // direction of the selected input element.
1249 TEST_F(RenderViewImplTest, OnSetTextDirection) {
1250 // Load an HTML page consisting of a <textarea> element and a <div> element.
1251 // This test changes the text direction of the <textarea> element, and
1252 // writes the values of its 'dir' attribute and its 'direction' property to
1253 // verify that the text direction is changed.
1254 view()->set_send_content_state_immediately(true);
1255 LoadHTML("<html>"
1256 "<head>"
1257 "</head>"
1258 "<body>"
1259 "<textarea id=\"test\"></textarea>"
1260 "<div id=\"result\" contenteditable=\"true\"></div>"
1261 "</body>"
1262 "</html>");
1263 render_thread_->sink().ClearMessages();
1265 static const struct {
1266 WebTextDirection direction;
1267 const wchar_t* expected_result;
1268 } kTextDirection[] = {
1269 { blink::WebTextDirectionRightToLeft, L"\x000A" L"rtl,rtl" },
1270 { blink::WebTextDirectionLeftToRight, L"\x000A" L"ltr,ltr" },
1272 for (size_t i = 0; i < arraysize(kTextDirection); ++i) {
1273 // Set the text direction of the <textarea> element.
1274 ExecuteJavaScript("document.getElementById('test').focus();");
1275 view()->OnSetTextDirection(kTextDirection[i].direction);
1277 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1278 // property to the <div> element.
1279 ExecuteJavaScript("var result = document.getElementById('result');"
1280 "var node = document.getElementById('test');"
1281 "var style = getComputedStyle(node, null);"
1282 "result.innerText ="
1283 " node.getAttribute('dir') + ',' +"
1284 " style.getPropertyValue('direction');");
1286 // Copy the document content to std::wstring and compare with the
1287 // expected result.
1288 const int kMaxOutputCharacters = 16;
1289 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
1290 EXPECT_EQ(base::WideToUTF16(kTextDirection[i].expected_result), output);
1294 // see http://crbug.com/238750
1295 #if defined(OS_WIN)
1296 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent
1297 #else
1298 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent
1299 #endif
1301 // Test that we can receive correct DOM events when we send input events
1302 // through the RenderWidget::OnHandleInputEvent() function.
1303 TEST_F(RenderViewImplTest, MAYBE_OnHandleKeyboardEvent) {
1304 #if !defined(OS_MACOSX)
1305 // Load an HTML page consisting of one <input> element and three
1306 // contentediable <div> elements.
1307 // The <input> element is used for sending keyboard events, and the <div>
1308 // elements are used for writing DOM events in the following format:
1309 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1310 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1311 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1312 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1313 view()->set_send_content_state_immediately(true);
1314 LoadHTML("<html>"
1315 "<head>"
1316 "<title></title>"
1317 "<script type='text/javascript' language='javascript'>"
1318 "function OnKeyEvent(ev) {"
1319 " var result = document.getElementById(ev.type);"
1320 " result.innerText ="
1321 " (ev.which || ev.keyCode) + ',' +"
1322 " ev.shiftKey + ',' +"
1323 " ev.ctrlKey + ',' +"
1324 " ev.altKey;"
1325 " return true;"
1327 "</script>"
1328 "</head>"
1329 "<body>"
1330 "<input id='test' type='text'"
1331 " onkeydown='return OnKeyEvent(event);'"
1332 " onkeypress='return OnKeyEvent(event);'"
1333 " onkeyup='return OnKeyEvent(event);'>"
1334 "</input>"
1335 "<div id='keydown' contenteditable='true'>"
1336 "</div>"
1337 "<div id='keypress' contenteditable='true'>"
1338 "</div>"
1339 "<div id='keyup' contenteditable='true'>"
1340 "</div>"
1341 "</body>"
1342 "</html>");
1343 ExecuteJavaScript("document.getElementById('test').focus();");
1344 render_thread_->sink().ClearMessages();
1346 static const MockKeyboard::Layout kLayouts[] = {
1347 #if defined(OS_WIN)
1348 // Since we ignore the mock keyboard layout on Linux and instead just use
1349 // the screen's keyboard layout, these trivially pass. They are commented
1350 // out to avoid the illusion that they work.
1351 MockKeyboard::LAYOUT_ARABIC,
1352 MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1353 MockKeyboard::LAYOUT_FRENCH,
1354 MockKeyboard::LAYOUT_HEBREW,
1355 MockKeyboard::LAYOUT_RUSSIAN,
1356 #endif
1357 MockKeyboard::LAYOUT_UNITED_STATES,
1360 for (size_t i = 0; i < arraysize(kLayouts); ++i) {
1361 // For each key code, we send three keyboard events.
1362 // * we press only the key;
1363 // * we press the key and a left-shift key, and;
1364 // * we press the key and a right-alt (AltGr) key.
1365 // For each modifiers, we need a string used for formatting its expected
1366 // result. (See the above comment for its format.)
1367 static const struct {
1368 MockKeyboard::Modifiers modifiers;
1369 const char* expected_result;
1370 } kModifierData[] = {
1371 {MockKeyboard::NONE, "false,false,false"},
1372 {MockKeyboard::LEFT_SHIFT, "true,false,false"},
1373 #if defined(OS_WIN)
1374 {MockKeyboard::RIGHT_ALT, "false,false,true"},
1375 #endif
1378 MockKeyboard::Layout layout = kLayouts[i];
1379 for (size_t j = 0; j < arraysize(kModifierData); ++j) {
1380 // Virtual key codes used for this test.
1381 static const int kKeyCodes[] = {
1382 '0', '1', '2', '3', '4', '5', '6', '7',
1383 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1384 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1385 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1386 'W', 'X', 'Y', 'Z',
1387 ui::VKEY_OEM_1,
1388 ui::VKEY_OEM_PLUS,
1389 ui::VKEY_OEM_COMMA,
1390 ui::VKEY_OEM_MINUS,
1391 ui::VKEY_OEM_PERIOD,
1392 ui::VKEY_OEM_2,
1393 ui::VKEY_OEM_3,
1394 ui::VKEY_OEM_4,
1395 ui::VKEY_OEM_5,
1396 ui::VKEY_OEM_6,
1397 ui::VKEY_OEM_7,
1398 #if defined(OS_WIN)
1399 // Not sure how to handle this key on Linux.
1400 ui::VKEY_OEM_8,
1401 #endif
1404 MockKeyboard::Modifiers modifiers = kModifierData[j].modifiers;
1405 for (size_t k = 0; k < arraysize(kKeyCodes); ++k) {
1406 // Send a keyboard event to the RenderView object.
1407 // We should test a keyboard event only when the given keyboard-layout
1408 // driver is installed in a PC and the driver can assign a Unicode
1409 // charcter for the given tuple (key-code and modifiers).
1410 int key_code = kKeyCodes[k];
1411 base::string16 char_code;
1412 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1413 continue;
1415 // Create an expected result from the virtual-key code, the character
1416 // code, and the modifier-key status.
1417 // We format a string that emulates a DOM-event string produced hy
1418 // our JavaScript function. (See the above comment for the format.)
1419 static char expected_result[1024];
1420 expected_result[0] = 0;
1421 base::snprintf(&expected_result[0],
1422 sizeof(expected_result),
1423 "\n" // texts in the <input> element
1424 "%d,%s\n" // texts in the first <div> element
1425 "%d,%s\n" // texts in the second <div> element
1426 "%d,%s", // texts in the third <div> element
1427 key_code, kModifierData[j].expected_result,
1428 static_cast<int>(char_code[0]),
1429 kModifierData[j].expected_result,
1430 key_code, kModifierData[j].expected_result);
1432 // Retrieve the text in the test page and compare it with the expected
1433 // text created from a virtual-key code, a character code, and the
1434 // modifier-key status.
1435 const int kMaxOutputCharacters = 1024;
1436 std::string output = base::UTF16ToUTF8(
1437 GetMainFrame()->contentAsText(kMaxOutputCharacters));
1438 EXPECT_EQ(expected_result, output);
1442 #else
1443 NOTIMPLEMENTED();
1444 #endif
1447 // Test that our EditorClientImpl class can insert characters when we send
1448 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1449 // This test is for preventing regressions caused only when we use non-US
1450 // keyboards, such as Issue 10846.
1451 // see http://crbug.com/244562
1452 #if defined(OS_WIN)
1453 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1454 #else
1455 #define MAYBE_InsertCharacters InsertCharacters
1456 #endif
1457 TEST_F(RenderViewImplTest, MAYBE_InsertCharacters) {
1458 #if !defined(OS_MACOSX)
1459 static const struct {
1460 MockKeyboard::Layout layout;
1461 const wchar_t* expected_result;
1462 } kLayouts[] = {
1463 #if 0
1464 // Disabled these keyboard layouts because buildbots do not have their
1465 // keyboard-layout drivers installed.
1466 {MockKeyboard::LAYOUT_ARABIC,
1467 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1468 L"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1469 L"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1470 L"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1471 L"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1472 L"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1473 L"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1474 L"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1475 L"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1476 L"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1477 L"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1478 L"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1479 L"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1480 L"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1481 L"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1482 L"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1483 L"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1485 {MockKeyboard::LAYOUT_HEBREW,
1486 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1487 L"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1488 L"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1489 L"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1490 L"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1491 L"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1492 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1493 L"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1494 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1495 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1496 L"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1497 L"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1498 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1499 L"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1500 L"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1501 L"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1502 L"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1503 L"\x003b\x005d\x005c\x005b\x002c"
1505 #endif
1506 #if defined(OS_WIN)
1507 // On Linux, the only way to test alternate keyboard layouts is to change
1508 // the keyboard layout of the whole screen. I'm worried about the side
1509 // effects this may have on the buildbots.
1510 {MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1511 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1512 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1513 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1514 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1515 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1516 L"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1517 L"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1518 L"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1519 L"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1520 L"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1521 L"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1522 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1523 L"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1524 L"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1525 L"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1526 L"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1527 L"\x003c"
1529 {MockKeyboard::LAYOUT_FRENCH,
1530 L"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1531 L"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1532 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1533 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1534 L"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1535 L"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1536 L"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1537 L"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1538 L"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1539 L"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1540 L"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1541 L"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1542 L"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1543 L"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1544 L"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1545 L"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1546 L"\x003b\x003a\x00f9\x0029\x002a\x0021"
1548 {MockKeyboard::LAYOUT_RUSSIAN,
1549 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1550 L"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1551 L"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1552 L"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1553 L"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1554 L"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1555 L"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1556 L"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1557 L"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1558 L"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1559 L"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1560 L"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1561 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1562 L"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1563 L"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1564 L"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1565 L"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1566 L"\x0451\x0445\x005c\x044a\x044d"
1568 #endif // defined(OS_WIN)
1569 {MockKeyboard::LAYOUT_UNITED_STATES,
1570 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1571 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1572 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1573 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1574 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1575 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1576 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1577 L"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1578 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1579 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1580 L"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1581 L"\x003f\x007e\x007b\x007c\x007d\x0022"
1582 #if defined(OS_WIN)
1583 // This is ifdefed out for Linux to correspond to the fact that we don't
1584 // test alt+keystroke for now.
1585 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1586 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1587 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1588 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1589 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1590 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1591 #endif
1595 for (size_t i = 0; i < arraysize(kLayouts); ++i) {
1596 // Load an HTML page consisting of one <div> element.
1597 // This <div> element is used by the EditorClientImpl class to insert
1598 // characters received through the RenderWidget::OnHandleInputEvent()
1599 // function.
1600 view()->set_send_content_state_immediately(true);
1601 LoadHTML("<html>"
1602 "<head>"
1603 "<title></title>"
1604 "</head>"
1605 "<body>"
1606 "<div id='test' contenteditable='true'>"
1607 "</div>"
1608 "</body>"
1609 "</html>");
1610 ExecuteJavaScript("document.getElementById('test').focus();");
1611 render_thread_->sink().ClearMessages();
1613 // For each key code, we send three keyboard events.
1614 // * Pressing only the key;
1615 // * Pressing the key and a left-shift key, and;
1616 // * Pressing the key and a right-alt (AltGr) key.
1617 static const MockKeyboard::Modifiers kModifiers[] = {
1618 MockKeyboard::NONE,
1619 MockKeyboard::LEFT_SHIFT,
1620 #if defined(OS_WIN)
1621 MockKeyboard::RIGHT_ALT,
1622 #endif
1625 MockKeyboard::Layout layout = kLayouts[i].layout;
1626 for (size_t j = 0; j < arraysize(kModifiers); ++j) {
1627 // Virtual key codes used for this test.
1628 static const int kKeyCodes[] = {
1629 '0', '1', '2', '3', '4', '5', '6', '7',
1630 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1631 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1632 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1633 'W', 'X', 'Y', 'Z',
1634 ui::VKEY_OEM_1,
1635 ui::VKEY_OEM_PLUS,
1636 ui::VKEY_OEM_COMMA,
1637 ui::VKEY_OEM_MINUS,
1638 ui::VKEY_OEM_PERIOD,
1639 ui::VKEY_OEM_2,
1640 ui::VKEY_OEM_3,
1641 ui::VKEY_OEM_4,
1642 ui::VKEY_OEM_5,
1643 ui::VKEY_OEM_6,
1644 ui::VKEY_OEM_7,
1645 #if defined(OS_WIN)
1646 // Unclear how to handle this on Linux.
1647 ui::VKEY_OEM_8,
1648 #endif
1651 MockKeyboard::Modifiers modifiers = kModifiers[j];
1652 for (size_t k = 0; k < arraysize(kKeyCodes); ++k) {
1653 // Send a keyboard event to the RenderView object.
1654 // We should test a keyboard event only when the given keyboard-layout
1655 // driver is installed in a PC and the driver can assign a Unicode
1656 // charcter for the given tuple (layout, key-code, and modifiers).
1657 int key_code = kKeyCodes[k];
1658 base::string16 char_code;
1659 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1660 continue;
1664 // Retrieve the text in the test page and compare it with the expected
1665 // text created from a virtual-key code, a character code, and the
1666 // modifier-key status.
1667 const int kMaxOutputCharacters = 4096;
1668 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
1669 EXPECT_EQ(base::WideToUTF16(kLayouts[i].expected_result), output);
1671 #else
1672 NOTIMPLEMENTED();
1673 #endif
1676 // Crashy, http://crbug.com/53247.
1677 TEST_F(RenderViewImplTest, DISABLED_DidFailProvisionalLoadWithErrorForError) {
1678 GetMainFrame()->enableViewSourceMode(true);
1679 WebURLError error;
1680 error.domain = WebString::fromUTF8(net::kErrorDomain);
1681 error.reason = net::ERR_FILE_NOT_FOUND;
1682 error.unreachableURL = GURL("http://foo");
1683 WebLocalFrame* web_frame = GetMainFrame();
1685 // Start a load that will reach provisional state synchronously,
1686 // but won't complete synchronously.
1687 CommonNavigationParams common_params;
1688 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1689 common_params.url = GURL("data:text/html,test data");
1690 NavigateMainFrame(common_params, StartNavigationParams(),
1691 RequestNavigationParams());
1693 // An error occurred.
1694 view()->GetMainRenderFrame()->didFailProvisionalLoad(
1695 web_frame, error, blink::WebStandardCommit);
1696 // Frame should exit view-source mode.
1697 EXPECT_FALSE(web_frame->isViewSourceModeEnabled());
1700 TEST_F(RenderViewImplTest, DidFailProvisionalLoadWithErrorForCancellation) {
1701 GetMainFrame()->enableViewSourceMode(true);
1702 WebURLError error;
1703 error.domain = WebString::fromUTF8(net::kErrorDomain);
1704 error.reason = net::ERR_ABORTED;
1705 error.unreachableURL = GURL("http://foo");
1706 WebLocalFrame* web_frame = GetMainFrame();
1708 // Start a load that will reach provisional state synchronously,
1709 // but won't complete synchronously.
1710 CommonNavigationParams common_params;
1711 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1712 common_params.url = GURL("data:text/html,test data");
1713 NavigateMainFrame(common_params, StartNavigationParams(),
1714 RequestNavigationParams());
1716 // A cancellation occurred.
1717 view()->GetMainRenderFrame()->didFailProvisionalLoad(
1718 web_frame, error, blink::WebStandardCommit);
1719 // Frame should stay in view-source mode.
1720 EXPECT_TRUE(web_frame->isViewSourceModeEnabled());
1723 // Regression test for http://crbug.com/41562
1724 TEST_F(RenderViewImplTest, UpdateTargetURLWithInvalidURL) {
1725 const GURL invalid_gurl("http://");
1726 view()->setMouseOverURL(blink::WebURL(invalid_gurl));
1727 EXPECT_EQ(invalid_gurl, view()->target_url_);
1730 TEST_F(RenderViewImplTest, SetHistoryLengthAndOffset) {
1731 // No history to merge; one committed page.
1732 view()->OnSetHistoryOffsetAndLength(0, 1);
1733 EXPECT_EQ(1, view()->history_list_length_);
1734 EXPECT_EQ(0, view()->history_list_offset_);
1736 // History of length 1 to merge; one committed page.
1737 view()->OnSetHistoryOffsetAndLength(1, 2);
1738 EXPECT_EQ(2, view()->history_list_length_);
1739 EXPECT_EQ(1, view()->history_list_offset_);
1742 TEST_F(RenderViewImplTest, ContextMenu) {
1743 LoadHTML("<div>Page A</div>");
1745 // Create a right click in the center of the iframe. (I'm hoping this will
1746 // make this a bit more robust in case of some other formatting or other bug.)
1747 WebMouseEvent mouse_event;
1748 mouse_event.type = WebInputEvent::MouseDown;
1749 mouse_event.button = WebMouseEvent::ButtonRight;
1750 mouse_event.x = 250;
1751 mouse_event.y = 250;
1752 mouse_event.globalX = 250;
1753 mouse_event.globalY = 250;
1755 SendWebMouseEvent(mouse_event);
1757 // Now simulate the corresponding up event which should display the menu
1758 mouse_event.type = WebInputEvent::MouseUp;
1759 SendWebMouseEvent(mouse_event);
1761 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
1762 FrameHostMsg_ContextMenu::ID));
1765 TEST_F(RenderViewImplTest, TestBackForward) {
1766 LoadHTML("<div id=pagename>Page A</div>");
1767 PageState page_a_state =
1768 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1769 int was_page_a = -1;
1770 base::string16 check_page_a =
1771 base::ASCIIToUTF16(
1772 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1773 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1774 EXPECT_EQ(1, was_page_a);
1776 LoadHTML("<div id=pagename>Page B</div>");
1777 int was_page_b = -1;
1778 base::string16 check_page_b =
1779 base::ASCIIToUTF16(
1780 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1781 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1782 EXPECT_EQ(1, was_page_b);
1784 PageState back_state =
1785 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1787 LoadHTML("<div id=pagename>Page C</div>");
1788 int was_page_c = -1;
1789 base::string16 check_page_c =
1790 base::ASCIIToUTF16(
1791 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1792 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1793 EXPECT_EQ(1, was_page_c);
1795 PageState forward_state =
1796 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1797 GoBack(back_state);
1798 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1799 EXPECT_EQ(1, was_page_b);
1801 PageState back_state2 =
1802 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1804 GoForward(forward_state);
1805 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1806 EXPECT_EQ(1, was_page_c);
1808 GoBack(back_state2);
1809 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1810 EXPECT_EQ(1, was_page_b);
1812 forward_state =
1813 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1814 GoBack(page_a_state);
1815 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1816 EXPECT_EQ(1, was_page_a);
1818 GoForward(forward_state);
1819 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1820 EXPECT_EQ(1, was_page_b);
1823 #if defined(OS_MACOSX) || defined(USE_AURA)
1824 TEST_F(RenderViewImplTest, GetCompositionCharacterBoundsTest) {
1826 #if defined(OS_WIN)
1827 // http://crbug.com/304193
1828 if (base::win::GetVersion() < base::win::VERSION_VISTA)
1829 return;
1830 #endif
1832 LoadHTML("<textarea id=\"test\"></textarea>");
1833 ExecuteJavaScript("document.getElementById('test').focus();");
1835 const base::string16 empty_string;
1836 const std::vector<blink::WebCompositionUnderline> empty_underline;
1837 std::vector<gfx::Rect> bounds;
1838 view()->OnSetFocus(true);
1839 view()->OnSetInputMethodActive(true);
1841 // ASCII composition
1842 const base::string16 ascii_composition = base::UTF8ToUTF16("aiueo");
1843 view()->OnImeSetComposition(ascii_composition, empty_underline, 0, 0);
1844 view()->GetCompositionCharacterBounds(&bounds);
1845 ASSERT_EQ(ascii_composition.size(), bounds.size());
1846 for (size_t i = 0; i < bounds.size(); ++i)
1847 EXPECT_LT(0, bounds[i].width());
1848 view()->OnImeConfirmComposition(
1849 empty_string, gfx::Range::InvalidRange(), false);
1851 // Non surrogate pair unicode character.
1852 const base::string16 unicode_composition = base::UTF8ToUTF16(
1853 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1854 view()->OnImeSetComposition(unicode_composition, empty_underline, 0, 0);
1855 view()->GetCompositionCharacterBounds(&bounds);
1856 ASSERT_EQ(unicode_composition.size(), bounds.size());
1857 for (size_t i = 0; i < bounds.size(); ++i)
1858 EXPECT_LT(0, bounds[i].width());
1859 view()->OnImeConfirmComposition(
1860 empty_string, gfx::Range::InvalidRange(), false);
1862 // Surrogate pair character.
1863 const base::string16 surrogate_pair_char =
1864 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1865 view()->OnImeSetComposition(surrogate_pair_char,
1866 empty_underline,
1869 view()->GetCompositionCharacterBounds(&bounds);
1870 ASSERT_EQ(surrogate_pair_char.size(), bounds.size());
1871 EXPECT_LT(0, bounds[0].width());
1872 EXPECT_EQ(0, bounds[1].width());
1873 view()->OnImeConfirmComposition(
1874 empty_string, gfx::Range::InvalidRange(), false);
1876 // Mixed string.
1877 const base::string16 surrogate_pair_mixed_composition =
1878 surrogate_pair_char + base::UTF8ToUTF16("\xE3\x81\x82") +
1879 surrogate_pair_char + base::UTF8ToUTF16("b") + surrogate_pair_char;
1880 const size_t utf16_length = 8UL;
1881 const bool is_surrogate_pair_empty_rect[8] = {
1882 false, true, false, false, true, false, false, true };
1883 view()->OnImeSetComposition(surrogate_pair_mixed_composition,
1884 empty_underline,
1887 view()->GetCompositionCharacterBounds(&bounds);
1888 ASSERT_EQ(utf16_length, bounds.size());
1889 for (size_t i = 0; i < utf16_length; ++i) {
1890 if (is_surrogate_pair_empty_rect[i]) {
1891 EXPECT_EQ(0, bounds[i].width());
1892 } else {
1893 EXPECT_LT(0, bounds[i].width());
1896 view()->OnImeConfirmComposition(
1897 empty_string, gfx::Range::InvalidRange(), false);
1899 #endif
1901 TEST_F(RenderViewImplTest, ZoomLimit) {
1902 const double kMinZoomLevel = ZoomFactorToZoomLevel(kMinimumZoomFactor);
1903 const double kMaxZoomLevel = ZoomFactorToZoomLevel(kMaximumZoomFactor);
1905 // Verifies navigation to a URL with preset zoom level indeed sets the level.
1906 // Regression test for http://crbug.com/139559, where the level was not
1907 // properly set when it is out of the default zoom limits of WebView.
1908 CommonNavigationParams common_params;
1909 common_params.url = GURL("data:text/html,min_zoomlimit_test");
1910 view()->OnSetZoomLevelForLoadingURL(common_params.url, kMinZoomLevel);
1911 NavigateMainFrame(common_params, StartNavigationParams(),
1912 RequestNavigationParams());
1913 ProcessPendingMessages();
1914 EXPECT_DOUBLE_EQ(kMinZoomLevel, view()->GetWebView()->zoomLevel());
1916 // It should work even when the zoom limit is temporarily changed in the page.
1917 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
1918 ZoomFactorToZoomLevel(1.0));
1919 common_params.url = GURL("data:text/html,max_zoomlimit_test");
1920 view()->OnSetZoomLevelForLoadingURL(common_params.url, kMaxZoomLevel);
1921 NavigateMainFrame(common_params, StartNavigationParams(),
1922 RequestNavigationParams());
1923 ProcessPendingMessages();
1924 EXPECT_DOUBLE_EQ(kMaxZoomLevel, view()->GetWebView()->zoomLevel());
1927 TEST_F(RenderViewImplTest, SetEditableSelectionAndComposition) {
1928 // Load an HTML page consisting of an input field.
1929 LoadHTML("<html>"
1930 "<head>"
1931 "</head>"
1932 "<body>"
1933 "<input id=\"test1\" value=\"some test text hello\"></input>"
1934 "</body>"
1935 "</html>");
1936 ExecuteJavaScript("document.getElementById('test1').focus();");
1937 SetEditableSelectionOffsets(4, 8);
1938 const std::vector<blink::WebCompositionUnderline> empty_underline;
1939 SetCompositionFromExistingText(7, 10, empty_underline);
1940 blink::WebTextInputInfo info = view()->webview()->textInputInfo();
1941 EXPECT_EQ(4, info.selectionStart);
1942 EXPECT_EQ(8, info.selectionEnd);
1943 EXPECT_EQ(7, info.compositionStart);
1944 EXPECT_EQ(10, info.compositionEnd);
1945 Unselect();
1946 info = view()->webview()->textInputInfo();
1947 EXPECT_EQ(0, info.selectionStart);
1948 EXPECT_EQ(0, info.selectionEnd);
1952 TEST_F(RenderViewImplTest, OnExtendSelectionAndDelete) {
1953 // Load an HTML page consisting of an input field.
1954 LoadHTML("<html>"
1955 "<head>"
1956 "</head>"
1957 "<body>"
1958 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
1959 "</body>"
1960 "</html>");
1961 ExecuteJavaScript("document.getElementById('test1').focus();");
1962 SetEditableSelectionOffsets(10, 10);
1963 ExtendSelectionAndDelete(3, 4);
1964 blink::WebTextInputInfo info = view()->webview()->textInputInfo();
1965 EXPECT_EQ("abcdefgopqrstuvwxyz", info.value);
1966 EXPECT_EQ(7, info.selectionStart);
1967 EXPECT_EQ(7, info.selectionEnd);
1968 SetEditableSelectionOffsets(4, 8);
1969 ExtendSelectionAndDelete(2, 5);
1970 info = view()->webview()->textInputInfo();
1971 EXPECT_EQ("abuvwxyz", info.value);
1972 EXPECT_EQ(2, info.selectionStart);
1973 EXPECT_EQ(2, info.selectionEnd);
1976 // Test that the navigating specific frames works correctly.
1977 TEST_F(RenderViewImplTest, NavigateSubframe) {
1978 // Load page A.
1979 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
1981 // Navigate the frame only.
1982 CommonNavigationParams common_params;
1983 RequestNavigationParams request_params;
1984 common_params.url = GURL("data:text/html,world");
1985 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1986 common_params.transition = ui::PAGE_TRANSITION_TYPED;
1987 request_params.current_history_list_length = 1;
1988 request_params.current_history_list_offset = 0;
1989 request_params.pending_history_list_offset = 1;
1990 request_params.page_id = -1;
1991 request_params.browser_navigation_start =
1992 base::TimeTicks::FromInternalValue(1);
1994 RenderFrameImpl* subframe = RenderFrameImpl::FromWebFrame(
1995 view()->webview()->findFrameByName("frame"));
1996 NavigateFrame(subframe, common_params, StartNavigationParams(),
1997 request_params);
1998 FrameLoadWaiter(subframe).Wait();
2000 // Copy the document content to std::wstring and compare with the
2001 // expected result.
2002 const int kMaxOutputCharacters = 256;
2003 std::string output = base::UTF16ToUTF8(
2004 GetMainFrame()->contentAsText(kMaxOutputCharacters));
2005 EXPECT_EQ(output, "hello \n\nworld");
2008 // This test ensures that a RenderFrame object is created for the top level
2009 // frame in the RenderView.
2010 TEST_F(RenderViewImplTest, BasicRenderFrame) {
2011 EXPECT_TRUE(view()->main_render_frame_);
2014 TEST_F(RenderViewImplTest, GetSSLStatusOfFrame) {
2015 LoadHTML("<!DOCTYPE html><html><body></body></html>");
2017 WebLocalFrame* frame = GetMainFrame();
2018 SSLStatus ssl_status = view()->GetSSLStatusOfFrame(frame);
2019 EXPECT_FALSE(net::IsCertStatusError(ssl_status.cert_status));
2021 const_cast<blink::WebURLResponse&>(frame->dataSource()->response()).
2022 setSecurityInfo(
2023 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS, 0, 0,
2024 SignedCertificateTimestampIDStatusList()));
2025 ssl_status = view()->GetSSLStatusOfFrame(frame);
2026 EXPECT_TRUE(net::IsCertStatusError(ssl_status.cert_status));
2029 TEST_F(RenderViewImplTest, MessageOrderInDidChangeSelection) {
2030 view()->OnSetInputMethodActive(true);
2031 view()->set_send_content_state_immediately(true);
2032 LoadHTML("<textarea id=\"test\"></textarea>");
2034 view()->handling_input_event_ = true;
2035 ExecuteJavaScript("document.getElementById('test').focus();");
2037 bool is_input_type_called = false;
2038 bool is_selection_called = false;
2039 size_t last_input_type = 0;
2040 size_t last_selection = 0;
2042 for (size_t i = 0; i < render_thread_->sink().message_count(); ++i) {
2043 const uint32 type = render_thread_->sink().GetMessageAt(i)->type();
2044 if (type == ViewHostMsg_TextInputTypeChanged::ID) {
2045 is_input_type_called = true;
2046 last_input_type = i;
2047 } else if (type == ViewHostMsg_SelectionChanged::ID) {
2048 is_selection_called = true;
2049 last_selection = i;
2053 EXPECT_TRUE(is_input_type_called);
2054 EXPECT_TRUE(is_selection_called);
2056 // InputTypeChange shold be called earlier than SelectionChanged.
2057 EXPECT_LT(last_input_type, last_selection);
2060 class SuppressErrorPageTest : public RenderViewImplTest {
2061 public:
2062 ContentRendererClient* CreateContentRendererClient() override {
2063 return new TestContentRendererClient;
2066 RenderViewImpl* view() {
2067 return static_cast<RenderViewImpl*>(view_);
2070 RenderFrameImpl* frame() {
2071 return static_cast<RenderFrameImpl*>(view()->GetMainRenderFrame());
2074 private:
2075 class TestContentRendererClient : public ContentRendererClient {
2076 public:
2077 bool ShouldSuppressErrorPage(RenderFrame* render_frame,
2078 const GURL& url) override {
2079 return url == GURL("http://example.com/suppress");
2082 void GetNavigationErrorStrings(content::RenderView* render_view,
2083 blink::WebFrame* frame,
2084 const blink::WebURLRequest& failed_request,
2085 const blink::WebURLError& error,
2086 std::string* error_html,
2087 base::string16* error_description) override {
2088 if (error_html)
2089 *error_html = "A suffusion of yellow.";
2094 #if defined(OS_ANDROID)
2095 // Crashing on Android: http://crbug.com/311341
2096 #define MAYBE_Suppresses DISABLED_Suppresses
2097 #else
2098 #define MAYBE_Suppresses Suppresses
2099 #endif
2101 TEST_F(SuppressErrorPageTest, MAYBE_Suppresses) {
2102 WebURLError error;
2103 error.domain = WebString::fromUTF8(net::kErrorDomain);
2104 error.reason = net::ERR_FILE_NOT_FOUND;
2105 error.unreachableURL = GURL("http://example.com/suppress");
2106 WebLocalFrame* web_frame = GetMainFrame();
2108 // Start a load that will reach provisional state synchronously,
2109 // but won't complete synchronously.
2110 CommonNavigationParams common_params;
2111 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2112 common_params.url = GURL("data:text/html,test data");
2113 NavigateMainFrame(common_params, StartNavigationParams(),
2114 RequestNavigationParams());
2116 // An error occurred.
2117 view()->GetMainRenderFrame()->didFailProvisionalLoad(
2118 web_frame, error, blink::WebStandardCommit);
2119 const int kMaxOutputCharacters = 22;
2120 EXPECT_EQ("",
2121 base::UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters)));
2124 #if defined(OS_ANDROID)
2125 // Crashing on Android: http://crbug.com/311341
2126 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2127 #else
2128 #define MAYBE_DoesNotSuppress DoesNotSuppress
2129 #endif
2131 TEST_F(SuppressErrorPageTest, MAYBE_DoesNotSuppress) {
2132 WebURLError error;
2133 error.domain = WebString::fromUTF8(net::kErrorDomain);
2134 error.reason = net::ERR_FILE_NOT_FOUND;
2135 error.unreachableURL = GURL("http://example.com/dont-suppress");
2136 WebLocalFrame* web_frame = GetMainFrame();
2138 // Start a load that will reach provisional state synchronously,
2139 // but won't complete synchronously.
2140 CommonNavigationParams common_params;
2141 common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2142 common_params.url = GURL("data:text/html,test data");
2143 NavigateMainFrame(common_params, StartNavigationParams(),
2144 RequestNavigationParams());
2146 // An error occurred.
2147 view()->GetMainRenderFrame()->didFailProvisionalLoad(
2148 web_frame, error, blink::WebStandardCommit);
2149 // The error page itself is loaded asynchronously.
2150 FrameLoadWaiter(frame()).Wait();
2151 const int kMaxOutputCharacters = 22;
2152 EXPECT_EQ("A suffusion of yellow.",
2153 base::UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters)));
2156 // Tests if IME API's candidatewindow* events sent from browser are handled
2157 // in renderer.
2158 TEST_F(RenderViewImplTest, SendCandidateWindowEvents) {
2159 // Sends an HTML with an <input> element and scripts to the renderer.
2160 // The script handles all 3 of candidatewindow* events for an
2161 // InputMethodContext object and once it received 'show', 'update', 'hide'
2162 // should appear in the result div.
2163 LoadHTML("<input id='test'>"
2164 "<div id='result'>Result: </div>"
2165 "<script>"
2166 "window.onload = function() {"
2167 " var result = document.getElementById('result');"
2168 " var test = document.getElementById('test');"
2169 " test.focus();"
2170 " var context = test.inputMethodContext;"
2171 " if (context) {"
2172 " context.oncandidatewindowshow = function() {"
2173 " result.innerText += 'show'; };"
2174 " context.oncandidatewindowupdate = function(){"
2175 " result.innerText += 'update'; };"
2176 " context.oncandidatewindowhide = function(){"
2177 " result.innerText += 'hide'; };"
2178 " }"
2179 "};"
2180 "</script>");
2182 // Fire candidatewindow events.
2183 view()->OnCandidateWindowShown();
2184 view()->OnCandidateWindowUpdated();
2185 view()->OnCandidateWindowHidden();
2187 // Retrieve the content and check if it is expected.
2188 const int kMaxOutputCharacters = 50;
2189 std::string output = base::UTF16ToUTF8(
2190 GetMainFrame()->contentAsText(kMaxOutputCharacters));
2191 EXPECT_EQ(output, "\nResult:showupdatehide");
2194 // Ensure the render view sends favicon url update events correctly.
2195 TEST_F(RenderViewImplTest, SendFaviconURLUpdateEvent) {
2196 // An event should be sent when a favicon url exists.
2197 LoadHTML("<html>"
2198 "<head>"
2199 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2200 "</head>"
2201 "</html>");
2202 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
2203 ViewHostMsg_UpdateFaviconURL::ID));
2204 render_thread_->sink().ClearMessages();
2206 // An event should not be sent if no favicon url exists. This is an assumption
2207 // made by some of Chrome's favicon handling.
2208 LoadHTML("<html>"
2209 "<head>"
2210 "</head>"
2211 "</html>");
2212 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
2213 ViewHostMsg_UpdateFaviconURL::ID));
2216 TEST_F(RenderViewImplTest, FocusElementCallsFocusedNodeChanged) {
2217 LoadHTML("<input id='test1' value='hello1'></input>"
2218 "<input id='test2' value='hello2'></input>");
2220 ExecuteJavaScript("document.getElementById('test1').focus();");
2221 const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
2222 ViewHostMsg_FocusedNodeChanged::ID);
2223 EXPECT_TRUE(msg1);
2225 ViewHostMsg_FocusedNodeChanged::Param params;
2226 ViewHostMsg_FocusedNodeChanged::Read(msg1, &params);
2227 EXPECT_TRUE(get<0>(params));
2228 render_thread_->sink().ClearMessages();
2230 ExecuteJavaScript("document.getElementById('test2').focus();");
2231 const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching(
2232 ViewHostMsg_FocusedNodeChanged::ID);
2233 EXPECT_TRUE(msg2);
2234 ViewHostMsg_FocusedNodeChanged::Read(msg2, &params);
2235 EXPECT_TRUE(get<0>(params));
2236 render_thread_->sink().ClearMessages();
2238 view()->webview()->clearFocusedElement();
2239 const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching(
2240 ViewHostMsg_FocusedNodeChanged::ID);
2241 EXPECT_TRUE(msg3);
2242 ViewHostMsg_FocusedNodeChanged::Read(msg3, &params);
2243 EXPECT_FALSE(get<0>(params));
2244 render_thread_->sink().ClearMessages();
2247 TEST_F(RenderViewImplTest, ServiceWorkerNetworkProviderSetup) {
2248 ServiceWorkerNetworkProvider* provider = NULL;
2249 RequestExtraData* extra_data = NULL;
2251 // Make sure each new document has a new provider and
2252 // that the main request is tagged with the provider's id.
2253 LoadHTML("<b>A Document</b>");
2254 ASSERT_TRUE(GetMainFrame()->dataSource());
2255 provider = ServiceWorkerNetworkProvider::FromDocumentState(
2256 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2257 ASSERT_TRUE(provider);
2258 extra_data = static_cast<RequestExtraData*>(
2259 GetMainFrame()->dataSource()->request().extraData());
2260 ASSERT_TRUE(extra_data);
2261 EXPECT_EQ(extra_data->service_worker_provider_id(),
2262 provider->provider_id());
2263 int provider1_id = provider->provider_id();
2265 LoadHTML("<b>New Document B Goes Here</b>");
2266 ASSERT_TRUE(GetMainFrame()->dataSource());
2267 provider = ServiceWorkerNetworkProvider::FromDocumentState(
2268 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2269 ASSERT_TRUE(provider);
2270 EXPECT_NE(provider1_id, provider->provider_id());
2271 extra_data = static_cast<RequestExtraData*>(
2272 GetMainFrame()->dataSource()->request().extraData());
2273 ASSERT_TRUE(extra_data);
2274 EXPECT_EQ(extra_data->service_worker_provider_id(),
2275 provider->provider_id());
2277 // See that subresource requests are also tagged with the provider's id.
2278 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2279 blink::WebURLRequest request(GURL("http://foo.com"));
2280 request.setRequestContext(blink::WebURLRequest::RequestContextSubresource);
2281 blink::WebURLResponse redirect_response;
2282 frame()->willSendRequest(GetMainFrame(), 0, request, redirect_response);
2283 extra_data = static_cast<RequestExtraData*>(request.extraData());
2284 ASSERT_TRUE(extra_data);
2285 EXPECT_EQ(extra_data->service_worker_provider_id(),
2286 provider->provider_id());
2289 TEST_F(RenderViewImplTest, OnSetAccessibilityMode) {
2290 ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
2291 ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2293 SetAccessibilityMode(AccessibilityModeTreeOnly);
2294 ASSERT_EQ(AccessibilityModeTreeOnly, frame()->accessibility_mode());
2295 ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2297 SetAccessibilityMode(AccessibilityModeOff);
2298 ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
2299 ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2301 SetAccessibilityMode(AccessibilityModeComplete);
2302 ASSERT_EQ(AccessibilityModeComplete, frame()->accessibility_mode());
2303 ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2306 TEST_F(RenderViewImplTest, ScreenMetricsEmulation) {
2307 LoadHTML("<body style='min-height:1000px;'></body>");
2309 blink::WebDeviceEmulationParams params;
2310 base::string16 get_width = base::ASCIIToUTF16("Number(window.innerWidth)");
2311 base::string16 get_height = base::ASCIIToUTF16("Number(window.innerHeight)");
2312 int width, height;
2314 params.viewSize.width = 327;
2315 params.viewSize.height = 415;
2316 view()->OnEnableDeviceEmulation(params);
2317 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width));
2318 EXPECT_EQ(params.viewSize.width, width);
2319 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height));
2320 EXPECT_EQ(params.viewSize.height, height);
2322 params.viewSize.width = 1005;
2323 params.viewSize.height = 1102;
2324 view()->OnEnableDeviceEmulation(params);
2325 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width));
2326 EXPECT_EQ(params.viewSize.width, width);
2327 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height));
2328 EXPECT_EQ(params.viewSize.height, height);
2330 view()->OnDisableDeviceEmulation();
2332 view()->OnEnableDeviceEmulation(params);
2333 // Don't disable here to test that emulation is being shutdown properly.
2336 // Sanity checks for the Navigation Timing API |navigationStart| override. We
2337 // are asserting only most basic constraints, as TimeTicks (passed as the
2338 // override) are not comparable with the wall time (returned by the Blink API).
2339 TEST_F(RenderViewImplTest, NavigationStartOverride) {
2340 // Verify that a navigation that claims to have started at the earliest
2341 // possible TimeTicks is indeed reported as one that started before
2342 // OnNavigate() is called.
2343 base::Time before_navigation = base::Time::Now();
2344 CommonNavigationParams early_common_params;
2345 StartNavigationParams early_start_params;
2346 RequestNavigationParams early_request_params;
2347 early_common_params.url = GURL("data:text/html,<div>Page</div>");
2348 early_common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2349 early_common_params.transition = ui::PAGE_TRANSITION_TYPED;
2350 early_start_params.is_post = true;
2351 early_request_params.browser_navigation_start =
2352 base::TimeTicks::FromInternalValue(1);
2354 NavigateMainFrame(early_common_params, early_start_params,
2355 early_request_params);
2356 ProcessPendingMessages();
2358 base::Time early_nav_reported_start =
2359 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2360 EXPECT_LT(early_nav_reported_start, before_navigation);
2362 // Verify that a navigation that claims to have started in the future - 42
2363 // days from now is *not* reported as one that starts in the future; as we
2364 // sanitize the override allowing a maximum of ::Now().
2365 CommonNavigationParams late_common_params;
2366 RequestNavigationParams late_request_params;
2367 StartNavigationParams late_start_params;
2368 late_common_params.url = GURL("data:text/html,<div>Another page</div>");
2369 late_common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2370 late_common_params.transition = ui::PAGE_TRANSITION_TYPED;
2371 late_start_params.is_post = true;
2372 late_request_params.browser_navigation_start =
2373 base::TimeTicks::Now() + base::TimeDelta::FromDays(42);
2375 NavigateMainFrame(late_common_params, late_start_params, late_request_params);
2376 ProcessPendingMessages();
2377 base::Time after_navigation =
2378 base::Time::Now() + base::TimeDelta::FromDays(1);
2380 base::Time late_nav_reported_start =
2381 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2382 EXPECT_LE(late_nav_reported_start, after_navigation);
2385 TEST_F(RenderViewImplTest, PreferredSizeZoomed) {
2386 LoadHTML("<body style='margin:0;'><div style='display:inline-block; "
2387 "width:400px; height:400px;'/></body>");
2388 view()->webview()->mainFrame()->setCanHaveScrollbars(false);
2389 EnablePreferredSizeMode();
2391 gfx::Size size = GetPreferredSize();
2392 EXPECT_EQ(gfx::Size(400, 400), size);
2394 SetZoomLevel(ZoomFactorToZoomLevel(2.0));
2395 size = GetPreferredSize();
2396 EXPECT_EQ(gfx::Size(800, 800), size);
2399 // Ensure the RenderViewImpl history list is properly updated when starting a
2400 // new browser-initiated navigation.
2401 TEST_F(RenderViewImplTest, HistoryIsProperlyUpdatedOnNavigation) {
2402 EXPECT_EQ(0, view()->historyBackListCount());
2403 EXPECT_EQ(0, view()->historyBackListCount() +
2404 view()->historyForwardListCount() + 1);
2406 // Receive a Navigate message with history parameters.
2407 RequestNavigationParams request_params;
2408 request_params.current_history_list_length = 2;
2409 request_params.current_history_list_offset = 1;
2410 request_params.pending_history_list_offset = 2;
2411 request_params.page_id = -1;
2412 NavigateMainFrame(CommonNavigationParams(), StartNavigationParams(),
2413 request_params);
2415 // The history list in RenderView should have been updated.
2416 EXPECT_EQ(1, view()->historyBackListCount());
2417 EXPECT_EQ(2, view()->historyBackListCount() +
2418 view()->historyForwardListCount() + 1);
2421 TEST_F(DevToolsAgentTest, DevToolsResumeOnClose) {
2422 Attach();
2423 EXPECT_FALSE(IsPaused());
2424 DispatchDevToolsMessage("{\"id\":1,\"method\":\"Debugger.enable\"}");
2426 // Executing javascript will pause the thread and create nested message loop.
2427 // Posting task simulates message coming from browser.
2428 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
2429 &DevToolsAgentTest::CloseWhilePaused, base::Unretained(this)));
2430 ExecuteJavaScript("debugger;");
2432 // CloseWhilePaused should resume execution and continue here.
2433 EXPECT_FALSE(IsPaused());
2434 Detach();
2437 } // namespace content