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