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