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