Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / renderer / render_view_browsertest.cc
blob6b8232db120b2e3699b59ed93f8aec762391c925
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/page_zoom.h"
23 #include "content/public/common/url_constants.h"
24 #include "content/public/common/url_utils.h"
25 #include "content/public/renderer/content_renderer_client.h"
26 #include "content/public/renderer/document_state.h"
27 #include "content/public/renderer/navigation_state.h"
28 #include "content/public/test/browser_test_utils.h"
29 #include "content/public/test/render_view_test.h"
30 #include "content/public/test/test_utils.h"
31 #include "content/renderer/accessibility/renderer_accessibility.h"
32 #include "content/renderer/accessibility/renderer_accessibility_complete.h"
33 #include "content/renderer/accessibility/renderer_accessibility_focus_only.h"
34 #include "content/renderer/history_controller.h"
35 #include "content/renderer/history_serialization.h"
36 #include "content/renderer/render_process.h"
37 #include "content/renderer/render_view_impl.h"
38 #include "content/shell/browser/shell.h"
39 #include "content/shell/browser/shell_browser_context.h"
40 #include "content/test/frame_load_waiter.h"
41 #include "content/test/mock_keyboard.h"
42 #include "net/base/net_errors.h"
43 #include "net/cert/cert_status_flags.h"
44 #include "testing/gtest/include/gtest/gtest.h"
45 #include "third_party/WebKit/public/platform/WebData.h"
46 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
47 #include "third_party/WebKit/public/platform/WebString.h"
48 #include "third_party/WebKit/public/platform/WebURLResponse.h"
49 #include "third_party/WebKit/public/web/WebDataSource.h"
50 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
51 #include "third_party/WebKit/public/web/WebHistoryItem.h"
52 #include "third_party/WebKit/public/web/WebLocalFrame.h"
53 #include "third_party/WebKit/public/web/WebPerformance.h"
54 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
55 #include "third_party/WebKit/public/web/WebView.h"
56 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
57 #include "ui/events/keycodes/keyboard_codes.h"
58 #include "ui/gfx/codec/jpeg_codec.h"
59 #include "ui/gfx/range/range.h"
61 #if defined(USE_AURA)
62 #include "ui/events/event.h"
63 #endif
65 #if defined(USE_AURA) && defined(USE_X11)
66 #include <X11/Xlib.h>
67 #include "ui/events/event_constants.h"
68 #include "ui/events/keycodes/keyboard_code_conversion.h"
69 #include "ui/events/test/events_test_utils.h"
70 #include "ui/events/test/events_test_utils_x11.h"
71 #endif
73 #if defined(USE_OZONE)
74 #include "ui/events/keycodes/keyboard_code_conversion.h"
75 #endif
77 using blink::WebFrame;
78 using blink::WebInputEvent;
79 using blink::WebLocalFrame;
80 using blink::WebMouseEvent;
81 using blink::WebRuntimeFeatures;
82 using blink::WebString;
83 using blink::WebTextDirection;
84 using blink::WebURLError;
86 namespace content {
88 namespace {
90 static const int kProxyRoutingId = 13;
92 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
93 // Converts MockKeyboard::Modifiers to ui::EventFlags.
94 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers) {
95 static struct ModifierMap {
96 MockKeyboard::Modifiers src;
97 int dst;
98 } kModifierMap[] = {
99 { MockKeyboard::LEFT_SHIFT, ui::EF_SHIFT_DOWN },
100 { MockKeyboard::RIGHT_SHIFT, ui::EF_SHIFT_DOWN },
101 { MockKeyboard::LEFT_CONTROL, ui::EF_CONTROL_DOWN },
102 { MockKeyboard::RIGHT_CONTROL, ui::EF_CONTROL_DOWN },
103 { MockKeyboard::LEFT_ALT, ui::EF_ALT_DOWN },
104 { MockKeyboard::RIGHT_ALT, ui::EF_ALT_DOWN },
106 int flags = 0;
107 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kModifierMap); ++i) {
108 if (kModifierMap[i].src & modifiers) {
109 flags |= kModifierMap[i].dst;
112 return flags;
114 #endif
116 class WebUITestWebUIControllerFactory : public WebUIControllerFactory {
117 public:
118 virtual WebUIController* CreateWebUIControllerForURL(
119 WebUI* web_ui, const GURL& url) const OVERRIDE {
120 return NULL;
122 virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
123 const GURL& url) const OVERRIDE {
124 return WebUI::kNoWebUI;
126 virtual bool UseWebUIForURL(BrowserContext* browser_context,
127 const GURL& url) const OVERRIDE {
128 return HasWebUIScheme(url);
130 virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
131 const GURL& url) const OVERRIDE {
132 return HasWebUIScheme(url);
136 } // namespace
138 class RenderViewImplTest : public RenderViewTest {
139 public:
140 RenderViewImplTest() {
141 // Attach a pseudo keyboard device to this object.
142 mock_keyboard_.reset(new MockKeyboard());
145 virtual ~RenderViewImplTest() {}
147 virtual void SetUp() OVERRIDE {
148 RenderViewTest::SetUp();
149 // Enable Blink's experimental and test only features so that test code
150 // does not have to bother enabling each feature.
151 WebRuntimeFeatures::enableExperimentalFeatures(true);
152 WebRuntimeFeatures::enableTestOnlyFeatures(true);
155 RenderViewImpl* view() {
156 return static_cast<RenderViewImpl*>(view_);
159 int view_page_id() {
160 return view()->page_id_;
163 RenderFrameImpl* frame() {
164 return static_cast<RenderFrameImpl*>(view()->GetMainRenderFrame());
167 // Sends IPC messages that emulates a key-press event.
168 int SendKeyEvent(MockKeyboard::Layout layout,
169 int key_code,
170 MockKeyboard::Modifiers modifiers,
171 base::string16* output) {
172 #if defined(OS_WIN)
173 // Retrieve the Unicode character for the given tuple (keyboard-layout,
174 // key-code, and modifiers).
175 // Exit when a keyboard-layout driver cannot assign a Unicode character to
176 // the tuple to prevent sending an invalid key code to the RenderView
177 // object.
178 CHECK(mock_keyboard_.get());
179 CHECK(output);
180 int length = mock_keyboard_->GetCharacters(layout, key_code, modifiers,
181 output);
182 if (length != 1)
183 return -1;
185 // Create IPC messages from Windows messages and send them to our
186 // back-end.
187 // A keyboard event of Windows consists of three Windows messages:
188 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
189 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
190 // WM_CHAR sends a composed Unicode character.
191 MSG msg1 = { NULL, WM_KEYDOWN, key_code, 0 };
192 #if defined(USE_AURA)
193 ui::KeyEvent evt1(msg1);
194 NativeWebKeyboardEvent keydown_event(&evt1);
195 #else
196 NativeWebKeyboardEvent keydown_event(msg1);
197 #endif
198 SendNativeKeyEvent(keydown_event);
200 MSG msg2 = { NULL, WM_CHAR, (*output)[0], 0 };
201 #if defined(USE_AURA)
202 ui::KeyEvent evt2(msg2);
203 NativeWebKeyboardEvent char_event(&evt2);
204 #else
205 NativeWebKeyboardEvent char_event(msg2);
206 #endif
207 SendNativeKeyEvent(char_event);
209 MSG msg3 = { NULL, WM_KEYUP, key_code, 0 };
210 #if defined(USE_AURA)
211 ui::KeyEvent evt3(msg3);
212 NativeWebKeyboardEvent keyup_event(&evt3);
213 #else
214 NativeWebKeyboardEvent keyup_event(msg3);
215 #endif
216 SendNativeKeyEvent(keyup_event);
218 return length;
219 #elif defined(USE_AURA) && defined(USE_X11)
220 // We ignore |layout|, which means we are only testing the layout of the
221 // current locale. TODO(mazda): fix this to respect |layout|.
222 CHECK(output);
223 const int flags = ConvertMockKeyboardModifier(modifiers);
225 ui::ScopedXI2Event xevent;
226 xevent.InitKeyEvent(ui::ET_KEY_PRESSED,
227 static_cast<ui::KeyboardCode>(key_code),
228 flags);
229 ui::KeyEvent event1(xevent);
230 NativeWebKeyboardEvent keydown_event(&event1);
231 SendNativeKeyEvent(keydown_event);
233 // X11 doesn't actually have native character events, but give the test
234 // what it wants.
235 xevent.InitKeyEvent(ui::ET_KEY_PRESSED,
236 static_cast<ui::KeyboardCode>(key_code),
237 flags);
238 ui::KeyEvent event2(xevent);
239 ui::KeyEventTestApi test_event2(&event2);
240 test_event2.set_is_char(true);
241 NativeWebKeyboardEvent char_event(&event2);
242 SendNativeKeyEvent(char_event);
244 xevent.InitKeyEvent(ui::ET_KEY_RELEASED,
245 static_cast<ui::KeyboardCode>(key_code),
246 flags);
247 ui::KeyEvent event3(xevent);
248 NativeWebKeyboardEvent keyup_event(&event3);
249 SendNativeKeyEvent(keyup_event);
251 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
252 flags);
253 output->assign(1, static_cast<base::char16>(c));
254 return 1;
255 #elif defined(USE_OZONE)
256 const int flags = ConvertMockKeyboardModifier(modifiers);
258 // Ozone's native events are ui::Events. So first create the "native" event,
259 // then create the actual ui::KeyEvent with the native event.
260 ui::KeyEvent keydown_native_event(ui::ET_KEY_PRESSED,
261 static_cast<ui::KeyboardCode>(key_code),
262 flags);
263 ui::KeyEvent keydown_event(&keydown_native_event);
264 NativeWebKeyboardEvent keydown_web_event(&keydown_event);
265 SendNativeKeyEvent(keydown_web_event);
267 ui::KeyEvent char_native_event(static_cast<base::char16>(key_code),
268 static_cast<ui::KeyboardCode>(key_code),
269 flags);
270 ui::KeyEvent char_event(&char_native_event);
271 NativeWebKeyboardEvent char_web_event(&char_event);
272 SendNativeKeyEvent(char_web_event);
274 ui::KeyEvent keyup_native_event(ui::ET_KEY_RELEASED,
275 static_cast<ui::KeyboardCode>(key_code),
276 flags);
277 ui::KeyEvent keyup_event(&keyup_native_event);
278 NativeWebKeyboardEvent keyup_web_event(&keyup_event);
279 SendNativeKeyEvent(keyup_web_event);
281 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
282 flags);
283 output->assign(1, static_cast<base::char16>(c));
284 return 1;
285 #else
286 NOTIMPLEMENTED();
287 return L'\0';
288 #endif
291 private:
292 scoped_ptr<MockKeyboard> mock_keyboard_;
295 // Test that we get form state change notifications when input fields change.
296 TEST_F(RenderViewImplTest, DISABLED_OnNavStateChanged) {
297 // Don't want any delay for form state sync changes. This will still post a
298 // message so updates will get coalesced, but as soon as we spin the message
299 // loop, it will generate an update.
300 view()->set_send_content_state_immediately(true);
302 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
304 // We should NOT have gotten a form state change notification yet.
305 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
306 ViewHostMsg_UpdateState::ID));
307 render_thread_->sink().ClearMessages();
309 // Change the value of the input. We should have gotten an update state
310 // notification. We need to spin the message loop to catch this update.
311 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';");
312 ProcessPendingMessages();
313 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
314 ViewHostMsg_UpdateState::ID));
317 TEST_F(RenderViewImplTest, OnNavigationHttpPost) {
318 FrameMsg_Navigate_Params nav_params;
320 // An http url will trigger a resource load so cannot be used here.
321 nav_params.url = GURL("data:text/html,<div>Page</div>");
322 nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
323 nav_params.transition = PAGE_TRANSITION_TYPED;
324 nav_params.page_id = -1;
325 nav_params.is_post = true;
326 nav_params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
328 // Set up post data.
329 const unsigned char* raw_data = reinterpret_cast<const unsigned char*>(
330 "post \0\ndata");
331 const unsigned int length = 11;
332 const std::vector<unsigned char> post_data(raw_data, raw_data + length);
333 nav_params.browser_initiated_post_data = post_data;
335 frame()->OnNavigate(nav_params);
336 ProcessPendingMessages();
338 const IPC::Message* frame_navigate_msg =
339 render_thread_->sink().GetUniqueMessageMatching(
340 FrameHostMsg_DidCommitProvisionalLoad::ID);
341 EXPECT_TRUE(frame_navigate_msg);
343 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params;
344 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
345 &host_nav_params);
346 EXPECT_TRUE(host_nav_params.a.is_post);
348 // Check post data sent to browser matches
349 EXPECT_TRUE(host_nav_params.a.page_state.IsValid());
350 scoped_ptr<HistoryEntry> entry =
351 PageStateToHistoryEntry(host_nav_params.a.page_state);
352 blink::WebHTTPBody body = entry->root().httpBody();
353 blink::WebHTTPBody::Element element;
354 bool successful = body.elementAt(0, element);
355 EXPECT_TRUE(successful);
356 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData, element.type);
357 EXPECT_EQ(length, element.data.size());
358 EXPECT_EQ(0, memcmp(raw_data, element.data.data(), length));
361 TEST_F(RenderViewImplTest, DecideNavigationPolicy) {
362 WebUITestWebUIControllerFactory factory;
363 WebUIControllerFactory::RegisterFactory(&factory);
365 DocumentState state;
366 state.set_navigation_state(NavigationState::CreateContentInitiated());
368 // Navigations to normal HTTP URLs can be handled locally.
369 blink::WebURLRequest request(GURL("http://foo.com"));
370 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
371 policy_info.frame = GetMainFrame();
372 policy_info.extraData = &state;
373 policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
374 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
375 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
376 policy_info);
377 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab, policy);
379 // Verify that form posts to WebUI URLs will be sent to the browser process.
380 blink::WebURLRequest form_request(GURL("chrome://foo"));
381 blink::WebFrameClient::NavigationPolicyInfo form_policy_info(form_request);
382 form_policy_info.frame = GetMainFrame();
383 form_policy_info.extraData = &state;
384 form_policy_info.navigationType = blink::WebNavigationTypeFormSubmitted;
385 form_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
386 form_request.setHTTPMethod("POST");
387 policy = frame()->decidePolicyForNavigation(form_policy_info);
388 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
390 // Verify that popup links to WebUI URLs also are sent to browser.
391 blink::WebURLRequest popup_request(GURL("chrome://foo"));
392 blink::WebFrameClient::NavigationPolicyInfo popup_policy_info(popup_request);
393 popup_policy_info.frame = GetMainFrame();
394 popup_policy_info.extraData = &state;
395 popup_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
396 popup_policy_info.defaultPolicy = blink::WebNavigationPolicyNewForegroundTab;
397 policy = frame()->decidePolicyForNavigation(popup_policy_info);
398 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
401 TEST_F(RenderViewImplTest, DecideNavigationPolicyHandlesAllTopLevel) {
402 DocumentState state;
403 state.set_navigation_state(NavigationState::CreateContentInitiated());
405 RendererPreferences prefs = view()->renderer_preferences();
406 prefs.browser_handles_all_top_level_requests = true;
407 view()->OnSetRendererPrefs(prefs);
409 const blink::WebNavigationType kNavTypes[] = {
410 blink::WebNavigationTypeLinkClicked,
411 blink::WebNavigationTypeFormSubmitted,
412 blink::WebNavigationTypeBackForward,
413 blink::WebNavigationTypeReload,
414 blink::WebNavigationTypeFormResubmitted,
415 blink::WebNavigationTypeOther,
418 blink::WebURLRequest request(GURL("http://foo.com"));
419 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
420 policy_info.frame = GetMainFrame();
421 policy_info.extraData = &state;
422 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
424 for (size_t i = 0; i < arraysize(kNavTypes); ++i) {
425 policy_info.navigationType = kNavTypes[i];
427 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
428 policy_info);
429 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
433 TEST_F(RenderViewImplTest, DecideNavigationPolicyForWebUI) {
434 // Enable bindings to simulate a WebUI view.
435 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI);
437 DocumentState state;
438 state.set_navigation_state(NavigationState::CreateContentInitiated());
440 // Navigations to normal HTTP URLs will be sent to browser process.
441 blink::WebURLRequest request(GURL("http://foo.com"));
442 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
443 policy_info.frame = GetMainFrame();
444 policy_info.extraData = &state;
445 policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
446 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
448 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
449 policy_info);
450 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
452 // Navigations to WebUI URLs will also be sent to browser process.
453 blink::WebURLRequest webui_request(GURL("chrome://foo"));
454 blink::WebFrameClient::NavigationPolicyInfo webui_policy_info(webui_request);
455 webui_policy_info.frame = GetMainFrame();
456 webui_policy_info.extraData = &state;
457 webui_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
458 webui_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
459 policy = frame()->decidePolicyForNavigation(webui_policy_info);
460 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
462 // Verify that form posts to data URLs will be sent to the browser process.
463 blink::WebURLRequest data_request(GURL("data:text/html,foo"));
464 blink::WebFrameClient::NavigationPolicyInfo data_policy_info(data_request);
465 data_policy_info.frame = GetMainFrame();
466 data_policy_info.extraData = &state;
467 data_policy_info.navigationType = blink::WebNavigationTypeFormSubmitted;
468 data_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
469 data_request.setHTTPMethod("POST");
470 policy = frame()->decidePolicyForNavigation(data_policy_info);
471 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
473 // Verify that a popup that creates a view first and then navigates to a
474 // normal HTTP URL will be sent to the browser process, even though the
475 // new view does not have any enabled_bindings_.
476 blink::WebURLRequest popup_request(GURL("http://foo.com"));
477 blink::WebView* new_web_view = view()->createView(
478 GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
479 blink::WebNavigationPolicyNewForegroundTab, false);
480 RenderViewImpl* new_view = RenderViewImpl::FromWebView(new_web_view);
481 blink::WebFrameClient::NavigationPolicyInfo popup_policy_info(popup_request);
482 popup_policy_info.frame = new_web_view->mainFrame()->toWebLocalFrame();
483 popup_policy_info.extraData = &state;
484 popup_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
485 popup_policy_info.defaultPolicy = blink::WebNavigationPolicyNewForegroundTab;
486 policy = static_cast<RenderFrameImpl*>(new_view->GetMainRenderFrame())->
487 decidePolicyForNavigation(popup_policy_info);
488 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
490 // Clean up after the new view so we don't leak it.
491 new_view->Close();
492 new_view->Release();
495 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
496 // already swapped out. http://crbug.com/93427.
497 TEST_F(RenderViewImplTest, SendSwapOutACK) {
498 LoadHTML("<div>Page A</div>");
499 int initial_page_id = view_page_id();
501 // Increment the ref count so that we don't exit when swapping out.
502 RenderProcess::current()->AddRefProcess();
504 // Respond to a swap out request.
505 view()->main_render_frame()->OnSwapOut(kProxyRoutingId);
507 // Ensure the swap out commits synchronously.
508 EXPECT_NE(initial_page_id, view_page_id());
510 // Check for a valid OnSwapOutACK.
511 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
512 FrameHostMsg_SwapOut_ACK::ID);
513 ASSERT_TRUE(msg);
515 // It is possible to get another swap out request. Ensure that we send
516 // an ACK, even if we don't have to do anything else.
517 render_thread_->sink().ClearMessages();
518 view()->main_render_frame()->OnSwapOut(kProxyRoutingId);
519 const IPC::Message* msg2 = render_thread_->sink().GetUniqueMessageMatching(
520 FrameHostMsg_SwapOut_ACK::ID);
521 ASSERT_TRUE(msg2);
523 // If we navigate back to this RenderView, ensure we don't send a state
524 // update for the swapped out URL. (http://crbug.com/72235)
525 FrameMsg_Navigate_Params nav_params;
526 nav_params.url = GURL("data:text/html,<div>Page B</div>");
527 nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
528 nav_params.transition = PAGE_TRANSITION_TYPED;
529 nav_params.current_history_list_length = 1;
530 nav_params.current_history_list_offset = 0;
531 nav_params.pending_history_list_offset = 1;
532 nav_params.page_id = -1;
533 nav_params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
534 frame()->OnNavigate(nav_params);
535 ProcessPendingMessages();
536 const IPC::Message* msg3 = render_thread_->sink().GetUniqueMessageMatching(
537 ViewHostMsg_UpdateState::ID);
538 EXPECT_FALSE(msg3);
541 // Ensure the RenderViewImpl reloads the previous page if a reload request
542 // arrives while it is showing swappedout://. http://crbug.com/143155.
543 TEST_F(RenderViewImplTest, ReloadWhileSwappedOut) {
544 // Load page A.
545 LoadHTML("<div>Page A</div>");
547 // Load page B, which will trigger an UpdateState message for page A.
548 LoadHTML("<div>Page B</div>");
550 // Check for a valid UpdateState message for page A.
551 ProcessPendingMessages();
552 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
553 ViewHostMsg_UpdateState::ID);
554 ASSERT_TRUE(msg_A);
555 ViewHostMsg_UpdateState::Param params;
556 ViewHostMsg_UpdateState::Read(msg_A, &params);
557 int page_id_A = params.a;
558 PageState state_A = params.b;
559 EXPECT_EQ(1, page_id_A);
560 render_thread_->sink().ClearMessages();
562 // Back to page A (page_id 1) and commit.
563 FrameMsg_Navigate_Params params_A;
564 params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL;
565 params_A.transition = PAGE_TRANSITION_FORWARD_BACK;
566 params_A.current_history_list_length = 2;
567 params_A.current_history_list_offset = 1;
568 params_A.pending_history_list_offset = 0;
569 params_A.page_id = 1;
570 params_A.page_state = state_A;
571 params_A.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
572 frame()->OnNavigate(params_A);
573 ProcessPendingMessages();
575 // Respond to a swap out request.
576 view()->main_render_frame()->OnSwapOut(kProxyRoutingId);
578 // Check for a OnSwapOutACK.
579 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
580 FrameHostMsg_SwapOut_ACK::ID);
581 ASSERT_TRUE(msg);
582 render_thread_->sink().ClearMessages();
584 // It is possible to get a reload request at this point, containing the
585 // params.page_state of the initial page (e.g., if the new page fails the
586 // provisional load in the renderer process, after we unload the old page).
587 // Ensure the old page gets reloaded, not swappedout://.
588 FrameMsg_Navigate_Params nav_params;
589 nav_params.url = GURL("data:text/html,<div>Page A</div>");
590 nav_params.navigation_type = FrameMsg_Navigate_Type::RELOAD;
591 nav_params.transition = PAGE_TRANSITION_RELOAD;
592 nav_params.current_history_list_length = 2;
593 nav_params.current_history_list_offset = 0;
594 nav_params.pending_history_list_offset = 0;
595 nav_params.page_id = 1;
596 nav_params.page_state = state_A;
597 nav_params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
598 frame()->OnNavigate(nav_params);
599 ProcessPendingMessages();
601 // Verify page A committed, not swappedout://.
602 const IPC::Message* frame_navigate_msg =
603 render_thread_->sink().GetUniqueMessageMatching(
604 FrameHostMsg_DidCommitProvisionalLoad::ID);
605 EXPECT_TRUE(frame_navigate_msg);
607 // Read URL out of the parent trait of the params object.
608 FrameHostMsg_DidCommitProvisionalLoad::Param commit_params;
609 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
610 &commit_params);
611 EXPECT_NE(GURL("swappedout://"), commit_params.a.url);
615 // Test that we get the correct UpdateState message when we go back twice
616 // quickly without committing. Regression test for http://crbug.com/58082.
617 // Disabled: http://crbug.com/157357 .
618 TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) {
619 // Load page A.
620 LoadHTML("<div>Page A</div>");
622 // Load page B, which will trigger an UpdateState message for page A.
623 LoadHTML("<div>Page B</div>");
625 // Check for a valid UpdateState message for page A.
626 ProcessPendingMessages();
627 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
628 ViewHostMsg_UpdateState::ID);
629 ASSERT_TRUE(msg_A);
630 ViewHostMsg_UpdateState::Param param;
631 ViewHostMsg_UpdateState::Read(msg_A, &param);
632 int page_id_A = param.a;
633 PageState state_A = param.b;
634 EXPECT_EQ(1, page_id_A);
635 render_thread_->sink().ClearMessages();
637 // Load page C, which will trigger an UpdateState message for page B.
638 LoadHTML("<div>Page C</div>");
640 // Check for a valid UpdateState for page B.
641 ProcessPendingMessages();
642 const IPC::Message* msg_B = render_thread_->sink().GetUniqueMessageMatching(
643 ViewHostMsg_UpdateState::ID);
644 ASSERT_TRUE(msg_B);
645 ViewHostMsg_UpdateState::Read(msg_B, &param);
646 int page_id_B = param.a;
647 PageState state_B = param.b;
648 EXPECT_EQ(2, page_id_B);
649 EXPECT_NE(state_A, state_B);
650 render_thread_->sink().ClearMessages();
652 // Load page D, which will trigger an UpdateState message for page C.
653 LoadHTML("<div>Page D</div>");
655 // Check for a valid UpdateState for page C.
656 ProcessPendingMessages();
657 const IPC::Message* msg_C = render_thread_->sink().GetUniqueMessageMatching(
658 ViewHostMsg_UpdateState::ID);
659 ASSERT_TRUE(msg_C);
660 ViewHostMsg_UpdateState::Read(msg_C, &param);
661 int page_id_C = param.a;
662 PageState state_C = param.b;
663 EXPECT_EQ(3, page_id_C);
664 EXPECT_NE(state_B, state_C);
665 render_thread_->sink().ClearMessages();
667 // Go back to C and commit, preparing for our real test.
668 FrameMsg_Navigate_Params params_C;
669 params_C.navigation_type = FrameMsg_Navigate_Type::NORMAL;
670 params_C.transition = PAGE_TRANSITION_FORWARD_BACK;
671 params_C.current_history_list_length = 4;
672 params_C.current_history_list_offset = 3;
673 params_C.pending_history_list_offset = 2;
674 params_C.page_id = 3;
675 params_C.page_state = state_C;
676 params_C.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
677 frame()->OnNavigate(params_C);
678 ProcessPendingMessages();
679 render_thread_->sink().ClearMessages();
681 // Go back twice quickly, such that page B does not have a chance to commit.
682 // This leads to two changes to the back/forward list but only one change to
683 // the RenderView's page ID.
685 // Back to page B (page_id 2), without committing.
686 FrameMsg_Navigate_Params params_B;
687 params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
688 params_B.transition = PAGE_TRANSITION_FORWARD_BACK;
689 params_B.current_history_list_length = 4;
690 params_B.current_history_list_offset = 2;
691 params_B.pending_history_list_offset = 1;
692 params_B.page_id = 2;
693 params_B.page_state = state_B;
694 params_B.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
695 frame()->OnNavigate(params_B);
697 // Back to page A (page_id 1) and commit.
698 FrameMsg_Navigate_Params params;
699 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
700 params.transition = PAGE_TRANSITION_FORWARD_BACK;
701 params_B.current_history_list_length = 4;
702 params_B.current_history_list_offset = 2;
703 params_B.pending_history_list_offset = 0;
704 params.page_id = 1;
705 params.page_state = state_A;
706 params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
707 frame()->OnNavigate(params);
708 ProcessPendingMessages();
710 // Now ensure that the UpdateState message we receive is consistent
711 // and represents page C in both page_id and state.
712 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
713 ViewHostMsg_UpdateState::ID);
714 ASSERT_TRUE(msg);
715 ViewHostMsg_UpdateState::Read(msg, &param);
716 int page_id = param.a;
717 PageState state = param.b;
718 EXPECT_EQ(page_id_C, page_id);
719 EXPECT_NE(state_A, state);
720 EXPECT_NE(state_B, state);
721 EXPECT_EQ(state_C, state);
724 // Test that the history_page_ids_ list can reveal when a stale back/forward
725 // navigation arrives from the browser and can be ignored. See
726 // http://crbug.com/86758.
727 TEST_F(RenderViewImplTest, StaleNavigationsIgnored) {
728 // Load page A.
729 LoadHTML("<div>Page A</div>");
730 EXPECT_EQ(1, view()->history_list_length_);
731 EXPECT_EQ(0, view()->history_list_offset_);
732 EXPECT_EQ(1, view()->history_page_ids_[0]);
734 // Load page B, which will trigger an UpdateState message for page A.
735 LoadHTML("<div>Page B</div>");
736 EXPECT_EQ(2, view()->history_list_length_);
737 EXPECT_EQ(1, view()->history_list_offset_);
738 EXPECT_EQ(2, view()->history_page_ids_[1]);
740 // Check for a valid UpdateState message for page A.
741 ProcessPendingMessages();
742 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
743 ViewHostMsg_UpdateState::ID);
744 ASSERT_TRUE(msg_A);
745 ViewHostMsg_UpdateState::Param param;
746 ViewHostMsg_UpdateState::Read(msg_A, &param);
747 int page_id_A = param.a;
748 PageState state_A = param.b;
749 EXPECT_EQ(1, page_id_A);
750 render_thread_->sink().ClearMessages();
752 // Back to page A (page_id 1) and commit.
753 FrameMsg_Navigate_Params params_A;
754 params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL;
755 params_A.transition = PAGE_TRANSITION_FORWARD_BACK;
756 params_A.current_history_list_length = 2;
757 params_A.current_history_list_offset = 1;
758 params_A.pending_history_list_offset = 0;
759 params_A.page_id = 1;
760 params_A.page_state = state_A;
761 params_A.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
762 frame()->OnNavigate(params_A);
763 ProcessPendingMessages();
765 // A new navigation commits, clearing the forward history.
766 LoadHTML("<div>Page C</div>");
767 EXPECT_EQ(2, view()->history_list_length_);
768 EXPECT_EQ(1, view()->history_list_offset_);
769 EXPECT_EQ(3, view()->history_page_ids_[1]);
771 // The browser then sends a stale navigation to B, which should be ignored.
772 FrameMsg_Navigate_Params params_B;
773 params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
774 params_B.transition = PAGE_TRANSITION_FORWARD_BACK;
775 params_B.current_history_list_length = 2;
776 params_B.current_history_list_offset = 0;
777 params_B.pending_history_list_offset = 1;
778 params_B.page_id = 2;
779 params_B.page_state = state_A; // Doesn't matter, just has to be present.
780 params_B.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
781 frame()->OnNavigate(params_B);
783 // State should be unchanged.
784 EXPECT_EQ(2, view()->history_list_length_);
785 EXPECT_EQ(1, view()->history_list_offset_);
786 EXPECT_EQ(3, view()->history_page_ids_[1]);
789 // Test that we do not ignore navigations after the entry limit is reached,
790 // in which case the browser starts dropping entries from the front. In this
791 // case, we'll see a page_id mismatch but the RenderView's id will be older,
792 // not newer, than params.page_id. Use this as a cue that we should update the
793 // state and not treat it like a navigation to a cropped forward history item.
794 // See http://crbug.com/89798.
795 TEST_F(RenderViewImplTest, DontIgnoreBackAfterNavEntryLimit) {
796 // Load page A.
797 LoadHTML("<div>Page A</div>");
798 EXPECT_EQ(1, view()->history_list_length_);
799 EXPECT_EQ(0, view()->history_list_offset_);
800 EXPECT_EQ(1, view()->history_page_ids_[0]);
802 // Load page B, which will trigger an UpdateState message for page A.
803 LoadHTML("<div>Page B</div>");
804 EXPECT_EQ(2, view()->history_list_length_);
805 EXPECT_EQ(1, view()->history_list_offset_);
806 EXPECT_EQ(2, view()->history_page_ids_[1]);
808 // Check for a valid UpdateState message for page A.
809 ProcessPendingMessages();
810 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
811 ViewHostMsg_UpdateState::ID);
812 ASSERT_TRUE(msg_A);
813 ViewHostMsg_UpdateState::Param param;
814 ViewHostMsg_UpdateState::Read(msg_A, &param);
815 int page_id_A = param.a;
816 PageState state_A = param.b;
817 EXPECT_EQ(1, page_id_A);
818 render_thread_->sink().ClearMessages();
820 // Load page C, which will trigger an UpdateState message for page B.
821 LoadHTML("<div>Page C</div>");
822 EXPECT_EQ(3, view()->history_list_length_);
823 EXPECT_EQ(2, view()->history_list_offset_);
824 EXPECT_EQ(3, view()->history_page_ids_[2]);
826 // Check for a valid UpdateState message 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 = param.a;
833 PageState state_B = param.b;
834 EXPECT_EQ(2, page_id_B);
835 render_thread_->sink().ClearMessages();
837 // Suppose the browser has limited the number of NavigationEntries to 2.
838 // It has now dropped the first entry, but the renderer isn't notified.
839 // Ensure that going back to page B (page_id 2) at offset 0 is successful.
840 FrameMsg_Navigate_Params params_B;
841 params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
842 params_B.transition = PAGE_TRANSITION_FORWARD_BACK;
843 params_B.current_history_list_length = 2;
844 params_B.current_history_list_offset = 1;
845 params_B.pending_history_list_offset = 0;
846 params_B.page_id = 2;
847 params_B.page_state = state_B;
848 params_B.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
849 frame()->OnNavigate(params_B);
850 ProcessPendingMessages();
852 EXPECT_EQ(2, view()->history_list_length_);
853 EXPECT_EQ(0, view()->history_list_offset_);
854 EXPECT_EQ(2, view()->history_page_ids_[0]);
857 // Test that our IME backend sends a notification message when the input focus
858 // changes.
859 TEST_F(RenderViewImplTest, OnImeTypeChanged) {
860 // Enable our IME backend code.
861 view()->OnSetInputMethodActive(true);
863 // Load an HTML page consisting of two input fields.
864 view()->set_send_content_state_immediately(true);
865 LoadHTML("<html>"
866 "<head>"
867 "</head>"
868 "<body>"
869 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
870 "<input id=\"test2\" type=\"password\"></input>"
871 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
872 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
873 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
874 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
875 "</input>"
876 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
877 "</input>"
878 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
879 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
880 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
881 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
882 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
883 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
884 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
885 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
886 "</body>"
887 "</html>");
888 render_thread_->sink().ClearMessages();
890 struct InputModeTestCase {
891 const char* input_id;
892 ui::TextInputMode expected_mode;
894 static const InputModeTestCase kInputModeTestCases[] = {
895 {"test1", ui::TEXT_INPUT_MODE_DEFAULT},
896 {"test3", ui::TEXT_INPUT_MODE_VERBATIM},
897 {"test4", ui::TEXT_INPUT_MODE_LATIN},
898 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME},
899 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE},
900 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN},
901 {"test8", ui::TEXT_INPUT_MODE_KANA},
902 {"test9", ui::TEXT_INPUT_MODE_KATAKANA},
903 {"test10", ui::TEXT_INPUT_MODE_NUMERIC},
904 {"test11", ui::TEXT_INPUT_MODE_TEL},
905 {"test12", ui::TEXT_INPUT_MODE_EMAIL},
906 {"test13", ui::TEXT_INPUT_MODE_URL},
907 {"test14", ui::TEXT_INPUT_MODE_DEFAULT},
908 {"test15", ui::TEXT_INPUT_MODE_VERBATIM},
911 const int kRepeatCount = 10;
912 for (int i = 0; i < kRepeatCount; i++) {
913 // Move the input focus to the first <input> element, where we should
914 // activate IMEs.
915 ExecuteJavaScript("document.getElementById('test1').focus();");
916 ProcessPendingMessages();
917 render_thread_->sink().ClearMessages();
919 // Update the IME status and verify if our IME backend sends an IPC message
920 // to activate IMEs.
921 view()->UpdateTextInputState(
922 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
923 const IPC::Message* msg = render_thread_->sink().GetMessageAt(0);
924 EXPECT_TRUE(msg != NULL);
925 EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type());
926 ViewHostMsg_TextInputStateChanged::Param params;
927 ViewHostMsg_TextInputStateChanged::Read(msg, &params);
928 ViewHostMsg_TextInputState_Params p = params.a;
929 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, p.type);
930 EXPECT_EQ(true, p.can_compose_inline);
932 // Move the input focus to the second <input> element, where we should
933 // de-activate IMEs.
934 ExecuteJavaScript("document.getElementById('test2').focus();");
935 ProcessPendingMessages();
936 render_thread_->sink().ClearMessages();
938 // Update the IME status and verify if our IME backend sends an IPC message
939 // to de-activate IMEs.
940 view()->UpdateTextInputState(
941 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
942 msg = render_thread_->sink().GetMessageAt(0);
943 EXPECT_TRUE(msg != NULL);
944 EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type());
945 ViewHostMsg_TextInputStateChanged::Read(msg, &params);
946 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, params.a.type);
948 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kInputModeTestCases); j++) {
949 const InputModeTestCase* test_case = &kInputModeTestCases[j];
950 std::string javascript =
951 base::StringPrintf("document.getElementById('%s').focus();",
952 test_case->input_id);
953 // Move the input focus to the target <input> element, where we should
954 // activate IMEs.
955 ExecuteJavaScript(javascript.c_str());
956 ProcessPendingMessages();
957 render_thread_->sink().ClearMessages();
959 // Update the IME status and verify if our IME backend sends an IPC
960 // message to activate IMEs.
961 view()->UpdateTextInputState(
962 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
963 msg = render_thread_->sink().GetMessageAt(0);
964 EXPECT_TRUE(msg != NULL);
965 EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type());
966 ViewHostMsg_TextInputStateChanged::Read(msg, &params);
967 EXPECT_EQ(test_case->expected_mode, params.a.mode);
972 // Test that our IME backend can compose CJK words.
973 // Our IME front-end sends many platform-independent messages to the IME backend
974 // while it composes CJK words. This test sends the minimal messages captured
975 // on my local environment directly to the IME backend to verify if the backend
976 // can compose CJK words without any problems.
977 // This test uses an array of command sets because an IME composotion does not
978 // only depends on IME events, but also depends on window events, e.g. moving
979 // the window focus while composing a CJK text. To handle such complicated
980 // cases, this test should not only call IME-related functions in the
981 // RenderWidget class, but also call some RenderWidget members, e.g.
982 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc.
983 TEST_F(RenderViewImplTest, ImeComposition) {
984 enum ImeCommand {
985 IME_INITIALIZE,
986 IME_SETINPUTMODE,
987 IME_SETFOCUS,
988 IME_SETCOMPOSITION,
989 IME_CONFIRMCOMPOSITION,
990 IME_CANCELCOMPOSITION
992 struct ImeMessage {
993 ImeCommand command;
994 bool enable;
995 int selection_start;
996 int selection_end;
997 const wchar_t* ime_string;
998 const wchar_t* result;
1000 static const ImeMessage kImeMessages[] = {
1001 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
1002 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1003 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1004 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1005 {IME_SETCOMPOSITION, false, 1, 1, L"n", L"n"},
1006 {IME_SETCOMPOSITION, false, 2, 2, L"ni", L"ni"},
1007 {IME_SETCOMPOSITION, false, 3, 3, L"nih", L"nih"},
1008 {IME_SETCOMPOSITION, false, 4, 4, L"niha", L"niha"},
1009 {IME_SETCOMPOSITION, false, 5, 5, L"nihao", L"nihao"},
1010 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"\x4F60\x597D", L"\x4F60\x597D"},
1011 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
1012 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1013 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1014 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1015 {IME_SETCOMPOSITION, false, 0, 1, L"\xFF4B", L"\xFF4B"},
1016 {IME_SETCOMPOSITION, false, 0, 1, L"\x304B", L"\x304B"},
1017 {IME_SETCOMPOSITION, false, 0, 2, L"\x304B\xFF4E", L"\x304B\xFF4E"},
1018 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\xFF4A",
1019 L"\x304B\x3093\xFF4A"},
1020 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\x3058",
1021 L"\x304B\x3093\x3058"},
1022 {IME_SETCOMPOSITION, false, 0, 2, L"\x611F\x3058", L"\x611F\x3058"},
1023 {IME_SETCOMPOSITION, false, 0, 2, L"\x6F22\x5B57", L"\x6F22\x5B57"},
1024 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1025 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1026 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1027 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1028 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1029 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1030 {IME_SETCOMPOSITION, false, 0, 1, L"\x3147", L"\x3147"},
1031 {IME_SETCOMPOSITION, false, 0, 1, L"\xC544", L"\xC544"},
1032 {IME_SETCOMPOSITION, false, 0, 1, L"\xC548", L"\xC548"},
1033 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1034 {IME_SETCOMPOSITION, false, 0, 1, L"\x3134", L"\xC548\x3134"},
1035 {IME_SETCOMPOSITION, false, 0, 1, L"\xB140", L"\xC548\xB140"},
1036 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1037 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1038 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1039 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548\xB155"},
1042 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kImeMessages); i++) {
1043 const ImeMessage* ime_message = &kImeMessages[i];
1044 switch (ime_message->command) {
1045 case IME_INITIALIZE:
1046 // Load an HTML page consisting of a content-editable <div> element,
1047 // and move the input focus to the <div> element, where we can use
1048 // IMEs.
1049 view()->OnSetInputMethodActive(ime_message->enable);
1050 view()->set_send_content_state_immediately(true);
1051 LoadHTML("<html>"
1052 "<head>"
1053 "</head>"
1054 "<body>"
1055 "<div id=\"test1\" contenteditable=\"true\"></div>"
1056 "</body>"
1057 "</html>");
1058 ExecuteJavaScript("document.getElementById('test1').focus();");
1059 break;
1061 case IME_SETINPUTMODE:
1062 // Activate (or deactivate) our IME back-end.
1063 view()->OnSetInputMethodActive(ime_message->enable);
1064 break;
1066 case IME_SETFOCUS:
1067 // Update the window focus.
1068 view()->OnSetFocus(ime_message->enable);
1069 break;
1071 case IME_SETCOMPOSITION:
1072 view()->OnImeSetComposition(
1073 base::WideToUTF16(ime_message->ime_string),
1074 std::vector<blink::WebCompositionUnderline>(),
1075 ime_message->selection_start,
1076 ime_message->selection_end);
1077 break;
1079 case IME_CONFIRMCOMPOSITION:
1080 view()->OnImeConfirmComposition(
1081 base::WideToUTF16(ime_message->ime_string),
1082 gfx::Range::InvalidRange(),
1083 false);
1084 break;
1086 case IME_CANCELCOMPOSITION:
1087 view()->OnImeSetComposition(
1088 base::string16(),
1089 std::vector<blink::WebCompositionUnderline>(),
1090 0, 0);
1091 break;
1094 // Update the status of our IME back-end.
1095 // TODO(hbono): we should verify messages to be sent from the back-end.
1096 view()->UpdateTextInputState(
1097 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
1098 ProcessPendingMessages();
1099 render_thread_->sink().ClearMessages();
1101 if (ime_message->result) {
1102 // Retrieve the content of this page and compare it with the expected
1103 // result.
1104 const int kMaxOutputCharacters = 128;
1105 base::string16 output =
1106 GetMainFrame()->contentAsText(kMaxOutputCharacters);
1107 EXPECT_EQ(base::WideToUTF16(ime_message->result), output);
1112 // Test that the RenderView::OnSetTextDirection() function can change the text
1113 // direction of the selected input element.
1114 TEST_F(RenderViewImplTest, OnSetTextDirection) {
1115 // Load an HTML page consisting of a <textarea> element and a <div> element.
1116 // This test changes the text direction of the <textarea> element, and
1117 // writes the values of its 'dir' attribute and its 'direction' property to
1118 // verify that the text direction is changed.
1119 view()->set_send_content_state_immediately(true);
1120 LoadHTML("<html>"
1121 "<head>"
1122 "</head>"
1123 "<body>"
1124 "<textarea id=\"test\"></textarea>"
1125 "<div id=\"result\" contenteditable=\"true\"></div>"
1126 "</body>"
1127 "</html>");
1128 render_thread_->sink().ClearMessages();
1130 static const struct {
1131 WebTextDirection direction;
1132 const wchar_t* expected_result;
1133 } kTextDirection[] = {
1134 { blink::WebTextDirectionRightToLeft, L"\x000A" L"rtl,rtl" },
1135 { blink::WebTextDirectionLeftToRight, L"\x000A" L"ltr,ltr" },
1137 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTextDirection); ++i) {
1138 // Set the text direction of the <textarea> element.
1139 ExecuteJavaScript("document.getElementById('test').focus();");
1140 view()->OnSetTextDirection(kTextDirection[i].direction);
1142 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1143 // property to the <div> element.
1144 ExecuteJavaScript("var result = document.getElementById('result');"
1145 "var node = document.getElementById('test');"
1146 "var style = getComputedStyle(node, null);"
1147 "result.innerText ="
1148 " node.getAttribute('dir') + ',' +"
1149 " style.getPropertyValue('direction');");
1151 // Copy the document content to std::wstring and compare with the
1152 // expected result.
1153 const int kMaxOutputCharacters = 16;
1154 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
1155 EXPECT_EQ(base::WideToUTF16(kTextDirection[i].expected_result), output);
1159 // see http://crbug.com/238750
1160 #if defined(OS_WIN)
1161 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent
1162 #else
1163 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent
1164 #endif
1166 // Test that we can receive correct DOM events when we send input events
1167 // through the RenderWidget::OnHandleInputEvent() function.
1168 TEST_F(RenderViewImplTest, MAYBE_OnHandleKeyboardEvent) {
1169 #if !defined(OS_MACOSX)
1170 // Load an HTML page consisting of one <input> element and three
1171 // contentediable <div> elements.
1172 // The <input> element is used for sending keyboard events, and the <div>
1173 // elements are used for writing DOM events in the following format:
1174 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1175 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1176 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1177 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1178 view()->set_send_content_state_immediately(true);
1179 LoadHTML("<html>"
1180 "<head>"
1181 "<title></title>"
1182 "<script type='text/javascript' language='javascript'>"
1183 "function OnKeyEvent(ev) {"
1184 " var result = document.getElementById(ev.type);"
1185 " result.innerText ="
1186 " (ev.which || ev.keyCode) + ',' +"
1187 " ev.shiftKey + ',' +"
1188 " ev.ctrlKey + ',' +"
1189 " ev.altKey;"
1190 " return true;"
1192 "</script>"
1193 "</head>"
1194 "<body>"
1195 "<input id='test' type='text'"
1196 " onkeydown='return OnKeyEvent(event);'"
1197 " onkeypress='return OnKeyEvent(event);'"
1198 " onkeyup='return OnKeyEvent(event);'>"
1199 "</input>"
1200 "<div id='keydown' contenteditable='true'>"
1201 "</div>"
1202 "<div id='keypress' contenteditable='true'>"
1203 "</div>"
1204 "<div id='keyup' contenteditable='true'>"
1205 "</div>"
1206 "</body>"
1207 "</html>");
1208 ExecuteJavaScript("document.getElementById('test').focus();");
1209 render_thread_->sink().ClearMessages();
1211 static const MockKeyboard::Layout kLayouts[] = {
1212 #if defined(OS_WIN)
1213 // Since we ignore the mock keyboard layout on Linux and instead just use
1214 // the screen's keyboard layout, these trivially pass. They are commented
1215 // out to avoid the illusion that they work.
1216 MockKeyboard::LAYOUT_ARABIC,
1217 MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1218 MockKeyboard::LAYOUT_FRENCH,
1219 MockKeyboard::LAYOUT_HEBREW,
1220 MockKeyboard::LAYOUT_RUSSIAN,
1221 #endif
1222 MockKeyboard::LAYOUT_UNITED_STATES,
1225 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLayouts); ++i) {
1226 // For each key code, we send three keyboard events.
1227 // * we press only the key;
1228 // * we press the key and a left-shift key, and;
1229 // * we press the key and a right-alt (AltGr) key.
1230 // For each modifiers, we need a string used for formatting its expected
1231 // result. (See the above comment for its format.)
1232 static const struct {
1233 MockKeyboard::Modifiers modifiers;
1234 const char* expected_result;
1235 } kModifierData[] = {
1236 {MockKeyboard::NONE, "false,false,false"},
1237 {MockKeyboard::LEFT_SHIFT, "true,false,false"},
1238 #if defined(OS_WIN)
1239 {MockKeyboard::RIGHT_ALT, "false,false,true"},
1240 #endif
1243 MockKeyboard::Layout layout = kLayouts[i];
1244 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kModifierData); ++j) {
1245 // Virtual key codes used for this test.
1246 static const int kKeyCodes[] = {
1247 '0', '1', '2', '3', '4', '5', '6', '7',
1248 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1249 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1250 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1251 'W', 'X', 'Y', 'Z',
1252 ui::VKEY_OEM_1,
1253 ui::VKEY_OEM_PLUS,
1254 ui::VKEY_OEM_COMMA,
1255 ui::VKEY_OEM_MINUS,
1256 ui::VKEY_OEM_PERIOD,
1257 ui::VKEY_OEM_2,
1258 ui::VKEY_OEM_3,
1259 ui::VKEY_OEM_4,
1260 ui::VKEY_OEM_5,
1261 ui::VKEY_OEM_6,
1262 ui::VKEY_OEM_7,
1263 #if defined(OS_WIN)
1264 // Not sure how to handle this key on Linux.
1265 ui::VKEY_OEM_8,
1266 #endif
1269 MockKeyboard::Modifiers modifiers = kModifierData[j].modifiers;
1270 for (size_t k = 0; k < ARRAYSIZE_UNSAFE(kKeyCodes); ++k) {
1271 // Send a keyboard event to the RenderView object.
1272 // We should test a keyboard event only when the given keyboard-layout
1273 // driver is installed in a PC and the driver can assign a Unicode
1274 // charcter for the given tuple (key-code and modifiers).
1275 int key_code = kKeyCodes[k];
1276 base::string16 char_code;
1277 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1278 continue;
1280 // Create an expected result from the virtual-key code, the character
1281 // code, and the modifier-key status.
1282 // We format a string that emulates a DOM-event string produced hy
1283 // our JavaScript function. (See the above comment for the format.)
1284 static char expected_result[1024];
1285 expected_result[0] = 0;
1286 base::snprintf(&expected_result[0],
1287 sizeof(expected_result),
1288 "\n" // texts in the <input> element
1289 "%d,%s\n" // texts in the first <div> element
1290 "%d,%s\n" // texts in the second <div> element
1291 "%d,%s", // texts in the third <div> element
1292 key_code, kModifierData[j].expected_result,
1293 static_cast<int>(char_code[0]),
1294 kModifierData[j].expected_result,
1295 key_code, kModifierData[j].expected_result);
1297 // Retrieve the text in the test page and compare it with the expected
1298 // text created from a virtual-key code, a character code, and the
1299 // modifier-key status.
1300 const int kMaxOutputCharacters = 1024;
1301 std::string output = base::UTF16ToUTF8(
1302 GetMainFrame()->contentAsText(kMaxOutputCharacters));
1303 EXPECT_EQ(expected_result, output);
1307 #else
1308 NOTIMPLEMENTED();
1309 #endif
1312 // Test that our EditorClientImpl class can insert characters when we send
1313 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1314 // This test is for preventing regressions caused only when we use non-US
1315 // keyboards, such as Issue 10846.
1316 // see http://crbug.com/244562
1317 #if defined(OS_WIN)
1318 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1319 #else
1320 #define MAYBE_InsertCharacters InsertCharacters
1321 #endif
1322 TEST_F(RenderViewImplTest, MAYBE_InsertCharacters) {
1323 #if !defined(OS_MACOSX)
1324 static const struct {
1325 MockKeyboard::Layout layout;
1326 const wchar_t* expected_result;
1327 } kLayouts[] = {
1328 #if 0
1329 // Disabled these keyboard layouts because buildbots do not have their
1330 // keyboard-layout drivers installed.
1331 {MockKeyboard::LAYOUT_ARABIC,
1332 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1333 L"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1334 L"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1335 L"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1336 L"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1337 L"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1338 L"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1339 L"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1340 L"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1341 L"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1342 L"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1343 L"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1344 L"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1345 L"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1346 L"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1347 L"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1348 L"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1350 {MockKeyboard::LAYOUT_HEBREW,
1351 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1352 L"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1353 L"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1354 L"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1355 L"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1356 L"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1357 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1358 L"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1359 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1360 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1361 L"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1362 L"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1363 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1364 L"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1365 L"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1366 L"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1367 L"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1368 L"\x003b\x005d\x005c\x005b\x002c"
1370 #endif
1371 #if defined(OS_WIN)
1372 // On Linux, the only way to test alternate keyboard layouts is to change
1373 // the keyboard layout of the whole screen. I'm worried about the side
1374 // effects this may have on the buildbots.
1375 {MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1376 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1377 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1378 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1379 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1380 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1381 L"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1382 L"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1383 L"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1384 L"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1385 L"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1386 L"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1387 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1388 L"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1389 L"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1390 L"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1391 L"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1392 L"\x003c"
1394 {MockKeyboard::LAYOUT_FRENCH,
1395 L"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1396 L"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1397 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1398 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1399 L"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1400 L"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1401 L"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1402 L"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1403 L"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1404 L"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1405 L"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1406 L"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1407 L"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1408 L"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1409 L"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1410 L"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1411 L"\x003b\x003a\x00f9\x0029\x002a\x0021"
1413 {MockKeyboard::LAYOUT_RUSSIAN,
1414 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1415 L"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1416 L"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1417 L"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1418 L"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1419 L"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1420 L"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1421 L"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1422 L"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1423 L"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1424 L"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1425 L"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1426 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1427 L"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1428 L"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1429 L"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1430 L"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1431 L"\x0451\x0445\x005c\x044a\x044d"
1433 #endif // defined(OS_WIN)
1434 {MockKeyboard::LAYOUT_UNITED_STATES,
1435 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1436 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1437 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1438 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1439 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1440 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1441 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1442 L"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1443 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1444 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1445 L"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1446 L"\x003f\x007e\x007b\x007c\x007d\x0022"
1447 #if defined(OS_WIN)
1448 // This is ifdefed out for Linux to correspond to the fact that we don't
1449 // test alt+keystroke for now.
1450 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1451 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1452 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1453 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1454 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1455 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1456 #endif
1460 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLayouts); ++i) {
1461 // Load an HTML page consisting of one <div> element.
1462 // This <div> element is used by the EditorClientImpl class to insert
1463 // characters received through the RenderWidget::OnHandleInputEvent()
1464 // function.
1465 view()->set_send_content_state_immediately(true);
1466 LoadHTML("<html>"
1467 "<head>"
1468 "<title></title>"
1469 "</head>"
1470 "<body>"
1471 "<div id='test' contenteditable='true'>"
1472 "</div>"
1473 "</body>"
1474 "</html>");
1475 ExecuteJavaScript("document.getElementById('test').focus();");
1476 render_thread_->sink().ClearMessages();
1478 // For each key code, we send three keyboard events.
1479 // * Pressing only the key;
1480 // * Pressing the key and a left-shift key, and;
1481 // * Pressing the key and a right-alt (AltGr) key.
1482 static const MockKeyboard::Modifiers kModifiers[] = {
1483 MockKeyboard::NONE,
1484 MockKeyboard::LEFT_SHIFT,
1485 #if defined(OS_WIN)
1486 MockKeyboard::RIGHT_ALT,
1487 #endif
1490 MockKeyboard::Layout layout = kLayouts[i].layout;
1491 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kModifiers); ++j) {
1492 // Virtual key codes used for this test.
1493 static const int kKeyCodes[] = {
1494 '0', '1', '2', '3', '4', '5', '6', '7',
1495 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1496 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1497 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1498 'W', 'X', 'Y', 'Z',
1499 ui::VKEY_OEM_1,
1500 ui::VKEY_OEM_PLUS,
1501 ui::VKEY_OEM_COMMA,
1502 ui::VKEY_OEM_MINUS,
1503 ui::VKEY_OEM_PERIOD,
1504 ui::VKEY_OEM_2,
1505 ui::VKEY_OEM_3,
1506 ui::VKEY_OEM_4,
1507 ui::VKEY_OEM_5,
1508 ui::VKEY_OEM_6,
1509 ui::VKEY_OEM_7,
1510 #if defined(OS_WIN)
1511 // Unclear how to handle this on Linux.
1512 ui::VKEY_OEM_8,
1513 #endif
1516 MockKeyboard::Modifiers modifiers = kModifiers[j];
1517 for (size_t k = 0; k < ARRAYSIZE_UNSAFE(kKeyCodes); ++k) {
1518 // Send a keyboard event to the RenderView object.
1519 // We should test a keyboard event only when the given keyboard-layout
1520 // driver is installed in a PC and the driver can assign a Unicode
1521 // charcter for the given tuple (layout, key-code, and modifiers).
1522 int key_code = kKeyCodes[k];
1523 base::string16 char_code;
1524 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1525 continue;
1529 // Retrieve the text in the test page and compare it with the expected
1530 // text created from a virtual-key code, a character code, and the
1531 // modifier-key status.
1532 const int kMaxOutputCharacters = 4096;
1533 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
1534 EXPECT_EQ(base::WideToUTF16(kLayouts[i].expected_result), output);
1536 #else
1537 NOTIMPLEMENTED();
1538 #endif
1541 // Crashy, http://crbug.com/53247.
1542 TEST_F(RenderViewImplTest, DISABLED_DidFailProvisionalLoadWithErrorForError) {
1543 GetMainFrame()->enableViewSourceMode(true);
1544 WebURLError error;
1545 error.domain = WebString::fromUTF8(net::kErrorDomain);
1546 error.reason = net::ERR_FILE_NOT_FOUND;
1547 error.unreachableURL = GURL("http://foo");
1548 WebLocalFrame* web_frame = GetMainFrame();
1550 // Start a load that will reach provisional state synchronously,
1551 // but won't complete synchronously.
1552 FrameMsg_Navigate_Params params;
1553 params.page_id = -1;
1554 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1555 params.url = GURL("data:text/html,test data");
1556 params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
1557 frame()->OnNavigate(params);
1559 // An error occurred.
1560 view()->main_render_frame()->didFailProvisionalLoad(web_frame, error);
1561 // Frame should exit view-source mode.
1562 EXPECT_FALSE(web_frame->isViewSourceModeEnabled());
1565 TEST_F(RenderViewImplTest, DidFailProvisionalLoadWithErrorForCancellation) {
1566 GetMainFrame()->enableViewSourceMode(true);
1567 WebURLError error;
1568 error.domain = WebString::fromUTF8(net::kErrorDomain);
1569 error.reason = net::ERR_ABORTED;
1570 error.unreachableURL = GURL("http://foo");
1571 WebLocalFrame* web_frame = GetMainFrame();
1573 // Start a load that will reach provisional state synchronously,
1574 // but won't complete synchronously.
1575 FrameMsg_Navigate_Params params;
1576 params.page_id = -1;
1577 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1578 params.url = GURL("data:text/html,test data");
1579 params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
1580 frame()->OnNavigate(params);
1582 // A cancellation occurred.
1583 view()->main_render_frame()->didFailProvisionalLoad(web_frame, error);
1584 // Frame should stay in view-source mode.
1585 EXPECT_TRUE(web_frame->isViewSourceModeEnabled());
1588 // Regression test for http://crbug.com/41562
1589 TEST_F(RenderViewImplTest, UpdateTargetURLWithInvalidURL) {
1590 const GURL invalid_gurl("http://");
1591 view()->setMouseOverURL(blink::WebURL(invalid_gurl));
1592 EXPECT_EQ(invalid_gurl, view()->target_url_);
1595 TEST_F(RenderViewImplTest, SetHistoryLengthAndPrune) {
1596 int expected_page_id = -1;
1598 // No history to merge and no committed pages.
1599 view()->OnSetHistoryLengthAndPrune(0, -1);
1600 EXPECT_EQ(0, view()->history_list_length_);
1601 EXPECT_EQ(-1, view()->history_list_offset_);
1603 // History to merge and no committed pages.
1604 view()->OnSetHistoryLengthAndPrune(2, -1);
1605 EXPECT_EQ(2, view()->history_list_length_);
1606 EXPECT_EQ(1, view()->history_list_offset_);
1607 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1608 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1609 ClearHistory();
1611 blink::WebHistoryItem item;
1612 item.initialize();
1614 // No history to merge and a committed page to be kept.
1615 frame()->didCommitProvisionalLoad(GetMainFrame(),
1616 item,
1617 blink::WebStandardCommit);
1618 expected_page_id = view()->page_id_;
1619 view()->OnSetHistoryLengthAndPrune(0, expected_page_id);
1620 EXPECT_EQ(1, view()->history_list_length_);
1621 EXPECT_EQ(0, view()->history_list_offset_);
1622 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1623 ClearHistory();
1625 // No history to merge and a committed page to be pruned.
1626 frame()->didCommitProvisionalLoad(GetMainFrame(),
1627 item,
1628 blink::WebStandardCommit);
1629 expected_page_id = view()->page_id_;
1630 view()->OnSetHistoryLengthAndPrune(0, expected_page_id + 1);
1631 EXPECT_EQ(0, view()->history_list_length_);
1632 EXPECT_EQ(-1, view()->history_list_offset_);
1633 ClearHistory();
1635 // No history to merge and a committed page that the browser was unaware of.
1636 frame()->didCommitProvisionalLoad(GetMainFrame(),
1637 item,
1638 blink::WebStandardCommit);
1639 expected_page_id = view()->page_id_;
1640 view()->OnSetHistoryLengthAndPrune(0, -1);
1641 EXPECT_EQ(1, view()->history_list_length_);
1642 EXPECT_EQ(0, view()->history_list_offset_);
1643 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1644 ClearHistory();
1646 // History to merge and a committed page to be kept.
1647 frame()->didCommitProvisionalLoad(GetMainFrame(),
1648 item,
1649 blink::WebStandardCommit);
1650 expected_page_id = view()->page_id_;
1651 view()->OnSetHistoryLengthAndPrune(2, expected_page_id);
1652 EXPECT_EQ(3, view()->history_list_length_);
1653 EXPECT_EQ(2, view()->history_list_offset_);
1654 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1655 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1656 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1657 ClearHistory();
1659 // History to merge and a committed page to be pruned.
1660 frame()->didCommitProvisionalLoad(GetMainFrame(),
1661 item,
1662 blink::WebStandardCommit);
1663 expected_page_id = view()->page_id_;
1664 view()->OnSetHistoryLengthAndPrune(2, expected_page_id + 1);
1665 EXPECT_EQ(2, view()->history_list_length_);
1666 EXPECT_EQ(1, view()->history_list_offset_);
1667 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1668 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1669 ClearHistory();
1671 // History to merge and a committed page that the browser was unaware of.
1672 frame()->didCommitProvisionalLoad(GetMainFrame(),
1673 item,
1674 blink::WebStandardCommit);
1675 expected_page_id = view()->page_id_;
1676 view()->OnSetHistoryLengthAndPrune(2, -1);
1677 EXPECT_EQ(3, view()->history_list_length_);
1678 EXPECT_EQ(2, view()->history_list_offset_);
1679 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1680 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1681 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1682 ClearHistory();
1684 int expected_page_id_2 = -1;
1686 // No history to merge and two committed pages, both to be kept.
1687 frame()->didCommitProvisionalLoad(GetMainFrame(),
1688 item,
1689 blink::WebStandardCommit);
1690 expected_page_id = view()->page_id_;
1691 frame()->didCommitProvisionalLoad(GetMainFrame(),
1692 item,
1693 blink::WebStandardCommit);
1694 expected_page_id_2 = view()->page_id_;
1695 EXPECT_GT(expected_page_id_2, expected_page_id);
1696 view()->OnSetHistoryLengthAndPrune(0, expected_page_id);
1697 EXPECT_EQ(2, view()->history_list_length_);
1698 EXPECT_EQ(1, view()->history_list_offset_);
1699 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1700 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[1]);
1701 ClearHistory();
1703 // No history to merge and two committed pages, and only the second is kept.
1704 frame()->didCommitProvisionalLoad(GetMainFrame(),
1705 item,
1706 blink::WebStandardCommit);
1707 expected_page_id = view()->page_id_;
1708 frame()->didCommitProvisionalLoad(GetMainFrame(),
1709 item,
1710 blink::WebStandardCommit);
1711 expected_page_id_2 = view()->page_id_;
1712 EXPECT_GT(expected_page_id_2, expected_page_id);
1713 view()->OnSetHistoryLengthAndPrune(0, expected_page_id_2);
1714 EXPECT_EQ(1, view()->history_list_length_);
1715 EXPECT_EQ(0, view()->history_list_offset_);
1716 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[0]);
1717 ClearHistory();
1719 // No history to merge and two committed pages, both of which the browser was
1720 // unaware of.
1721 frame()->didCommitProvisionalLoad(GetMainFrame(),
1722 item,
1723 blink::WebStandardCommit);
1724 expected_page_id = view()->page_id_;
1725 frame()->didCommitProvisionalLoad(GetMainFrame(),
1726 item,
1727 blink::WebStandardCommit);
1728 expected_page_id_2 = view()->page_id_;
1729 EXPECT_GT(expected_page_id_2, expected_page_id);
1730 view()->OnSetHistoryLengthAndPrune(0, -1);
1731 EXPECT_EQ(2, view()->history_list_length_);
1732 EXPECT_EQ(1, view()->history_list_offset_);
1733 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1734 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[1]);
1735 ClearHistory();
1737 // History to merge and two committed pages, both to be kept.
1738 frame()->didCommitProvisionalLoad(GetMainFrame(),
1739 item,
1740 blink::WebStandardCommit);
1741 expected_page_id = view()->page_id_;
1742 frame()->didCommitProvisionalLoad(GetMainFrame(),
1743 item,
1744 blink::WebStandardCommit);
1745 expected_page_id_2 = view()->page_id_;
1746 EXPECT_GT(expected_page_id_2, expected_page_id);
1747 view()->OnSetHistoryLengthAndPrune(2, expected_page_id);
1748 EXPECT_EQ(4, view()->history_list_length_);
1749 EXPECT_EQ(3, view()->history_list_offset_);
1750 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1751 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1752 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1753 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[3]);
1754 ClearHistory();
1756 // History to merge and two committed pages, and only the second is kept.
1757 frame()->didCommitProvisionalLoad(GetMainFrame(),
1758 item,
1759 blink::WebStandardCommit);
1760 expected_page_id = view()->page_id_;
1761 frame()->didCommitProvisionalLoad(GetMainFrame(),
1762 item,
1763 blink::WebStandardCommit);
1764 expected_page_id_2 = view()->page_id_;
1765 EXPECT_GT(expected_page_id_2, expected_page_id);
1766 view()->OnSetHistoryLengthAndPrune(2, expected_page_id_2);
1767 EXPECT_EQ(3, view()->history_list_length_);
1768 EXPECT_EQ(2, view()->history_list_offset_);
1769 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1770 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1771 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[2]);
1772 ClearHistory();
1774 // History to merge and two committed pages, both of which the browser was
1775 // unaware of.
1776 frame()->didCommitProvisionalLoad(GetMainFrame(),
1777 item,
1778 blink::WebStandardCommit);
1779 expected_page_id = view()->page_id_;
1780 frame()->didCommitProvisionalLoad(GetMainFrame(),
1781 item,
1782 blink::WebStandardCommit);
1783 expected_page_id_2 = view()->page_id_;
1784 EXPECT_GT(expected_page_id_2, expected_page_id);
1785 view()->OnSetHistoryLengthAndPrune(2, -1);
1786 EXPECT_EQ(4, view()->history_list_length_);
1787 EXPECT_EQ(3, view()->history_list_offset_);
1788 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1789 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1790 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1791 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[3]);
1794 TEST_F(RenderViewImplTest, ContextMenu) {
1795 LoadHTML("<div>Page A</div>");
1797 // Create a right click in the center of the iframe. (I'm hoping this will
1798 // make this a bit more robust in case of some other formatting or other bug.)
1799 WebMouseEvent mouse_event;
1800 mouse_event.type = WebInputEvent::MouseDown;
1801 mouse_event.button = WebMouseEvent::ButtonRight;
1802 mouse_event.x = 250;
1803 mouse_event.y = 250;
1804 mouse_event.globalX = 250;
1805 mouse_event.globalY = 250;
1807 SendWebMouseEvent(mouse_event);
1809 // Now simulate the corresponding up event which should display the menu
1810 mouse_event.type = WebInputEvent::MouseUp;
1811 SendWebMouseEvent(mouse_event);
1813 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
1814 FrameHostMsg_ContextMenu::ID));
1817 TEST_F(RenderViewImplTest, TestBackForward) {
1818 LoadHTML("<div id=pagename>Page A</div>");
1819 PageState page_a_state =
1820 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1821 int was_page_a = -1;
1822 base::string16 check_page_a =
1823 base::ASCIIToUTF16(
1824 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1825 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1826 EXPECT_EQ(1, was_page_a);
1828 LoadHTML("<div id=pagename>Page B</div>");
1829 int was_page_b = -1;
1830 base::string16 check_page_b =
1831 base::ASCIIToUTF16(
1832 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1833 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1834 EXPECT_EQ(1, was_page_b);
1836 PageState back_state =
1837 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1839 LoadHTML("<div id=pagename>Page C</div>");
1840 int was_page_c = -1;
1841 base::string16 check_page_c =
1842 base::ASCIIToUTF16(
1843 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1844 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1845 EXPECT_EQ(1, was_page_b);
1847 PageState forward_state =
1848 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1849 GoBack(back_state);
1850 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1851 EXPECT_EQ(1, was_page_b);
1853 PageState back_state2 =
1854 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1856 GoForward(forward_state);
1857 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1858 EXPECT_EQ(1, was_page_c);
1860 GoBack(back_state2);
1861 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1862 EXPECT_EQ(1, was_page_b);
1864 forward_state =
1865 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1866 GoBack(page_a_state);
1867 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1868 EXPECT_EQ(1, was_page_a);
1870 GoForward(forward_state);
1871 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1872 EXPECT_EQ(1, was_page_b);
1875 #if defined(OS_MACOSX) || defined(USE_AURA)
1876 TEST_F(RenderViewImplTest, GetCompositionCharacterBoundsTest) {
1878 #if defined(OS_WIN)
1879 // http://crbug.com/304193
1880 if (base::win::GetVersion() < base::win::VERSION_VISTA)
1881 return;
1882 #endif
1884 LoadHTML("<textarea id=\"test\"></textarea>");
1885 ExecuteJavaScript("document.getElementById('test').focus();");
1887 const base::string16 empty_string;
1888 const std::vector<blink::WebCompositionUnderline> empty_underline;
1889 std::vector<gfx::Rect> bounds;
1890 view()->OnSetFocus(true);
1891 view()->OnSetInputMethodActive(true);
1893 // ASCII composition
1894 const base::string16 ascii_composition = base::UTF8ToUTF16("aiueo");
1895 view()->OnImeSetComposition(ascii_composition, empty_underline, 0, 0);
1896 view()->GetCompositionCharacterBounds(&bounds);
1897 ASSERT_EQ(ascii_composition.size(), bounds.size());
1898 for (size_t i = 0; i < bounds.size(); ++i)
1899 EXPECT_LT(0, bounds[i].width());
1900 view()->OnImeConfirmComposition(
1901 empty_string, gfx::Range::InvalidRange(), false);
1903 // Non surrogate pair unicode character.
1904 const base::string16 unicode_composition = base::UTF8ToUTF16(
1905 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1906 view()->OnImeSetComposition(unicode_composition, empty_underline, 0, 0);
1907 view()->GetCompositionCharacterBounds(&bounds);
1908 ASSERT_EQ(unicode_composition.size(), bounds.size());
1909 for (size_t i = 0; i < bounds.size(); ++i)
1910 EXPECT_LT(0, bounds[i].width());
1911 view()->OnImeConfirmComposition(
1912 empty_string, gfx::Range::InvalidRange(), false);
1914 // Surrogate pair character.
1915 const base::string16 surrogate_pair_char =
1916 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1917 view()->OnImeSetComposition(surrogate_pair_char,
1918 empty_underline,
1921 view()->GetCompositionCharacterBounds(&bounds);
1922 ASSERT_EQ(surrogate_pair_char.size(), bounds.size());
1923 EXPECT_LT(0, bounds[0].width());
1924 EXPECT_EQ(0, bounds[1].width());
1925 view()->OnImeConfirmComposition(
1926 empty_string, gfx::Range::InvalidRange(), false);
1928 // Mixed string.
1929 const base::string16 surrogate_pair_mixed_composition =
1930 surrogate_pair_char + base::UTF8ToUTF16("\xE3\x81\x82") +
1931 surrogate_pair_char + base::UTF8ToUTF16("b") + surrogate_pair_char;
1932 const size_t utf16_length = 8UL;
1933 const bool is_surrogate_pair_empty_rect[8] = {
1934 false, true, false, false, true, false, false, true };
1935 view()->OnImeSetComposition(surrogate_pair_mixed_composition,
1936 empty_underline,
1939 view()->GetCompositionCharacterBounds(&bounds);
1940 ASSERT_EQ(utf16_length, bounds.size());
1941 for (size_t i = 0; i < utf16_length; ++i) {
1942 if (is_surrogate_pair_empty_rect[i]) {
1943 EXPECT_EQ(0, bounds[i].width());
1944 } else {
1945 EXPECT_LT(0, bounds[i].width());
1948 view()->OnImeConfirmComposition(
1949 empty_string, gfx::Range::InvalidRange(), false);
1951 #endif
1953 TEST_F(RenderViewImplTest, ZoomLimit) {
1954 const double kMinZoomLevel = ZoomFactorToZoomLevel(kMinimumZoomFactor);
1955 const double kMaxZoomLevel = ZoomFactorToZoomLevel(kMaximumZoomFactor);
1957 FrameMsg_Navigate_Params params;
1958 params.page_id = -1;
1959 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1960 params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
1962 // Verifies navigation to a URL with preset zoom level indeed sets the level.
1963 // Regression test for http://crbug.com/139559, where the level was not
1964 // properly set when it is out of the default zoom limits of WebView.
1965 params.url = GURL("data:text/html,min_zoomlimit_test");
1966 view()->OnSetZoomLevelForLoadingURL(params.url, kMinZoomLevel);
1967 frame()->OnNavigate(params);
1968 ProcessPendingMessages();
1969 EXPECT_DOUBLE_EQ(kMinZoomLevel, view()->GetWebView()->zoomLevel());
1971 // It should work even when the zoom limit is temporarily changed in the page.
1972 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
1973 ZoomFactorToZoomLevel(1.0));
1974 params.url = GURL("data:text/html,max_zoomlimit_test");
1975 view()->OnSetZoomLevelForLoadingURL(params.url, kMaxZoomLevel);
1976 frame()->OnNavigate(params);
1977 ProcessPendingMessages();
1978 EXPECT_DOUBLE_EQ(kMaxZoomLevel, view()->GetWebView()->zoomLevel());
1981 TEST_F(RenderViewImplTest, SetEditableSelectionAndComposition) {
1982 // Load an HTML page consisting of an input field.
1983 LoadHTML("<html>"
1984 "<head>"
1985 "</head>"
1986 "<body>"
1987 "<input id=\"test1\" value=\"some test text hello\"></input>"
1988 "</body>"
1989 "</html>");
1990 ExecuteJavaScript("document.getElementById('test1').focus();");
1991 frame()->OnSetEditableSelectionOffsets(4, 8);
1992 const std::vector<blink::WebCompositionUnderline> empty_underline;
1993 frame()->OnSetCompositionFromExistingText(7, 10, empty_underline);
1994 blink::WebTextInputInfo info = view()->webview()->textInputInfo();
1995 EXPECT_EQ(4, info.selectionStart);
1996 EXPECT_EQ(8, info.selectionEnd);
1997 EXPECT_EQ(7, info.compositionStart);
1998 EXPECT_EQ(10, info.compositionEnd);
1999 frame()->OnUnselect();
2000 info = view()->webview()->textInputInfo();
2001 EXPECT_EQ(0, info.selectionStart);
2002 EXPECT_EQ(0, info.selectionEnd);
2006 TEST_F(RenderViewImplTest, OnExtendSelectionAndDelete) {
2007 // Load an HTML page consisting of an input field.
2008 LoadHTML("<html>"
2009 "<head>"
2010 "</head>"
2011 "<body>"
2012 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
2013 "</body>"
2014 "</html>");
2015 ExecuteJavaScript("document.getElementById('test1').focus();");
2016 frame()->OnSetEditableSelectionOffsets(10, 10);
2017 frame()->OnExtendSelectionAndDelete(3, 4);
2018 blink::WebTextInputInfo info = view()->webview()->textInputInfo();
2019 EXPECT_EQ("abcdefgopqrstuvwxyz", info.value);
2020 EXPECT_EQ(7, info.selectionStart);
2021 EXPECT_EQ(7, info.selectionEnd);
2022 frame()->OnSetEditableSelectionOffsets(4, 8);
2023 frame()->OnExtendSelectionAndDelete(2, 5);
2024 info = view()->webview()->textInputInfo();
2025 EXPECT_EQ("abuvwxyz", info.value);
2026 EXPECT_EQ(2, info.selectionStart);
2027 EXPECT_EQ(2, info.selectionEnd);
2030 // Test that the navigating specific frames works correctly.
2031 TEST_F(RenderViewImplTest, NavigateFrame) {
2032 // Load page A.
2033 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
2035 // Navigate the frame only.
2036 FrameMsg_Navigate_Params nav_params;
2037 nav_params.url = GURL("data:text/html,world");
2038 nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2039 nav_params.transition = PAGE_TRANSITION_TYPED;
2040 nav_params.current_history_list_length = 1;
2041 nav_params.current_history_list_offset = 0;
2042 nav_params.pending_history_list_offset = 1;
2043 nav_params.page_id = -1;
2044 nav_params.frame_to_navigate = "frame";
2045 nav_params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
2046 frame()->OnNavigate(nav_params);
2047 FrameLoadWaiter(
2048 RenderFrame::FromWebFrame(frame()->GetWebFrame()->firstChild())).Wait();
2050 // Copy the document content to std::wstring and compare with the
2051 // expected result.
2052 const int kMaxOutputCharacters = 256;
2053 std::string output = base::UTF16ToUTF8(
2054 GetMainFrame()->contentAsText(kMaxOutputCharacters));
2055 EXPECT_EQ(output, "hello \n\nworld");
2058 // This test ensures that a RenderFrame object is created for the top level
2059 // frame in the RenderView.
2060 TEST_F(RenderViewImplTest, BasicRenderFrame) {
2061 EXPECT_TRUE(view()->main_render_frame_.get());
2064 TEST_F(RenderViewImplTest, GetSSLStatusOfFrame) {
2065 LoadHTML("<!DOCTYPE html><html><body></body></html>");
2067 WebLocalFrame* frame = GetMainFrame();
2068 SSLStatus ssl_status = view()->GetSSLStatusOfFrame(frame);
2069 EXPECT_FALSE(net::IsCertStatusError(ssl_status.cert_status));
2071 const_cast<blink::WebURLResponse&>(frame->dataSource()->response()).
2072 setSecurityInfo(
2073 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS, 0, 0,
2074 SignedCertificateTimestampIDStatusList()));
2075 ssl_status = view()->GetSSLStatusOfFrame(frame);
2076 EXPECT_TRUE(net::IsCertStatusError(ssl_status.cert_status));
2079 TEST_F(RenderViewImplTest, MessageOrderInDidChangeSelection) {
2080 view()->OnSetInputMethodActive(true);
2081 view()->set_send_content_state_immediately(true);
2082 LoadHTML("<textarea id=\"test\"></textarea>");
2084 view()->handling_input_event_ = true;
2085 ExecuteJavaScript("document.getElementById('test').focus();");
2087 bool is_input_type_called = false;
2088 bool is_selection_called = false;
2089 size_t last_input_type = 0;
2090 size_t last_selection = 0;
2092 for (size_t i = 0; i < render_thread_->sink().message_count(); ++i) {
2093 const uint32 type = render_thread_->sink().GetMessageAt(i)->type();
2094 if (type == ViewHostMsg_TextInputStateChanged::ID) {
2095 is_input_type_called = true;
2096 last_input_type = i;
2097 } else if (type == ViewHostMsg_SelectionChanged::ID) {
2098 is_selection_called = true;
2099 last_selection = i;
2103 EXPECT_TRUE(is_input_type_called);
2104 EXPECT_TRUE(is_selection_called);
2106 // InputTypeChange shold be called earlier than SelectionChanged.
2107 EXPECT_LT(last_input_type, last_selection);
2110 class SuppressErrorPageTest : public RenderViewTest {
2111 public:
2112 virtual ContentRendererClient* CreateContentRendererClient() OVERRIDE {
2113 return new TestContentRendererClient;
2116 RenderViewImpl* view() {
2117 return static_cast<RenderViewImpl*>(view_);
2120 RenderFrameImpl* frame() {
2121 return static_cast<RenderFrameImpl*>(view()->GetMainRenderFrame());
2124 private:
2125 class TestContentRendererClient : public ContentRendererClient {
2126 public:
2127 virtual bool ShouldSuppressErrorPage(RenderFrame* render_frame,
2128 const GURL& url) OVERRIDE {
2129 return url == GURL("http://example.com/suppress");
2132 virtual void GetNavigationErrorStrings(
2133 content::RenderView* render_view,
2134 blink::WebFrame* frame,
2135 const blink::WebURLRequest& failed_request,
2136 const blink::WebURLError& error,
2137 std::string* error_html,
2138 base::string16* error_description) OVERRIDE {
2139 if (error_html)
2140 *error_html = "A suffusion of yellow.";
2145 #if defined(OS_ANDROID)
2146 // Crashing on Android: http://crbug.com/311341
2147 #define MAYBE_Suppresses DISABLED_Suppresses
2148 #else
2149 #define MAYBE_Suppresses Suppresses
2150 #endif
2152 TEST_F(SuppressErrorPageTest, MAYBE_Suppresses) {
2153 WebURLError error;
2154 error.domain = WebString::fromUTF8(net::kErrorDomain);
2155 error.reason = net::ERR_FILE_NOT_FOUND;
2156 error.unreachableURL = GURL("http://example.com/suppress");
2157 WebLocalFrame* web_frame = GetMainFrame();
2159 // Start a load that will reach provisional state synchronously,
2160 // but won't complete synchronously.
2161 FrameMsg_Navigate_Params params;
2162 params.page_id = -1;
2163 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2164 params.url = GURL("data:text/html,test data");
2165 params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
2166 frame()->OnNavigate(params);
2168 // An error occurred.
2169 view()->main_render_frame()->didFailProvisionalLoad(web_frame, error);
2170 const int kMaxOutputCharacters = 22;
2171 EXPECT_EQ("",
2172 base::UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters)));
2175 #if defined(OS_ANDROID)
2176 // Crashing on Android: http://crbug.com/311341
2177 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2178 #else
2179 #define MAYBE_DoesNotSuppress DoesNotSuppress
2180 #endif
2182 TEST_F(SuppressErrorPageTest, MAYBE_DoesNotSuppress) {
2183 WebURLError error;
2184 error.domain = WebString::fromUTF8(net::kErrorDomain);
2185 error.reason = net::ERR_FILE_NOT_FOUND;
2186 error.unreachableURL = GURL("http://example.com/dont-suppress");
2187 WebLocalFrame* web_frame = GetMainFrame();
2189 // Start a load that will reach provisional state synchronously,
2190 // but won't complete synchronously.
2191 FrameMsg_Navigate_Params params;
2192 params.page_id = -1;
2193 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2194 params.url = GURL("data:text/html,test data");
2195 params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
2196 frame()->OnNavigate(params);
2198 // An error occurred.
2199 view()->main_render_frame()->didFailProvisionalLoad(web_frame, error);
2200 // The error page itself is loaded asynchronously.
2201 FrameLoadWaiter(frame()).Wait();
2202 const int kMaxOutputCharacters = 22;
2203 EXPECT_EQ("A suffusion of yellow.",
2204 base::UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters)));
2207 // Tests if IME API's candidatewindow* events sent from browser are handled
2208 // in renderer.
2209 TEST_F(RenderViewImplTest, SendCandidateWindowEvents) {
2210 // Sends an HTML with an <input> element and scripts to the renderer.
2211 // The script handles all 3 of candidatewindow* events for an
2212 // InputMethodContext object and once it received 'show', 'update', 'hide'
2213 // should appear in the result div.
2214 LoadHTML("<input id='test'>"
2215 "<div id='result'>Result: </div>"
2216 "<script>"
2217 "window.onload = function() {"
2218 " var result = document.getElementById('result');"
2219 " var test = document.getElementById('test');"
2220 " test.focus();"
2221 " var context = test.inputMethodContext;"
2222 " if (context) {"
2223 " context.oncandidatewindowshow = function() {"
2224 " result.innerText += 'show'; };"
2225 " context.oncandidatewindowupdate = function(){"
2226 " result.innerText += 'update'; };"
2227 " context.oncandidatewindowhide = function(){"
2228 " result.innerText += 'hide'; };"
2229 " }"
2230 "};"
2231 "</script>");
2233 // Fire candidatewindow events.
2234 view()->OnCandidateWindowShown();
2235 view()->OnCandidateWindowUpdated();
2236 view()->OnCandidateWindowHidden();
2238 // Retrieve the content and check if it is expected.
2239 const int kMaxOutputCharacters = 50;
2240 std::string output = base::UTF16ToUTF8(
2241 GetMainFrame()->contentAsText(kMaxOutputCharacters));
2242 EXPECT_EQ(output, "\nResult:showupdatehide");
2245 // Ensure the render view sends favicon url update events correctly.
2246 TEST_F(RenderViewImplTest, SendFaviconURLUpdateEvent) {
2247 // An event should be sent when a favicon url exists.
2248 LoadHTML("<html>"
2249 "<head>"
2250 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2251 "</head>"
2252 "</html>");
2253 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
2254 ViewHostMsg_UpdateFaviconURL::ID));
2255 render_thread_->sink().ClearMessages();
2257 // An event should not be sent if no favicon url exists. This is an assumption
2258 // made by some of Chrome's favicon handling.
2259 LoadHTML("<html>"
2260 "<head>"
2261 "</head>"
2262 "</html>");
2263 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
2264 ViewHostMsg_UpdateFaviconURL::ID));
2267 TEST_F(RenderViewImplTest, FocusElementCallsFocusedNodeChanged) {
2268 LoadHTML("<input id='test1' value='hello1'></input>"
2269 "<input id='test2' value='hello2'></input>");
2271 ExecuteJavaScript("document.getElementById('test1').focus();");
2272 const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
2273 ViewHostMsg_FocusedNodeChanged::ID);
2274 EXPECT_TRUE(msg1);
2276 ViewHostMsg_FocusedNodeChanged::Param params;
2277 ViewHostMsg_FocusedNodeChanged::Read(msg1, &params);
2278 EXPECT_TRUE(params.a);
2279 render_thread_->sink().ClearMessages();
2281 ExecuteJavaScript("document.getElementById('test2').focus();");
2282 const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching(
2283 ViewHostMsg_FocusedNodeChanged::ID);
2284 EXPECT_TRUE(msg2);
2285 ViewHostMsg_FocusedNodeChanged::Read(msg2, &params);
2286 EXPECT_TRUE(params.a);
2287 render_thread_->sink().ClearMessages();
2289 view()->webview()->clearFocusedElement();
2290 const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching(
2291 ViewHostMsg_FocusedNodeChanged::ID);
2292 EXPECT_TRUE(msg3);
2293 ViewHostMsg_FocusedNodeChanged::Read(msg3, &params);
2294 EXPECT_FALSE(params.a);
2295 render_thread_->sink().ClearMessages();
2298 TEST_F(RenderViewImplTest, ServiceWorkerNetworkProviderSetup) {
2299 ServiceWorkerNetworkProvider* provider = NULL;
2300 RequestExtraData* extra_data = NULL;
2302 // Make sure each new document has a new provider and
2303 // that the main request is tagged with the provider's id.
2304 LoadHTML("<b>A Document</b>");
2305 ASSERT_TRUE(GetMainFrame()->dataSource());
2306 provider = ServiceWorkerNetworkProvider::FromDocumentState(
2307 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2308 ASSERT_TRUE(provider);
2309 extra_data = static_cast<RequestExtraData*>(
2310 GetMainFrame()->dataSource()->request().extraData());
2311 ASSERT_TRUE(extra_data);
2312 EXPECT_EQ(extra_data->service_worker_provider_id(),
2313 provider->provider_id());
2314 int provider1_id = provider->provider_id();
2316 LoadHTML("<b>New Document B Goes Here</b>");
2317 ASSERT_TRUE(GetMainFrame()->dataSource());
2318 provider = ServiceWorkerNetworkProvider::FromDocumentState(
2319 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2320 ASSERT_TRUE(provider);
2321 EXPECT_NE(provider1_id, provider->provider_id());
2322 extra_data = static_cast<RequestExtraData*>(
2323 GetMainFrame()->dataSource()->request().extraData());
2324 ASSERT_TRUE(extra_data);
2325 EXPECT_EQ(extra_data->service_worker_provider_id(),
2326 provider->provider_id());
2328 // See that subresource requests are also tagged with the provider's id.
2329 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2330 blink::WebURLRequest request(GURL("http://foo.com"));
2331 request.setRequestContext(blink::WebURLRequest::RequestContextSubresource);
2332 blink::WebURLResponse redirect_response;
2333 frame()->willSendRequest(GetMainFrame(), 0, request, redirect_response);
2334 extra_data = static_cast<RequestExtraData*>(request.extraData());
2335 ASSERT_TRUE(extra_data);
2336 EXPECT_EQ(extra_data->service_worker_provider_id(),
2337 provider->provider_id());
2340 TEST_F(RenderViewImplTest, OnSetAccessibilityMode) {
2341 ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
2342 ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2344 frame()->OnSetAccessibilityMode(AccessibilityModeTreeOnly);
2345 ASSERT_EQ(AccessibilityModeTreeOnly, frame()->accessibility_mode());
2346 ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2347 ASSERT_EQ(RendererAccessibilityTypeComplete,
2348 frame()->renderer_accessibility()->GetType());
2350 frame()->OnSetAccessibilityMode(AccessibilityModeOff);
2351 ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
2352 ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2354 frame()->OnSetAccessibilityMode(AccessibilityModeComplete);
2355 ASSERT_EQ(AccessibilityModeComplete, frame()->accessibility_mode());
2356 ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2357 ASSERT_EQ(RendererAccessibilityTypeComplete,
2358 frame()->renderer_accessibility()->GetType());
2360 frame()->OnSetAccessibilityMode(AccessibilityModeEditableTextOnly);
2361 ASSERT_EQ(AccessibilityModeEditableTextOnly, frame()->accessibility_mode());
2362 ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2363 ASSERT_EQ(RendererAccessibilityTypeFocusOnly,
2364 frame()->renderer_accessibility()->GetType());
2367 TEST_F(RenderViewImplTest, ScreenMetricsEmulation) {
2368 LoadHTML("<body style='min-height:1000px;'></body>");
2370 blink::WebDeviceEmulationParams params;
2371 base::string16 get_width = base::ASCIIToUTF16("Number(window.innerWidth)");
2372 base::string16 get_height = base::ASCIIToUTF16("Number(window.innerHeight)");
2373 int width, height;
2375 params.viewSize.width = 327;
2376 params.viewSize.height = 415;
2377 view()->EnableScreenMetricsEmulation(params);
2378 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width));
2379 EXPECT_EQ(params.viewSize.width, width);
2380 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height));
2381 EXPECT_EQ(params.viewSize.height, height);
2383 params.viewSize.width = 1005;
2384 params.viewSize.height = 1102;
2385 view()->EnableScreenMetricsEmulation(params);
2386 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width));
2387 EXPECT_EQ(params.viewSize.width, width);
2388 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height));
2389 EXPECT_EQ(params.viewSize.height, height);
2391 view()->DisableScreenMetricsEmulation();
2393 view()->EnableScreenMetricsEmulation(params);
2394 // Don't disable here to test that emulation is being shutdown properly.
2397 // Sanity checks for the Navigation Timing API |navigationStart| override. We
2398 // are asserting only most basic constraints, as TimeTicks (passed as the
2399 // override) are not comparable with the wall time (returned by the Blink API).
2400 TEST_F(RenderViewImplTest, NavigationStartOverride) {
2401 // Verify that a navigation that claims to have started at the earliest
2402 // possible TimeTicks is indeed reported as one that started before
2403 // OnNavigate() is called.
2404 base::Time before_navigation = base::Time::Now();
2405 FrameMsg_Navigate_Params early_nav_params;
2406 early_nav_params.url = GURL("data:text/html,<div>Page</div>");
2407 early_nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2408 early_nav_params.transition = PAGE_TRANSITION_TYPED;
2409 early_nav_params.page_id = -1;
2410 early_nav_params.is_post = true;
2411 early_nav_params.browser_navigation_start =
2412 base::TimeTicks::FromInternalValue(1);
2414 frame()->OnNavigate(early_nav_params);
2415 ProcessPendingMessages();
2417 base::Time early_nav_reported_start =
2418 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2419 EXPECT_LT(early_nav_reported_start, before_navigation);
2421 // Verify that a navigation that claims to have started in the future - 42
2422 // days from now is *not* reported as one that starts in the future; as we
2423 // sanitize the override allowing a maximum of ::Now().
2424 FrameMsg_Navigate_Params late_nav_params;
2425 late_nav_params.url = GURL("data:text/html,<div>Another page</div>");
2426 late_nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2427 late_nav_params.transition = PAGE_TRANSITION_TYPED;
2428 late_nav_params.page_id = -1;
2429 late_nav_params.is_post = true;
2430 late_nav_params.browser_navigation_start =
2431 base::TimeTicks::Now() + base::TimeDelta::FromDays(42);
2433 frame()->OnNavigate(late_nav_params);
2434 ProcessPendingMessages();
2435 base::Time after_navigation =
2436 base::Time::Now() + base::TimeDelta::FromDays(1);
2438 base::Time late_nav_reported_start =
2439 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2440 EXPECT_LE(late_nav_reported_start, after_navigation);
2443 } // namespace content