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