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