OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/command_line.h" | 5 #include "base/command_line.h" |
6 #include "base/strings/string_number_conversions.h" | 6 #include "base/strings/string_number_conversions.h" |
7 #include "chrome/browser/renderer_context_menu/render_view_context_menu_browsert
est_util.h" | 7 #include "chrome/browser/renderer_context_menu/render_view_context_menu_browsert
est_util.h" |
8 #include "chrome/browser/ui/browser.h" | 8 #include "chrome/browser/ui/browser.h" |
9 #include "chrome/browser/ui/browser_window.h" | 9 #include "chrome/browser/ui/browser_window.h" |
10 #include "chrome/browser/ui/exclusive_access/fullscreen_controller_test.h" | 10 #include "chrome/browser/ui/exclusive_access/fullscreen_controller_test.h" |
11 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 11 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
12 #include "chrome/test/base/in_process_browser_test.h" | 12 #include "chrome/test/base/in_process_browser_test.h" |
13 #include "chrome/test/base/interactive_test_utils.h" | 13 #include "chrome/test/base/interactive_test_utils.h" |
14 #include "chrome/test/base/ui_test_utils.h" | 14 #include "chrome/test/base/ui_test_utils.h" |
15 #include "components/guest_view/browser/guest_view_manager_delegate.h" | 15 #include "components/guest_view/browser/guest_view_manager_delegate.h" |
16 #include "components/guest_view/browser/test_guest_view_manager.h" | 16 #include "components/guest_view/browser/test_guest_view_manager.h" |
17 #include "content/public/browser/navigation_handle.h" | 17 #include "content/public/browser/navigation_handle.h" |
18 #include "content/public/browser/render_frame_host.h" | 18 #include "content/public/browser/render_frame_host.h" |
19 #include "content/public/browser/render_widget_host.h" | 19 #include "content/public/browser/render_widget_host.h" |
20 #include "content/public/browser/render_widget_host_view.h" | 20 #include "content/public/browser/render_widget_host_view.h" |
21 #include "content/public/browser/web_contents.h" | 21 #include "content/public/browser/web_contents.h" |
22 #include "content/public/test/browser_test_utils.h" | 22 #include "content/public/test/browser_test_utils.h" |
23 #include "content/public/test/content_browser_test_utils.h" | 23 #include "content/public/test/content_browser_test_utils.h" |
24 #include "content/public/test/test_navigation_observer.h" | 24 #include "content/public/test/test_navigation_observer.h" |
25 #include "content/public/test/test_utils.h" | 25 #include "content/public/test/test_utils.h" |
26 #include "extensions/browser/api/extensions_api_client.h" | 26 #include "extensions/browser/api/extensions_api_client.h" |
27 #include "extensions/common/constants.h" | 27 #include "extensions/common/constants.h" |
28 #include "net/dns/mock_host_resolver.h" | 28 #include "net/dns/mock_host_resolver.h" |
29 #include "net/test/embedded_test_server/embedded_test_server.h" | 29 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 30 #include "ui/base/test/ui_controls.h" |
30 #include "ui/display/display.h" | 31 #include "ui/display/display.h" |
31 #include "ui/display/screen.h" | 32 #include "ui/display/screen.h" |
32 #include "url/gurl.h" | 33 #include "url/gurl.h" |
33 | 34 |
34 class SitePerProcessInteractiveBrowserTest : public InProcessBrowserTest { | 35 class SitePerProcessInteractiveBrowserTest : public InProcessBrowserTest { |
35 public: | 36 public: |
36 SitePerProcessInteractiveBrowserTest() {} | 37 SitePerProcessInteractiveBrowserTest() {} |
37 ~SitePerProcessInteractiveBrowserTest() override {} | 38 ~SitePerProcessInteractiveBrowserTest() override {} |
38 | 39 |
39 void SetUpCommandLine(base::CommandLine* command_line) override { | 40 void SetUpCommandLine(base::CommandLine* command_line) override { |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 EXPECT_EQ("\"child2-focused-input2\"", press_tab_and_wait_for_message(true)); | 274 EXPECT_EQ("\"child2-focused-input2\"", press_tab_and_wait_for_message(true)); |
274 EXPECT_EQ(child2, web_contents->GetFocusedFrame()); | 275 EXPECT_EQ(child2, web_contents->GetFocusedFrame()); |
275 EXPECT_EQ("\"child2-focused-input1\"", press_tab_and_wait_for_message(true)); | 276 EXPECT_EQ("\"child2-focused-input1\"", press_tab_and_wait_for_message(true)); |
276 EXPECT_EQ("\"child1-focused-input2\"", press_tab_and_wait_for_message(true)); | 277 EXPECT_EQ("\"child1-focused-input2\"", press_tab_and_wait_for_message(true)); |
277 EXPECT_EQ(child1, web_contents->GetFocusedFrame()); | 278 EXPECT_EQ(child1, web_contents->GetFocusedFrame()); |
278 EXPECT_EQ("\"child1-focused-input1\"", press_tab_and_wait_for_message(true)); | 279 EXPECT_EQ("\"child1-focused-input1\"", press_tab_and_wait_for_message(true)); |
279 EXPECT_EQ("\"root-focused-input1\"", press_tab_and_wait_for_message(true)); | 280 EXPECT_EQ("\"root-focused-input1\"", press_tab_and_wait_for_message(true)); |
280 EXPECT_EQ(main_frame, web_contents->GetFocusedFrame()); | 281 EXPECT_EQ(main_frame, web_contents->GetFocusedFrame()); |
281 } | 282 } |
282 | 283 |
| 284 // TODO(https://crbug.com/702330): Enable this test. |
| 285 // Ensures that renderers know to advance focus to sibling frames and parent |
| 286 // frames in the presence of mouse click initiated focus changes. |
| 287 IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, |
| 288 DISABLED_TabAndMouseFocusNavigation) { |
| 289 GURL main_url(embedded_test_server()->GetURL( |
| 290 "a.com", "/cross_site_iframe_factory.html?a(b,c)")); |
| 291 ui_test_utils::NavigateToURL(browser(), main_url); |
| 292 |
| 293 content::WebContents* web_contents = |
| 294 browser()->tab_strip_model()->GetActiveWebContents(); |
| 295 |
| 296 content::RenderFrameHost* main_frame = web_contents->GetMainFrame(); |
| 297 content::RenderFrameHost* child1 = ChildFrameAt(main_frame, 0); |
| 298 ASSERT_NE(nullptr, child1); |
| 299 content::RenderFrameHost* child2 = ChildFrameAt(main_frame, 1); |
| 300 ASSERT_NE(nullptr, child2); |
| 301 |
| 302 // Assign a name to each frame. This will be sent along in test messages |
| 303 // from focus events. |
| 304 EXPECT_TRUE(ExecuteScript(main_frame, "window.name = 'root';")); |
| 305 EXPECT_TRUE(ExecuteScript(child1, "window.name = 'child1';")); |
| 306 EXPECT_TRUE(ExecuteScript(child2, "window.name = 'child2';")); |
| 307 |
| 308 // This script will insert two <input> fields in the document, one at the |
| 309 // beginning and one at the end. For root frame, this means that we will |
| 310 // have an <input>, then two <iframe> elements, then another <input>. |
| 311 // The script will send back the coordinates to click for each <input>, in the |
| 312 // document's space. Additionally, the outer frame will return the top left |
| 313 // point of each <iframe> to transform the coordinates of the inner <input> |
| 314 // elements. For example, main frame: 497,18;497,185:381,59;499,59 and each |
| 315 // iframe: 55,18;55,67 |
| 316 std::string script = |
| 317 "function onFocus(e) {" |
| 318 " console.log(window.name+'-focused-'+ e.target.id);" |
| 319 " domAutomationController.setAutomationId(0);" |
| 320 " domAutomationController.send(window.name + '-focused-' + e.target.id);" |
| 321 "}" |
| 322 "" |
| 323 "function getElementCoords(element) {" |
| 324 " var rect = element.getBoundingClientRect();" |
| 325 " return Math.floor(rect.left + 0.5 * rect.width) +','+" |
| 326 " Math.floor(rect.top + 0.5 * rect.height);" |
| 327 "}" |
| 328 "function getIframeCoords(element) {" |
| 329 " var rect = element.getBoundingClientRect();" |
| 330 " return Math.floor(rect.left) +','+" |
| 331 " Math.floor(rect.top);" |
| 332 "}" |
| 333 "" |
| 334 "document.styleSheets[0].insertRule('input {width:100%;margin:0;}', 1);" |
| 335 "document.styleSheets[0].insertRule('h2 {margin:0;}', 1);" |
| 336 "var input1 = document.createElement('input');" |
| 337 "input1.id = 'input1';" |
| 338 "input1.addEventListener('focus', onFocus, false);" |
| 339 "var input2 = document.createElement('input');" |
| 340 "input2.id = 'input2';" |
| 341 "input2.addEventListener('focus', onFocus, false);" |
| 342 "document.body.insertBefore(input1, document.body.firstChild);" |
| 343 "document.body.appendChild(input2);" |
| 344 "" |
| 345 "var frames = document.querySelectorAll('iframe');" |
| 346 "frames = Array.prototype.map.call(frames, getIframeCoords).join(';');" |
| 347 "var inputCoords = [input1, input2].map(getElementCoords).join(';');" |
| 348 "if (frames) {" |
| 349 " inputCoords = inputCoords + ':' + frames;" |
| 350 "}" |
| 351 "domAutomationController.send(inputCoords);"; |
| 352 |
| 353 auto parse_points = [](const std::string& input, const gfx::Point& offset) { |
| 354 base::StringPairs pieces; |
| 355 base::SplitStringIntoKeyValuePairs(input, ',', ';', &pieces); |
| 356 std::vector<gfx::Point> points; |
| 357 for (const auto& piece : pieces) { |
| 358 int x, y; |
| 359 EXPECT_TRUE(base::StringToInt(piece.first, &x)); |
| 360 EXPECT_TRUE(base::StringToInt(piece.second, &y)); |
| 361 points.push_back(gfx::Point(x + offset.x(), y + offset.y())); |
| 362 } |
| 363 return points; |
| 364 }; |
| 365 auto parse_points_and_offsets = [parse_points](const std::string& input) { |
| 366 auto pieces = base::SplitString(input, ":", base::TRIM_WHITESPACE, |
| 367 base::SPLIT_WANT_NONEMPTY); |
| 368 gfx::Point empty_offset; |
| 369 return make_pair(parse_points(pieces[0], empty_offset), |
| 370 parse_points(pieces[1], empty_offset)); |
| 371 }; |
| 372 |
| 373 // Add two input fields to each of the three frames and retrieve click |
| 374 // coordinates. |
| 375 std::string result; |
| 376 EXPECT_TRUE(ExecuteScriptAndExtractString(main_frame, script, &result)); |
| 377 auto parsed = parse_points_and_offsets(result); |
| 378 auto main_frame_input_coords = parsed.first; |
| 379 auto iframe1_offset = parsed.second[0]; |
| 380 auto iframe2_offset = parsed.second[1]; |
| 381 |
| 382 EXPECT_TRUE(ExecuteScriptAndExtractString(child1, script, &result)); |
| 383 auto child1_input_coords = parse_points(result, iframe1_offset); |
| 384 EXPECT_TRUE(ExecuteScriptAndExtractString(child2, script, &result)); |
| 385 auto child2_input_coords = parse_points(result, iframe2_offset); |
| 386 |
| 387 // Helper to simulate a tab press and wait for a focus message. |
| 388 auto press_tab_and_wait_for_message = [web_contents](bool reverse) { |
| 389 content::DOMMessageQueue msg_queue; |
| 390 std::string reply; |
| 391 SimulateKeyPress(web_contents, ui::DomKey::TAB, ui::DomCode::TAB, |
| 392 ui::VKEY_TAB, false, reverse /* shift */, false, false); |
| 393 EXPECT_TRUE(msg_queue.WaitForMessage(&reply)); |
| 394 return reply; |
| 395 }; |
| 396 |
| 397 auto click_element_and_wait_for_message = |
| 398 [web_contents](const gfx::Point& point) { |
| 399 content::DOMMessageQueue msg_queue; |
| 400 |
| 401 auto content_bounds = web_contents->GetContainerBounds(); |
| 402 ui_controls::SendMouseMove(point.x() + content_bounds.x(), |
| 403 point.y() + content_bounds.y()); |
| 404 ui_controls::SendMouseClick(ui_controls::LEFT); |
| 405 |
| 406 std::string reply; |
| 407 EXPECT_TRUE(msg_queue.WaitForMessage(&reply)); |
| 408 return reply; |
| 409 }; |
| 410 |
| 411 // Tab from child1 back to root. |
| 412 EXPECT_EQ("\"root-focused-input1\"", |
| 413 click_element_and_wait_for_message(main_frame_input_coords[0])); |
| 414 EXPECT_EQ(main_frame, web_contents->GetFocusedFrame()); |
| 415 EXPECT_EQ("\"child1-focused-input1\"", |
| 416 click_element_and_wait_for_message(child1_input_coords[0])); |
| 417 EXPECT_EQ(child1, web_contents->GetFocusedFrame()); |
| 418 EXPECT_EQ("\"root-focused-input1\"", press_tab_and_wait_for_message(true)); |
| 419 EXPECT_EQ(main_frame, web_contents->GetFocusedFrame()); |
| 420 |
| 421 // Tab from child2 forward to root. |
| 422 EXPECT_EQ("\"root-focused-input2\"", |
| 423 click_element_and_wait_for_message(main_frame_input_coords[1])); |
| 424 EXPECT_EQ(main_frame, web_contents->GetFocusedFrame()); |
| 425 EXPECT_EQ("\"child2-focused-input2\"", |
| 426 click_element_and_wait_for_message(child2_input_coords[1])); |
| 427 EXPECT_EQ(child2, web_contents->GetFocusedFrame()); |
| 428 EXPECT_EQ("\"root-focused-input2\"", press_tab_and_wait_for_message(false)); |
| 429 EXPECT_EQ(main_frame, web_contents->GetFocusedFrame()); |
| 430 |
| 431 // Tab forward from child1 to child2. |
| 432 EXPECT_EQ("\"child2-focused-input1\"", |
| 433 click_element_and_wait_for_message(child2_input_coords[0])); |
| 434 EXPECT_EQ(child2, web_contents->GetFocusedFrame()); |
| 435 EXPECT_EQ("\"child1-focused-input2\"", |
| 436 click_element_and_wait_for_message(child1_input_coords[1])); |
| 437 EXPECT_EQ(child1, web_contents->GetFocusedFrame()); |
| 438 EXPECT_EQ("\"child2-focused-input1\"", press_tab_and_wait_for_message(false)); |
| 439 EXPECT_EQ(child2, web_contents->GetFocusedFrame()); |
| 440 |
| 441 // Tab backward from child2 to child1. |
| 442 EXPECT_EQ("\"child1-focused-input2\"", |
| 443 click_element_and_wait_for_message(child1_input_coords[1])); |
| 444 EXPECT_EQ(child1, web_contents->GetFocusedFrame()); |
| 445 EXPECT_EQ("\"child2-focused-input1\"", |
| 446 click_element_and_wait_for_message(child2_input_coords[0])); |
| 447 EXPECT_EQ(child2, web_contents->GetFocusedFrame()); |
| 448 EXPECT_EQ("\"child1-focused-input2\"", press_tab_and_wait_for_message(true)); |
| 449 EXPECT_EQ(child1, web_contents->GetFocusedFrame()); |
| 450 |
| 451 // Ensure there are no pending focus events after tabbing. |
| 452 EXPECT_EQ("\"root-focused-input1\"", |
| 453 click_element_and_wait_for_message(main_frame_input_coords[0])) |
| 454 << "Unexpected extra focus events."; |
| 455 } |
| 456 |
283 namespace { | 457 namespace { |
284 | 458 |
285 // Helper to retrieve the frame's (window.innerWidth, window.innerHeight). | 459 // Helper to retrieve the frame's (window.innerWidth, window.innerHeight). |
286 gfx::Size GetFrameSize(content::RenderFrameHost* frame) { | 460 gfx::Size GetFrameSize(content::RenderFrameHost* frame) { |
287 int width = 0; | 461 int width = 0; |
288 EXPECT_TRUE(ExecuteScriptAndExtractInt( | 462 EXPECT_TRUE(ExecuteScriptAndExtractInt( |
289 frame, "domAutomationController.send(window.innerWidth);", &width)); | 463 frame, "domAutomationController.send(window.innerWidth);", &width)); |
290 | 464 |
291 int height = 0; | 465 int height = 0; |
292 EXPECT_TRUE(ExecuteScriptAndExtractInt( | 466 EXPECT_TRUE(ExecuteScriptAndExtractInt( |
(...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
917 send_right_mouse_event(child_view->GetRenderWidgetHost(), 10, 20, | 1091 send_right_mouse_event(child_view->GetRenderWidgetHost(), 10, 20, |
918 blink::WebInputEvent::MouseUp); | 1092 blink::WebInputEvent::MouseUp); |
919 menu_waiter.WaitForMenuOpenAndClose(); | 1093 menu_waiter.WaitForMenuOpenAndClose(); |
920 | 1094 |
921 gfx::Point point_in_root_window = | 1095 gfx::Point point_in_root_window = |
922 child_view->TransformPointToRootCoordSpace(gfx::Point(10, 20)); | 1096 child_view->TransformPointToRootCoordSpace(gfx::Point(10, 20)); |
923 | 1097 |
924 EXPECT_EQ(point_in_root_window.x(), menu_waiter.params().x); | 1098 EXPECT_EQ(point_in_root_window.x(), menu_waiter.params().x); |
925 EXPECT_EQ(point_in_root_window.y(), menu_waiter.params().y); | 1099 EXPECT_EQ(point_in_root_window.y(), menu_waiter.params().y); |
926 } | 1100 } |
OLD | NEW |