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