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