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