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