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