Removing uses of X11 native key events.
[chromium-blink-merge.git] / content / renderer / render_view_browsertest.cc
blob5752e37f4421491347d8f1693f036531a5c58049
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/frame_load_waiter.h"
30 #include "content/public/test/render_view_test.h"
31 #include "content/public/test/test_utils.h"
32 #include "content/renderer/accessibility/renderer_accessibility.h"
33 #include "content/renderer/accessibility/renderer_accessibility_complete.h"
34 #include "content/renderer/accessibility/renderer_accessibility_focus_only.h"
35 #include "content/renderer/history_controller.h"
36 #include "content/renderer/history_serialization.h"
37 #include "content/renderer/render_process.h"
38 #include "content/renderer/render_view_impl.h"
39 #include "content/shell/browser/shell.h"
40 #include "content/shell/browser/shell_browser_context.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 event2.set_character(GetCharacterFromKeyCode(event2.key_code(),
240 event2.flags()));
241 ui::KeyEventTestApi test_event2(&event2);
242 test_event2.set_is_char(true);
243 NativeWebKeyboardEvent char_event(&event2);
244 SendNativeKeyEvent(char_event);
246 xevent.InitKeyEvent(ui::ET_KEY_RELEASED,
247 static_cast<ui::KeyboardCode>(key_code),
248 flags);
249 ui::KeyEvent event3(xevent);
250 NativeWebKeyboardEvent keyup_event(&event3);
251 SendNativeKeyEvent(keyup_event);
253 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
254 flags);
255 output->assign(1, static_cast<base::char16>(c));
256 return 1;
257 #elif defined(USE_OZONE)
258 const int flags = ConvertMockKeyboardModifier(modifiers);
260 ui::KeyEvent keydown_event(ui::ET_KEY_PRESSED,
261 static_cast<ui::KeyboardCode>(key_code),
262 flags);
263 NativeWebKeyboardEvent keydown_web_event(&keydown_event);
264 SendNativeKeyEvent(keydown_web_event);
266 ui::KeyEvent char_event(keydown_event.GetCharacter(),
267 static_cast<ui::KeyboardCode>(key_code),
268 flags);
269 NativeWebKeyboardEvent char_web_event(&char_event);
270 SendNativeKeyEvent(char_web_event);
272 ui::KeyEvent keyup_event(ui::ET_KEY_RELEASED,
273 static_cast<ui::KeyboardCode>(key_code),
274 flags);
275 NativeWebKeyboardEvent keyup_web_event(&keyup_event);
276 SendNativeKeyEvent(keyup_web_event);
278 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
279 flags);
280 output->assign(1, static_cast<base::char16>(c));
281 return 1;
282 #else
283 NOTIMPLEMENTED();
284 return L'\0';
285 #endif
288 private:
289 scoped_ptr<MockKeyboard> mock_keyboard_;
292 TEST_F(RenderViewImplTest, SaveImageFromDataURL) {
293 const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
294 ViewHostMsg_SaveImageFromDataURL::ID);
295 EXPECT_FALSE(msg1);
296 render_thread_->sink().ClearMessages();
298 const std::string image_data_url =
299 "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
301 view()->saveImageFromDataURL(WebString::fromUTF8(image_data_url));
302 ProcessPendingMessages();
303 const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching(
304 ViewHostMsg_SaveImageFromDataURL::ID);
305 EXPECT_TRUE(msg2);
307 ViewHostMsg_SaveImageFromDataURL::Param param1;
308 ViewHostMsg_SaveImageFromDataURL::Read(msg2, &param1);
309 EXPECT_EQ(param1.b.length(), image_data_url.length());
310 EXPECT_EQ(param1.b, image_data_url);
312 ProcessPendingMessages();
313 render_thread_->sink().ClearMessages();
315 const std::string large_data_url(1024 * 1024 * 10 - 1, 'd');
317 view()->saveImageFromDataURL(WebString::fromUTF8(large_data_url));
318 ProcessPendingMessages();
319 const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching(
320 ViewHostMsg_SaveImageFromDataURL::ID);
321 EXPECT_TRUE(msg3);
323 ViewHostMsg_SaveImageFromDataURL::Param param2;
324 ViewHostMsg_SaveImageFromDataURL::Read(msg3, &param2);
325 EXPECT_EQ(param2.b.length(), large_data_url.length());
326 EXPECT_EQ(param2.b, large_data_url);
328 ProcessPendingMessages();
329 render_thread_->sink().ClearMessages();
331 const std::string exceeded_data_url(1024 * 1024 * 10 + 1, 'd');
333 view()->saveImageFromDataURL(WebString::fromUTF8(exceeded_data_url));
334 ProcessPendingMessages();
335 const IPC::Message* msg4 = render_thread_->sink().GetFirstMessageMatching(
336 ViewHostMsg_SaveImageFromDataURL::ID);
337 EXPECT_FALSE(msg4);
340 // Test that we get form state change notifications when input fields change.
341 TEST_F(RenderViewImplTest, DISABLED_OnNavStateChanged) {
342 // Don't want any delay for form state sync changes. This will still post a
343 // message so updates will get coalesced, but as soon as we spin the message
344 // loop, it will generate an update.
345 view()->set_send_content_state_immediately(true);
347 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
349 // We should NOT have gotten a form state change notification yet.
350 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
351 ViewHostMsg_UpdateState::ID));
352 render_thread_->sink().ClearMessages();
354 // Change the value of the input. We should have gotten an update state
355 // notification. We need to spin the message loop to catch this update.
356 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';");
357 ProcessPendingMessages();
358 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
359 ViewHostMsg_UpdateState::ID));
362 TEST_F(RenderViewImplTest, OnNavigationHttpPost) {
363 FrameMsg_Navigate_Params nav_params;
365 // An http url will trigger a resource load so cannot be used here.
366 nav_params.url = GURL("data:text/html,<div>Page</div>");
367 nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
368 nav_params.transition = ui::PAGE_TRANSITION_TYPED;
369 nav_params.page_id = -1;
370 nav_params.is_post = true;
371 nav_params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
373 // Set up post data.
374 const unsigned char* raw_data = reinterpret_cast<const unsigned char*>(
375 "post \0\ndata");
376 const unsigned int length = 11;
377 const std::vector<unsigned char> post_data(raw_data, raw_data + length);
378 nav_params.browser_initiated_post_data = post_data;
380 frame()->OnNavigate(nav_params);
381 ProcessPendingMessages();
383 const IPC::Message* frame_navigate_msg =
384 render_thread_->sink().GetUniqueMessageMatching(
385 FrameHostMsg_DidCommitProvisionalLoad::ID);
386 EXPECT_TRUE(frame_navigate_msg);
388 FrameHostMsg_DidCommitProvisionalLoad::Param host_nav_params;
389 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
390 &host_nav_params);
391 EXPECT_TRUE(host_nav_params.a.is_post);
393 // Check post data sent to browser matches
394 EXPECT_TRUE(host_nav_params.a.page_state.IsValid());
395 scoped_ptr<HistoryEntry> entry =
396 PageStateToHistoryEntry(host_nav_params.a.page_state);
397 blink::WebHTTPBody body = entry->root().httpBody();
398 blink::WebHTTPBody::Element element;
399 bool successful = body.elementAt(0, element);
400 EXPECT_TRUE(successful);
401 EXPECT_EQ(blink::WebHTTPBody::Element::TypeData, element.type);
402 EXPECT_EQ(length, element.data.size());
403 EXPECT_EQ(0, memcmp(raw_data, element.data.data(), length));
406 TEST_F(RenderViewImplTest, DecideNavigationPolicy) {
407 WebUITestWebUIControllerFactory factory;
408 WebUIControllerFactory::RegisterFactory(&factory);
410 DocumentState state;
411 state.set_navigation_state(NavigationState::CreateContentInitiated());
413 // Navigations to normal HTTP URLs can be handled locally.
414 blink::WebURLRequest request(GURL("http://foo.com"));
415 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
416 policy_info.frame = GetMainFrame();
417 policy_info.extraData = &state;
418 policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
419 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
420 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
421 policy_info);
422 EXPECT_EQ(blink::WebNavigationPolicyCurrentTab, policy);
424 // Verify that form posts to WebUI URLs will be sent to the browser process.
425 blink::WebURLRequest form_request(GURL("chrome://foo"));
426 blink::WebFrameClient::NavigationPolicyInfo form_policy_info(form_request);
427 form_policy_info.frame = GetMainFrame();
428 form_policy_info.extraData = &state;
429 form_policy_info.navigationType = blink::WebNavigationTypeFormSubmitted;
430 form_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
431 form_request.setHTTPMethod("POST");
432 policy = frame()->decidePolicyForNavigation(form_policy_info);
433 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
435 // Verify that popup links to WebUI URLs also are sent to browser.
436 blink::WebURLRequest popup_request(GURL("chrome://foo"));
437 blink::WebFrameClient::NavigationPolicyInfo popup_policy_info(popup_request);
438 popup_policy_info.frame = GetMainFrame();
439 popup_policy_info.extraData = &state;
440 popup_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
441 popup_policy_info.defaultPolicy = blink::WebNavigationPolicyNewForegroundTab;
442 policy = frame()->decidePolicyForNavigation(popup_policy_info);
443 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
446 TEST_F(RenderViewImplTest, DecideNavigationPolicyHandlesAllTopLevel) {
447 DocumentState state;
448 state.set_navigation_state(NavigationState::CreateContentInitiated());
450 RendererPreferences prefs = view()->renderer_preferences();
451 prefs.browser_handles_all_top_level_requests = true;
452 view()->OnSetRendererPrefs(prefs);
454 const blink::WebNavigationType kNavTypes[] = {
455 blink::WebNavigationTypeLinkClicked,
456 blink::WebNavigationTypeFormSubmitted,
457 blink::WebNavigationTypeBackForward,
458 blink::WebNavigationTypeReload,
459 blink::WebNavigationTypeFormResubmitted,
460 blink::WebNavigationTypeOther,
463 blink::WebURLRequest request(GURL("http://foo.com"));
464 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
465 policy_info.frame = GetMainFrame();
466 policy_info.extraData = &state;
467 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
469 for (size_t i = 0; i < arraysize(kNavTypes); ++i) {
470 policy_info.navigationType = kNavTypes[i];
472 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
473 policy_info);
474 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
478 TEST_F(RenderViewImplTest, DecideNavigationPolicyForWebUI) {
479 // Enable bindings to simulate a WebUI view.
480 view()->OnAllowBindings(BINDINGS_POLICY_WEB_UI);
482 DocumentState state;
483 state.set_navigation_state(NavigationState::CreateContentInitiated());
485 // Navigations to normal HTTP URLs will be sent to browser process.
486 blink::WebURLRequest request(GURL("http://foo.com"));
487 blink::WebFrameClient::NavigationPolicyInfo policy_info(request);
488 policy_info.frame = GetMainFrame();
489 policy_info.extraData = &state;
490 policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
491 policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
493 blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
494 policy_info);
495 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
497 // Navigations to WebUI URLs will also be sent to browser process.
498 blink::WebURLRequest webui_request(GURL("chrome://foo"));
499 blink::WebFrameClient::NavigationPolicyInfo webui_policy_info(webui_request);
500 webui_policy_info.frame = GetMainFrame();
501 webui_policy_info.extraData = &state;
502 webui_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
503 webui_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
504 policy = frame()->decidePolicyForNavigation(webui_policy_info);
505 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
507 // Verify that form posts to data URLs will be sent to the browser process.
508 blink::WebURLRequest data_request(GURL("data:text/html,foo"));
509 blink::WebFrameClient::NavigationPolicyInfo data_policy_info(data_request);
510 data_policy_info.frame = GetMainFrame();
511 data_policy_info.extraData = &state;
512 data_policy_info.navigationType = blink::WebNavigationTypeFormSubmitted;
513 data_policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
514 data_request.setHTTPMethod("POST");
515 policy = frame()->decidePolicyForNavigation(data_policy_info);
516 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
518 // Verify that a popup that creates a view first and then navigates to a
519 // normal HTTP URL will be sent to the browser process, even though the
520 // new view does not have any enabled_bindings_.
521 blink::WebURLRequest popup_request(GURL("http://foo.com"));
522 blink::WebView* new_web_view = view()->createView(
523 GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
524 blink::WebNavigationPolicyNewForegroundTab, false);
525 RenderViewImpl* new_view = RenderViewImpl::FromWebView(new_web_view);
526 blink::WebFrameClient::NavigationPolicyInfo popup_policy_info(popup_request);
527 popup_policy_info.frame = new_web_view->mainFrame()->toWebLocalFrame();
528 popup_policy_info.extraData = &state;
529 popup_policy_info.navigationType = blink::WebNavigationTypeLinkClicked;
530 popup_policy_info.defaultPolicy = blink::WebNavigationPolicyNewForegroundTab;
531 policy = static_cast<RenderFrameImpl*>(new_view->GetMainRenderFrame())->
532 decidePolicyForNavigation(popup_policy_info);
533 EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
535 // Clean up after the new view so we don't leak it.
536 new_view->Close();
537 new_view->Release();
540 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
541 // already swapped out. http://crbug.com/93427.
542 TEST_F(RenderViewImplTest, SendSwapOutACK) {
543 LoadHTML("<div>Page A</div>");
544 int initial_page_id = view_page_id();
546 // Increment the ref count so that we don't exit when swapping out.
547 RenderProcess::current()->AddRefProcess();
549 // Respond to a swap out request.
550 view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId);
552 // Ensure the swap out commits synchronously.
553 EXPECT_NE(initial_page_id, view_page_id());
555 // Check for a valid OnSwapOutACK.
556 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
557 FrameHostMsg_SwapOut_ACK::ID);
558 ASSERT_TRUE(msg);
560 // It is possible to get another swap out request. Ensure that we send
561 // an ACK, even if we don't have to do anything else.
562 render_thread_->sink().ClearMessages();
563 view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId);
564 const IPC::Message* msg2 = render_thread_->sink().GetUniqueMessageMatching(
565 FrameHostMsg_SwapOut_ACK::ID);
566 ASSERT_TRUE(msg2);
568 // If we navigate back to this RenderView, ensure we don't send a state
569 // update for the swapped out URL. (http://crbug.com/72235)
570 FrameMsg_Navigate_Params nav_params;
571 nav_params.url = GURL("data:text/html,<div>Page B</div>");
572 nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
573 nav_params.transition = ui::PAGE_TRANSITION_TYPED;
574 nav_params.current_history_list_length = 1;
575 nav_params.current_history_list_offset = 0;
576 nav_params.pending_history_list_offset = 1;
577 nav_params.page_id = -1;
578 nav_params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
579 frame()->OnNavigate(nav_params);
580 ProcessPendingMessages();
581 const IPC::Message* msg3 = render_thread_->sink().GetUniqueMessageMatching(
582 ViewHostMsg_UpdateState::ID);
583 EXPECT_FALSE(msg3);
586 // Ensure the RenderViewImpl reloads the previous page if a reload request
587 // arrives while it is showing swappedout://. http://crbug.com/143155.
588 TEST_F(RenderViewImplTest, ReloadWhileSwappedOut) {
589 // Load page A.
590 LoadHTML("<div>Page A</div>");
592 // Load page B, which will trigger an UpdateState message for page A.
593 LoadHTML("<div>Page B</div>");
595 // Check for a valid UpdateState message for page A.
596 ProcessPendingMessages();
597 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
598 ViewHostMsg_UpdateState::ID);
599 ASSERT_TRUE(msg_A);
600 ViewHostMsg_UpdateState::Param params;
601 ViewHostMsg_UpdateState::Read(msg_A, &params);
602 int page_id_A = params.a;
603 PageState state_A = params.b;
604 EXPECT_EQ(1, page_id_A);
605 render_thread_->sink().ClearMessages();
607 // Back to page A (page_id 1) and commit.
608 FrameMsg_Navigate_Params params_A;
609 params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL;
610 params_A.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
611 params_A.current_history_list_length = 2;
612 params_A.current_history_list_offset = 1;
613 params_A.pending_history_list_offset = 0;
614 params_A.page_id = 1;
615 params_A.page_state = state_A;
616 params_A.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
617 frame()->OnNavigate(params_A);
618 ProcessPendingMessages();
620 // Respond to a swap out request.
621 view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId);
623 // Check for a OnSwapOutACK.
624 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
625 FrameHostMsg_SwapOut_ACK::ID);
626 ASSERT_TRUE(msg);
627 render_thread_->sink().ClearMessages();
629 // It is possible to get a reload request at this point, containing the
630 // params.page_state of the initial page (e.g., if the new page fails the
631 // provisional load in the renderer process, after we unload the old page).
632 // Ensure the old page gets reloaded, not swappedout://.
633 FrameMsg_Navigate_Params nav_params;
634 nav_params.url = GURL("data:text/html,<div>Page A</div>");
635 nav_params.navigation_type = FrameMsg_Navigate_Type::RELOAD;
636 nav_params.transition = ui::PAGE_TRANSITION_RELOAD;
637 nav_params.current_history_list_length = 2;
638 nav_params.current_history_list_offset = 0;
639 nav_params.pending_history_list_offset = 0;
640 nav_params.page_id = 1;
641 nav_params.page_state = state_A;
642 nav_params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
643 frame()->OnNavigate(nav_params);
644 ProcessPendingMessages();
646 // Verify page A committed, not swappedout://.
647 const IPC::Message* frame_navigate_msg =
648 render_thread_->sink().GetUniqueMessageMatching(
649 FrameHostMsg_DidCommitProvisionalLoad::ID);
650 EXPECT_TRUE(frame_navigate_msg);
652 // Read URL out of the parent trait of the params object.
653 FrameHostMsg_DidCommitProvisionalLoad::Param commit_params;
654 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
655 &commit_params);
656 EXPECT_NE(GURL("swappedout://"), commit_params.a.url);
660 // Test that we get the correct UpdateState message when we go back twice
661 // quickly without committing. Regression test for http://crbug.com/58082.
662 // Disabled: http://crbug.com/157357 .
663 TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) {
664 // Load page A.
665 LoadHTML("<div>Page A</div>");
667 // Load page B, which will trigger an UpdateState message for page A.
668 LoadHTML("<div>Page B</div>");
670 // Check for a valid UpdateState message for page A.
671 ProcessPendingMessages();
672 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
673 ViewHostMsg_UpdateState::ID);
674 ASSERT_TRUE(msg_A);
675 ViewHostMsg_UpdateState::Param param;
676 ViewHostMsg_UpdateState::Read(msg_A, &param);
677 int page_id_A = param.a;
678 PageState state_A = param.b;
679 EXPECT_EQ(1, page_id_A);
680 render_thread_->sink().ClearMessages();
682 // Load page C, which will trigger an UpdateState message for page B.
683 LoadHTML("<div>Page C</div>");
685 // Check for a valid UpdateState for page B.
686 ProcessPendingMessages();
687 const IPC::Message* msg_B = render_thread_->sink().GetUniqueMessageMatching(
688 ViewHostMsg_UpdateState::ID);
689 ASSERT_TRUE(msg_B);
690 ViewHostMsg_UpdateState::Read(msg_B, &param);
691 int page_id_B = param.a;
692 PageState state_B = param.b;
693 EXPECT_EQ(2, page_id_B);
694 EXPECT_NE(state_A, state_B);
695 render_thread_->sink().ClearMessages();
697 // Load page D, which will trigger an UpdateState message for page C.
698 LoadHTML("<div>Page D</div>");
700 // Check for a valid UpdateState for page C.
701 ProcessPendingMessages();
702 const IPC::Message* msg_C = render_thread_->sink().GetUniqueMessageMatching(
703 ViewHostMsg_UpdateState::ID);
704 ASSERT_TRUE(msg_C);
705 ViewHostMsg_UpdateState::Read(msg_C, &param);
706 int page_id_C = param.a;
707 PageState state_C = param.b;
708 EXPECT_EQ(3, page_id_C);
709 EXPECT_NE(state_B, state_C);
710 render_thread_->sink().ClearMessages();
712 // Go back to C and commit, preparing for our real test.
713 FrameMsg_Navigate_Params params_C;
714 params_C.navigation_type = FrameMsg_Navigate_Type::NORMAL;
715 params_C.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
716 params_C.current_history_list_length = 4;
717 params_C.current_history_list_offset = 3;
718 params_C.pending_history_list_offset = 2;
719 params_C.page_id = 3;
720 params_C.page_state = state_C;
721 params_C.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
722 frame()->OnNavigate(params_C);
723 ProcessPendingMessages();
724 render_thread_->sink().ClearMessages();
726 // Go back twice quickly, such that page B does not have a chance to commit.
727 // This leads to two changes to the back/forward list but only one change to
728 // the RenderView's page ID.
730 // Back to page B (page_id 2), without committing.
731 FrameMsg_Navigate_Params params_B;
732 params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
733 params_B.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
734 params_B.current_history_list_length = 4;
735 params_B.current_history_list_offset = 2;
736 params_B.pending_history_list_offset = 1;
737 params_B.page_id = 2;
738 params_B.page_state = state_B;
739 params_B.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
740 frame()->OnNavigate(params_B);
742 // Back to page A (page_id 1) and commit.
743 FrameMsg_Navigate_Params params;
744 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
745 params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
746 params_B.current_history_list_length = 4;
747 params_B.current_history_list_offset = 2;
748 params_B.pending_history_list_offset = 0;
749 params.page_id = 1;
750 params.page_state = state_A;
751 params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
752 frame()->OnNavigate(params);
753 ProcessPendingMessages();
755 // Now ensure that the UpdateState message we receive is consistent
756 // and represents page C in both page_id and state.
757 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
758 ViewHostMsg_UpdateState::ID);
759 ASSERT_TRUE(msg);
760 ViewHostMsg_UpdateState::Read(msg, &param);
761 int page_id = param.a;
762 PageState state = param.b;
763 EXPECT_EQ(page_id_C, page_id);
764 EXPECT_NE(state_A, state);
765 EXPECT_NE(state_B, state);
766 EXPECT_EQ(state_C, state);
769 // Test that the history_page_ids_ list can reveal when a stale back/forward
770 // navigation arrives from the browser and can be ignored. See
771 // http://crbug.com/86758.
772 TEST_F(RenderViewImplTest, StaleNavigationsIgnored) {
773 // Load page A.
774 LoadHTML("<div>Page A</div>");
775 EXPECT_EQ(1, view()->history_list_length_);
776 EXPECT_EQ(0, view()->history_list_offset_);
777 EXPECT_EQ(1, view()->history_page_ids_[0]);
779 // Load page B, which will trigger an UpdateState message for page A.
780 LoadHTML("<div>Page B</div>");
781 EXPECT_EQ(2, view()->history_list_length_);
782 EXPECT_EQ(1, view()->history_list_offset_);
783 EXPECT_EQ(2, view()->history_page_ids_[1]);
785 // Check for a valid UpdateState message for page A.
786 ProcessPendingMessages();
787 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
788 ViewHostMsg_UpdateState::ID);
789 ASSERT_TRUE(msg_A);
790 ViewHostMsg_UpdateState::Param param;
791 ViewHostMsg_UpdateState::Read(msg_A, &param);
792 int page_id_A = param.a;
793 PageState state_A = param.b;
794 EXPECT_EQ(1, page_id_A);
795 render_thread_->sink().ClearMessages();
797 // Back to page A (page_id 1) and commit.
798 FrameMsg_Navigate_Params params_A;
799 params_A.navigation_type = FrameMsg_Navigate_Type::NORMAL;
800 params_A.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
801 params_A.current_history_list_length = 2;
802 params_A.current_history_list_offset = 1;
803 params_A.pending_history_list_offset = 0;
804 params_A.page_id = 1;
805 params_A.page_state = state_A;
806 params_A.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
807 frame()->OnNavigate(params_A);
808 ProcessPendingMessages();
810 // A new navigation commits, clearing the forward history.
811 LoadHTML("<div>Page C</div>");
812 EXPECT_EQ(2, view()->history_list_length_);
813 EXPECT_EQ(1, view()->history_list_offset_);
814 EXPECT_EQ(3, view()->history_page_ids_[1]);
816 // The browser then sends a stale navigation to B, which should be ignored.
817 FrameMsg_Navigate_Params params_B;
818 params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
819 params_B.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
820 params_B.current_history_list_length = 2;
821 params_B.current_history_list_offset = 0;
822 params_B.pending_history_list_offset = 1;
823 params_B.page_id = 2;
824 params_B.page_state = state_A; // Doesn't matter, just has to be present.
825 params_B.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
826 frame()->OnNavigate(params_B);
828 // State should be unchanged.
829 EXPECT_EQ(2, view()->history_list_length_);
830 EXPECT_EQ(1, view()->history_list_offset_);
831 EXPECT_EQ(3, view()->history_page_ids_[1]);
834 // Test that we do not ignore navigations after the entry limit is reached,
835 // in which case the browser starts dropping entries from the front. In this
836 // case, we'll see a page_id mismatch but the RenderView's id will be older,
837 // not newer, than params.page_id. Use this as a cue that we should update the
838 // state and not treat it like a navigation to a cropped forward history item.
839 // See http://crbug.com/89798.
840 TEST_F(RenderViewImplTest, DontIgnoreBackAfterNavEntryLimit) {
841 // Load page A.
842 LoadHTML("<div>Page A</div>");
843 EXPECT_EQ(1, view()->history_list_length_);
844 EXPECT_EQ(0, view()->history_list_offset_);
845 EXPECT_EQ(1, view()->history_page_ids_[0]);
847 // Load page B, which will trigger an UpdateState message for page A.
848 LoadHTML("<div>Page B</div>");
849 EXPECT_EQ(2, view()->history_list_length_);
850 EXPECT_EQ(1, view()->history_list_offset_);
851 EXPECT_EQ(2, view()->history_page_ids_[1]);
853 // Check for a valid UpdateState message for page A.
854 ProcessPendingMessages();
855 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
856 ViewHostMsg_UpdateState::ID);
857 ASSERT_TRUE(msg_A);
858 ViewHostMsg_UpdateState::Param param;
859 ViewHostMsg_UpdateState::Read(msg_A, &param);
860 int page_id_A = param.a;
861 PageState state_A = param.b;
862 EXPECT_EQ(1, page_id_A);
863 render_thread_->sink().ClearMessages();
865 // Load page C, which will trigger an UpdateState message for page B.
866 LoadHTML("<div>Page C</div>");
867 EXPECT_EQ(3, view()->history_list_length_);
868 EXPECT_EQ(2, view()->history_list_offset_);
869 EXPECT_EQ(3, view()->history_page_ids_[2]);
871 // Check for a valid UpdateState message for page B.
872 ProcessPendingMessages();
873 const IPC::Message* msg_B = render_thread_->sink().GetUniqueMessageMatching(
874 ViewHostMsg_UpdateState::ID);
875 ASSERT_TRUE(msg_B);
876 ViewHostMsg_UpdateState::Read(msg_B, &param);
877 int page_id_B = param.a;
878 PageState state_B = param.b;
879 EXPECT_EQ(2, page_id_B);
880 render_thread_->sink().ClearMessages();
882 // Suppose the browser has limited the number of NavigationEntries to 2.
883 // It has now dropped the first entry, but the renderer isn't notified.
884 // Ensure that going back to page B (page_id 2) at offset 0 is successful.
885 FrameMsg_Navigate_Params params_B;
886 params_B.navigation_type = FrameMsg_Navigate_Type::NORMAL;
887 params_B.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
888 params_B.current_history_list_length = 2;
889 params_B.current_history_list_offset = 1;
890 params_B.pending_history_list_offset = 0;
891 params_B.page_id = 2;
892 params_B.page_state = state_B;
893 params_B.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
894 frame()->OnNavigate(params_B);
895 ProcessPendingMessages();
897 EXPECT_EQ(2, view()->history_list_length_);
898 EXPECT_EQ(0, view()->history_list_offset_);
899 EXPECT_EQ(2, view()->history_page_ids_[0]);
902 // Test that our IME backend sends a notification message when the input focus
903 // changes.
904 TEST_F(RenderViewImplTest, OnImeTypeChanged) {
905 // Enable our IME backend code.
906 view()->OnSetInputMethodActive(true);
908 // Load an HTML page consisting of two input fields.
909 view()->set_send_content_state_immediately(true);
910 LoadHTML("<html>"
911 "<head>"
912 "</head>"
913 "<body>"
914 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
915 "<input id=\"test2\" type=\"password\"></input>"
916 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
917 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
918 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
919 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
920 "</input>"
921 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
922 "</input>"
923 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
924 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
925 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
926 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
927 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
928 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
929 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
930 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
931 "</body>"
932 "</html>");
933 render_thread_->sink().ClearMessages();
935 struct InputModeTestCase {
936 const char* input_id;
937 ui::TextInputMode expected_mode;
939 static const InputModeTestCase kInputModeTestCases[] = {
940 {"test1", ui::TEXT_INPUT_MODE_DEFAULT},
941 {"test3", ui::TEXT_INPUT_MODE_VERBATIM},
942 {"test4", ui::TEXT_INPUT_MODE_LATIN},
943 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME},
944 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE},
945 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN},
946 {"test8", ui::TEXT_INPUT_MODE_KANA},
947 {"test9", ui::TEXT_INPUT_MODE_KATAKANA},
948 {"test10", ui::TEXT_INPUT_MODE_NUMERIC},
949 {"test11", ui::TEXT_INPUT_MODE_TEL},
950 {"test12", ui::TEXT_INPUT_MODE_EMAIL},
951 {"test13", ui::TEXT_INPUT_MODE_URL},
952 {"test14", ui::TEXT_INPUT_MODE_DEFAULT},
953 {"test15", ui::TEXT_INPUT_MODE_VERBATIM},
956 const int kRepeatCount = 10;
957 for (int i = 0; i < kRepeatCount; i++) {
958 // Move the input focus to the first <input> element, where we should
959 // activate IMEs.
960 ExecuteJavaScript("document.getElementById('test1').focus();");
961 ProcessPendingMessages();
962 render_thread_->sink().ClearMessages();
964 // Update the IME status and verify if our IME backend sends an IPC message
965 // to activate IMEs.
966 view()->UpdateTextInputState(
967 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
968 const IPC::Message* msg = render_thread_->sink().GetMessageAt(0);
969 EXPECT_TRUE(msg != NULL);
970 EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type());
971 ViewHostMsg_TextInputStateChanged::Param params;
972 ViewHostMsg_TextInputStateChanged::Read(msg, &params);
973 ViewHostMsg_TextInputState_Params p = params.a;
974 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, p.type);
975 EXPECT_EQ(true, p.can_compose_inline);
977 // Move the input focus to the second <input> element, where we should
978 // de-activate IMEs.
979 ExecuteJavaScript("document.getElementById('test2').focus();");
980 ProcessPendingMessages();
981 render_thread_->sink().ClearMessages();
983 // Update the IME status and verify if our IME backend sends an IPC message
984 // to de-activate IMEs.
985 view()->UpdateTextInputState(
986 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
987 msg = render_thread_->sink().GetMessageAt(0);
988 EXPECT_TRUE(msg != NULL);
989 EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type());
990 ViewHostMsg_TextInputStateChanged::Read(msg, &params);
991 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, params.a.type);
993 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kInputModeTestCases); j++) {
994 const InputModeTestCase* test_case = &kInputModeTestCases[j];
995 std::string javascript =
996 base::StringPrintf("document.getElementById('%s').focus();",
997 test_case->input_id);
998 // Move the input focus to the target <input> element, where we should
999 // activate IMEs.
1000 ExecuteJavaScript(javascript.c_str());
1001 ProcessPendingMessages();
1002 render_thread_->sink().ClearMessages();
1004 // Update the IME status and verify if our IME backend sends an IPC
1005 // message to activate IMEs.
1006 view()->UpdateTextInputState(
1007 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
1008 msg = render_thread_->sink().GetMessageAt(0);
1009 EXPECT_TRUE(msg != NULL);
1010 EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type());
1011 ViewHostMsg_TextInputStateChanged::Read(msg, &params);
1012 EXPECT_EQ(test_case->expected_mode, params.a.mode);
1017 // Test that our IME backend can compose CJK words.
1018 // Our IME front-end sends many platform-independent messages to the IME backend
1019 // while it composes CJK words. This test sends the minimal messages captured
1020 // on my local environment directly to the IME backend to verify if the backend
1021 // can compose CJK words without any problems.
1022 // This test uses an array of command sets because an IME composotion does not
1023 // only depends on IME events, but also depends on window events, e.g. moving
1024 // the window focus while composing a CJK text. To handle such complicated
1025 // cases, this test should not only call IME-related functions in the
1026 // RenderWidget class, but also call some RenderWidget members, e.g.
1027 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc.
1028 TEST_F(RenderViewImplTest, ImeComposition) {
1029 enum ImeCommand {
1030 IME_INITIALIZE,
1031 IME_SETINPUTMODE,
1032 IME_SETFOCUS,
1033 IME_SETCOMPOSITION,
1034 IME_CONFIRMCOMPOSITION,
1035 IME_CANCELCOMPOSITION
1037 struct ImeMessage {
1038 ImeCommand command;
1039 bool enable;
1040 int selection_start;
1041 int selection_end;
1042 const wchar_t* ime_string;
1043 const wchar_t* result;
1045 static const ImeMessage kImeMessages[] = {
1046 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
1047 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1048 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1049 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1050 {IME_SETCOMPOSITION, false, 1, 1, L"n", L"n"},
1051 {IME_SETCOMPOSITION, false, 2, 2, L"ni", L"ni"},
1052 {IME_SETCOMPOSITION, false, 3, 3, L"nih", L"nih"},
1053 {IME_SETCOMPOSITION, false, 4, 4, L"niha", L"niha"},
1054 {IME_SETCOMPOSITION, false, 5, 5, L"nihao", L"nihao"},
1055 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"\x4F60\x597D", L"\x4F60\x597D"},
1056 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
1057 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1058 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1059 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1060 {IME_SETCOMPOSITION, false, 0, 1, L"\xFF4B", L"\xFF4B"},
1061 {IME_SETCOMPOSITION, false, 0, 1, L"\x304B", L"\x304B"},
1062 {IME_SETCOMPOSITION, false, 0, 2, L"\x304B\xFF4E", L"\x304B\xFF4E"},
1063 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\xFF4A",
1064 L"\x304B\x3093\xFF4A"},
1065 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\x3058",
1066 L"\x304B\x3093\x3058"},
1067 {IME_SETCOMPOSITION, false, 0, 2, L"\x611F\x3058", L"\x611F\x3058"},
1068 {IME_SETCOMPOSITION, false, 0, 2, L"\x6F22\x5B57", L"\x6F22\x5B57"},
1069 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1070 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1071 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1072 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1073 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1074 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1075 {IME_SETCOMPOSITION, false, 0, 1, L"\x3147", L"\x3147"},
1076 {IME_SETCOMPOSITION, false, 0, 1, L"\xC544", L"\xC544"},
1077 {IME_SETCOMPOSITION, false, 0, 1, L"\xC548", L"\xC548"},
1078 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1079 {IME_SETCOMPOSITION, false, 0, 1, L"\x3134", L"\xC548\x3134"},
1080 {IME_SETCOMPOSITION, false, 0, 1, L"\xB140", L"\xC548\xB140"},
1081 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1082 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1083 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1084 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548\xB155"},
1087 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kImeMessages); i++) {
1088 const ImeMessage* ime_message = &kImeMessages[i];
1089 switch (ime_message->command) {
1090 case IME_INITIALIZE:
1091 // Load an HTML page consisting of a content-editable <div> element,
1092 // and move the input focus to the <div> element, where we can use
1093 // IMEs.
1094 view()->OnSetInputMethodActive(ime_message->enable);
1095 view()->set_send_content_state_immediately(true);
1096 LoadHTML("<html>"
1097 "<head>"
1098 "</head>"
1099 "<body>"
1100 "<div id=\"test1\" contenteditable=\"true\"></div>"
1101 "</body>"
1102 "</html>");
1103 ExecuteJavaScript("document.getElementById('test1').focus();");
1104 break;
1106 case IME_SETINPUTMODE:
1107 // Activate (or deactivate) our IME back-end.
1108 view()->OnSetInputMethodActive(ime_message->enable);
1109 break;
1111 case IME_SETFOCUS:
1112 // Update the window focus.
1113 view()->OnSetFocus(ime_message->enable);
1114 break;
1116 case IME_SETCOMPOSITION:
1117 view()->OnImeSetComposition(
1118 base::WideToUTF16(ime_message->ime_string),
1119 std::vector<blink::WebCompositionUnderline>(),
1120 ime_message->selection_start,
1121 ime_message->selection_end);
1122 break;
1124 case IME_CONFIRMCOMPOSITION:
1125 view()->OnImeConfirmComposition(
1126 base::WideToUTF16(ime_message->ime_string),
1127 gfx::Range::InvalidRange(),
1128 false);
1129 break;
1131 case IME_CANCELCOMPOSITION:
1132 view()->OnImeSetComposition(
1133 base::string16(),
1134 std::vector<blink::WebCompositionUnderline>(),
1135 0, 0);
1136 break;
1139 // Update the status of our IME back-end.
1140 // TODO(hbono): we should verify messages to be sent from the back-end.
1141 view()->UpdateTextInputState(
1142 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME);
1143 ProcessPendingMessages();
1144 render_thread_->sink().ClearMessages();
1146 if (ime_message->result) {
1147 // Retrieve the content of this page and compare it with the expected
1148 // result.
1149 const int kMaxOutputCharacters = 128;
1150 base::string16 output =
1151 GetMainFrame()->contentAsText(kMaxOutputCharacters);
1152 EXPECT_EQ(base::WideToUTF16(ime_message->result), output);
1157 // Test that the RenderView::OnSetTextDirection() function can change the text
1158 // direction of the selected input element.
1159 TEST_F(RenderViewImplTest, OnSetTextDirection) {
1160 // Load an HTML page consisting of a <textarea> element and a <div> element.
1161 // This test changes the text direction of the <textarea> element, and
1162 // writes the values of its 'dir' attribute and its 'direction' property to
1163 // verify that the text direction is changed.
1164 view()->set_send_content_state_immediately(true);
1165 LoadHTML("<html>"
1166 "<head>"
1167 "</head>"
1168 "<body>"
1169 "<textarea id=\"test\"></textarea>"
1170 "<div id=\"result\" contenteditable=\"true\"></div>"
1171 "</body>"
1172 "</html>");
1173 render_thread_->sink().ClearMessages();
1175 static const struct {
1176 WebTextDirection direction;
1177 const wchar_t* expected_result;
1178 } kTextDirection[] = {
1179 { blink::WebTextDirectionRightToLeft, L"\x000A" L"rtl,rtl" },
1180 { blink::WebTextDirectionLeftToRight, L"\x000A" L"ltr,ltr" },
1182 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTextDirection); ++i) {
1183 // Set the text direction of the <textarea> element.
1184 ExecuteJavaScript("document.getElementById('test').focus();");
1185 view()->OnSetTextDirection(kTextDirection[i].direction);
1187 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1188 // property to the <div> element.
1189 ExecuteJavaScript("var result = document.getElementById('result');"
1190 "var node = document.getElementById('test');"
1191 "var style = getComputedStyle(node, null);"
1192 "result.innerText ="
1193 " node.getAttribute('dir') + ',' +"
1194 " style.getPropertyValue('direction');");
1196 // Copy the document content to std::wstring and compare with the
1197 // expected result.
1198 const int kMaxOutputCharacters = 16;
1199 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
1200 EXPECT_EQ(base::WideToUTF16(kTextDirection[i].expected_result), output);
1204 // see http://crbug.com/238750
1205 #if defined(OS_WIN)
1206 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent
1207 #else
1208 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent
1209 #endif
1211 // Test that we can receive correct DOM events when we send input events
1212 // through the RenderWidget::OnHandleInputEvent() function.
1213 TEST_F(RenderViewImplTest, MAYBE_OnHandleKeyboardEvent) {
1214 #if !defined(OS_MACOSX)
1215 // Load an HTML page consisting of one <input> element and three
1216 // contentediable <div> elements.
1217 // The <input> element is used for sending keyboard events, and the <div>
1218 // elements are used for writing DOM events in the following format:
1219 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1220 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1221 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1222 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1223 view()->set_send_content_state_immediately(true);
1224 LoadHTML("<html>"
1225 "<head>"
1226 "<title></title>"
1227 "<script type='text/javascript' language='javascript'>"
1228 "function OnKeyEvent(ev) {"
1229 " var result = document.getElementById(ev.type);"
1230 " result.innerText ="
1231 " (ev.which || ev.keyCode) + ',' +"
1232 " ev.shiftKey + ',' +"
1233 " ev.ctrlKey + ',' +"
1234 " ev.altKey;"
1235 " return true;"
1237 "</script>"
1238 "</head>"
1239 "<body>"
1240 "<input id='test' type='text'"
1241 " onkeydown='return OnKeyEvent(event);'"
1242 " onkeypress='return OnKeyEvent(event);'"
1243 " onkeyup='return OnKeyEvent(event);'>"
1244 "</input>"
1245 "<div id='keydown' contenteditable='true'>"
1246 "</div>"
1247 "<div id='keypress' contenteditable='true'>"
1248 "</div>"
1249 "<div id='keyup' contenteditable='true'>"
1250 "</div>"
1251 "</body>"
1252 "</html>");
1253 ExecuteJavaScript("document.getElementById('test').focus();");
1254 render_thread_->sink().ClearMessages();
1256 static const MockKeyboard::Layout kLayouts[] = {
1257 #if defined(OS_WIN)
1258 // Since we ignore the mock keyboard layout on Linux and instead just use
1259 // the screen's keyboard layout, these trivially pass. They are commented
1260 // out to avoid the illusion that they work.
1261 MockKeyboard::LAYOUT_ARABIC,
1262 MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1263 MockKeyboard::LAYOUT_FRENCH,
1264 MockKeyboard::LAYOUT_HEBREW,
1265 MockKeyboard::LAYOUT_RUSSIAN,
1266 #endif
1267 MockKeyboard::LAYOUT_UNITED_STATES,
1270 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLayouts); ++i) {
1271 // For each key code, we send three keyboard events.
1272 // * we press only the key;
1273 // * we press the key and a left-shift key, and;
1274 // * we press the key and a right-alt (AltGr) key.
1275 // For each modifiers, we need a string used for formatting its expected
1276 // result. (See the above comment for its format.)
1277 static const struct {
1278 MockKeyboard::Modifiers modifiers;
1279 const char* expected_result;
1280 } kModifierData[] = {
1281 {MockKeyboard::NONE, "false,false,false"},
1282 {MockKeyboard::LEFT_SHIFT, "true,false,false"},
1283 #if defined(OS_WIN)
1284 {MockKeyboard::RIGHT_ALT, "false,false,true"},
1285 #endif
1288 MockKeyboard::Layout layout = kLayouts[i];
1289 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kModifierData); ++j) {
1290 // Virtual key codes used for this test.
1291 static const int kKeyCodes[] = {
1292 '0', '1', '2', '3', '4', '5', '6', '7',
1293 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1294 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1295 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1296 'W', 'X', 'Y', 'Z',
1297 ui::VKEY_OEM_1,
1298 ui::VKEY_OEM_PLUS,
1299 ui::VKEY_OEM_COMMA,
1300 ui::VKEY_OEM_MINUS,
1301 ui::VKEY_OEM_PERIOD,
1302 ui::VKEY_OEM_2,
1303 ui::VKEY_OEM_3,
1304 ui::VKEY_OEM_4,
1305 ui::VKEY_OEM_5,
1306 ui::VKEY_OEM_6,
1307 ui::VKEY_OEM_7,
1308 #if defined(OS_WIN)
1309 // Not sure how to handle this key on Linux.
1310 ui::VKEY_OEM_8,
1311 #endif
1314 MockKeyboard::Modifiers modifiers = kModifierData[j].modifiers;
1315 for (size_t k = 0; k < ARRAYSIZE_UNSAFE(kKeyCodes); ++k) {
1316 // Send a keyboard event to the RenderView object.
1317 // We should test a keyboard event only when the given keyboard-layout
1318 // driver is installed in a PC and the driver can assign a Unicode
1319 // charcter for the given tuple (key-code and modifiers).
1320 int key_code = kKeyCodes[k];
1321 base::string16 char_code;
1322 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1323 continue;
1325 // Create an expected result from the virtual-key code, the character
1326 // code, and the modifier-key status.
1327 // We format a string that emulates a DOM-event string produced hy
1328 // our JavaScript function. (See the above comment for the format.)
1329 static char expected_result[1024];
1330 expected_result[0] = 0;
1331 base::snprintf(&expected_result[0],
1332 sizeof(expected_result),
1333 "\n" // texts in the <input> element
1334 "%d,%s\n" // texts in the first <div> element
1335 "%d,%s\n" // texts in the second <div> element
1336 "%d,%s", // texts in the third <div> element
1337 key_code, kModifierData[j].expected_result,
1338 static_cast<int>(char_code[0]),
1339 kModifierData[j].expected_result,
1340 key_code, kModifierData[j].expected_result);
1342 // Retrieve the text in the test page and compare it with the expected
1343 // text created from a virtual-key code, a character code, and the
1344 // modifier-key status.
1345 const int kMaxOutputCharacters = 1024;
1346 std::string output = base::UTF16ToUTF8(
1347 GetMainFrame()->contentAsText(kMaxOutputCharacters));
1348 EXPECT_EQ(expected_result, output);
1352 #else
1353 NOTIMPLEMENTED();
1354 #endif
1357 // Test that our EditorClientImpl class can insert characters when we send
1358 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1359 // This test is for preventing regressions caused only when we use non-US
1360 // keyboards, such as Issue 10846.
1361 // see http://crbug.com/244562
1362 #if defined(OS_WIN)
1363 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1364 #else
1365 #define MAYBE_InsertCharacters InsertCharacters
1366 #endif
1367 TEST_F(RenderViewImplTest, MAYBE_InsertCharacters) {
1368 #if !defined(OS_MACOSX)
1369 static const struct {
1370 MockKeyboard::Layout layout;
1371 const wchar_t* expected_result;
1372 } kLayouts[] = {
1373 #if 0
1374 // Disabled these keyboard layouts because buildbots do not have their
1375 // keyboard-layout drivers installed.
1376 {MockKeyboard::LAYOUT_ARABIC,
1377 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1378 L"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1379 L"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1380 L"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1381 L"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1382 L"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1383 L"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1384 L"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1385 L"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1386 L"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1387 L"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1388 L"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1389 L"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1390 L"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1391 L"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1392 L"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1393 L"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1395 {MockKeyboard::LAYOUT_HEBREW,
1396 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1397 L"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1398 L"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1399 L"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1400 L"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1401 L"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1402 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1403 L"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1404 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1405 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1406 L"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1407 L"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1408 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1409 L"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1410 L"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1411 L"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1412 L"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1413 L"\x003b\x005d\x005c\x005b\x002c"
1415 #endif
1416 #if defined(OS_WIN)
1417 // On Linux, the only way to test alternate keyboard layouts is to change
1418 // the keyboard layout of the whole screen. I'm worried about the side
1419 // effects this may have on the buildbots.
1420 {MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1421 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1422 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1423 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1424 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1425 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1426 L"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1427 L"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1428 L"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1429 L"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1430 L"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1431 L"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1432 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1433 L"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1434 L"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1435 L"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1436 L"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1437 L"\x003c"
1439 {MockKeyboard::LAYOUT_FRENCH,
1440 L"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1441 L"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1442 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1443 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1444 L"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1445 L"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1446 L"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1447 L"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1448 L"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1449 L"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1450 L"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1451 L"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1452 L"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1453 L"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1454 L"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1455 L"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1456 L"\x003b\x003a\x00f9\x0029\x002a\x0021"
1458 {MockKeyboard::LAYOUT_RUSSIAN,
1459 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1460 L"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1461 L"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1462 L"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1463 L"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1464 L"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1465 L"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1466 L"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1467 L"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1468 L"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1469 L"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1470 L"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1471 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1472 L"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1473 L"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1474 L"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1475 L"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1476 L"\x0451\x0445\x005c\x044a\x044d"
1478 #endif // defined(OS_WIN)
1479 {MockKeyboard::LAYOUT_UNITED_STATES,
1480 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1481 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1482 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1483 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1484 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1485 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1486 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1487 L"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1488 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1489 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1490 L"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1491 L"\x003f\x007e\x007b\x007c\x007d\x0022"
1492 #if defined(OS_WIN)
1493 // This is ifdefed out for Linux to correspond to the fact that we don't
1494 // test alt+keystroke for now.
1495 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1496 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1497 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1498 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1499 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1500 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1501 #endif
1505 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLayouts); ++i) {
1506 // Load an HTML page consisting of one <div> element.
1507 // This <div> element is used by the EditorClientImpl class to insert
1508 // characters received through the RenderWidget::OnHandleInputEvent()
1509 // function.
1510 view()->set_send_content_state_immediately(true);
1511 LoadHTML("<html>"
1512 "<head>"
1513 "<title></title>"
1514 "</head>"
1515 "<body>"
1516 "<div id='test' contenteditable='true'>"
1517 "</div>"
1518 "</body>"
1519 "</html>");
1520 ExecuteJavaScript("document.getElementById('test').focus();");
1521 render_thread_->sink().ClearMessages();
1523 // For each key code, we send three keyboard events.
1524 // * Pressing only the key;
1525 // * Pressing the key and a left-shift key, and;
1526 // * Pressing the key and a right-alt (AltGr) key.
1527 static const MockKeyboard::Modifiers kModifiers[] = {
1528 MockKeyboard::NONE,
1529 MockKeyboard::LEFT_SHIFT,
1530 #if defined(OS_WIN)
1531 MockKeyboard::RIGHT_ALT,
1532 #endif
1535 MockKeyboard::Layout layout = kLayouts[i].layout;
1536 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kModifiers); ++j) {
1537 // Virtual key codes used for this test.
1538 static const int kKeyCodes[] = {
1539 '0', '1', '2', '3', '4', '5', '6', '7',
1540 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1541 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1542 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1543 'W', 'X', 'Y', 'Z',
1544 ui::VKEY_OEM_1,
1545 ui::VKEY_OEM_PLUS,
1546 ui::VKEY_OEM_COMMA,
1547 ui::VKEY_OEM_MINUS,
1548 ui::VKEY_OEM_PERIOD,
1549 ui::VKEY_OEM_2,
1550 ui::VKEY_OEM_3,
1551 ui::VKEY_OEM_4,
1552 ui::VKEY_OEM_5,
1553 ui::VKEY_OEM_6,
1554 ui::VKEY_OEM_7,
1555 #if defined(OS_WIN)
1556 // Unclear how to handle this on Linux.
1557 ui::VKEY_OEM_8,
1558 #endif
1561 MockKeyboard::Modifiers modifiers = kModifiers[j];
1562 for (size_t k = 0; k < ARRAYSIZE_UNSAFE(kKeyCodes); ++k) {
1563 // Send a keyboard event to the RenderView object.
1564 // We should test a keyboard event only when the given keyboard-layout
1565 // driver is installed in a PC and the driver can assign a Unicode
1566 // charcter for the given tuple (layout, key-code, and modifiers).
1567 int key_code = kKeyCodes[k];
1568 base::string16 char_code;
1569 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1570 continue;
1574 // Retrieve the text in the test page and compare it with the expected
1575 // text created from a virtual-key code, a character code, and the
1576 // modifier-key status.
1577 const int kMaxOutputCharacters = 4096;
1578 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
1579 EXPECT_EQ(base::WideToUTF16(kLayouts[i].expected_result), output);
1581 #else
1582 NOTIMPLEMENTED();
1583 #endif
1586 // Crashy, http://crbug.com/53247.
1587 TEST_F(RenderViewImplTest, DISABLED_DidFailProvisionalLoadWithErrorForError) {
1588 GetMainFrame()->enableViewSourceMode(true);
1589 WebURLError error;
1590 error.domain = WebString::fromUTF8(net::kErrorDomain);
1591 error.reason = net::ERR_FILE_NOT_FOUND;
1592 error.unreachableURL = GURL("http://foo");
1593 WebLocalFrame* web_frame = GetMainFrame();
1595 // Start a load that will reach provisional state synchronously,
1596 // but won't complete synchronously.
1597 FrameMsg_Navigate_Params params;
1598 params.page_id = -1;
1599 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1600 params.url = GURL("data:text/html,test data");
1601 params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
1602 frame()->OnNavigate(params);
1604 // An error occurred.
1605 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame, error);
1606 // Frame should exit view-source mode.
1607 EXPECT_FALSE(web_frame->isViewSourceModeEnabled());
1610 TEST_F(RenderViewImplTest, DidFailProvisionalLoadWithErrorForCancellation) {
1611 GetMainFrame()->enableViewSourceMode(true);
1612 WebURLError error;
1613 error.domain = WebString::fromUTF8(net::kErrorDomain);
1614 error.reason = net::ERR_ABORTED;
1615 error.unreachableURL = GURL("http://foo");
1616 WebLocalFrame* web_frame = GetMainFrame();
1618 // Start a load that will reach provisional state synchronously,
1619 // but won't complete synchronously.
1620 FrameMsg_Navigate_Params params;
1621 params.page_id = -1;
1622 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1623 params.url = GURL("data:text/html,test data");
1624 params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
1625 frame()->OnNavigate(params);
1627 // A cancellation occurred.
1628 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame, error);
1629 // Frame should stay in view-source mode.
1630 EXPECT_TRUE(web_frame->isViewSourceModeEnabled());
1633 // Regression test for http://crbug.com/41562
1634 TEST_F(RenderViewImplTest, UpdateTargetURLWithInvalidURL) {
1635 const GURL invalid_gurl("http://");
1636 view()->setMouseOverURL(blink::WebURL(invalid_gurl));
1637 EXPECT_EQ(invalid_gurl, view()->target_url_);
1640 TEST_F(RenderViewImplTest, SetHistoryLengthAndPrune) {
1641 int expected_page_id = -1;
1643 // No history to merge and no committed pages.
1644 view()->OnSetHistoryLengthAndPrune(0, -1);
1645 EXPECT_EQ(0, view()->history_list_length_);
1646 EXPECT_EQ(-1, view()->history_list_offset_);
1648 // History to merge and no committed pages.
1649 view()->OnSetHistoryLengthAndPrune(2, -1);
1650 EXPECT_EQ(2, view()->history_list_length_);
1651 EXPECT_EQ(1, view()->history_list_offset_);
1652 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1653 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1654 ClearHistory();
1656 blink::WebHistoryItem item;
1657 item.initialize();
1659 // No history to merge and a committed page to be kept.
1660 frame()->didCommitProvisionalLoad(GetMainFrame(),
1661 item,
1662 blink::WebStandardCommit);
1663 expected_page_id = view()->page_id_;
1664 view()->OnSetHistoryLengthAndPrune(0, expected_page_id);
1665 EXPECT_EQ(1, view()->history_list_length_);
1666 EXPECT_EQ(0, view()->history_list_offset_);
1667 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1668 ClearHistory();
1670 // No history to merge and a committed page to be pruned.
1671 frame()->didCommitProvisionalLoad(GetMainFrame(),
1672 item,
1673 blink::WebStandardCommit);
1674 expected_page_id = view()->page_id_;
1675 view()->OnSetHistoryLengthAndPrune(0, expected_page_id + 1);
1676 EXPECT_EQ(0, view()->history_list_length_);
1677 EXPECT_EQ(-1, view()->history_list_offset_);
1678 ClearHistory();
1680 // No history to merge and a committed page that the browser was unaware of.
1681 frame()->didCommitProvisionalLoad(GetMainFrame(),
1682 item,
1683 blink::WebStandardCommit);
1684 expected_page_id = view()->page_id_;
1685 view()->OnSetHistoryLengthAndPrune(0, -1);
1686 EXPECT_EQ(1, view()->history_list_length_);
1687 EXPECT_EQ(0, view()->history_list_offset_);
1688 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1689 ClearHistory();
1691 // History to merge and a committed page to be kept.
1692 frame()->didCommitProvisionalLoad(GetMainFrame(),
1693 item,
1694 blink::WebStandardCommit);
1695 expected_page_id = view()->page_id_;
1696 view()->OnSetHistoryLengthAndPrune(2, expected_page_id);
1697 EXPECT_EQ(3, view()->history_list_length_);
1698 EXPECT_EQ(2, view()->history_list_offset_);
1699 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1700 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1701 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1702 ClearHistory();
1704 // History to merge and a committed page to be pruned.
1705 frame()->didCommitProvisionalLoad(GetMainFrame(),
1706 item,
1707 blink::WebStandardCommit);
1708 expected_page_id = view()->page_id_;
1709 view()->OnSetHistoryLengthAndPrune(2, expected_page_id + 1);
1710 EXPECT_EQ(2, view()->history_list_length_);
1711 EXPECT_EQ(1, view()->history_list_offset_);
1712 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1713 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1714 ClearHistory();
1716 // History to merge and a committed page that the browser was unaware of.
1717 frame()->didCommitProvisionalLoad(GetMainFrame(),
1718 item,
1719 blink::WebStandardCommit);
1720 expected_page_id = view()->page_id_;
1721 view()->OnSetHistoryLengthAndPrune(2, -1);
1722 EXPECT_EQ(3, view()->history_list_length_);
1723 EXPECT_EQ(2, view()->history_list_offset_);
1724 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1725 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1726 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1727 ClearHistory();
1729 int expected_page_id_2 = -1;
1731 // No history to merge and two committed pages, both to be kept.
1732 frame()->didCommitProvisionalLoad(GetMainFrame(),
1733 item,
1734 blink::WebStandardCommit);
1735 expected_page_id = view()->page_id_;
1736 frame()->didCommitProvisionalLoad(GetMainFrame(),
1737 item,
1738 blink::WebStandardCommit);
1739 expected_page_id_2 = view()->page_id_;
1740 EXPECT_GT(expected_page_id_2, expected_page_id);
1741 view()->OnSetHistoryLengthAndPrune(0, expected_page_id);
1742 EXPECT_EQ(2, view()->history_list_length_);
1743 EXPECT_EQ(1, view()->history_list_offset_);
1744 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1745 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[1]);
1746 ClearHistory();
1748 // No history to merge and two committed pages, and only the second is kept.
1749 frame()->didCommitProvisionalLoad(GetMainFrame(),
1750 item,
1751 blink::WebStandardCommit);
1752 expected_page_id = view()->page_id_;
1753 frame()->didCommitProvisionalLoad(GetMainFrame(),
1754 item,
1755 blink::WebStandardCommit);
1756 expected_page_id_2 = view()->page_id_;
1757 EXPECT_GT(expected_page_id_2, expected_page_id);
1758 view()->OnSetHistoryLengthAndPrune(0, expected_page_id_2);
1759 EXPECT_EQ(1, view()->history_list_length_);
1760 EXPECT_EQ(0, view()->history_list_offset_);
1761 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[0]);
1762 ClearHistory();
1764 // No history to merge and two committed pages, both of which the browser was
1765 // unaware of.
1766 frame()->didCommitProvisionalLoad(GetMainFrame(),
1767 item,
1768 blink::WebStandardCommit);
1769 expected_page_id = view()->page_id_;
1770 frame()->didCommitProvisionalLoad(GetMainFrame(),
1771 item,
1772 blink::WebStandardCommit);
1773 expected_page_id_2 = view()->page_id_;
1774 EXPECT_GT(expected_page_id_2, expected_page_id);
1775 view()->OnSetHistoryLengthAndPrune(0, -1);
1776 EXPECT_EQ(2, view()->history_list_length_);
1777 EXPECT_EQ(1, view()->history_list_offset_);
1778 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1779 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[1]);
1780 ClearHistory();
1782 // History to merge and two committed pages, both to be kept.
1783 frame()->didCommitProvisionalLoad(GetMainFrame(),
1784 item,
1785 blink::WebStandardCommit);
1786 expected_page_id = view()->page_id_;
1787 frame()->didCommitProvisionalLoad(GetMainFrame(),
1788 item,
1789 blink::WebStandardCommit);
1790 expected_page_id_2 = view()->page_id_;
1791 EXPECT_GT(expected_page_id_2, expected_page_id);
1792 view()->OnSetHistoryLengthAndPrune(2, expected_page_id);
1793 EXPECT_EQ(4, view()->history_list_length_);
1794 EXPECT_EQ(3, view()->history_list_offset_);
1795 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1796 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1797 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1798 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[3]);
1799 ClearHistory();
1801 // History to merge and two committed pages, and only the second is kept.
1802 frame()->didCommitProvisionalLoad(GetMainFrame(),
1803 item,
1804 blink::WebStandardCommit);
1805 expected_page_id = view()->page_id_;
1806 frame()->didCommitProvisionalLoad(GetMainFrame(),
1807 item,
1808 blink::WebStandardCommit);
1809 expected_page_id_2 = view()->page_id_;
1810 EXPECT_GT(expected_page_id_2, expected_page_id);
1811 view()->OnSetHistoryLengthAndPrune(2, expected_page_id_2);
1812 EXPECT_EQ(3, view()->history_list_length_);
1813 EXPECT_EQ(2, view()->history_list_offset_);
1814 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1815 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1816 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[2]);
1817 ClearHistory();
1819 // History to merge and two committed pages, both of which the browser was
1820 // unaware of.
1821 frame()->didCommitProvisionalLoad(GetMainFrame(),
1822 item,
1823 blink::WebStandardCommit);
1824 expected_page_id = view()->page_id_;
1825 frame()->didCommitProvisionalLoad(GetMainFrame(),
1826 item,
1827 blink::WebStandardCommit);
1828 expected_page_id_2 = view()->page_id_;
1829 EXPECT_GT(expected_page_id_2, expected_page_id);
1830 view()->OnSetHistoryLengthAndPrune(2, -1);
1831 EXPECT_EQ(4, view()->history_list_length_);
1832 EXPECT_EQ(3, view()->history_list_offset_);
1833 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1834 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1835 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1836 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[3]);
1839 TEST_F(RenderViewImplTest, ContextMenu) {
1840 LoadHTML("<div>Page A</div>");
1842 // Create a right click in the center of the iframe. (I'm hoping this will
1843 // make this a bit more robust in case of some other formatting or other bug.)
1844 WebMouseEvent mouse_event;
1845 mouse_event.type = WebInputEvent::MouseDown;
1846 mouse_event.button = WebMouseEvent::ButtonRight;
1847 mouse_event.x = 250;
1848 mouse_event.y = 250;
1849 mouse_event.globalX = 250;
1850 mouse_event.globalY = 250;
1852 SendWebMouseEvent(mouse_event);
1854 // Now simulate the corresponding up event which should display the menu
1855 mouse_event.type = WebInputEvent::MouseUp;
1856 SendWebMouseEvent(mouse_event);
1858 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
1859 FrameHostMsg_ContextMenu::ID));
1862 TEST_F(RenderViewImplTest, TestBackForward) {
1863 LoadHTML("<div id=pagename>Page A</div>");
1864 PageState page_a_state =
1865 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1866 int was_page_a = -1;
1867 base::string16 check_page_a =
1868 base::ASCIIToUTF16(
1869 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1870 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1871 EXPECT_EQ(1, was_page_a);
1873 LoadHTML("<div id=pagename>Page B</div>");
1874 int was_page_b = -1;
1875 base::string16 check_page_b =
1876 base::ASCIIToUTF16(
1877 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1878 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1879 EXPECT_EQ(1, was_page_b);
1881 PageState back_state =
1882 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1884 LoadHTML("<div id=pagename>Page C</div>");
1885 int was_page_c = -1;
1886 base::string16 check_page_c =
1887 base::ASCIIToUTF16(
1888 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1889 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1890 EXPECT_EQ(1, was_page_b);
1892 PageState forward_state =
1893 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1894 GoBack(back_state);
1895 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1896 EXPECT_EQ(1, was_page_b);
1898 PageState back_state2 =
1899 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1901 GoForward(forward_state);
1902 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1903 EXPECT_EQ(1, was_page_c);
1905 GoBack(back_state2);
1906 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1907 EXPECT_EQ(1, was_page_b);
1909 forward_state =
1910 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1911 GoBack(page_a_state);
1912 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1913 EXPECT_EQ(1, was_page_a);
1915 GoForward(forward_state);
1916 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1917 EXPECT_EQ(1, was_page_b);
1920 #if defined(OS_MACOSX) || defined(USE_AURA)
1921 TEST_F(RenderViewImplTest, GetCompositionCharacterBoundsTest) {
1923 #if defined(OS_WIN)
1924 // http://crbug.com/304193
1925 if (base::win::GetVersion() < base::win::VERSION_VISTA)
1926 return;
1927 #endif
1929 LoadHTML("<textarea id=\"test\"></textarea>");
1930 ExecuteJavaScript("document.getElementById('test').focus();");
1932 const base::string16 empty_string;
1933 const std::vector<blink::WebCompositionUnderline> empty_underline;
1934 std::vector<gfx::Rect> bounds;
1935 view()->OnSetFocus(true);
1936 view()->OnSetInputMethodActive(true);
1938 // ASCII composition
1939 const base::string16 ascii_composition = base::UTF8ToUTF16("aiueo");
1940 view()->OnImeSetComposition(ascii_composition, empty_underline, 0, 0);
1941 view()->GetCompositionCharacterBounds(&bounds);
1942 ASSERT_EQ(ascii_composition.size(), bounds.size());
1943 for (size_t i = 0; i < bounds.size(); ++i)
1944 EXPECT_LT(0, bounds[i].width());
1945 view()->OnImeConfirmComposition(
1946 empty_string, gfx::Range::InvalidRange(), false);
1948 // Non surrogate pair unicode character.
1949 const base::string16 unicode_composition = base::UTF8ToUTF16(
1950 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1951 view()->OnImeSetComposition(unicode_composition, empty_underline, 0, 0);
1952 view()->GetCompositionCharacterBounds(&bounds);
1953 ASSERT_EQ(unicode_composition.size(), bounds.size());
1954 for (size_t i = 0; i < bounds.size(); ++i)
1955 EXPECT_LT(0, bounds[i].width());
1956 view()->OnImeConfirmComposition(
1957 empty_string, gfx::Range::InvalidRange(), false);
1959 // Surrogate pair character.
1960 const base::string16 surrogate_pair_char =
1961 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1962 view()->OnImeSetComposition(surrogate_pair_char,
1963 empty_underline,
1966 view()->GetCompositionCharacterBounds(&bounds);
1967 ASSERT_EQ(surrogate_pair_char.size(), bounds.size());
1968 EXPECT_LT(0, bounds[0].width());
1969 EXPECT_EQ(0, bounds[1].width());
1970 view()->OnImeConfirmComposition(
1971 empty_string, gfx::Range::InvalidRange(), false);
1973 // Mixed string.
1974 const base::string16 surrogate_pair_mixed_composition =
1975 surrogate_pair_char + base::UTF8ToUTF16("\xE3\x81\x82") +
1976 surrogate_pair_char + base::UTF8ToUTF16("b") + surrogate_pair_char;
1977 const size_t utf16_length = 8UL;
1978 const bool is_surrogate_pair_empty_rect[8] = {
1979 false, true, false, false, true, false, false, true };
1980 view()->OnImeSetComposition(surrogate_pair_mixed_composition,
1981 empty_underline,
1984 view()->GetCompositionCharacterBounds(&bounds);
1985 ASSERT_EQ(utf16_length, bounds.size());
1986 for (size_t i = 0; i < utf16_length; ++i) {
1987 if (is_surrogate_pair_empty_rect[i]) {
1988 EXPECT_EQ(0, bounds[i].width());
1989 } else {
1990 EXPECT_LT(0, bounds[i].width());
1993 view()->OnImeConfirmComposition(
1994 empty_string, gfx::Range::InvalidRange(), false);
1996 #endif
1998 TEST_F(RenderViewImplTest, ZoomLimit) {
1999 const double kMinZoomLevel = ZoomFactorToZoomLevel(kMinimumZoomFactor);
2000 const double kMaxZoomLevel = ZoomFactorToZoomLevel(kMaximumZoomFactor);
2002 FrameMsg_Navigate_Params params;
2003 params.page_id = -1;
2004 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2005 params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
2007 // Verifies navigation to a URL with preset zoom level indeed sets the level.
2008 // Regression test for http://crbug.com/139559, where the level was not
2009 // properly set when it is out of the default zoom limits of WebView.
2010 params.url = GURL("data:text/html,min_zoomlimit_test");
2011 view()->OnSetZoomLevelForLoadingURL(params.url, kMinZoomLevel);
2012 frame()->OnNavigate(params);
2013 ProcessPendingMessages();
2014 EXPECT_DOUBLE_EQ(kMinZoomLevel, view()->GetWebView()->zoomLevel());
2016 // It should work even when the zoom limit is temporarily changed in the page.
2017 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
2018 ZoomFactorToZoomLevel(1.0));
2019 params.url = GURL("data:text/html,max_zoomlimit_test");
2020 view()->OnSetZoomLevelForLoadingURL(params.url, kMaxZoomLevel);
2021 frame()->OnNavigate(params);
2022 ProcessPendingMessages();
2023 EXPECT_DOUBLE_EQ(kMaxZoomLevel, view()->GetWebView()->zoomLevel());
2026 TEST_F(RenderViewImplTest, SetEditableSelectionAndComposition) {
2027 // Load an HTML page consisting of an input field.
2028 LoadHTML("<html>"
2029 "<head>"
2030 "</head>"
2031 "<body>"
2032 "<input id=\"test1\" value=\"some test text hello\"></input>"
2033 "</body>"
2034 "</html>");
2035 ExecuteJavaScript("document.getElementById('test1').focus();");
2036 frame()->OnSetEditableSelectionOffsets(4, 8);
2037 const std::vector<blink::WebCompositionUnderline> empty_underline;
2038 frame()->OnSetCompositionFromExistingText(7, 10, empty_underline);
2039 blink::WebTextInputInfo info = view()->webview()->textInputInfo();
2040 EXPECT_EQ(4, info.selectionStart);
2041 EXPECT_EQ(8, info.selectionEnd);
2042 EXPECT_EQ(7, info.compositionStart);
2043 EXPECT_EQ(10, info.compositionEnd);
2044 frame()->OnUnselect();
2045 info = view()->webview()->textInputInfo();
2046 EXPECT_EQ(0, info.selectionStart);
2047 EXPECT_EQ(0, info.selectionEnd);
2051 TEST_F(RenderViewImplTest, OnExtendSelectionAndDelete) {
2052 // Load an HTML page consisting of an input field.
2053 LoadHTML("<html>"
2054 "<head>"
2055 "</head>"
2056 "<body>"
2057 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
2058 "</body>"
2059 "</html>");
2060 ExecuteJavaScript("document.getElementById('test1').focus();");
2061 frame()->OnSetEditableSelectionOffsets(10, 10);
2062 frame()->OnExtendSelectionAndDelete(3, 4);
2063 blink::WebTextInputInfo info = view()->webview()->textInputInfo();
2064 EXPECT_EQ("abcdefgopqrstuvwxyz", info.value);
2065 EXPECT_EQ(7, info.selectionStart);
2066 EXPECT_EQ(7, info.selectionEnd);
2067 frame()->OnSetEditableSelectionOffsets(4, 8);
2068 frame()->OnExtendSelectionAndDelete(2, 5);
2069 info = view()->webview()->textInputInfo();
2070 EXPECT_EQ("abuvwxyz", info.value);
2071 EXPECT_EQ(2, info.selectionStart);
2072 EXPECT_EQ(2, info.selectionEnd);
2075 // Test that the navigating specific frames works correctly.
2076 TEST_F(RenderViewImplTest, NavigateFrame) {
2077 // Load page A.
2078 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
2080 // Navigate the frame only.
2081 FrameMsg_Navigate_Params nav_params;
2082 nav_params.url = GURL("data:text/html,world");
2083 nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2084 nav_params.transition = ui::PAGE_TRANSITION_TYPED;
2085 nav_params.current_history_list_length = 1;
2086 nav_params.current_history_list_offset = 0;
2087 nav_params.pending_history_list_offset = 1;
2088 nav_params.page_id = -1;
2089 nav_params.frame_to_navigate = "frame";
2090 nav_params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
2091 frame()->OnNavigate(nav_params);
2092 FrameLoadWaiter(
2093 RenderFrame::FromWebFrame(frame()->GetWebFrame()->firstChild())).Wait();
2095 // Copy the document content to std::wstring and compare with the
2096 // expected result.
2097 const int kMaxOutputCharacters = 256;
2098 std::string output = base::UTF16ToUTF8(
2099 GetMainFrame()->contentAsText(kMaxOutputCharacters));
2100 EXPECT_EQ(output, "hello \n\nworld");
2103 // This test ensures that a RenderFrame object is created for the top level
2104 // frame in the RenderView.
2105 TEST_F(RenderViewImplTest, BasicRenderFrame) {
2106 EXPECT_TRUE(view()->main_render_frame_.get());
2109 TEST_F(RenderViewImplTest, GetSSLStatusOfFrame) {
2110 LoadHTML("<!DOCTYPE html><html><body></body></html>");
2112 WebLocalFrame* frame = GetMainFrame();
2113 SSLStatus ssl_status = view()->GetSSLStatusOfFrame(frame);
2114 EXPECT_FALSE(net::IsCertStatusError(ssl_status.cert_status));
2116 const_cast<blink::WebURLResponse&>(frame->dataSource()->response()).
2117 setSecurityInfo(
2118 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS, 0, 0,
2119 SignedCertificateTimestampIDStatusList()));
2120 ssl_status = view()->GetSSLStatusOfFrame(frame);
2121 EXPECT_TRUE(net::IsCertStatusError(ssl_status.cert_status));
2124 TEST_F(RenderViewImplTest, MessageOrderInDidChangeSelection) {
2125 view()->OnSetInputMethodActive(true);
2126 view()->set_send_content_state_immediately(true);
2127 LoadHTML("<textarea id=\"test\"></textarea>");
2129 view()->handling_input_event_ = true;
2130 ExecuteJavaScript("document.getElementById('test').focus();");
2132 bool is_input_type_called = false;
2133 bool is_selection_called = false;
2134 size_t last_input_type = 0;
2135 size_t last_selection = 0;
2137 for (size_t i = 0; i < render_thread_->sink().message_count(); ++i) {
2138 const uint32 type = render_thread_->sink().GetMessageAt(i)->type();
2139 if (type == ViewHostMsg_TextInputStateChanged::ID) {
2140 is_input_type_called = true;
2141 last_input_type = i;
2142 } else if (type == ViewHostMsg_SelectionChanged::ID) {
2143 is_selection_called = true;
2144 last_selection = i;
2148 EXPECT_TRUE(is_input_type_called);
2149 EXPECT_TRUE(is_selection_called);
2151 // InputTypeChange shold be called earlier than SelectionChanged.
2152 EXPECT_LT(last_input_type, last_selection);
2155 class SuppressErrorPageTest : public RenderViewTest {
2156 public:
2157 virtual ContentRendererClient* CreateContentRendererClient() OVERRIDE {
2158 return new TestContentRendererClient;
2161 RenderViewImpl* view() {
2162 return static_cast<RenderViewImpl*>(view_);
2165 RenderFrameImpl* frame() {
2166 return static_cast<RenderFrameImpl*>(view()->GetMainRenderFrame());
2169 private:
2170 class TestContentRendererClient : public ContentRendererClient {
2171 public:
2172 virtual bool ShouldSuppressErrorPage(RenderFrame* render_frame,
2173 const GURL& url) OVERRIDE {
2174 return url == GURL("http://example.com/suppress");
2177 virtual void GetNavigationErrorStrings(
2178 content::RenderView* render_view,
2179 blink::WebFrame* frame,
2180 const blink::WebURLRequest& failed_request,
2181 const blink::WebURLError& error,
2182 std::string* error_html,
2183 base::string16* error_description) OVERRIDE {
2184 if (error_html)
2185 *error_html = "A suffusion of yellow.";
2190 #if defined(OS_ANDROID)
2191 // Crashing on Android: http://crbug.com/311341
2192 #define MAYBE_Suppresses DISABLED_Suppresses
2193 #else
2194 #define MAYBE_Suppresses Suppresses
2195 #endif
2197 TEST_F(SuppressErrorPageTest, MAYBE_Suppresses) {
2198 WebURLError error;
2199 error.domain = WebString::fromUTF8(net::kErrorDomain);
2200 error.reason = net::ERR_FILE_NOT_FOUND;
2201 error.unreachableURL = GURL("http://example.com/suppress");
2202 WebLocalFrame* web_frame = GetMainFrame();
2204 // Start a load that will reach provisional state synchronously,
2205 // but won't complete synchronously.
2206 FrameMsg_Navigate_Params params;
2207 params.page_id = -1;
2208 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2209 params.url = GURL("data:text/html,test data");
2210 params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
2211 frame()->OnNavigate(params);
2213 // An error occurred.
2214 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame, error);
2215 const int kMaxOutputCharacters = 22;
2216 EXPECT_EQ("",
2217 base::UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters)));
2220 #if defined(OS_ANDROID)
2221 // Crashing on Android: http://crbug.com/311341
2222 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2223 #else
2224 #define MAYBE_DoesNotSuppress DoesNotSuppress
2225 #endif
2227 TEST_F(SuppressErrorPageTest, MAYBE_DoesNotSuppress) {
2228 WebURLError error;
2229 error.domain = WebString::fromUTF8(net::kErrorDomain);
2230 error.reason = net::ERR_FILE_NOT_FOUND;
2231 error.unreachableURL = GURL("http://example.com/dont-suppress");
2232 WebLocalFrame* web_frame = GetMainFrame();
2234 // Start a load that will reach provisional state synchronously,
2235 // but won't complete synchronously.
2236 FrameMsg_Navigate_Params params;
2237 params.page_id = -1;
2238 params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2239 params.url = GURL("data:text/html,test data");
2240 params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
2241 frame()->OnNavigate(params);
2243 // An error occurred.
2244 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame, error);
2245 // The error page itself is loaded asynchronously.
2246 FrameLoadWaiter(frame()).Wait();
2247 const int kMaxOutputCharacters = 22;
2248 EXPECT_EQ("A suffusion of yellow.",
2249 base::UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters)));
2252 // Tests if IME API's candidatewindow* events sent from browser are handled
2253 // in renderer.
2254 TEST_F(RenderViewImplTest, SendCandidateWindowEvents) {
2255 // Sends an HTML with an <input> element and scripts to the renderer.
2256 // The script handles all 3 of candidatewindow* events for an
2257 // InputMethodContext object and once it received 'show', 'update', 'hide'
2258 // should appear in the result div.
2259 LoadHTML("<input id='test'>"
2260 "<div id='result'>Result: </div>"
2261 "<script>"
2262 "window.onload = function() {"
2263 " var result = document.getElementById('result');"
2264 " var test = document.getElementById('test');"
2265 " test.focus();"
2266 " var context = test.inputMethodContext;"
2267 " if (context) {"
2268 " context.oncandidatewindowshow = function() {"
2269 " result.innerText += 'show'; };"
2270 " context.oncandidatewindowupdate = function(){"
2271 " result.innerText += 'update'; };"
2272 " context.oncandidatewindowhide = function(){"
2273 " result.innerText += 'hide'; };"
2274 " }"
2275 "};"
2276 "</script>");
2278 // Fire candidatewindow events.
2279 view()->OnCandidateWindowShown();
2280 view()->OnCandidateWindowUpdated();
2281 view()->OnCandidateWindowHidden();
2283 // Retrieve the content and check if it is expected.
2284 const int kMaxOutputCharacters = 50;
2285 std::string output = base::UTF16ToUTF8(
2286 GetMainFrame()->contentAsText(kMaxOutputCharacters));
2287 EXPECT_EQ(output, "\nResult:showupdatehide");
2290 // Ensure the render view sends favicon url update events correctly.
2291 TEST_F(RenderViewImplTest, SendFaviconURLUpdateEvent) {
2292 // An event should be sent when a favicon url exists.
2293 LoadHTML("<html>"
2294 "<head>"
2295 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2296 "</head>"
2297 "</html>");
2298 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
2299 ViewHostMsg_UpdateFaviconURL::ID));
2300 render_thread_->sink().ClearMessages();
2302 // An event should not be sent if no favicon url exists. This is an assumption
2303 // made by some of Chrome's favicon handling.
2304 LoadHTML("<html>"
2305 "<head>"
2306 "</head>"
2307 "</html>");
2308 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
2309 ViewHostMsg_UpdateFaviconURL::ID));
2312 TEST_F(RenderViewImplTest, FocusElementCallsFocusedNodeChanged) {
2313 LoadHTML("<input id='test1' value='hello1'></input>"
2314 "<input id='test2' value='hello2'></input>");
2316 ExecuteJavaScript("document.getElementById('test1').focus();");
2317 const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
2318 ViewHostMsg_FocusedNodeChanged::ID);
2319 EXPECT_TRUE(msg1);
2321 ViewHostMsg_FocusedNodeChanged::Param params;
2322 ViewHostMsg_FocusedNodeChanged::Read(msg1, &params);
2323 EXPECT_TRUE(params.a);
2324 render_thread_->sink().ClearMessages();
2326 ExecuteJavaScript("document.getElementById('test2').focus();");
2327 const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching(
2328 ViewHostMsg_FocusedNodeChanged::ID);
2329 EXPECT_TRUE(msg2);
2330 ViewHostMsg_FocusedNodeChanged::Read(msg2, &params);
2331 EXPECT_TRUE(params.a);
2332 render_thread_->sink().ClearMessages();
2334 view()->webview()->clearFocusedElement();
2335 const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching(
2336 ViewHostMsg_FocusedNodeChanged::ID);
2337 EXPECT_TRUE(msg3);
2338 ViewHostMsg_FocusedNodeChanged::Read(msg3, &params);
2339 EXPECT_FALSE(params.a);
2340 render_thread_->sink().ClearMessages();
2343 TEST_F(RenderViewImplTest, ServiceWorkerNetworkProviderSetup) {
2344 ServiceWorkerNetworkProvider* provider = NULL;
2345 RequestExtraData* extra_data = NULL;
2347 // Make sure each new document has a new provider and
2348 // that the main request is tagged with the provider's id.
2349 LoadHTML("<b>A Document</b>");
2350 ASSERT_TRUE(GetMainFrame()->dataSource());
2351 provider = ServiceWorkerNetworkProvider::FromDocumentState(
2352 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2353 ASSERT_TRUE(provider);
2354 extra_data = static_cast<RequestExtraData*>(
2355 GetMainFrame()->dataSource()->request().extraData());
2356 ASSERT_TRUE(extra_data);
2357 EXPECT_EQ(extra_data->service_worker_provider_id(),
2358 provider->provider_id());
2359 int provider1_id = provider->provider_id();
2361 LoadHTML("<b>New Document B Goes Here</b>");
2362 ASSERT_TRUE(GetMainFrame()->dataSource());
2363 provider = ServiceWorkerNetworkProvider::FromDocumentState(
2364 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2365 ASSERT_TRUE(provider);
2366 EXPECT_NE(provider1_id, provider->provider_id());
2367 extra_data = static_cast<RequestExtraData*>(
2368 GetMainFrame()->dataSource()->request().extraData());
2369 ASSERT_TRUE(extra_data);
2370 EXPECT_EQ(extra_data->service_worker_provider_id(),
2371 provider->provider_id());
2373 // See that subresource requests are also tagged with the provider's id.
2374 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2375 blink::WebURLRequest request(GURL("http://foo.com"));
2376 request.setRequestContext(blink::WebURLRequest::RequestContextSubresource);
2377 blink::WebURLResponse redirect_response;
2378 frame()->willSendRequest(GetMainFrame(), 0, request, redirect_response);
2379 extra_data = static_cast<RequestExtraData*>(request.extraData());
2380 ASSERT_TRUE(extra_data);
2381 EXPECT_EQ(extra_data->service_worker_provider_id(),
2382 provider->provider_id());
2385 TEST_F(RenderViewImplTest, OnSetAccessibilityMode) {
2386 ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
2387 ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2389 frame()->OnSetAccessibilityMode(AccessibilityModeTreeOnly);
2390 ASSERT_EQ(AccessibilityModeTreeOnly, frame()->accessibility_mode());
2391 ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2392 ASSERT_EQ(RendererAccessibilityTypeComplete,
2393 frame()->renderer_accessibility()->GetType());
2395 frame()->OnSetAccessibilityMode(AccessibilityModeOff);
2396 ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
2397 ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2399 frame()->OnSetAccessibilityMode(AccessibilityModeComplete);
2400 ASSERT_EQ(AccessibilityModeComplete, frame()->accessibility_mode());
2401 ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2402 ASSERT_EQ(RendererAccessibilityTypeComplete,
2403 frame()->renderer_accessibility()->GetType());
2405 frame()->OnSetAccessibilityMode(AccessibilityModeEditableTextOnly);
2406 ASSERT_EQ(AccessibilityModeEditableTextOnly, frame()->accessibility_mode());
2407 ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2408 ASSERT_EQ(RendererAccessibilityTypeFocusOnly,
2409 frame()->renderer_accessibility()->GetType());
2412 TEST_F(RenderViewImplTest, ScreenMetricsEmulation) {
2413 LoadHTML("<body style='min-height:1000px;'></body>");
2415 blink::WebDeviceEmulationParams params;
2416 base::string16 get_width = base::ASCIIToUTF16("Number(window.innerWidth)");
2417 base::string16 get_height = base::ASCIIToUTF16("Number(window.innerHeight)");
2418 int width, height;
2420 params.viewSize.width = 327;
2421 params.viewSize.height = 415;
2422 view()->EnableScreenMetricsEmulation(params);
2423 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width));
2424 EXPECT_EQ(params.viewSize.width, width);
2425 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height));
2426 EXPECT_EQ(params.viewSize.height, height);
2428 params.viewSize.width = 1005;
2429 params.viewSize.height = 1102;
2430 view()->EnableScreenMetricsEmulation(params);
2431 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width));
2432 EXPECT_EQ(params.viewSize.width, width);
2433 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height));
2434 EXPECT_EQ(params.viewSize.height, height);
2436 view()->DisableScreenMetricsEmulation();
2438 view()->EnableScreenMetricsEmulation(params);
2439 // Don't disable here to test that emulation is being shutdown properly.
2442 // Sanity checks for the Navigation Timing API |navigationStart| override. We
2443 // are asserting only most basic constraints, as TimeTicks (passed as the
2444 // override) are not comparable with the wall time (returned by the Blink API).
2445 TEST_F(RenderViewImplTest, NavigationStartOverride) {
2446 // Verify that a navigation that claims to have started at the earliest
2447 // possible TimeTicks is indeed reported as one that started before
2448 // OnNavigate() is called.
2449 base::Time before_navigation = base::Time::Now();
2450 FrameMsg_Navigate_Params early_nav_params;
2451 early_nav_params.url = GURL("data:text/html,<div>Page</div>");
2452 early_nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2453 early_nav_params.transition = ui::PAGE_TRANSITION_TYPED;
2454 early_nav_params.page_id = -1;
2455 early_nav_params.is_post = true;
2456 early_nav_params.browser_navigation_start =
2457 base::TimeTicks::FromInternalValue(1);
2459 frame()->OnNavigate(early_nav_params);
2460 ProcessPendingMessages();
2462 base::Time early_nav_reported_start =
2463 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2464 EXPECT_LT(early_nav_reported_start, before_navigation);
2466 // Verify that a navigation that claims to have started in the future - 42
2467 // days from now is *not* reported as one that starts in the future; as we
2468 // sanitize the override allowing a maximum of ::Now().
2469 FrameMsg_Navigate_Params late_nav_params;
2470 late_nav_params.url = GURL("data:text/html,<div>Another page</div>");
2471 late_nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2472 late_nav_params.transition = ui::PAGE_TRANSITION_TYPED;
2473 late_nav_params.page_id = -1;
2474 late_nav_params.is_post = true;
2475 late_nav_params.browser_navigation_start =
2476 base::TimeTicks::Now() + base::TimeDelta::FromDays(42);
2478 frame()->OnNavigate(late_nav_params);
2479 ProcessPendingMessages();
2480 base::Time after_navigation =
2481 base::Time::Now() + base::TimeDelta::FromDays(1);
2483 base::Time late_nav_reported_start =
2484 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2485 EXPECT_LE(late_nav_reported_start, after_navigation);
2488 } // namespace content