Roll WebRTC 7546:7549.
[chromium-blink-merge.git] / content / renderer / render_view_browsertest.cc
blob484d5d6c7eda2927d3e3fc66682fd0a20a716191
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/history_controller.h"
35 #include "content/renderer/history_serialization.h"
36 #include "content/renderer/render_process.h"
37 #include "content/renderer/render_view_impl.h"
38 #include "content/shell/browser/shell.h"
39 #include "content/shell/browser/shell_browser_context.h"
40 #include "content/test/mock_keyboard.h"
41 #include "net/base/net_errors.h"
42 #include "net/cert/cert_status_flags.h"
43 #include "testing/gtest/include/gtest/gtest.h"
44 #include "third_party/WebKit/public/platform/WebData.h"
45 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
46 #include "third_party/WebKit/public/platform/WebString.h"
47 #include "third_party/WebKit/public/platform/WebURLResponse.h"
48 #include "third_party/WebKit/public/web/WebDataSource.h"
49 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
50 #include "third_party/WebKit/public/web/WebHistoryItem.h"
51 #include "third_party/WebKit/public/web/WebLocalFrame.h"
52 #include "third_party/WebKit/public/web/WebPerformance.h"
53 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
54 #include "third_party/WebKit/public/web/WebView.h"
55 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
56 #include "ui/events/keycodes/keyboard_codes.h"
57 #include "ui/gfx/codec/jpeg_codec.h"
58 #include "ui/gfx/range/range.h"
60 #if defined(USE_AURA)
61 #include "ui/events/event.h"
62 #endif
64 #if defined(USE_AURA) && defined(USE_X11)
65 #include <X11/Xlib.h>
66 #include "ui/events/event_constants.h"
67 #include "ui/events/keycodes/keyboard_code_conversion.h"
68 #include "ui/events/test/events_test_utils.h"
69 #include "ui/events/test/events_test_utils_x11.h"
70 #endif
72 #if defined(USE_OZONE)
73 #include "ui/events/keycodes/keyboard_code_conversion.h"
74 #endif
76 using blink::WebFrame;
77 using blink::WebInputEvent;
78 using blink::WebLocalFrame;
79 using blink::WebMouseEvent;
80 using blink::WebRuntimeFeatures;
81 using blink::WebString;
82 using blink::WebTextDirection;
83 using blink::WebURLError;
85 namespace content {
87 namespace {
89 static const int kProxyRoutingId = 13;
91 #if (defined(USE_AURA) && defined(USE_X11)) || defined(USE_OZONE)
92 // Converts MockKeyboard::Modifiers to ui::EventFlags.
93 int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers) {
94 static struct ModifierMap {
95 MockKeyboard::Modifiers src;
96 int dst;
97 } kModifierMap[] = {
98 { MockKeyboard::LEFT_SHIFT, ui::EF_SHIFT_DOWN },
99 { MockKeyboard::RIGHT_SHIFT, ui::EF_SHIFT_DOWN },
100 { MockKeyboard::LEFT_CONTROL, ui::EF_CONTROL_DOWN },
101 { MockKeyboard::RIGHT_CONTROL, ui::EF_CONTROL_DOWN },
102 { MockKeyboard::LEFT_ALT, ui::EF_ALT_DOWN },
103 { MockKeyboard::RIGHT_ALT, ui::EF_ALT_DOWN },
105 int flags = 0;
106 for (size_t i = 0; i < arraysize(kModifierMap); ++i) {
107 if (kModifierMap[i].src & modifiers) {
108 flags |= kModifierMap[i].dst;
111 return flags;
113 #endif
115 class WebUITestWebUIControllerFactory : public WebUIControllerFactory {
116 public:
117 WebUIController* CreateWebUIControllerForURL(WebUI* web_ui,
118 const GURL& url) const override {
119 return NULL;
121 WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
122 const GURL& url) const override {
123 return WebUI::kNoWebUI;
125 bool UseWebUIForURL(BrowserContext* browser_context,
126 const GURL& url) const override {
127 return HasWebUIScheme(url);
129 bool UseWebUIBindingsForURL(BrowserContext* browser_context,
130 const GURL& url) const override {
131 return HasWebUIScheme(url);
135 } // namespace
137 class RenderViewImplTest : public RenderViewTest {
138 public:
139 RenderViewImplTest() {
140 // Attach a pseudo keyboard device to this object.
141 mock_keyboard_.reset(new MockKeyboard());
144 ~RenderViewImplTest() override {}
146 void SetUp() override {
147 RenderViewTest::SetUp();
148 // Enable Blink's experimental and test only features so that test code
149 // does not have to bother enabling each feature.
150 WebRuntimeFeatures::enableExperimentalFeatures(true);
151 WebRuntimeFeatures::enableTestOnlyFeatures(true);
154 RenderViewImpl* view() {
155 return static_cast<RenderViewImpl*>(view_);
158 int view_page_id() {
159 return view()->page_id_;
162 RenderFrameImpl* frame() {
163 return static_cast<RenderFrameImpl*>(view()->GetMainRenderFrame());
166 // Sends IPC messages that emulates a key-press event.
167 int SendKeyEvent(MockKeyboard::Layout layout,
168 int key_code,
169 MockKeyboard::Modifiers modifiers,
170 base::string16* output) {
171 #if defined(OS_WIN)
172 // Retrieve the Unicode character for the given tuple (keyboard-layout,
173 // key-code, and modifiers).
174 // Exit when a keyboard-layout driver cannot assign a Unicode character to
175 // the tuple to prevent sending an invalid key code to the RenderView
176 // object.
177 CHECK(mock_keyboard_.get());
178 CHECK(output);
179 int length = mock_keyboard_->GetCharacters(layout, key_code, modifiers,
180 output);
181 if (length != 1)
182 return -1;
184 // Create IPC messages from Windows messages and send them to our
185 // back-end.
186 // A keyboard event of Windows consists of three Windows messages:
187 // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
188 // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
189 // WM_CHAR sends a composed Unicode character.
190 MSG msg1 = { NULL, WM_KEYDOWN, key_code, 0 };
191 #if defined(USE_AURA)
192 ui::KeyEvent evt1(msg1);
193 NativeWebKeyboardEvent keydown_event(&evt1);
194 #else
195 NativeWebKeyboardEvent keydown_event(msg1);
196 #endif
197 SendNativeKeyEvent(keydown_event);
199 MSG msg2 = { NULL, WM_CHAR, (*output)[0], 0 };
200 #if defined(USE_AURA)
201 ui::KeyEvent evt2(msg2);
202 NativeWebKeyboardEvent char_event(&evt2);
203 #else
204 NativeWebKeyboardEvent char_event(msg2);
205 #endif
206 SendNativeKeyEvent(char_event);
208 MSG msg3 = { NULL, WM_KEYUP, key_code, 0 };
209 #if defined(USE_AURA)
210 ui::KeyEvent evt3(msg3);
211 NativeWebKeyboardEvent keyup_event(&evt3);
212 #else
213 NativeWebKeyboardEvent keyup_event(msg3);
214 #endif
215 SendNativeKeyEvent(keyup_event);
217 return length;
218 #elif defined(USE_AURA) && defined(USE_X11)
219 // We ignore |layout|, which means we are only testing the layout of the
220 // current locale. TODO(mazda): fix this to respect |layout|.
221 CHECK(output);
222 const int flags = ConvertMockKeyboardModifier(modifiers);
224 ui::ScopedXI2Event xevent;
225 xevent.InitKeyEvent(ui::ET_KEY_PRESSED,
226 static_cast<ui::KeyboardCode>(key_code),
227 flags);
228 ui::KeyEvent event1(xevent);
229 NativeWebKeyboardEvent keydown_event(&event1);
230 SendNativeKeyEvent(keydown_event);
232 // X11 doesn't actually have native character events, but give the test
233 // what it wants.
234 xevent.InitKeyEvent(ui::ET_KEY_PRESSED,
235 static_cast<ui::KeyboardCode>(key_code),
236 flags);
237 ui::KeyEvent event2(xevent);
238 event2.set_character(GetCharacterFromKeyCode(event2.key_code(),
239 event2.flags()));
240 ui::KeyEventTestApi test_event2(&event2);
241 test_event2.set_is_char(true);
242 NativeWebKeyboardEvent char_event(&event2);
243 SendNativeKeyEvent(char_event);
245 xevent.InitKeyEvent(ui::ET_KEY_RELEASED,
246 static_cast<ui::KeyboardCode>(key_code),
247 flags);
248 ui::KeyEvent event3(xevent);
249 NativeWebKeyboardEvent keyup_event(&event3);
250 SendNativeKeyEvent(keyup_event);
252 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
253 flags);
254 output->assign(1, static_cast<base::char16>(c));
255 return 1;
256 #elif defined(USE_OZONE)
257 const int flags = ConvertMockKeyboardModifier(modifiers);
259 ui::KeyEvent keydown_event(ui::ET_KEY_PRESSED,
260 static_cast<ui::KeyboardCode>(key_code),
261 flags);
262 NativeWebKeyboardEvent keydown_web_event(&keydown_event);
263 SendNativeKeyEvent(keydown_web_event);
265 ui::KeyEvent char_event(keydown_event.GetCharacter(),
266 static_cast<ui::KeyboardCode>(key_code),
267 flags);
268 NativeWebKeyboardEvent char_web_event(&char_event);
269 SendNativeKeyEvent(char_web_event);
271 ui::KeyEvent keyup_event(ui::ET_KEY_RELEASED,
272 static_cast<ui::KeyboardCode>(key_code),
273 flags);
274 NativeWebKeyboardEvent keyup_web_event(&keyup_event);
275 SendNativeKeyEvent(keyup_web_event);
277 long c = GetCharacterFromKeyCode(static_cast<ui::KeyboardCode>(key_code),
278 flags);
279 output->assign(1, static_cast<base::char16>(c));
280 return 1;
281 #else
282 NOTIMPLEMENTED();
283 return L'\0';
284 #endif
287 private:
288 scoped_ptr<MockKeyboard> mock_keyboard_;
291 TEST_F(RenderViewImplTest, SaveImageFromDataURL) {
292 const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
293 ViewHostMsg_SaveImageFromDataURL::ID);
294 EXPECT_FALSE(msg1);
295 render_thread_->sink().ClearMessages();
297 const std::string image_data_url =
298 "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
300 view()->saveImageFromDataURL(WebString::fromUTF8(image_data_url));
301 ProcessPendingMessages();
302 const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching(
303 ViewHostMsg_SaveImageFromDataURL::ID);
304 EXPECT_TRUE(msg2);
306 ViewHostMsg_SaveImageFromDataURL::Param param1;
307 ViewHostMsg_SaveImageFromDataURL::Read(msg2, &param1);
308 EXPECT_EQ(param1.b.length(), image_data_url.length());
309 EXPECT_EQ(param1.b, image_data_url);
311 ProcessPendingMessages();
312 render_thread_->sink().ClearMessages();
314 const std::string large_data_url(1024 * 1024 * 10 - 1, 'd');
316 view()->saveImageFromDataURL(WebString::fromUTF8(large_data_url));
317 ProcessPendingMessages();
318 const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching(
319 ViewHostMsg_SaveImageFromDataURL::ID);
320 EXPECT_TRUE(msg3);
322 ViewHostMsg_SaveImageFromDataURL::Param param2;
323 ViewHostMsg_SaveImageFromDataURL::Read(msg3, &param2);
324 EXPECT_EQ(param2.b.length(), large_data_url.length());
325 EXPECT_EQ(param2.b, large_data_url);
327 ProcessPendingMessages();
328 render_thread_->sink().ClearMessages();
330 const std::string exceeded_data_url(1024 * 1024 * 10 + 1, 'd');
332 view()->saveImageFromDataURL(WebString::fromUTF8(exceeded_data_url));
333 ProcessPendingMessages();
334 const IPC::Message* msg4 = render_thread_->sink().GetFirstMessageMatching(
335 ViewHostMsg_SaveImageFromDataURL::ID);
336 EXPECT_FALSE(msg4);
339 // Test that we get form state change notifications when input fields change.
340 TEST_F(RenderViewImplTest, DISABLED_OnNavStateChanged) {
341 // Don't want any delay for form state sync changes. This will still post a
342 // message so updates will get coalesced, but as soon as we spin the message
343 // loop, it will generate an update.
344 view()->set_send_content_state_immediately(true);
346 LoadHTML("<input type=\"text\" id=\"elt_text\"></input>");
348 // We should NOT have gotten a form state change notification yet.
349 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
350 ViewHostMsg_UpdateState::ID));
351 render_thread_->sink().ClearMessages();
353 // Change the value of the input. We should have gotten an update state
354 // notification. We need to spin the message loop to catch this update.
355 ExecuteJavaScript("document.getElementById('elt_text').value = 'foo';");
356 ProcessPendingMessages();
357 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
358 ViewHostMsg_UpdateState::ID));
361 TEST_F(RenderViewImplTest, OnNavigationHttpPost) {
362 FrameMsg_Navigate_Params nav_params;
364 // An http url will trigger a resource load so cannot be used here.
365 nav_params.common_params.url = GURL("data:text/html,<div>Page</div>");
366 nav_params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
367 nav_params.common_params.transition = ui::PAGE_TRANSITION_TYPED;
368 nav_params.page_id = -1;
369 nav_params.request_params.is_post = true;
370 nav_params.commit_params.browser_navigation_start =
371 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.request_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.common_params.url = GURL("data:text/html,<div>Page B</div>");
572 nav_params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
573 nav_params.common_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.commit_params.browser_navigation_start =
579 base::TimeTicks::FromInternalValue(1);
580 frame()->OnNavigate(nav_params);
581 ProcessPendingMessages();
582 const IPC::Message* msg3 = render_thread_->sink().GetUniqueMessageMatching(
583 ViewHostMsg_UpdateState::ID);
584 EXPECT_FALSE(msg3);
587 // Ensure the RenderViewImpl reloads the previous page if a reload request
588 // arrives while it is showing swappedout://. http://crbug.com/143155.
589 TEST_F(RenderViewImplTest, ReloadWhileSwappedOut) {
590 // Load page A.
591 LoadHTML("<div>Page A</div>");
593 // Load page B, which will trigger an UpdateState message for page A.
594 LoadHTML("<div>Page B</div>");
596 // Check for a valid UpdateState message for page A.
597 ProcessPendingMessages();
598 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
599 ViewHostMsg_UpdateState::ID);
600 ASSERT_TRUE(msg_A);
601 ViewHostMsg_UpdateState::Param params;
602 ViewHostMsg_UpdateState::Read(msg_A, &params);
603 int page_id_A = params.a;
604 PageState state_A = params.b;
605 EXPECT_EQ(1, page_id_A);
606 render_thread_->sink().ClearMessages();
608 // Back to page A (page_id 1) and commit.
609 FrameMsg_Navigate_Params params_A;
610 params_A.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
611 params_A.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
612 params_A.current_history_list_length = 2;
613 params_A.current_history_list_offset = 1;
614 params_A.pending_history_list_offset = 0;
615 params_A.page_id = 1;
616 params_A.commit_params.page_state = state_A;
617 params_A.commit_params.browser_navigation_start =
618 base::TimeTicks::FromInternalValue(1);
619 frame()->OnNavigate(params_A);
620 ProcessPendingMessages();
622 // Respond to a swap out request.
623 view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId);
625 // Check for a OnSwapOutACK.
626 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
627 FrameHostMsg_SwapOut_ACK::ID);
628 ASSERT_TRUE(msg);
629 render_thread_->sink().ClearMessages();
631 // It is possible to get a reload request at this point, containing the
632 // params.page_state of the initial page (e.g., if the new page fails the
633 // provisional load in the renderer process, after we unload the old page).
634 // Ensure the old page gets reloaded, not swappedout://.
635 FrameMsg_Navigate_Params nav_params;
636 nav_params.common_params.url = GURL("data:text/html,<div>Page A</div>");
637 nav_params.common_params.navigation_type = FrameMsg_Navigate_Type::RELOAD;
638 nav_params.common_params.transition = ui::PAGE_TRANSITION_RELOAD;
639 nav_params.current_history_list_length = 2;
640 nav_params.current_history_list_offset = 0;
641 nav_params.pending_history_list_offset = 0;
642 nav_params.page_id = 1;
643 nav_params.commit_params.page_state = state_A;
644 nav_params.commit_params.browser_navigation_start =
645 base::TimeTicks::FromInternalValue(1);
646 frame()->OnNavigate(nav_params);
647 ProcessPendingMessages();
649 // Verify page A committed, not swappedout://.
650 const IPC::Message* frame_navigate_msg =
651 render_thread_->sink().GetUniqueMessageMatching(
652 FrameHostMsg_DidCommitProvisionalLoad::ID);
653 EXPECT_TRUE(frame_navigate_msg);
655 // Read URL out of the parent trait of the params object.
656 FrameHostMsg_DidCommitProvisionalLoad::Param commit_params;
657 FrameHostMsg_DidCommitProvisionalLoad::Read(frame_navigate_msg,
658 &commit_params);
659 EXPECT_NE(GURL("swappedout://"), commit_params.a.url);
663 // Test that we get the correct UpdateState message when we go back twice
664 // quickly without committing. Regression test for http://crbug.com/58082.
665 // Disabled: http://crbug.com/157357 .
666 TEST_F(RenderViewImplTest, DISABLED_LastCommittedUpdateState) {
667 // Load page A.
668 LoadHTML("<div>Page A</div>");
670 // Load page B, which will trigger an UpdateState message for page A.
671 LoadHTML("<div>Page B</div>");
673 // Check for a valid UpdateState message for page A.
674 ProcessPendingMessages();
675 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
676 ViewHostMsg_UpdateState::ID);
677 ASSERT_TRUE(msg_A);
678 ViewHostMsg_UpdateState::Param param;
679 ViewHostMsg_UpdateState::Read(msg_A, &param);
680 int page_id_A = param.a;
681 PageState state_A = param.b;
682 EXPECT_EQ(1, page_id_A);
683 render_thread_->sink().ClearMessages();
685 // Load page C, which will trigger an UpdateState message for page B.
686 LoadHTML("<div>Page C</div>");
688 // Check for a valid UpdateState for page B.
689 ProcessPendingMessages();
690 const IPC::Message* msg_B = render_thread_->sink().GetUniqueMessageMatching(
691 ViewHostMsg_UpdateState::ID);
692 ASSERT_TRUE(msg_B);
693 ViewHostMsg_UpdateState::Read(msg_B, &param);
694 int page_id_B = param.a;
695 PageState state_B = param.b;
696 EXPECT_EQ(2, page_id_B);
697 EXPECT_NE(state_A, state_B);
698 render_thread_->sink().ClearMessages();
700 // Load page D, which will trigger an UpdateState message for page C.
701 LoadHTML("<div>Page D</div>");
703 // Check for a valid UpdateState for page C.
704 ProcessPendingMessages();
705 const IPC::Message* msg_C = render_thread_->sink().GetUniqueMessageMatching(
706 ViewHostMsg_UpdateState::ID);
707 ASSERT_TRUE(msg_C);
708 ViewHostMsg_UpdateState::Read(msg_C, &param);
709 int page_id_C = param.a;
710 PageState state_C = param.b;
711 EXPECT_EQ(3, page_id_C);
712 EXPECT_NE(state_B, state_C);
713 render_thread_->sink().ClearMessages();
715 // Go back to C and commit, preparing for our real test.
716 FrameMsg_Navigate_Params params_C;
717 params_C.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
718 params_C.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
719 params_C.current_history_list_length = 4;
720 params_C.current_history_list_offset = 3;
721 params_C.pending_history_list_offset = 2;
722 params_C.page_id = 3;
723 params_C.commit_params.page_state = state_C;
724 params_C.commit_params.browser_navigation_start =
725 base::TimeTicks::FromInternalValue(1);
726 frame()->OnNavigate(params_C);
727 ProcessPendingMessages();
728 render_thread_->sink().ClearMessages();
730 // Go back twice quickly, such that page B does not have a chance to commit.
731 // This leads to two changes to the back/forward list but only one change to
732 // the RenderView's page ID.
734 // Back to page B (page_id 2), without committing.
735 FrameMsg_Navigate_Params params_B;
736 params_B.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
737 params_B.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
738 params_B.current_history_list_length = 4;
739 params_B.current_history_list_offset = 2;
740 params_B.pending_history_list_offset = 1;
741 params_B.page_id = 2;
742 params_B.commit_params.page_state = state_B;
743 params_B.commit_params.browser_navigation_start =
744 base::TimeTicks::FromInternalValue(1);
745 frame()->OnNavigate(params_B);
747 // Back to page A (page_id 1) and commit.
748 FrameMsg_Navigate_Params params;
749 params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
750 params.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
751 params_B.current_history_list_length = 4;
752 params_B.current_history_list_offset = 2;
753 params_B.pending_history_list_offset = 0;
754 params.page_id = 1;
755 params.commit_params.page_state = state_A;
756 params.commit_params.browser_navigation_start =
757 base::TimeTicks::FromInternalValue(1);
758 frame()->OnNavigate(params);
759 ProcessPendingMessages();
761 // Now ensure that the UpdateState message we receive is consistent
762 // and represents page C in both page_id and state.
763 const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
764 ViewHostMsg_UpdateState::ID);
765 ASSERT_TRUE(msg);
766 ViewHostMsg_UpdateState::Read(msg, &param);
767 int page_id = param.a;
768 PageState state = param.b;
769 EXPECT_EQ(page_id_C, page_id);
770 EXPECT_NE(state_A, state);
771 EXPECT_NE(state_B, state);
772 EXPECT_EQ(state_C, state);
775 // Test that the history_page_ids_ list can reveal when a stale back/forward
776 // navigation arrives from the browser and can be ignored. See
777 // http://crbug.com/86758.
778 TEST_F(RenderViewImplTest, StaleNavigationsIgnored) {
779 // Load page A.
780 LoadHTML("<div>Page A</div>");
781 EXPECT_EQ(1, view()->history_list_length_);
782 EXPECT_EQ(0, view()->history_list_offset_);
783 EXPECT_EQ(1, view()->history_page_ids_[0]);
785 // Load page B, which will trigger an UpdateState message for page A.
786 LoadHTML("<div>Page B</div>");
787 EXPECT_EQ(2, view()->history_list_length_);
788 EXPECT_EQ(1, view()->history_list_offset_);
789 EXPECT_EQ(2, view()->history_page_ids_[1]);
791 // Check for a valid UpdateState message for page A.
792 ProcessPendingMessages();
793 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
794 ViewHostMsg_UpdateState::ID);
795 ASSERT_TRUE(msg_A);
796 ViewHostMsg_UpdateState::Param param;
797 ViewHostMsg_UpdateState::Read(msg_A, &param);
798 int page_id_A = param.a;
799 PageState state_A = param.b;
800 EXPECT_EQ(1, page_id_A);
801 render_thread_->sink().ClearMessages();
803 // Back to page A (page_id 1) and commit.
804 FrameMsg_Navigate_Params params_A;
805 params_A.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
806 params_A.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
807 params_A.current_history_list_length = 2;
808 params_A.current_history_list_offset = 1;
809 params_A.pending_history_list_offset = 0;
810 params_A.page_id = 1;
811 params_A.commit_params.page_state = state_A;
812 params_A.commit_params.browser_navigation_start =
813 base::TimeTicks::FromInternalValue(1);
814 frame()->OnNavigate(params_A);
815 ProcessPendingMessages();
817 // A new navigation commits, clearing the forward history.
818 LoadHTML("<div>Page C</div>");
819 EXPECT_EQ(2, view()->history_list_length_);
820 EXPECT_EQ(1, view()->history_list_offset_);
821 EXPECT_EQ(3, view()->history_page_ids_[1]);
823 // The browser then sends a stale navigation to B, which should be ignored.
824 FrameMsg_Navigate_Params params_B;
825 params_B.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
826 params_B.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
827 params_B.current_history_list_length = 2;
828 params_B.current_history_list_offset = 0;
829 params_B.pending_history_list_offset = 1;
830 params_B.page_id = 2;
831 params_B.commit_params.page_state =
832 state_A; // Doesn't matter, just has to be present.
833 params_B.commit_params.browser_navigation_start =
834 base::TimeTicks::FromInternalValue(1);
835 frame()->OnNavigate(params_B);
837 // State should be unchanged.
838 EXPECT_EQ(2, view()->history_list_length_);
839 EXPECT_EQ(1, view()->history_list_offset_);
840 EXPECT_EQ(3, view()->history_page_ids_[1]);
843 // Test that we do not ignore navigations after the entry limit is reached,
844 // in which case the browser starts dropping entries from the front. In this
845 // case, we'll see a page_id mismatch but the RenderView's id will be older,
846 // not newer, than params.page_id. Use this as a cue that we should update the
847 // state and not treat it like a navigation to a cropped forward history item.
848 // See http://crbug.com/89798.
849 TEST_F(RenderViewImplTest, DontIgnoreBackAfterNavEntryLimit) {
850 // Load page A.
851 LoadHTML("<div>Page A</div>");
852 EXPECT_EQ(1, view()->history_list_length_);
853 EXPECT_EQ(0, view()->history_list_offset_);
854 EXPECT_EQ(1, view()->history_page_ids_[0]);
856 // Load page B, which will trigger an UpdateState message for page A.
857 LoadHTML("<div>Page B</div>");
858 EXPECT_EQ(2, view()->history_list_length_);
859 EXPECT_EQ(1, view()->history_list_offset_);
860 EXPECT_EQ(2, view()->history_page_ids_[1]);
862 // Check for a valid UpdateState message for page A.
863 ProcessPendingMessages();
864 const IPC::Message* msg_A = render_thread_->sink().GetUniqueMessageMatching(
865 ViewHostMsg_UpdateState::ID);
866 ASSERT_TRUE(msg_A);
867 ViewHostMsg_UpdateState::Param param;
868 ViewHostMsg_UpdateState::Read(msg_A, &param);
869 int page_id_A = param.a;
870 PageState state_A = param.b;
871 EXPECT_EQ(1, page_id_A);
872 render_thread_->sink().ClearMessages();
874 // Load page C, which will trigger an UpdateState message for page B.
875 LoadHTML("<div>Page C</div>");
876 EXPECT_EQ(3, view()->history_list_length_);
877 EXPECT_EQ(2, view()->history_list_offset_);
878 EXPECT_EQ(3, view()->history_page_ids_[2]);
880 // Check for a valid UpdateState message for page B.
881 ProcessPendingMessages();
882 const IPC::Message* msg_B = render_thread_->sink().GetUniqueMessageMatching(
883 ViewHostMsg_UpdateState::ID);
884 ASSERT_TRUE(msg_B);
885 ViewHostMsg_UpdateState::Read(msg_B, &param);
886 int page_id_B = param.a;
887 PageState state_B = param.b;
888 EXPECT_EQ(2, page_id_B);
889 render_thread_->sink().ClearMessages();
891 // Suppose the browser has limited the number of NavigationEntries to 2.
892 // It has now dropped the first entry, but the renderer isn't notified.
893 // Ensure that going back to page B (page_id 2) at offset 0 is successful.
894 FrameMsg_Navigate_Params params_B;
895 params_B.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
896 params_B.common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
897 params_B.current_history_list_length = 2;
898 params_B.current_history_list_offset = 1;
899 params_B.pending_history_list_offset = 0;
900 params_B.page_id = 2;
901 params_B.commit_params.page_state = state_B;
902 params_B.commit_params.browser_navigation_start =
903 base::TimeTicks::FromInternalValue(1);
904 frame()->OnNavigate(params_B);
905 ProcessPendingMessages();
907 EXPECT_EQ(2, view()->history_list_length_);
908 EXPECT_EQ(0, view()->history_list_offset_);
909 EXPECT_EQ(2, view()->history_page_ids_[0]);
912 // Test that our IME backend sends a notification message when the input focus
913 // changes.
914 TEST_F(RenderViewImplTest, OnImeTypeChanged) {
915 // Enable our IME backend code.
916 view()->OnSetInputMethodActive(true);
918 // Load an HTML page consisting of two input fields.
919 view()->set_send_content_state_immediately(true);
920 LoadHTML("<html>"
921 "<head>"
922 "</head>"
923 "<body>"
924 "<input id=\"test1\" type=\"text\" value=\"some text\"></input>"
925 "<input id=\"test2\" type=\"password\"></input>"
926 "<input id=\"test3\" type=\"text\" inputmode=\"verbatim\"></input>"
927 "<input id=\"test4\" type=\"text\" inputmode=\"latin\"></input>"
928 "<input id=\"test5\" type=\"text\" inputmode=\"latin-name\"></input>"
929 "<input id=\"test6\" type=\"text\" inputmode=\"latin-prose\">"
930 "</input>"
931 "<input id=\"test7\" type=\"text\" inputmode=\"full-width-latin\">"
932 "</input>"
933 "<input id=\"test8\" type=\"text\" inputmode=\"kana\"></input>"
934 "<input id=\"test9\" type=\"text\" inputmode=\"katakana\"></input>"
935 "<input id=\"test10\" type=\"text\" inputmode=\"numeric\"></input>"
936 "<input id=\"test11\" type=\"text\" inputmode=\"tel\"></input>"
937 "<input id=\"test12\" type=\"text\" inputmode=\"email\"></input>"
938 "<input id=\"test13\" type=\"text\" inputmode=\"url\"></input>"
939 "<input id=\"test14\" type=\"text\" inputmode=\"unknown\"></input>"
940 "<input id=\"test15\" type=\"text\" inputmode=\"verbatim\"></input>"
941 "</body>"
942 "</html>");
943 render_thread_->sink().ClearMessages();
945 struct InputModeTestCase {
946 const char* input_id;
947 ui::TextInputMode expected_mode;
949 static const InputModeTestCase kInputModeTestCases[] = {
950 {"test1", ui::TEXT_INPUT_MODE_DEFAULT},
951 {"test3", ui::TEXT_INPUT_MODE_VERBATIM},
952 {"test4", ui::TEXT_INPUT_MODE_LATIN},
953 {"test5", ui::TEXT_INPUT_MODE_LATIN_NAME},
954 {"test6", ui::TEXT_INPUT_MODE_LATIN_PROSE},
955 {"test7", ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN},
956 {"test8", ui::TEXT_INPUT_MODE_KANA},
957 {"test9", ui::TEXT_INPUT_MODE_KATAKANA},
958 {"test10", ui::TEXT_INPUT_MODE_NUMERIC},
959 {"test11", ui::TEXT_INPUT_MODE_TEL},
960 {"test12", ui::TEXT_INPUT_MODE_EMAIL},
961 {"test13", ui::TEXT_INPUT_MODE_URL},
962 {"test14", ui::TEXT_INPUT_MODE_DEFAULT},
963 {"test15", ui::TEXT_INPUT_MODE_VERBATIM},
966 const int kRepeatCount = 10;
967 for (int i = 0; i < kRepeatCount; i++) {
968 // Move the input focus to the first <input> element, where we should
969 // activate IMEs.
970 ExecuteJavaScript("document.getElementById('test1').focus();");
971 ProcessPendingMessages();
972 render_thread_->sink().ClearMessages();
974 // Update the IME status and verify if our IME backend sends an IPC message
975 // to activate IMEs.
976 view()->UpdateTextInputType();
977 const IPC::Message* msg = render_thread_->sink().GetMessageAt(0);
978 EXPECT_TRUE(msg != NULL);
979 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
980 ViewHostMsg_TextInputTypeChanged::Param params;
981 ViewHostMsg_TextInputTypeChanged::Read(msg, &params);
982 ui::TextInputType type = params.a;
983 ui::TextInputMode input_mode = params.b;
984 bool can_compose_inline = params.c;
985 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, type);
986 EXPECT_EQ(true, can_compose_inline);
988 // Move the input focus to the second <input> element, where we should
989 // de-activate IMEs.
990 ExecuteJavaScript("document.getElementById('test2').focus();");
991 ProcessPendingMessages();
992 render_thread_->sink().ClearMessages();
994 // Update the IME status and verify if our IME backend sends an IPC message
995 // to de-activate IMEs.
996 view()->UpdateTextInputType();
997 msg = render_thread_->sink().GetMessageAt(0);
998 EXPECT_TRUE(msg != NULL);
999 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
1000 ViewHostMsg_TextInputTypeChanged::Read(msg, & params);
1001 type = params.a;
1002 input_mode = params.b;
1003 EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD, type);
1005 for (size_t i = 0; i < arraysize(kInputModeTestCases); i++) {
1006 const InputModeTestCase* test_case = &kInputModeTestCases[i];
1007 std::string javascript =
1008 base::StringPrintf("document.getElementById('%s').focus();",
1009 test_case->input_id);
1010 // Move the input focus to the target <input> element, where we should
1011 // activate IMEs.
1012 ExecuteJavaScriptAndReturnIntValue(base::ASCIIToUTF16(javascript), NULL);
1013 ProcessPendingMessages();
1014 render_thread_->sink().ClearMessages();
1016 // Update the IME status and verify if our IME backend sends an IPC
1017 // message to activate IMEs.
1018 view()->UpdateTextInputType();
1019 const IPC::Message* msg = render_thread_->sink().GetMessageAt(0);
1020 EXPECT_TRUE(msg != NULL);
1021 EXPECT_EQ(ViewHostMsg_TextInputTypeChanged::ID, msg->type());
1022 ViewHostMsg_TextInputTypeChanged::Read(msg, & params);
1023 type = params.a;
1024 input_mode = params.b;
1025 EXPECT_EQ(test_case->expected_mode, input_mode);
1030 // Test that our IME backend can compose CJK words.
1031 // Our IME front-end sends many platform-independent messages to the IME backend
1032 // while it composes CJK words. This test sends the minimal messages captured
1033 // on my local environment directly to the IME backend to verify if the backend
1034 // can compose CJK words without any problems.
1035 // This test uses an array of command sets because an IME composotion does not
1036 // only depends on IME events, but also depends on window events, e.g. moving
1037 // the window focus while composing a CJK text. To handle such complicated
1038 // cases, this test should not only call IME-related functions in the
1039 // RenderWidget class, but also call some RenderWidget members, e.g.
1040 // ExecuteJavaScript(), RenderWidget::OnSetFocus(), etc.
1041 TEST_F(RenderViewImplTest, ImeComposition) {
1042 enum ImeCommand {
1043 IME_INITIALIZE,
1044 IME_SETINPUTMODE,
1045 IME_SETFOCUS,
1046 IME_SETCOMPOSITION,
1047 IME_CONFIRMCOMPOSITION,
1048 IME_CANCELCOMPOSITION
1050 struct ImeMessage {
1051 ImeCommand command;
1052 bool enable;
1053 int selection_start;
1054 int selection_end;
1055 const wchar_t* ime_string;
1056 const wchar_t* result;
1058 static const ImeMessage kImeMessages[] = {
1059 // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
1060 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1061 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1062 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1063 {IME_SETCOMPOSITION, false, 1, 1, L"n", L"n"},
1064 {IME_SETCOMPOSITION, false, 2, 2, L"ni", L"ni"},
1065 {IME_SETCOMPOSITION, false, 3, 3, L"nih", L"nih"},
1066 {IME_SETCOMPOSITION, false, 4, 4, L"niha", L"niha"},
1067 {IME_SETCOMPOSITION, false, 5, 5, L"nihao", L"nihao"},
1068 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"\x4F60\x597D", L"\x4F60\x597D"},
1069 // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
1070 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1071 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1072 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1073 {IME_SETCOMPOSITION, false, 0, 1, L"\xFF4B", L"\xFF4B"},
1074 {IME_SETCOMPOSITION, false, 0, 1, L"\x304B", L"\x304B"},
1075 {IME_SETCOMPOSITION, false, 0, 2, L"\x304B\xFF4E", L"\x304B\xFF4E"},
1076 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\xFF4A",
1077 L"\x304B\x3093\xFF4A"},
1078 {IME_SETCOMPOSITION, false, 0, 3, L"\x304B\x3093\x3058",
1079 L"\x304B\x3093\x3058"},
1080 {IME_SETCOMPOSITION, false, 0, 2, L"\x611F\x3058", L"\x611F\x3058"},
1081 {IME_SETCOMPOSITION, false, 0, 2, L"\x6F22\x5B57", L"\x6F22\x5B57"},
1082 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1083 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
1084 // Scenario 3: input a Korean word with Microsot IME (on Vista).
1085 {IME_INITIALIZE, true, 0, 0, NULL, NULL},
1086 {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
1087 {IME_SETFOCUS, true, 0, 0, NULL, NULL},
1088 {IME_SETCOMPOSITION, false, 0, 1, L"\x3147", L"\x3147"},
1089 {IME_SETCOMPOSITION, false, 0, 1, L"\xC544", L"\xC544"},
1090 {IME_SETCOMPOSITION, false, 0, 1, L"\xC548", L"\xC548"},
1091 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1092 {IME_SETCOMPOSITION, false, 0, 1, L"\x3134", L"\xC548\x3134"},
1093 {IME_SETCOMPOSITION, false, 0, 1, L"\xB140", L"\xC548\xB140"},
1094 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1095 {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\xC548"},
1096 {IME_SETCOMPOSITION, false, 0, 1, L"\xB155", L"\xC548\xB155"},
1097 {IME_CONFIRMCOMPOSITION, false, -1, -1, L"", L"\xC548\xB155"},
1100 for (size_t i = 0; i < arraysize(kImeMessages); i++) {
1101 const ImeMessage* ime_message = &kImeMessages[i];
1102 switch (ime_message->command) {
1103 case IME_INITIALIZE:
1104 // Load an HTML page consisting of a content-editable <div> element,
1105 // and move the input focus to the <div> element, where we can use
1106 // IMEs.
1107 view()->OnSetInputMethodActive(ime_message->enable);
1108 view()->set_send_content_state_immediately(true);
1109 LoadHTML("<html>"
1110 "<head>"
1111 "</head>"
1112 "<body>"
1113 "<div id=\"test1\" contenteditable=\"true\"></div>"
1114 "</body>"
1115 "</html>");
1116 ExecuteJavaScript("document.getElementById('test1').focus();");
1117 break;
1119 case IME_SETINPUTMODE:
1120 // Activate (or deactivate) our IME back-end.
1121 view()->OnSetInputMethodActive(ime_message->enable);
1122 break;
1124 case IME_SETFOCUS:
1125 // Update the window focus.
1126 view()->OnSetFocus(ime_message->enable);
1127 break;
1129 case IME_SETCOMPOSITION:
1130 view()->OnImeSetComposition(
1131 base::WideToUTF16(ime_message->ime_string),
1132 std::vector<blink::WebCompositionUnderline>(),
1133 ime_message->selection_start,
1134 ime_message->selection_end);
1135 break;
1137 case IME_CONFIRMCOMPOSITION:
1138 view()->OnImeConfirmComposition(
1139 base::WideToUTF16(ime_message->ime_string),
1140 gfx::Range::InvalidRange(),
1141 false);
1142 break;
1144 case IME_CANCELCOMPOSITION:
1145 view()->OnImeSetComposition(
1146 base::string16(),
1147 std::vector<blink::WebCompositionUnderline>(),
1148 0, 0);
1149 break;
1152 // Update the status of our IME back-end.
1153 // TODO(hbono): we should verify messages to be sent from the back-end.
1154 view()->UpdateTextInputType();
1155 ProcessPendingMessages();
1156 render_thread_->sink().ClearMessages();
1158 if (ime_message->result) {
1159 // Retrieve the content of this page and compare it with the expected
1160 // result.
1161 const int kMaxOutputCharacters = 128;
1162 base::string16 output =
1163 GetMainFrame()->contentAsText(kMaxOutputCharacters);
1164 EXPECT_EQ(base::WideToUTF16(ime_message->result), output);
1169 // Test that the RenderView::OnSetTextDirection() function can change the text
1170 // direction of the selected input element.
1171 TEST_F(RenderViewImplTest, OnSetTextDirection) {
1172 // Load an HTML page consisting of a <textarea> element and a <div> element.
1173 // This test changes the text direction of the <textarea> element, and
1174 // writes the values of its 'dir' attribute and its 'direction' property to
1175 // verify that the text direction is changed.
1176 view()->set_send_content_state_immediately(true);
1177 LoadHTML("<html>"
1178 "<head>"
1179 "</head>"
1180 "<body>"
1181 "<textarea id=\"test\"></textarea>"
1182 "<div id=\"result\" contenteditable=\"true\"></div>"
1183 "</body>"
1184 "</html>");
1185 render_thread_->sink().ClearMessages();
1187 static const struct {
1188 WebTextDirection direction;
1189 const wchar_t* expected_result;
1190 } kTextDirection[] = {
1191 { blink::WebTextDirectionRightToLeft, L"\x000A" L"rtl,rtl" },
1192 { blink::WebTextDirectionLeftToRight, L"\x000A" L"ltr,ltr" },
1194 for (size_t i = 0; i < arraysize(kTextDirection); ++i) {
1195 // Set the text direction of the <textarea> element.
1196 ExecuteJavaScript("document.getElementById('test').focus();");
1197 view()->OnSetTextDirection(kTextDirection[i].direction);
1199 // Write the values of its DOM 'dir' attribute and its CSS 'direction'
1200 // property to the <div> element.
1201 ExecuteJavaScript("var result = document.getElementById('result');"
1202 "var node = document.getElementById('test');"
1203 "var style = getComputedStyle(node, null);"
1204 "result.innerText ="
1205 " node.getAttribute('dir') + ',' +"
1206 " style.getPropertyValue('direction');");
1208 // Copy the document content to std::wstring and compare with the
1209 // expected result.
1210 const int kMaxOutputCharacters = 16;
1211 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
1212 EXPECT_EQ(base::WideToUTF16(kTextDirection[i].expected_result), output);
1216 // see http://crbug.com/238750
1217 #if defined(OS_WIN)
1218 #define MAYBE_OnHandleKeyboardEvent DISABLED_OnHandleKeyboardEvent
1219 #else
1220 #define MAYBE_OnHandleKeyboardEvent OnHandleKeyboardEvent
1221 #endif
1223 // Test that we can receive correct DOM events when we send input events
1224 // through the RenderWidget::OnHandleInputEvent() function.
1225 TEST_F(RenderViewImplTest, MAYBE_OnHandleKeyboardEvent) {
1226 #if !defined(OS_MACOSX)
1227 // Load an HTML page consisting of one <input> element and three
1228 // contentediable <div> elements.
1229 // The <input> element is used for sending keyboard events, and the <div>
1230 // elements are used for writing DOM events in the following format:
1231 // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
1232 // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
1233 // true when pressing an alt key, i.e. the |ev.metaKey| value is not
1234 // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
1235 view()->set_send_content_state_immediately(true);
1236 LoadHTML("<html>"
1237 "<head>"
1238 "<title></title>"
1239 "<script type='text/javascript' language='javascript'>"
1240 "function OnKeyEvent(ev) {"
1241 " var result = document.getElementById(ev.type);"
1242 " result.innerText ="
1243 " (ev.which || ev.keyCode) + ',' +"
1244 " ev.shiftKey + ',' +"
1245 " ev.ctrlKey + ',' +"
1246 " ev.altKey;"
1247 " return true;"
1249 "</script>"
1250 "</head>"
1251 "<body>"
1252 "<input id='test' type='text'"
1253 " onkeydown='return OnKeyEvent(event);'"
1254 " onkeypress='return OnKeyEvent(event);'"
1255 " onkeyup='return OnKeyEvent(event);'>"
1256 "</input>"
1257 "<div id='keydown' contenteditable='true'>"
1258 "</div>"
1259 "<div id='keypress' contenteditable='true'>"
1260 "</div>"
1261 "<div id='keyup' contenteditable='true'>"
1262 "</div>"
1263 "</body>"
1264 "</html>");
1265 ExecuteJavaScript("document.getElementById('test').focus();");
1266 render_thread_->sink().ClearMessages();
1268 static const MockKeyboard::Layout kLayouts[] = {
1269 #if defined(OS_WIN)
1270 // Since we ignore the mock keyboard layout on Linux and instead just use
1271 // the screen's keyboard layout, these trivially pass. They are commented
1272 // out to avoid the illusion that they work.
1273 MockKeyboard::LAYOUT_ARABIC,
1274 MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1275 MockKeyboard::LAYOUT_FRENCH,
1276 MockKeyboard::LAYOUT_HEBREW,
1277 MockKeyboard::LAYOUT_RUSSIAN,
1278 #endif
1279 MockKeyboard::LAYOUT_UNITED_STATES,
1282 for (size_t i = 0; i < arraysize(kLayouts); ++i) {
1283 // For each key code, we send three keyboard events.
1284 // * we press only the key;
1285 // * we press the key and a left-shift key, and;
1286 // * we press the key and a right-alt (AltGr) key.
1287 // For each modifiers, we need a string used for formatting its expected
1288 // result. (See the above comment for its format.)
1289 static const struct {
1290 MockKeyboard::Modifiers modifiers;
1291 const char* expected_result;
1292 } kModifierData[] = {
1293 {MockKeyboard::NONE, "false,false,false"},
1294 {MockKeyboard::LEFT_SHIFT, "true,false,false"},
1295 #if defined(OS_WIN)
1296 {MockKeyboard::RIGHT_ALT, "false,false,true"},
1297 #endif
1300 MockKeyboard::Layout layout = kLayouts[i];
1301 for (size_t j = 0; j < arraysize(kModifierData); ++j) {
1302 // Virtual key codes used for this test.
1303 static const int kKeyCodes[] = {
1304 '0', '1', '2', '3', '4', '5', '6', '7',
1305 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1306 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1307 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1308 'W', 'X', 'Y', 'Z',
1309 ui::VKEY_OEM_1,
1310 ui::VKEY_OEM_PLUS,
1311 ui::VKEY_OEM_COMMA,
1312 ui::VKEY_OEM_MINUS,
1313 ui::VKEY_OEM_PERIOD,
1314 ui::VKEY_OEM_2,
1315 ui::VKEY_OEM_3,
1316 ui::VKEY_OEM_4,
1317 ui::VKEY_OEM_5,
1318 ui::VKEY_OEM_6,
1319 ui::VKEY_OEM_7,
1320 #if defined(OS_WIN)
1321 // Not sure how to handle this key on Linux.
1322 ui::VKEY_OEM_8,
1323 #endif
1326 MockKeyboard::Modifiers modifiers = kModifierData[j].modifiers;
1327 for (size_t k = 0; k < arraysize(kKeyCodes); ++k) {
1328 // Send a keyboard event to the RenderView object.
1329 // We should test a keyboard event only when the given keyboard-layout
1330 // driver is installed in a PC and the driver can assign a Unicode
1331 // charcter for the given tuple (key-code and modifiers).
1332 int key_code = kKeyCodes[k];
1333 base::string16 char_code;
1334 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1335 continue;
1337 // Create an expected result from the virtual-key code, the character
1338 // code, and the modifier-key status.
1339 // We format a string that emulates a DOM-event string produced hy
1340 // our JavaScript function. (See the above comment for the format.)
1341 static char expected_result[1024];
1342 expected_result[0] = 0;
1343 base::snprintf(&expected_result[0],
1344 sizeof(expected_result),
1345 "\n" // texts in the <input> element
1346 "%d,%s\n" // texts in the first <div> element
1347 "%d,%s\n" // texts in the second <div> element
1348 "%d,%s", // texts in the third <div> element
1349 key_code, kModifierData[j].expected_result,
1350 static_cast<int>(char_code[0]),
1351 kModifierData[j].expected_result,
1352 key_code, kModifierData[j].expected_result);
1354 // Retrieve the text in the test page and compare it with the expected
1355 // text created from a virtual-key code, a character code, and the
1356 // modifier-key status.
1357 const int kMaxOutputCharacters = 1024;
1358 std::string output = base::UTF16ToUTF8(
1359 GetMainFrame()->contentAsText(kMaxOutputCharacters));
1360 EXPECT_EQ(expected_result, output);
1364 #else
1365 NOTIMPLEMENTED();
1366 #endif
1369 // Test that our EditorClientImpl class can insert characters when we send
1370 // keyboard events through the RenderWidget::OnHandleInputEvent() function.
1371 // This test is for preventing regressions caused only when we use non-US
1372 // keyboards, such as Issue 10846.
1373 // see http://crbug.com/244562
1374 #if defined(OS_WIN)
1375 #define MAYBE_InsertCharacters DISABLED_InsertCharacters
1376 #else
1377 #define MAYBE_InsertCharacters InsertCharacters
1378 #endif
1379 TEST_F(RenderViewImplTest, MAYBE_InsertCharacters) {
1380 #if !defined(OS_MACOSX)
1381 static const struct {
1382 MockKeyboard::Layout layout;
1383 const wchar_t* expected_result;
1384 } kLayouts[] = {
1385 #if 0
1386 // Disabled these keyboard layouts because buildbots do not have their
1387 // keyboard-layout drivers installed.
1388 {MockKeyboard::LAYOUT_ARABIC,
1389 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1390 L"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
1391 L"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
1392 L"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
1393 L"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
1394 L"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
1395 L"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
1396 L"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
1397 L"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
1398 L"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
1399 L"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
1400 L"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
1401 L"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
1402 L"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
1403 L"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
1404 L"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
1405 L"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
1407 {MockKeyboard::LAYOUT_HEBREW,
1408 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1409 L"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
1410 L"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
1411 L"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
1412 L"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
1413 L"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
1414 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1415 L"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1416 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1417 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1418 L"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
1419 L"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
1420 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1421 L"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
1422 L"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
1423 L"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
1424 L"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
1425 L"\x003b\x005d\x005c\x005b\x002c"
1427 #endif
1428 #if defined(OS_WIN)
1429 // On Linux, the only way to test alternate keyboard layouts is to change
1430 // the keyboard layout of the whole screen. I'm worried about the side
1431 // effects this may have on the buildbots.
1432 {MockKeyboard::LAYOUT_CANADIAN_FRENCH,
1433 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1434 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1435 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1436 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1437 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1438 L"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
1439 L"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
1440 L"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
1441 L"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
1442 L"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
1443 L"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
1444 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1445 L"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
1446 L"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
1447 L"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
1448 L"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
1449 L"\x003c"
1451 {MockKeyboard::LAYOUT_FRENCH,
1452 L"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
1453 L"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
1454 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1455 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1456 L"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
1457 L"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
1458 L"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
1459 L"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
1460 L"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
1461 L"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
1462 L"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
1463 L"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
1464 L"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
1465 L"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
1466 L"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
1467 L"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
1468 L"\x003b\x003a\x00f9\x0029\x002a\x0021"
1470 {MockKeyboard::LAYOUT_RUSSIAN,
1471 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1472 L"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
1473 L"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
1474 L"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
1475 L"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
1476 L"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
1477 L"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
1478 L"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
1479 L"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
1480 L"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
1481 L"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
1482 L"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
1483 L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
1484 L"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
1485 L"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
1486 L"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
1487 L"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
1488 L"\x0451\x0445\x005c\x044a\x044d"
1490 #endif // defined(OS_WIN)
1491 {MockKeyboard::LAYOUT_UNITED_STATES,
1492 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1493 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1494 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1495 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1496 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1497 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
1498 L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
1499 L"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
1500 L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
1501 L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
1502 L"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
1503 L"\x003f\x007e\x007b\x007c\x007d\x0022"
1504 #if defined(OS_WIN)
1505 // This is ifdefed out for Linux to correspond to the fact that we don't
1506 // test alt+keystroke for now.
1507 L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
1508 L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
1509 L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
1510 L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
1511 L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
1512 L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027"
1513 #endif
1517 for (size_t i = 0; i < arraysize(kLayouts); ++i) {
1518 // Load an HTML page consisting of one <div> element.
1519 // This <div> element is used by the EditorClientImpl class to insert
1520 // characters received through the RenderWidget::OnHandleInputEvent()
1521 // function.
1522 view()->set_send_content_state_immediately(true);
1523 LoadHTML("<html>"
1524 "<head>"
1525 "<title></title>"
1526 "</head>"
1527 "<body>"
1528 "<div id='test' contenteditable='true'>"
1529 "</div>"
1530 "</body>"
1531 "</html>");
1532 ExecuteJavaScript("document.getElementById('test').focus();");
1533 render_thread_->sink().ClearMessages();
1535 // For each key code, we send three keyboard events.
1536 // * Pressing only the key;
1537 // * Pressing the key and a left-shift key, and;
1538 // * Pressing the key and a right-alt (AltGr) key.
1539 static const MockKeyboard::Modifiers kModifiers[] = {
1540 MockKeyboard::NONE,
1541 MockKeyboard::LEFT_SHIFT,
1542 #if defined(OS_WIN)
1543 MockKeyboard::RIGHT_ALT,
1544 #endif
1547 MockKeyboard::Layout layout = kLayouts[i].layout;
1548 for (size_t j = 0; j < arraysize(kModifiers); ++j) {
1549 // Virtual key codes used for this test.
1550 static const int kKeyCodes[] = {
1551 '0', '1', '2', '3', '4', '5', '6', '7',
1552 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
1553 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1554 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
1555 'W', 'X', 'Y', 'Z',
1556 ui::VKEY_OEM_1,
1557 ui::VKEY_OEM_PLUS,
1558 ui::VKEY_OEM_COMMA,
1559 ui::VKEY_OEM_MINUS,
1560 ui::VKEY_OEM_PERIOD,
1561 ui::VKEY_OEM_2,
1562 ui::VKEY_OEM_3,
1563 ui::VKEY_OEM_4,
1564 ui::VKEY_OEM_5,
1565 ui::VKEY_OEM_6,
1566 ui::VKEY_OEM_7,
1567 #if defined(OS_WIN)
1568 // Unclear how to handle this on Linux.
1569 ui::VKEY_OEM_8,
1570 #endif
1573 MockKeyboard::Modifiers modifiers = kModifiers[j];
1574 for (size_t k = 0; k < arraysize(kKeyCodes); ++k) {
1575 // Send a keyboard event to the RenderView object.
1576 // We should test a keyboard event only when the given keyboard-layout
1577 // driver is installed in a PC and the driver can assign a Unicode
1578 // charcter for the given tuple (layout, key-code, and modifiers).
1579 int key_code = kKeyCodes[k];
1580 base::string16 char_code;
1581 if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
1582 continue;
1586 // Retrieve the text in the test page and compare it with the expected
1587 // text created from a virtual-key code, a character code, and the
1588 // modifier-key status.
1589 const int kMaxOutputCharacters = 4096;
1590 base::string16 output = GetMainFrame()->contentAsText(kMaxOutputCharacters);
1591 EXPECT_EQ(base::WideToUTF16(kLayouts[i].expected_result), output);
1593 #else
1594 NOTIMPLEMENTED();
1595 #endif
1598 // Crashy, http://crbug.com/53247.
1599 TEST_F(RenderViewImplTest, DISABLED_DidFailProvisionalLoadWithErrorForError) {
1600 GetMainFrame()->enableViewSourceMode(true);
1601 WebURLError error;
1602 error.domain = WebString::fromUTF8(net::kErrorDomain);
1603 error.reason = net::ERR_FILE_NOT_FOUND;
1604 error.unreachableURL = GURL("http://foo");
1605 WebLocalFrame* web_frame = GetMainFrame();
1607 // Start a load that will reach provisional state synchronously,
1608 // but won't complete synchronously.
1609 FrameMsg_Navigate_Params params;
1610 params.page_id = -1;
1611 params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1612 params.common_params.url = GURL("data:text/html,test data");
1613 params.commit_params.browser_navigation_start =
1614 base::TimeTicks::FromInternalValue(1);
1615 frame()->OnNavigate(params);
1617 // An error occurred.
1618 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame, error);
1619 // Frame should exit view-source mode.
1620 EXPECT_FALSE(web_frame->isViewSourceModeEnabled());
1623 TEST_F(RenderViewImplTest, DidFailProvisionalLoadWithErrorForCancellation) {
1624 GetMainFrame()->enableViewSourceMode(true);
1625 WebURLError error;
1626 error.domain = WebString::fromUTF8(net::kErrorDomain);
1627 error.reason = net::ERR_ABORTED;
1628 error.unreachableURL = GURL("http://foo");
1629 WebLocalFrame* web_frame = GetMainFrame();
1631 // Start a load that will reach provisional state synchronously,
1632 // but won't complete synchronously.
1633 FrameMsg_Navigate_Params params;
1634 params.page_id = -1;
1635 params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
1636 params.common_params.url = GURL("data:text/html,test data");
1637 params.commit_params.browser_navigation_start =
1638 base::TimeTicks::FromInternalValue(1);
1639 frame()->OnNavigate(params);
1641 // A cancellation occurred.
1642 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame, error);
1643 // Frame should stay in view-source mode.
1644 EXPECT_TRUE(web_frame->isViewSourceModeEnabled());
1647 // Regression test for http://crbug.com/41562
1648 TEST_F(RenderViewImplTest, UpdateTargetURLWithInvalidURL) {
1649 const GURL invalid_gurl("http://");
1650 view()->setMouseOverURL(blink::WebURL(invalid_gurl));
1651 EXPECT_EQ(invalid_gurl, view()->target_url_);
1654 TEST_F(RenderViewImplTest, SetHistoryLengthAndPrune) {
1655 int expected_page_id = -1;
1657 // No history to merge and no committed pages.
1658 view()->OnSetHistoryLengthAndPrune(0, -1);
1659 EXPECT_EQ(0, view()->history_list_length_);
1660 EXPECT_EQ(-1, view()->history_list_offset_);
1662 // History to merge and no committed pages.
1663 view()->OnSetHistoryLengthAndPrune(2, -1);
1664 EXPECT_EQ(2, view()->history_list_length_);
1665 EXPECT_EQ(1, view()->history_list_offset_);
1666 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1667 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1668 ClearHistory();
1670 blink::WebHistoryItem item;
1671 item.initialize();
1673 // No history to merge and a committed page to be kept.
1674 frame()->didCommitProvisionalLoad(GetMainFrame(),
1675 item,
1676 blink::WebStandardCommit);
1677 expected_page_id = view()->page_id_;
1678 view()->OnSetHistoryLengthAndPrune(0, expected_page_id);
1679 EXPECT_EQ(1, view()->history_list_length_);
1680 EXPECT_EQ(0, view()->history_list_offset_);
1681 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1682 ClearHistory();
1684 // No history to merge and a committed page to be pruned.
1685 frame()->didCommitProvisionalLoad(GetMainFrame(),
1686 item,
1687 blink::WebStandardCommit);
1688 expected_page_id = view()->page_id_;
1689 view()->OnSetHistoryLengthAndPrune(0, expected_page_id + 1);
1690 EXPECT_EQ(0, view()->history_list_length_);
1691 EXPECT_EQ(-1, view()->history_list_offset_);
1692 ClearHistory();
1694 // No history to merge and a committed page that the browser was unaware of.
1695 frame()->didCommitProvisionalLoad(GetMainFrame(),
1696 item,
1697 blink::WebStandardCommit);
1698 expected_page_id = view()->page_id_;
1699 view()->OnSetHistoryLengthAndPrune(0, -1);
1700 EXPECT_EQ(1, view()->history_list_length_);
1701 EXPECT_EQ(0, view()->history_list_offset_);
1702 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1703 ClearHistory();
1705 // History to merge and a committed page to be kept.
1706 frame()->didCommitProvisionalLoad(GetMainFrame(),
1707 item,
1708 blink::WebStandardCommit);
1709 expected_page_id = view()->page_id_;
1710 view()->OnSetHistoryLengthAndPrune(2, expected_page_id);
1711 EXPECT_EQ(3, view()->history_list_length_);
1712 EXPECT_EQ(2, view()->history_list_offset_);
1713 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1714 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1715 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1716 ClearHistory();
1718 // History to merge and a committed page to be pruned.
1719 frame()->didCommitProvisionalLoad(GetMainFrame(),
1720 item,
1721 blink::WebStandardCommit);
1722 expected_page_id = view()->page_id_;
1723 view()->OnSetHistoryLengthAndPrune(2, expected_page_id + 1);
1724 EXPECT_EQ(2, view()->history_list_length_);
1725 EXPECT_EQ(1, view()->history_list_offset_);
1726 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1727 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1728 ClearHistory();
1730 // History to merge and a committed page that the browser was unaware of.
1731 frame()->didCommitProvisionalLoad(GetMainFrame(),
1732 item,
1733 blink::WebStandardCommit);
1734 expected_page_id = view()->page_id_;
1735 view()->OnSetHistoryLengthAndPrune(2, -1);
1736 EXPECT_EQ(3, view()->history_list_length_);
1737 EXPECT_EQ(2, view()->history_list_offset_);
1738 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1739 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1740 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1741 ClearHistory();
1743 int expected_page_id_2 = -1;
1745 // No history to merge and two committed pages, both to be kept.
1746 frame()->didCommitProvisionalLoad(GetMainFrame(),
1747 item,
1748 blink::WebStandardCommit);
1749 expected_page_id = view()->page_id_;
1750 frame()->didCommitProvisionalLoad(GetMainFrame(),
1751 item,
1752 blink::WebStandardCommit);
1753 expected_page_id_2 = view()->page_id_;
1754 EXPECT_GT(expected_page_id_2, expected_page_id);
1755 view()->OnSetHistoryLengthAndPrune(0, expected_page_id);
1756 EXPECT_EQ(2, view()->history_list_length_);
1757 EXPECT_EQ(1, view()->history_list_offset_);
1758 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1759 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[1]);
1760 ClearHistory();
1762 // No history to merge and two committed pages, and only the second is kept.
1763 frame()->didCommitProvisionalLoad(GetMainFrame(),
1764 item,
1765 blink::WebStandardCommit);
1766 expected_page_id = view()->page_id_;
1767 frame()->didCommitProvisionalLoad(GetMainFrame(),
1768 item,
1769 blink::WebStandardCommit);
1770 expected_page_id_2 = view()->page_id_;
1771 EXPECT_GT(expected_page_id_2, expected_page_id);
1772 view()->OnSetHistoryLengthAndPrune(0, expected_page_id_2);
1773 EXPECT_EQ(1, view()->history_list_length_);
1774 EXPECT_EQ(0, view()->history_list_offset_);
1775 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[0]);
1776 ClearHistory();
1778 // No history to merge and two committed pages, both of which the browser was
1779 // unaware of.
1780 frame()->didCommitProvisionalLoad(GetMainFrame(),
1781 item,
1782 blink::WebStandardCommit);
1783 expected_page_id = view()->page_id_;
1784 frame()->didCommitProvisionalLoad(GetMainFrame(),
1785 item,
1786 blink::WebStandardCommit);
1787 expected_page_id_2 = view()->page_id_;
1788 EXPECT_GT(expected_page_id_2, expected_page_id);
1789 view()->OnSetHistoryLengthAndPrune(0, -1);
1790 EXPECT_EQ(2, view()->history_list_length_);
1791 EXPECT_EQ(1, view()->history_list_offset_);
1792 EXPECT_EQ(expected_page_id, view()->history_page_ids_[0]);
1793 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[1]);
1794 ClearHistory();
1796 // History to merge and two committed pages, both to be kept.
1797 frame()->didCommitProvisionalLoad(GetMainFrame(),
1798 item,
1799 blink::WebStandardCommit);
1800 expected_page_id = view()->page_id_;
1801 frame()->didCommitProvisionalLoad(GetMainFrame(),
1802 item,
1803 blink::WebStandardCommit);
1804 expected_page_id_2 = view()->page_id_;
1805 EXPECT_GT(expected_page_id_2, expected_page_id);
1806 view()->OnSetHistoryLengthAndPrune(2, expected_page_id);
1807 EXPECT_EQ(4, view()->history_list_length_);
1808 EXPECT_EQ(3, view()->history_list_offset_);
1809 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1810 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1811 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1812 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[3]);
1813 ClearHistory();
1815 // History to merge and two committed pages, and only the second is kept.
1816 frame()->didCommitProvisionalLoad(GetMainFrame(),
1817 item,
1818 blink::WebStandardCommit);
1819 expected_page_id = view()->page_id_;
1820 frame()->didCommitProvisionalLoad(GetMainFrame(),
1821 item,
1822 blink::WebStandardCommit);
1823 expected_page_id_2 = view()->page_id_;
1824 EXPECT_GT(expected_page_id_2, expected_page_id);
1825 view()->OnSetHistoryLengthAndPrune(2, expected_page_id_2);
1826 EXPECT_EQ(3, view()->history_list_length_);
1827 EXPECT_EQ(2, view()->history_list_offset_);
1828 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1829 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1830 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[2]);
1831 ClearHistory();
1833 // History to merge and two committed pages, both of which the browser was
1834 // unaware of.
1835 frame()->didCommitProvisionalLoad(GetMainFrame(),
1836 item,
1837 blink::WebStandardCommit);
1838 expected_page_id = view()->page_id_;
1839 frame()->didCommitProvisionalLoad(GetMainFrame(),
1840 item,
1841 blink::WebStandardCommit);
1842 expected_page_id_2 = view()->page_id_;
1843 EXPECT_GT(expected_page_id_2, expected_page_id);
1844 view()->OnSetHistoryLengthAndPrune(2, -1);
1845 EXPECT_EQ(4, view()->history_list_length_);
1846 EXPECT_EQ(3, view()->history_list_offset_);
1847 EXPECT_EQ(-1, view()->history_page_ids_[0]);
1848 EXPECT_EQ(-1, view()->history_page_ids_[1]);
1849 EXPECT_EQ(expected_page_id, view()->history_page_ids_[2]);
1850 EXPECT_EQ(expected_page_id_2, view()->history_page_ids_[3]);
1853 TEST_F(RenderViewImplTest, ContextMenu) {
1854 LoadHTML("<div>Page A</div>");
1856 // Create a right click in the center of the iframe. (I'm hoping this will
1857 // make this a bit more robust in case of some other formatting or other bug.)
1858 WebMouseEvent mouse_event;
1859 mouse_event.type = WebInputEvent::MouseDown;
1860 mouse_event.button = WebMouseEvent::ButtonRight;
1861 mouse_event.x = 250;
1862 mouse_event.y = 250;
1863 mouse_event.globalX = 250;
1864 mouse_event.globalY = 250;
1866 SendWebMouseEvent(mouse_event);
1868 // Now simulate the corresponding up event which should display the menu
1869 mouse_event.type = WebInputEvent::MouseUp;
1870 SendWebMouseEvent(mouse_event);
1872 EXPECT_TRUE(render_thread_->sink().GetUniqueMessageMatching(
1873 FrameHostMsg_ContextMenu::ID));
1876 TEST_F(RenderViewImplTest, TestBackForward) {
1877 LoadHTML("<div id=pagename>Page A</div>");
1878 PageState page_a_state =
1879 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1880 int was_page_a = -1;
1881 base::string16 check_page_a =
1882 base::ASCIIToUTF16(
1883 "Number(document.getElementById('pagename').innerHTML == 'Page A')");
1884 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1885 EXPECT_EQ(1, was_page_a);
1887 LoadHTML("<div id=pagename>Page B</div>");
1888 int was_page_b = -1;
1889 base::string16 check_page_b =
1890 base::ASCIIToUTF16(
1891 "Number(document.getElementById('pagename').innerHTML == 'Page B')");
1892 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1893 EXPECT_EQ(1, was_page_b);
1895 PageState back_state =
1896 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1898 LoadHTML("<div id=pagename>Page C</div>");
1899 int was_page_c = -1;
1900 base::string16 check_page_c =
1901 base::ASCIIToUTF16(
1902 "Number(document.getElementById('pagename').innerHTML == 'Page C')");
1903 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1904 EXPECT_EQ(1, was_page_b);
1906 PageState forward_state =
1907 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1908 GoBack(back_state);
1909 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1910 EXPECT_EQ(1, was_page_b);
1912 PageState back_state2 =
1913 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1915 GoForward(forward_state);
1916 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_c, &was_page_c));
1917 EXPECT_EQ(1, was_page_c);
1919 GoBack(back_state2);
1920 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1921 EXPECT_EQ(1, was_page_b);
1923 forward_state =
1924 HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
1925 GoBack(page_a_state);
1926 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_a, &was_page_a));
1927 EXPECT_EQ(1, was_page_a);
1929 GoForward(forward_state);
1930 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(check_page_b, &was_page_b));
1931 EXPECT_EQ(1, was_page_b);
1934 #if defined(OS_MACOSX) || defined(USE_AURA)
1935 TEST_F(RenderViewImplTest, GetCompositionCharacterBoundsTest) {
1937 #if defined(OS_WIN)
1938 // http://crbug.com/304193
1939 if (base::win::GetVersion() < base::win::VERSION_VISTA)
1940 return;
1941 #endif
1943 LoadHTML("<textarea id=\"test\"></textarea>");
1944 ExecuteJavaScript("document.getElementById('test').focus();");
1946 const base::string16 empty_string;
1947 const std::vector<blink::WebCompositionUnderline> empty_underline;
1948 std::vector<gfx::Rect> bounds;
1949 view()->OnSetFocus(true);
1950 view()->OnSetInputMethodActive(true);
1952 // ASCII composition
1953 const base::string16 ascii_composition = base::UTF8ToUTF16("aiueo");
1954 view()->OnImeSetComposition(ascii_composition, empty_underline, 0, 0);
1955 view()->GetCompositionCharacterBounds(&bounds);
1956 ASSERT_EQ(ascii_composition.size(), bounds.size());
1957 for (size_t i = 0; i < bounds.size(); ++i)
1958 EXPECT_LT(0, bounds[i].width());
1959 view()->OnImeConfirmComposition(
1960 empty_string, gfx::Range::InvalidRange(), false);
1962 // Non surrogate pair unicode character.
1963 const base::string16 unicode_composition = base::UTF8ToUTF16(
1964 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
1965 view()->OnImeSetComposition(unicode_composition, empty_underline, 0, 0);
1966 view()->GetCompositionCharacterBounds(&bounds);
1967 ASSERT_EQ(unicode_composition.size(), bounds.size());
1968 for (size_t i = 0; i < bounds.size(); ++i)
1969 EXPECT_LT(0, bounds[i].width());
1970 view()->OnImeConfirmComposition(
1971 empty_string, gfx::Range::InvalidRange(), false);
1973 // Surrogate pair character.
1974 const base::string16 surrogate_pair_char =
1975 base::UTF8ToUTF16("\xF0\xA0\xAE\x9F");
1976 view()->OnImeSetComposition(surrogate_pair_char,
1977 empty_underline,
1980 view()->GetCompositionCharacterBounds(&bounds);
1981 ASSERT_EQ(surrogate_pair_char.size(), bounds.size());
1982 EXPECT_LT(0, bounds[0].width());
1983 EXPECT_EQ(0, bounds[1].width());
1984 view()->OnImeConfirmComposition(
1985 empty_string, gfx::Range::InvalidRange(), false);
1987 // Mixed string.
1988 const base::string16 surrogate_pair_mixed_composition =
1989 surrogate_pair_char + base::UTF8ToUTF16("\xE3\x81\x82") +
1990 surrogate_pair_char + base::UTF8ToUTF16("b") + surrogate_pair_char;
1991 const size_t utf16_length = 8UL;
1992 const bool is_surrogate_pair_empty_rect[8] = {
1993 false, true, false, false, true, false, false, true };
1994 view()->OnImeSetComposition(surrogate_pair_mixed_composition,
1995 empty_underline,
1998 view()->GetCompositionCharacterBounds(&bounds);
1999 ASSERT_EQ(utf16_length, bounds.size());
2000 for (size_t i = 0; i < utf16_length; ++i) {
2001 if (is_surrogate_pair_empty_rect[i]) {
2002 EXPECT_EQ(0, bounds[i].width());
2003 } else {
2004 EXPECT_LT(0, bounds[i].width());
2007 view()->OnImeConfirmComposition(
2008 empty_string, gfx::Range::InvalidRange(), false);
2010 #endif
2012 TEST_F(RenderViewImplTest, ZoomLimit) {
2013 const double kMinZoomLevel = ZoomFactorToZoomLevel(kMinimumZoomFactor);
2014 const double kMaxZoomLevel = ZoomFactorToZoomLevel(kMaximumZoomFactor);
2016 FrameMsg_Navigate_Params params;
2017 params.page_id = -1;
2018 params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2019 params.commit_params.browser_navigation_start =
2020 base::TimeTicks::FromInternalValue(1);
2022 // Verifies navigation to a URL with preset zoom level indeed sets the level.
2023 // Regression test for http://crbug.com/139559, where the level was not
2024 // properly set when it is out of the default zoom limits of WebView.
2025 params.common_params.url = GURL("data:text/html,min_zoomlimit_test");
2026 view()->OnSetZoomLevelForLoadingURL(params.common_params.url, kMinZoomLevel);
2027 frame()->OnNavigate(params);
2028 ProcessPendingMessages();
2029 EXPECT_DOUBLE_EQ(kMinZoomLevel, view()->GetWebView()->zoomLevel());
2031 // It should work even when the zoom limit is temporarily changed in the page.
2032 view()->GetWebView()->zoomLimitsChanged(ZoomFactorToZoomLevel(1.0),
2033 ZoomFactorToZoomLevel(1.0));
2034 params.common_params.url = GURL("data:text/html,max_zoomlimit_test");
2035 view()->OnSetZoomLevelForLoadingURL(params.common_params.url, kMaxZoomLevel);
2036 frame()->OnNavigate(params);
2037 ProcessPendingMessages();
2038 EXPECT_DOUBLE_EQ(kMaxZoomLevel, view()->GetWebView()->zoomLevel());
2041 TEST_F(RenderViewImplTest, SetEditableSelectionAndComposition) {
2042 // Load an HTML page consisting of an input field.
2043 LoadHTML("<html>"
2044 "<head>"
2045 "</head>"
2046 "<body>"
2047 "<input id=\"test1\" value=\"some test text hello\"></input>"
2048 "</body>"
2049 "</html>");
2050 ExecuteJavaScript("document.getElementById('test1').focus();");
2051 frame()->OnSetEditableSelectionOffsets(4, 8);
2052 const std::vector<blink::WebCompositionUnderline> empty_underline;
2053 frame()->OnSetCompositionFromExistingText(7, 10, empty_underline);
2054 blink::WebTextInputInfo info = view()->webview()->textInputInfo();
2055 EXPECT_EQ(4, info.selectionStart);
2056 EXPECT_EQ(8, info.selectionEnd);
2057 EXPECT_EQ(7, info.compositionStart);
2058 EXPECT_EQ(10, info.compositionEnd);
2059 frame()->OnUnselect();
2060 info = view()->webview()->textInputInfo();
2061 EXPECT_EQ(0, info.selectionStart);
2062 EXPECT_EQ(0, info.selectionEnd);
2066 TEST_F(RenderViewImplTest, OnExtendSelectionAndDelete) {
2067 // Load an HTML page consisting of an input field.
2068 LoadHTML("<html>"
2069 "<head>"
2070 "</head>"
2071 "<body>"
2072 "<input id=\"test1\" value=\"abcdefghijklmnopqrstuvwxyz\"></input>"
2073 "</body>"
2074 "</html>");
2075 ExecuteJavaScript("document.getElementById('test1').focus();");
2076 frame()->OnSetEditableSelectionOffsets(10, 10);
2077 frame()->OnExtendSelectionAndDelete(3, 4);
2078 blink::WebTextInputInfo info = view()->webview()->textInputInfo();
2079 EXPECT_EQ("abcdefgopqrstuvwxyz", info.value);
2080 EXPECT_EQ(7, info.selectionStart);
2081 EXPECT_EQ(7, info.selectionEnd);
2082 frame()->OnSetEditableSelectionOffsets(4, 8);
2083 frame()->OnExtendSelectionAndDelete(2, 5);
2084 info = view()->webview()->textInputInfo();
2085 EXPECT_EQ("abuvwxyz", info.value);
2086 EXPECT_EQ(2, info.selectionStart);
2087 EXPECT_EQ(2, info.selectionEnd);
2090 // Test that the navigating specific frames works correctly.
2091 TEST_F(RenderViewImplTest, NavigateFrame) {
2092 // Load page A.
2093 LoadHTML("hello <iframe srcdoc='fail' name='frame'></iframe>");
2095 // Navigate the frame only.
2096 FrameMsg_Navigate_Params nav_params;
2097 nav_params.common_params.url = GURL("data:text/html,world");
2098 nav_params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2099 nav_params.common_params.transition = ui::PAGE_TRANSITION_TYPED;
2100 nav_params.current_history_list_length = 1;
2101 nav_params.current_history_list_offset = 0;
2102 nav_params.pending_history_list_offset = 1;
2103 nav_params.page_id = -1;
2104 nav_params.frame_to_navigate = "frame";
2105 nav_params.commit_params.browser_navigation_start =
2106 base::TimeTicks::FromInternalValue(1);
2107 frame()->OnNavigate(nav_params);
2108 FrameLoadWaiter(
2109 RenderFrame::FromWebFrame(frame()->GetWebFrame()->firstChild())).Wait();
2111 // Copy the document content to std::wstring and compare with the
2112 // expected result.
2113 const int kMaxOutputCharacters = 256;
2114 std::string output = base::UTF16ToUTF8(
2115 GetMainFrame()->contentAsText(kMaxOutputCharacters));
2116 EXPECT_EQ(output, "hello \n\nworld");
2119 // This test ensures that a RenderFrame object is created for the top level
2120 // frame in the RenderView.
2121 TEST_F(RenderViewImplTest, BasicRenderFrame) {
2122 EXPECT_TRUE(view()->main_render_frame_.get());
2125 TEST_F(RenderViewImplTest, GetSSLStatusOfFrame) {
2126 LoadHTML("<!DOCTYPE html><html><body></body></html>");
2128 WebLocalFrame* frame = GetMainFrame();
2129 SSLStatus ssl_status = view()->GetSSLStatusOfFrame(frame);
2130 EXPECT_FALSE(net::IsCertStatusError(ssl_status.cert_status));
2132 const_cast<blink::WebURLResponse&>(frame->dataSource()->response()).
2133 setSecurityInfo(
2134 SerializeSecurityInfo(0, net::CERT_STATUS_ALL_ERRORS, 0, 0,
2135 SignedCertificateTimestampIDStatusList()));
2136 ssl_status = view()->GetSSLStatusOfFrame(frame);
2137 EXPECT_TRUE(net::IsCertStatusError(ssl_status.cert_status));
2140 TEST_F(RenderViewImplTest, MessageOrderInDidChangeSelection) {
2141 view()->OnSetInputMethodActive(true);
2142 view()->set_send_content_state_immediately(true);
2143 LoadHTML("<textarea id=\"test\"></textarea>");
2145 view()->handling_input_event_ = true;
2146 ExecuteJavaScript("document.getElementById('test').focus();");
2148 bool is_input_type_called = false;
2149 bool is_selection_called = false;
2150 size_t last_input_type = 0;
2151 size_t last_selection = 0;
2153 for (size_t i = 0; i < render_thread_->sink().message_count(); ++i) {
2154 const uint32 type = render_thread_->sink().GetMessageAt(i)->type();
2155 if (type == ViewHostMsg_TextInputTypeChanged::ID) {
2156 is_input_type_called = true;
2157 last_input_type = i;
2158 } else if (type == ViewHostMsg_SelectionChanged::ID) {
2159 is_selection_called = true;
2160 last_selection = i;
2164 EXPECT_TRUE(is_input_type_called);
2165 EXPECT_TRUE(is_selection_called);
2167 // InputTypeChange shold be called earlier than SelectionChanged.
2168 EXPECT_LT(last_input_type, last_selection);
2171 class SuppressErrorPageTest : public RenderViewTest {
2172 public:
2173 ContentRendererClient* CreateContentRendererClient() override {
2174 return new TestContentRendererClient;
2177 RenderViewImpl* view() {
2178 return static_cast<RenderViewImpl*>(view_);
2181 RenderFrameImpl* frame() {
2182 return static_cast<RenderFrameImpl*>(view()->GetMainRenderFrame());
2185 private:
2186 class TestContentRendererClient : public ContentRendererClient {
2187 public:
2188 bool ShouldSuppressErrorPage(RenderFrame* render_frame,
2189 const GURL& url) override {
2190 return url == GURL("http://example.com/suppress");
2193 void GetNavigationErrorStrings(content::RenderView* render_view,
2194 blink::WebFrame* frame,
2195 const blink::WebURLRequest& failed_request,
2196 const blink::WebURLError& error,
2197 std::string* error_html,
2198 base::string16* error_description) override {
2199 if (error_html)
2200 *error_html = "A suffusion of yellow.";
2205 #if defined(OS_ANDROID)
2206 // Crashing on Android: http://crbug.com/311341
2207 #define MAYBE_Suppresses DISABLED_Suppresses
2208 #else
2209 #define MAYBE_Suppresses Suppresses
2210 #endif
2212 TEST_F(SuppressErrorPageTest, MAYBE_Suppresses) {
2213 WebURLError error;
2214 error.domain = WebString::fromUTF8(net::kErrorDomain);
2215 error.reason = net::ERR_FILE_NOT_FOUND;
2216 error.unreachableURL = GURL("http://example.com/suppress");
2217 WebLocalFrame* web_frame = GetMainFrame();
2219 // Start a load that will reach provisional state synchronously,
2220 // but won't complete synchronously.
2221 FrameMsg_Navigate_Params params;
2222 params.page_id = -1;
2223 params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2224 params.common_params.url = GURL("data:text/html,test data");
2225 params.commit_params.browser_navigation_start =
2226 base::TimeTicks::FromInternalValue(1);
2227 frame()->OnNavigate(params);
2229 // An error occurred.
2230 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame, error);
2231 const int kMaxOutputCharacters = 22;
2232 EXPECT_EQ("",
2233 base::UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters)));
2236 #if defined(OS_ANDROID)
2237 // Crashing on Android: http://crbug.com/311341
2238 #define MAYBE_DoesNotSuppress DISABLED_DoesNotSuppress
2239 #else
2240 #define MAYBE_DoesNotSuppress DoesNotSuppress
2241 #endif
2243 TEST_F(SuppressErrorPageTest, MAYBE_DoesNotSuppress) {
2244 WebURLError error;
2245 error.domain = WebString::fromUTF8(net::kErrorDomain);
2246 error.reason = net::ERR_FILE_NOT_FOUND;
2247 error.unreachableURL = GURL("http://example.com/dont-suppress");
2248 WebLocalFrame* web_frame = GetMainFrame();
2250 // Start a load that will reach provisional state synchronously,
2251 // but won't complete synchronously.
2252 FrameMsg_Navigate_Params params;
2253 params.page_id = -1;
2254 params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
2255 params.common_params.url = GURL("data:text/html,test data");
2256 params.commit_params.browser_navigation_start =
2257 base::TimeTicks::FromInternalValue(1);
2258 frame()->OnNavigate(params);
2260 // An error occurred.
2261 view()->GetMainRenderFrame()->didFailProvisionalLoad(web_frame, error);
2262 // The error page itself is loaded asynchronously.
2263 FrameLoadWaiter(frame()).Wait();
2264 const int kMaxOutputCharacters = 22;
2265 EXPECT_EQ("A suffusion of yellow.",
2266 base::UTF16ToASCII(web_frame->contentAsText(kMaxOutputCharacters)));
2269 // Tests if IME API's candidatewindow* events sent from browser are handled
2270 // in renderer.
2271 TEST_F(RenderViewImplTest, SendCandidateWindowEvents) {
2272 // Sends an HTML with an <input> element and scripts to the renderer.
2273 // The script handles all 3 of candidatewindow* events for an
2274 // InputMethodContext object and once it received 'show', 'update', 'hide'
2275 // should appear in the result div.
2276 LoadHTML("<input id='test'>"
2277 "<div id='result'>Result: </div>"
2278 "<script>"
2279 "window.onload = function() {"
2280 " var result = document.getElementById('result');"
2281 " var test = document.getElementById('test');"
2282 " test.focus();"
2283 " var context = test.inputMethodContext;"
2284 " if (context) {"
2285 " context.oncandidatewindowshow = function() {"
2286 " result.innerText += 'show'; };"
2287 " context.oncandidatewindowupdate = function(){"
2288 " result.innerText += 'update'; };"
2289 " context.oncandidatewindowhide = function(){"
2290 " result.innerText += 'hide'; };"
2291 " }"
2292 "};"
2293 "</script>");
2295 // Fire candidatewindow events.
2296 view()->OnCandidateWindowShown();
2297 view()->OnCandidateWindowUpdated();
2298 view()->OnCandidateWindowHidden();
2300 // Retrieve the content and check if it is expected.
2301 const int kMaxOutputCharacters = 50;
2302 std::string output = base::UTF16ToUTF8(
2303 GetMainFrame()->contentAsText(kMaxOutputCharacters));
2304 EXPECT_EQ(output, "\nResult:showupdatehide");
2307 // Ensure the render view sends favicon url update events correctly.
2308 TEST_F(RenderViewImplTest, SendFaviconURLUpdateEvent) {
2309 // An event should be sent when a favicon url exists.
2310 LoadHTML("<html>"
2311 "<head>"
2312 "<link rel='icon' href='http://www.google.com/favicon.ico'>"
2313 "</head>"
2314 "</html>");
2315 EXPECT_TRUE(render_thread_->sink().GetFirstMessageMatching(
2316 ViewHostMsg_UpdateFaviconURL::ID));
2317 render_thread_->sink().ClearMessages();
2319 // An event should not be sent if no favicon url exists. This is an assumption
2320 // made by some of Chrome's favicon handling.
2321 LoadHTML("<html>"
2322 "<head>"
2323 "</head>"
2324 "</html>");
2325 EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching(
2326 ViewHostMsg_UpdateFaviconURL::ID));
2329 TEST_F(RenderViewImplTest, FocusElementCallsFocusedNodeChanged) {
2330 LoadHTML("<input id='test1' value='hello1'></input>"
2331 "<input id='test2' value='hello2'></input>");
2333 ExecuteJavaScript("document.getElementById('test1').focus();");
2334 const IPC::Message* msg1 = render_thread_->sink().GetFirstMessageMatching(
2335 ViewHostMsg_FocusedNodeChanged::ID);
2336 EXPECT_TRUE(msg1);
2338 ViewHostMsg_FocusedNodeChanged::Param params;
2339 ViewHostMsg_FocusedNodeChanged::Read(msg1, &params);
2340 EXPECT_TRUE(params.a);
2341 render_thread_->sink().ClearMessages();
2343 ExecuteJavaScript("document.getElementById('test2').focus();");
2344 const IPC::Message* msg2 = render_thread_->sink().GetFirstMessageMatching(
2345 ViewHostMsg_FocusedNodeChanged::ID);
2346 EXPECT_TRUE(msg2);
2347 ViewHostMsg_FocusedNodeChanged::Read(msg2, &params);
2348 EXPECT_TRUE(params.a);
2349 render_thread_->sink().ClearMessages();
2351 view()->webview()->clearFocusedElement();
2352 const IPC::Message* msg3 = render_thread_->sink().GetFirstMessageMatching(
2353 ViewHostMsg_FocusedNodeChanged::ID);
2354 EXPECT_TRUE(msg3);
2355 ViewHostMsg_FocusedNodeChanged::Read(msg3, &params);
2356 EXPECT_FALSE(params.a);
2357 render_thread_->sink().ClearMessages();
2360 TEST_F(RenderViewImplTest, ServiceWorkerNetworkProviderSetup) {
2361 ServiceWorkerNetworkProvider* provider = NULL;
2362 RequestExtraData* extra_data = NULL;
2364 // Make sure each new document has a new provider and
2365 // that the main request is tagged with the provider's id.
2366 LoadHTML("<b>A Document</b>");
2367 ASSERT_TRUE(GetMainFrame()->dataSource());
2368 provider = ServiceWorkerNetworkProvider::FromDocumentState(
2369 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2370 ASSERT_TRUE(provider);
2371 extra_data = static_cast<RequestExtraData*>(
2372 GetMainFrame()->dataSource()->request().extraData());
2373 ASSERT_TRUE(extra_data);
2374 EXPECT_EQ(extra_data->service_worker_provider_id(),
2375 provider->provider_id());
2376 int provider1_id = provider->provider_id();
2378 LoadHTML("<b>New Document B Goes Here</b>");
2379 ASSERT_TRUE(GetMainFrame()->dataSource());
2380 provider = ServiceWorkerNetworkProvider::FromDocumentState(
2381 DocumentState::FromDataSource(GetMainFrame()->dataSource()));
2382 ASSERT_TRUE(provider);
2383 EXPECT_NE(provider1_id, provider->provider_id());
2384 extra_data = static_cast<RequestExtraData*>(
2385 GetMainFrame()->dataSource()->request().extraData());
2386 ASSERT_TRUE(extra_data);
2387 EXPECT_EQ(extra_data->service_worker_provider_id(),
2388 provider->provider_id());
2390 // See that subresource requests are also tagged with the provider's id.
2391 EXPECT_EQ(frame(), RenderFrameImpl::FromWebFrame(GetMainFrame()));
2392 blink::WebURLRequest request(GURL("http://foo.com"));
2393 request.setRequestContext(blink::WebURLRequest::RequestContextSubresource);
2394 blink::WebURLResponse redirect_response;
2395 frame()->willSendRequest(GetMainFrame(), 0, request, redirect_response);
2396 extra_data = static_cast<RequestExtraData*>(request.extraData());
2397 ASSERT_TRUE(extra_data);
2398 EXPECT_EQ(extra_data->service_worker_provider_id(),
2399 provider->provider_id());
2402 TEST_F(RenderViewImplTest, OnSetAccessibilityMode) {
2403 ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
2404 ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2406 frame()->OnSetAccessibilityMode(AccessibilityModeTreeOnly);
2407 ASSERT_EQ(AccessibilityModeTreeOnly, frame()->accessibility_mode());
2408 ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2409 ASSERT_EQ(RendererAccessibilityTypeComplete,
2410 frame()->renderer_accessibility()->GetType());
2412 frame()->OnSetAccessibilityMode(AccessibilityModeOff);
2413 ASSERT_EQ(AccessibilityModeOff, frame()->accessibility_mode());
2414 ASSERT_EQ((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2416 frame()->OnSetAccessibilityMode(AccessibilityModeComplete);
2417 ASSERT_EQ(AccessibilityModeComplete, frame()->accessibility_mode());
2418 ASSERT_NE((RendererAccessibility*) NULL, frame()->renderer_accessibility());
2419 ASSERT_EQ(RendererAccessibilityTypeComplete,
2420 frame()->renderer_accessibility()->GetType());
2423 TEST_F(RenderViewImplTest, ScreenMetricsEmulation) {
2424 LoadHTML("<body style='min-height:1000px;'></body>");
2426 blink::WebDeviceEmulationParams params;
2427 base::string16 get_width = base::ASCIIToUTF16("Number(window.innerWidth)");
2428 base::string16 get_height = base::ASCIIToUTF16("Number(window.innerHeight)");
2429 int width, height;
2431 params.viewSize.width = 327;
2432 params.viewSize.height = 415;
2433 view()->EnableScreenMetricsEmulation(params);
2434 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width));
2435 EXPECT_EQ(params.viewSize.width, width);
2436 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height));
2437 EXPECT_EQ(params.viewSize.height, height);
2439 params.viewSize.width = 1005;
2440 params.viewSize.height = 1102;
2441 view()->EnableScreenMetricsEmulation(params);
2442 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_width, &width));
2443 EXPECT_EQ(params.viewSize.width, width);
2444 EXPECT_TRUE(ExecuteJavaScriptAndReturnIntValue(get_height, &height));
2445 EXPECT_EQ(params.viewSize.height, height);
2447 view()->DisableScreenMetricsEmulation();
2449 view()->EnableScreenMetricsEmulation(params);
2450 // Don't disable here to test that emulation is being shutdown properly.
2453 // Sanity checks for the Navigation Timing API |navigationStart| override. We
2454 // are asserting only most basic constraints, as TimeTicks (passed as the
2455 // override) are not comparable with the wall time (returned by the Blink API).
2456 TEST_F(RenderViewImplTest, NavigationStartOverride) {
2457 // Verify that a navigation that claims to have started at the earliest
2458 // possible TimeTicks is indeed reported as one that started before
2459 // OnNavigate() is called.
2460 base::Time before_navigation = base::Time::Now();
2461 FrameMsg_Navigate_Params early_nav_params;
2462 early_nav_params.common_params.url = GURL("data:text/html,<div>Page</div>");
2463 early_nav_params.common_params.navigation_type =
2464 FrameMsg_Navigate_Type::NORMAL;
2465 early_nav_params.common_params.transition = ui::PAGE_TRANSITION_TYPED;
2466 early_nav_params.page_id = -1;
2467 early_nav_params.request_params.is_post = true;
2468 early_nav_params.commit_params.browser_navigation_start =
2469 base::TimeTicks::FromInternalValue(1);
2471 frame()->OnNavigate(early_nav_params);
2472 ProcessPendingMessages();
2474 base::Time early_nav_reported_start =
2475 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2476 EXPECT_LT(early_nav_reported_start, before_navigation);
2478 // Verify that a navigation that claims to have started in the future - 42
2479 // days from now is *not* reported as one that starts in the future; as we
2480 // sanitize the override allowing a maximum of ::Now().
2481 FrameMsg_Navigate_Params late_nav_params;
2482 late_nav_params.common_params.url =
2483 GURL("data:text/html,<div>Another page</div>");
2484 late_nav_params.common_params.navigation_type =
2485 FrameMsg_Navigate_Type::NORMAL;
2486 late_nav_params.common_params.transition = ui::PAGE_TRANSITION_TYPED;
2487 late_nav_params.page_id = -1;
2488 late_nav_params.request_params.is_post = true;
2489 late_nav_params.commit_params.browser_navigation_start =
2490 base::TimeTicks::Now() + base::TimeDelta::FromDays(42);
2492 frame()->OnNavigate(late_nav_params);
2493 ProcessPendingMessages();
2494 base::Time after_navigation =
2495 base::Time::Now() + base::TimeDelta::FromDays(1);
2497 base::Time late_nav_reported_start =
2498 base::Time::FromDoubleT(GetMainFrame()->performance().navigationStart());
2499 EXPECT_LE(late_nav_reported_start, after_navigation);
2502 } // namespace content