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