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