blob: 6f604ca7d3bfb98075e79675c53c82b1179d90c4 [file] [log] [blame]
[email protected]78089f02012-07-19 06:11:281// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/public/test/browser_test_utils.h"
6
avi652869c2015-12-25 01:48:457#include <stddef.h>
Lei Zhang6cef3262017-08-16 15:44:388
9#include <set>
tzik1068f1be2016-06-03 07:25:2010#include <tuple>
dchengf63a1252015-12-26 20:43:1311#include <utility>
avi652869c2015-12-25 01:48:4512
[email protected]e7e9c862014-08-21 22:00:3813#include "base/bind.h"
nickbfaea4ee2016-12-02 20:59:3114#include "base/bind_helpers.h"
[email protected]6dbb6992012-07-24 18:04:5415#include "base/command_line.h"
lukaszac7d6bd32017-07-11 00:19:3116#include "base/guid.h"
[email protected]7d478cb2012-07-24 17:19:4217#include "base/json/json_reader.h"
[email protected]c3c10f22013-07-25 14:21:1218#include "base/process/kill.h"
Ria Jiang79f58ed922018-04-10 03:30:5219#include "base/run_loop.h"
ahest29276c32017-01-19 07:36:3120#include "base/stl_util.h"
robc72f59f32016-10-14 09:35:1621#include "base/strings/pattern.h"
[email protected]26dd01c2013-06-12 13:52:1322#include "base/strings/string_number_conversions.h"
mgiuca77752c32015-02-05 07:31:1823#include "base/strings/string_piece.h"
lukaszac7d6bd32017-07-11 00:19:3124#include "base/strings/stringprintf.h"
[email protected]74ebfb12013-06-07 20:48:0025#include "base/strings/utf_string_conversions.h"
[email protected]88509ab2012-08-27 15:04:1426#include "base/synchronization/waitable_event.h"
Eric Seckler8652dcd52018-09-20 10:42:2827#include "base/task/post_task.h"
[email protected]6dbb6992012-07-24 18:04:5428#include "base/test/test_timeouts.h"
fdoray0c755de2016-10-19 15:28:4429#include "base/threading/thread_task_runner_handle.h"
[email protected]2e272852013-01-03 23:42:1130#include "base/values.h"
avi652869c2015-12-25 01:48:4531#include "build/build_config.h"
Fady Samueldea5e8f2017-07-19 21:41:3332#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
Fady Samuele4786072017-07-24 20:03:3833#include "components/viz/service/surfaces/surface.h"
34#include "components/viz/service/surfaces/surface_manager.h"
dmazzonifdfa2e02016-03-30 01:15:4335#include "content/browser/accessibility/browser_accessibility.h"
36#include "content/browser/accessibility/browser_accessibility_manager.h"
wjmacleanb65ea792016-07-07 22:17:0737#include "content/browser/browser_plugin/browser_plugin_guest.h"
Chris Blume12a26462018-04-22 02:00:1238#include "content/browser/browser_plugin/browser_plugin_message_filter.h"
wjmacleanb65ea792016-07-07 22:17:0739#include "content/browser/compositor/surface_utils.h"
Adithya Srinivasan0c72ff02018-08-13 19:47:2940#include "content/browser/fileapi/file_system_manager_impl.h"
wjmacleanb65ea792016-07-07 22:17:0741#include "content/browser/frame_host/cross_process_frame_connector.h"
alexmosaf3efeb2016-04-12 07:17:3942#include "content/browser/frame_host/frame_tree_node.h"
lfg1453e412017-04-11 00:48:5043#include "content/browser/frame_host/interstitial_page_impl.h"
alexmosaf3efeb2016-04-12 07:17:3944#include "content/browser/frame_host/render_frame_host_impl.h"
Xida Chen9658adb2018-08-17 18:38:3045#include "content/browser/frame_host/render_widget_host_view_guest.h"
Chris Blume12a26462018-04-22 02:00:1246#include "content/browser/renderer_host/render_process_host_impl.h"
[email protected]c8befac42014-05-22 15:13:2747#include "content/browser/renderer_host/render_widget_host_impl.h"
lfg1453e412017-04-11 00:48:5048#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
Ken Buchanandaef006b2017-08-17 18:32:1549#include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
Evan Stadef96e8132018-10-18 18:55:3850#include "content/browser/screen_orientation/screen_orientation_provider.h"
James Cook6929b872018-01-03 17:56:5651#include "content/browser/service_manager/service_manager_context.h"
nick7bb1c5c72014-12-24 01:37:1952#include "content/browser/web_contents/web_contents_impl.h"
[email protected]fc2b46b2014-05-03 16:33:4553#include "content/browser/web_contents/web_contents_view.h"
Chris Blume12a26462018-04-22 02:00:1254#include "content/common/browser_plugin/browser_plugin_messages.h"
nickbfaea4ee2016-12-02 20:59:3155#include "content/common/fileapi/webblob_messages.h"
lfg1453e412017-04-11 00:48:5056#include "content/common/frame_messages.h"
Fady Samuel799e72192018-04-25 21:16:5757#include "content/common/frame_visual_properties.h"
[email protected]c8befac42014-05-22 15:13:2758#include "content/common/input/synthetic_web_input_event_builders.h"
dtapuska0bd451a2016-02-18 17:08:1059#include "content/common/input_messages.h"
Albert J. Wong3c93c182018-09-27 17:29:4360#include "content/common/widget_messages.h"
[email protected]88509ab2012-08-27 15:04:1461#include "content/public/browser/browser_context.h"
dmazzoni5a0018c92016-07-18 21:45:3562#include "content/public/browser/browser_plugin_guest_manager.h"
Eric Seckler8652dcd52018-09-20 10:42:2863#include "content/public/browser/browser_task_traits.h"
dominicc4d8435d2016-07-22 03:43:3464#include "content/public/browser/browser_thread.h"
Bo Liu2a489402018-04-24 23:41:2765#include "content/public/browser/child_process_termination_info.h"
[email protected]e7e9c862014-08-21 22:00:3866#include "content/public/browser/histogram_fetcher.h"
lfg1453e412017-04-11 00:48:5067#include "content/public/browser/interstitial_page.h"
alexmos0785dd762014-11-13 19:59:3868#include "content/public/browser/navigation_entry.h"
csharrison4bd8a192016-08-02 18:03:1569#include "content/public/browser/navigation_handle.h"
70#include "content/public/browser/navigation_throttle.h"
Chong Zhangc40a6ce52017-12-10 03:00:2871#include "content/public/browser/network_service_instance.h"
[email protected]b5e34972012-09-26 03:50:2372#include "content/public/browser/notification_service.h"
[email protected]74ebfb12013-06-07 20:48:0073#include "content/public/browser/notification_types.h"
[email protected]ff4657ee2014-03-15 01:08:1574#include "content/public/browser/render_frame_host.h"
[email protected]e0f3e142012-07-26 03:31:3475#include "content/public/browser/render_process_host.h"
[email protected]26151fd2012-07-20 23:38:5776#include "content/public/browser/render_view_host.h"
jamb84299e2016-04-12 16:58:5977#include "content/public/browser/storage_partition.h"
[email protected]35daebe02012-07-20 05:40:5978#include "content/public/browser/web_contents.h"
Chong Zhangc40a6ce52017-12-10 03:00:2879#include "content/public/common/content_features.h"
John Abd-El-Malek7c5c7e4c2018-01-11 21:36:1680#include "content/public/common/content_switches.h"
Chong Zhangc40a6ce52017-12-10 03:00:2881#include "content/public/common/service_names.mojom.h"
Chris Blume12a26462018-04-22 02:00:1282#include "content/public/common/use_zoom_for_dsf_policy.h"
Chong Zhangc40a6ce52017-12-10 03:00:2883#include "content/public/test/simple_url_loader_test_helper.h"
nickbfaea4ee2016-12-02 20:59:3184#include "content/public/test/test_fileapi_operation_waiter.h"
Luciano Pacheco034fd9d2018-09-19 01:18:4085#include "content/public/test/test_launcher.h"
creis748a2c92015-12-15 18:09:3086#include "content/public/test/test_navigation_observer.h"
[email protected]35daebe02012-07-20 05:40:5987#include "content/public/test/test_utils.h"
dmazzoni25af8422016-06-28 20:29:5488#include "content/test/accessibility_browser_test_utils.h"
Charlie Reise2c2c492018-06-15 21:34:0489#include "content/test/did_commit_provisional_load_interceptor.h"
nickbfaea4ee2016-12-02 20:59:3190#include "ipc/ipc_security_test_util.h"
[email protected]d96cf752014-04-09 04:05:2891#include "net/base/filename_util.h"
Randy Smithe23356c22017-11-14 01:41:5092#include "net/base/io_buffer.h"
93#include "net/cookies/canonical_cookie.h"
dbeam49dab442016-08-20 00:49:5294#include "net/filter/gzip_header.h"
xunjieli6cc8b84b2016-11-08 15:23:3995#include "net/filter/gzip_source_stream.h"
96#include "net/filter/mock_source_stream.h"
naskob00afd82014-10-03 05:48:5997#include "net/test/embedded_test_server/embedded_test_server.h"
98#include "net/test/embedded_test_server/http_request.h"
99#include "net/test/embedded_test_server/http_response.h"
[email protected]6dbb6992012-07-24 18:04:54100#include "net/test/python_utils.h"
Chong Zhangc40a6ce52017-12-10 03:00:28101#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
102#include "net/url_request/url_request_context.h"
103#include "net/url_request/url_request_context_getter.h"
Yutaka Hiranod8789f92018-01-30 09:59:51104#include "services/network/public/cpp/features.h"
John Abd-El-Malekbdafede2018-02-06 15:10:36105#include "services/network/public/cpp/simple_url_loader.h"
Ken Rockot54311e62018-02-10 19:01:52106#include "services/network/public/mojom/cookie_manager.mojom.h"
107#include "services/network/public/mojom/network_service.mojom.h"
108#include "services/network/public/mojom/network_service_test.mojom.h"
Chong Zhangc40a6ce52017-12-10 03:00:28109#include "services/service_manager/public/cpp/connector.h"
nickbfaea4ee2016-12-02 20:59:31110#include "storage/browser/fileapi/file_system_context.h"
[email protected]35daebe02012-07-20 05:40:59111#include "testing/gtest/include/gtest/gtest.h"
Adithya Srinivasan0c72ff02018-08-13 19:47:29112#include "third_party/blink/public/mojom/filesystem/file_system.mojom.h"
dominicc4d8435d2016-07-22 03:43:34113#include "ui/base/clipboard/clipboard.h"
114#include "ui/base/clipboard/scoped_clipboard_writer.h"
[email protected]c2791c1a2013-08-22 07:18:35115#include "ui/base/resource/resource_bundle.h"
dominicc4d8435d2016-07-22 03:43:34116#include "ui/base/test/test_clipboard.h"
[email protected]6b6147472014-06-27 17:37:07117#include "ui/compositor/test/draw_waiter_for_test.h"
dtapuska899ac222017-01-03 18:09:16118#include "ui/events/base_event_utils.h"
lanweidb8214afd2014-10-27 17:58:42119#include "ui/events/gesture_detection/gesture_configuration.h"
kpschoedel103db442015-05-15 19:13:57120#include "ui/events/keycodes/dom/dom_code.h"
kpschoedel3b0960a2015-05-11 17:52:11121#include "ui/events/keycodes/dom/keycode_converter.h"
mfomitchev3ba450ad2017-04-03 18:20:40122#include "ui/latency/latency_info.h"
tfarina272c8d72014-09-07 05:48:46123#include "ui/resources/grit/webui_resources.h"
[email protected]35daebe02012-07-20 05:40:59124
[email protected]6b6147472014-06-27 17:37:07125#if defined(USE_AURA)
mcnee19fd2492017-06-01 14:42:43126#include "content/browser/renderer_host/overscroll_controller.h"
wjmacleane31234f2015-12-14 17:20:45127#include "content/browser/renderer_host/render_widget_host_view_aura.h"
[email protected]6b6147472014-06-27 17:37:07128#include "ui/aura/test/window_event_dispatcher_test_api.h"
129#include "ui/aura/window.h"
130#include "ui/aura/window_event_dispatcher.h"
131#include "ui/aura/window_tree_host.h"
wjmacleane31234f2015-12-14 17:20:45132#include "ui/events/event.h"
[email protected]6b6147472014-06-27 17:37:07133#endif // USE_AURA
134
[email protected]78089f02012-07-19 06:11:28135namespace content {
[email protected]7d478cb2012-07-24 17:19:42136namespace {
[email protected]26151fd2012-07-20 23:38:57137
meacerb47bc8782014-10-07 03:40:01138class InterstitialObserver : public content::WebContentsObserver {
139 public:
140 InterstitialObserver(content::WebContents* web_contents,
Wezf2311d72018-06-02 02:02:18141 base::OnceClosure attach_callback,
142 base::OnceClosure detach_callback)
meacerb47bc8782014-10-07 03:40:01143 : WebContentsObserver(web_contents),
Wezf2311d72018-06-02 02:02:18144 attach_callback_(std::move(attach_callback)),
145 detach_callback_(std::move(detach_callback)) {}
dchenge933b3e2014-10-21 11:44:09146 ~InterstitialObserver() override {}
meacerb47bc8782014-10-07 03:40:01147
148 // WebContentsObserver methods:
Wezf2311d72018-06-02 02:02:18149 void DidAttachInterstitialPage() override {
150 std::move(attach_callback_).Run();
151 }
152 void DidDetachInterstitialPage() override {
153 std::move(detach_callback_).Run();
154 }
meacerb47bc8782014-10-07 03:40:01155
156 private:
Wezf2311d72018-06-02 02:02:18157 base::OnceClosure attach_callback_;
158 base::OnceClosure detach_callback_;
meacerb47bc8782014-10-07 03:40:01159
160 DISALLOW_COPY_AND_ASSIGN(InterstitialObserver);
161};
162
[email protected]7d478cb2012-07-24 17:19:42163// Specifying a prototype so that we can add the WARN_UNUSED_RESULT attribute.
dcheng6003e0b2016-04-09 18:42:34164bool ExecuteScriptHelper(RenderFrameHost* render_frame_host,
Nick Carterb7e71312018-08-03 23:36:13165 const std::string& script,
vasiliib50cee4c92017-03-31 11:53:14166 bool user_gesture,
Nick Carterb7e71312018-08-03 23:36:13167 int world_id,
dcheng6003e0b2016-04-09 18:42:34168 std::unique_ptr<base::Value>* result)
169 WARN_UNUSED_RESULT;
[email protected]7d478cb2012-07-24 17:19:42170
lukaszafe9cc5e2017-07-19 20:18:41171// Executes the passed |script| in the frame specified by |render_frame_host|.
172// If |result| is not NULL, stores the value that the evaluation of the script
173// in |result|. Returns true on success.
[email protected]ff4657ee2014-03-15 01:08:15174bool ExecuteScriptHelper(RenderFrameHost* render_frame_host,
lukaszafe9cc5e2017-07-19 20:18:41175 const std::string& script,
vasiliib50cee4c92017-03-31 11:53:14176 bool user_gesture,
Nick Carterb7e71312018-08-03 23:36:13177 int world_id,
dcheng6003e0b2016-04-09 18:42:34178 std::unique_ptr<base::Value>* result) {
lukaszaf1cf6922016-11-03 00:21:43179 // TODO(lukasza): Only get messages from the specific |render_frame_host|.
180 DOMMessageQueue dom_message_queue(
181 WebContents::FromRenderFrameHost(render_frame_host));
Nick Carterb7e71312018-08-03 23:36:13182 base::string16 script16 = base::UTF8ToUTF16(script);
183 if (world_id == ISOLATED_WORLD_ID_GLOBAL) {
184 if (user_gesture)
185 render_frame_host->ExecuteJavaScriptWithUserGestureForTests(script16);
186 else
187 render_frame_host->ExecuteJavaScriptForTests(script16);
vasiliib50cee4c92017-03-31 11:53:14188 } else {
Nick Carterb7e71312018-08-03 23:36:13189 // Note that |user_gesture| here is ignored. We allow a value of |true|
190 // because it's the default, but in blink, the execution will occur with
191 // no user gesture.
192 render_frame_host->ExecuteJavaScriptInIsolatedWorld(
193 script16, RenderFrameHost::JavaScriptResultCallback(), world_id);
vasiliib50cee4c92017-03-31 11:53:14194 }
[email protected]ff4657ee2014-03-15 01:08:15195 std::string json;
lukaszaf1cf6922016-11-03 00:21:43196 if (!dom_message_queue.WaitForMessage(&json)) {
197 DLOG(ERROR) << "Cannot communicate with DOMMessageQueue.";
[email protected]ff4657ee2014-03-15 01:08:15198 return false;
199 }
200
201 // Nothing more to do for callers that ignore the returned JS value.
202 if (!result)
203 return true;
204
205 base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
estade69505de2015-05-20 22:46:58206 *result = reader.ReadToValue(json);
207 if (!*result) {
[email protected]ff4657ee2014-03-15 01:08:15208 DLOG(ERROR) << reader.GetErrorMessage();
209 return false;
210 }
211
212 return true;
213}
214
lukaszac7d6bd32017-07-11 00:19:31215bool ExecuteScriptWithUserGestureControl(RenderFrameHost* frame,
216 const std::string& script,
217 bool user_gesture) {
218 // TODO(lukasza): ExecuteScript should just call
219 // ExecuteJavaScriptWithUserGestureForTests and avoid modifying the original
220 // script (and at that point we should merge it with and remove
221 // ExecuteScriptAsync). This is difficult to change, because many tests
222 // depend on the message loop pumping done by ExecuteScriptHelper below (this
223 // is fragile - these tests should wait on a more specific thing instead).
224
Nick Carterb7e71312018-08-03 23:36:13225 // TODO(nick): This function can't be replaced with a call to ExecJs(), since
226 // ExecJs calls eval() which might be blocked by the page's CSP.
lukaszac7d6bd32017-07-11 00:19:31227 std::string expected_response = "ExecuteScript-" + base::GenerateGUID();
228 std::string new_script = base::StringPrintf(
229 R"( %s; // Original script.
230 window.domAutomationController.send('%s'); )",
231 script.c_str(), expected_response.c_str());
232
233 std::unique_ptr<base::Value> value;
Nick Carterb7e71312018-08-03 23:36:13234 if (!ExecuteScriptHelper(frame, new_script, user_gesture,
235 ISOLATED_WORLD_ID_GLOBAL, &value) ||
lukaszac7d6bd32017-07-11 00:19:31236 !value.get()) {
237 return false;
238 }
239
jdoerrie76cee9c2017-10-06 22:42:42240 DCHECK_EQ(base::Value::Type::STRING, value->type());
lukaszac7d6bd32017-07-11 00:19:31241 std::string actual_response;
242 if (value->GetAsString(&actual_response))
243 DCHECK_EQ(expected_response, actual_response);
244
245 return true;
246}
247
[email protected]180ef242013-11-07 06:50:46248void BuildSimpleWebKeyEvent(blink::WebInputEvent::Type type,
dtapuska8b1bdc82016-06-07 21:39:48249 ui::DomKey key,
250 ui::DomCode code,
[email protected]6dc5a332013-09-11 01:02:10251 ui::KeyboardCode key_code,
[email protected]26151fd2012-07-20 23:38:57252 NativeWebKeyboardEvent* event) {
Blink Reformat1c4d759e2017-04-09 16:34:54253 event->dom_key = key;
254 event->dom_code = static_cast<int>(code);
255 event->native_key_code = ui::KeycodeConverter::DomCodeToNativeKeycode(code);
256 event->windows_key_code = key_code;
257 event->is_system_key = false;
[email protected]26151fd2012-07-20 23:38:57258 event->skip_in_browser = true;
259
Blink Reformat1c4d759e2017-04-09 16:34:54260 if (type == blink::WebInputEvent::kChar ||
261 type == blink::WebInputEvent::kRawKeyDown) {
Vasilii Sukhanov886f65d2018-05-15 08:15:29262 // |key| is the only parameter that contains information about the case of
263 // the character. Use it to be able to generate lower case input.
264 if (key.IsCharacter()) {
265 event->text[0] = key.ToCharacter();
266 event->unmodified_text[0] = key.ToCharacter();
267 } else {
268 event->text[0] = key_code;
269 event->unmodified_text[0] = key_code;
270 }
[email protected]26151fd2012-07-20 23:38:57271 }
[email protected]ec8e05952013-09-19 21:45:40272}
[email protected]26151fd2012-07-20 23:38:57273
[email protected]ec8e05952013-09-19 21:45:40274void InjectRawKeyEvent(WebContents* web_contents,
[email protected]180ef242013-11-07 06:50:46275 blink::WebInputEvent::Type type,
dtapuska8b1bdc82016-06-07 21:39:48276 ui::DomKey key,
277 ui::DomCode code,
[email protected]ec8e05952013-09-19 21:45:40278 ui::KeyboardCode key_code,
[email protected]ec8e05952013-09-19 21:45:40279 int modifiers) {
dtapuska899ac222017-01-03 18:09:16280 NativeWebKeyboardEvent event(type, modifiers, base::TimeTicks::Now());
281 BuildSimpleWebKeyEvent(type, key, code, key_code, &event);
alexmosc4cbacb2015-11-21 01:29:22282 WebContentsImpl* web_contents_impl =
283 static_cast<WebContentsImpl*>(web_contents);
284 RenderWidgetHostImpl* main_frame_rwh =
285 web_contents_impl->GetMainFrame()->GetRenderWidgetHost();
286 web_contents_impl->GetFocusedRenderWidgetHost(main_frame_rwh)
alexmosc4d183e2015-11-06 00:46:52287 ->ForwardKeyboardEvent(event);
[email protected]26151fd2012-07-20 23:38:57288}
289
Lei Zhang6cef3262017-08-16 15:44:38290int SimulateModifierKeysDown(WebContents* web_contents,
291 bool control,
292 bool shift,
293 bool alt,
294 bool command) {
295 int modifiers = 0;
296
297 // The order of these key down events shouldn't matter for our simulation.
298 // For our simulation we can use either the left keys or the right keys.
299 if (control) {
300 modifiers |= blink::WebInputEvent::kControlKey;
301 InjectRawKeyEvent(web_contents, blink::WebInputEvent::kRawKeyDown,
302 ui::DomKey::CONTROL, ui::DomCode::CONTROL_LEFT,
303 ui::VKEY_CONTROL, modifiers);
304 }
305 if (shift) {
306 modifiers |= blink::WebInputEvent::kShiftKey;
307 InjectRawKeyEvent(web_contents, blink::WebInputEvent::kRawKeyDown,
308 ui::DomKey::SHIFT, ui::DomCode::SHIFT_LEFT,
309 ui::VKEY_SHIFT, modifiers);
310 }
311 if (alt) {
312 modifiers |= blink::WebInputEvent::kAltKey;
313 InjectRawKeyEvent(web_contents, blink::WebInputEvent::kRawKeyDown,
314 ui::DomKey::ALT, ui::DomCode::ALT_LEFT, ui::VKEY_MENU,
315 modifiers);
316 }
317 if (command) {
318 modifiers |= blink::WebInputEvent::kMetaKey;
319 InjectRawKeyEvent(web_contents, blink::WebInputEvent::kRawKeyDown,
320 ui::DomKey::META, ui::DomCode::META_LEFT,
321 ui::VKEY_COMMAND, modifiers);
322 }
323 return modifiers;
324}
325
326int SimulateModifierKeysUp(WebContents* web_contents,
327 bool control,
328 bool shift,
329 bool alt,
330 bool command,
331 int modifiers) {
332 // The order of these key releases shouldn't matter for our simulation.
333 if (control) {
334 modifiers &= ~blink::WebInputEvent::kControlKey;
335 InjectRawKeyEvent(web_contents, blink::WebInputEvent::kKeyUp,
336 ui::DomKey::CONTROL, ui::DomCode::CONTROL_LEFT,
337 ui::VKEY_CONTROL, modifiers);
338 }
339
340 if (shift) {
341 modifiers &= ~blink::WebInputEvent::kShiftKey;
342 InjectRawKeyEvent(web_contents, blink::WebInputEvent::kKeyUp,
343 ui::DomKey::SHIFT, ui::DomCode::SHIFT_LEFT,
344 ui::VKEY_SHIFT, modifiers);
345 }
346
347 if (alt) {
348 modifiers &= ~blink::WebInputEvent::kAltKey;
349 InjectRawKeyEvent(web_contents, blink::WebInputEvent::kKeyUp,
350 ui::DomKey::ALT, ui::DomCode::ALT_LEFT, ui::VKEY_MENU,
351 modifiers);
352 }
353
354 if (command) {
355 modifiers &= ~blink::WebInputEvent::kMetaKey;
356 InjectRawKeyEvent(web_contents, blink::WebInputEvent::kKeyUp,
357 ui::DomKey::META, ui::DomCode::META_LEFT,
358 ui::VKEY_COMMAND, modifiers);
359 }
360 return modifiers;
361}
362
363void SimulateKeyEvent(WebContents* web_contents,
364 ui::DomKey key,
365 ui::DomCode code,
366 ui::KeyboardCode key_code,
367 bool send_char,
368 int modifiers) {
369 InjectRawKeyEvent(web_contents, blink::WebInputEvent::kRawKeyDown, key, code,
370 key_code, modifiers);
371 if (send_char) {
372 InjectRawKeyEvent(web_contents, blink::WebInputEvent::kChar, key, code,
373 key_code, modifiers);
374 }
375 InjectRawKeyEvent(web_contents, blink::WebInputEvent::kKeyUp, key, code,
376 key_code, modifiers);
377}
378
379void SimulateKeyPressImpl(WebContents* web_contents,
380 ui::DomKey key,
381 ui::DomCode code,
382 ui::KeyboardCode key_code,
383 bool control,
384 bool shift,
385 bool alt,
386 bool command,
387 bool send_char) {
388 int modifiers =
389 SimulateModifierKeysDown(web_contents, control, shift, alt, command);
390 SimulateKeyEvent(web_contents, key, code, key_code, send_char, modifiers);
391 modifiers = SimulateModifierKeysUp(web_contents, control, shift, alt, command,
392 modifiers);
393 ASSERT_EQ(modifiers, 0);
394}
395
dcheng6003e0b2016-04-09 18:42:34396std::unique_ptr<net::test_server::HttpResponse>
martijn2037cd72016-11-10 20:11:32397CrossSiteRedirectResponseHandler(const net::EmbeddedTestServer* test_server,
dcheng6003e0b2016-04-09 18:42:34398 const net::test_server::HttpRequest& request) {
lukasza2ad8fef2016-05-24 23:00:43399 net::HttpStatusCode http_status_code;
naskob00afd82014-10-03 05:48:59400
lukasza2ad8fef2016-05-24 23:00:43401 // Inspect the prefix and extract the remainder of the url into |params|.
402 size_t length_of_chosen_prefix;
403 std::string prefix_302("/cross-site/");
404 std::string prefix_307("/cross-site-307/");
405 if (base::StartsWith(request.relative_url, prefix_302,
406 base::CompareCase::SENSITIVE)) {
407 http_status_code = net::HTTP_MOVED_PERMANENTLY;
408 length_of_chosen_prefix = prefix_302.length();
409 } else if (base::StartsWith(request.relative_url, prefix_307,
410 base::CompareCase::SENSITIVE)) {
411 http_status_code = net::HTTP_TEMPORARY_REDIRECT;
412 length_of_chosen_prefix = prefix_307.length();
413 } else {
414 // Unrecognized prefix - let somebody else handle this request.
415 return std::unique_ptr<net::test_server::HttpResponse>();
416 }
417 std::string params = request.relative_url.substr(length_of_chosen_prefix);
naskob00afd82014-10-03 05:48:59418
419 // A hostname to redirect to must be included in the URL, therefore at least
420 // one '/' character is expected.
421 size_t slash = params.find('/');
422 if (slash == std::string::npos)
dcheng6003e0b2016-04-09 18:42:34423 return std::unique_ptr<net::test_server::HttpResponse>();
naskob00afd82014-10-03 05:48:59424
425 // Replace the host of the URL with the one passed in the URL.
naskob00afd82014-10-03 05:48:59426 GURL::Replacements replace_host;
mgiuca77752c32015-02-05 07:31:18427 replace_host.SetHostStr(base::StringPiece(params).substr(0, slash));
martijn2037cd72016-11-10 20:11:32428 GURL redirect_server =
429 test_server->base_url().ReplaceComponents(replace_host);
naskob00afd82014-10-03 05:48:59430
431 // Append the real part of the path to the new URL.
432 std::string path = params.substr(slash + 1);
433 GURL redirect_target(redirect_server.Resolve(path));
434 DCHECK(redirect_target.is_valid());
435
dcheng6003e0b2016-04-09 18:42:34436 std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
naskob00afd82014-10-03 05:48:59437 new net::test_server::BasicHttpResponse);
lukasza2ad8fef2016-05-24 23:00:43438 http_response->set_code(http_status_code);
naskob00afd82014-10-03 05:48:59439 http_response->AddCustomHeader("Location", redirect_target.spec());
dchengf63a1252015-12-26 20:43:13440 return std::move(http_response);
naskob00afd82014-10-03 05:48:59441}
442
csharrison4bd8a192016-08-02 18:03:15443// Helper class used by the TestNavigationManager to pause navigations.
444// Note: the throttle should be added to the *end* of the list of throttles,
445// so all NavigationThrottles that should be attached observe the
446// WillStartRequest callback. RegisterThrottleForTesting has this behavior.
447class TestNavigationManagerThrottle : public NavigationThrottle {
448 public:
449 TestNavigationManagerThrottle(NavigationHandle* handle,
clamyd69748c2016-10-07 22:09:44450 base::Closure on_will_start_request_closure,
451 base::Closure on_will_process_response_closure)
csharrison4bd8a192016-08-02 18:03:15452 : NavigationThrottle(handle),
clamyd69748c2016-10-07 22:09:44453 on_will_start_request_closure_(on_will_start_request_closure),
454 on_will_process_response_closure_(on_will_process_response_closure) {}
csharrison4bd8a192016-08-02 18:03:15455 ~TestNavigationManagerThrottle() override {}
456
naskod8185572017-04-24 17:17:17457 const char* GetNameForLogging() override {
458 return "TestNavigationManagerThrottle";
459 }
460
csharrison4bd8a192016-08-02 18:03:15461 private:
462 // NavigationThrottle:
463 NavigationThrottle::ThrottleCheckResult WillStartRequest() override {
Eric Seckler8652dcd52018-09-20 10:42:28464 base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
465 on_will_start_request_closure_);
csharrison4bd8a192016-08-02 18:03:15466 return NavigationThrottle::DEFER;
467 }
468
clamyd69748c2016-10-07 22:09:44469 NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
Eric Seckler8652dcd52018-09-20 10:42:28470 base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
471 on_will_process_response_closure_);
clamyd69748c2016-10-07 22:09:44472 return NavigationThrottle::DEFER;
473 }
474
csharrison4bd8a192016-08-02 18:03:15475 base::Closure on_will_start_request_closure_;
clamyd69748c2016-10-07 22:09:44476 base::Closure on_will_process_response_closure_;
csharrison4bd8a192016-08-02 18:03:15477};
478
dbeam49dab442016-08-20 00:49:52479bool HasGzipHeader(const base::RefCountedMemory& maybe_gzipped) {
480 net::GZipHeader header;
481 net::GZipHeader::Status header_status = net::GZipHeader::INCOMPLETE_HEADER;
482 const char* header_end = nullptr;
483 while (header_status == net::GZipHeader::INCOMPLETE_HEADER) {
484 header_status = header.ReadMore(maybe_gzipped.front_as<char>(),
485 maybe_gzipped.size(),
486 &header_end);
487 }
488 return header_status == net::GZipHeader::COMPLETE_HEADER;
489}
490
491void AppendGzippedResource(const base::RefCountedMemory& encoded,
492 std::string* to_append) {
xunjieli6cc8b84b2016-11-08 15:23:39493 std::unique_ptr<net::MockSourceStream> source_stream(
494 new net::MockSourceStream());
495 source_stream->AddReadResult(encoded.front_as<char>(), encoded.size(),
496 net::OK, net::MockSourceStream::SYNC);
497 // Add an EOF.
498 source_stream->AddReadResult(encoded.front_as<char>() + encoded.size(), 0,
499 net::OK, net::MockSourceStream::SYNC);
500 std::unique_ptr<net::GzipSourceStream> filter = net::GzipSourceStream::Create(
501 std::move(source_stream), net::SourceStream::TYPE_GZIP);
502 scoped_refptr<net::IOBufferWithSize> dest_buffer =
Victor Costan63c8b3d2018-09-01 01:34:10503 base::MakeRefCounted<net::IOBufferWithSize>(4096);
xunjieli6cc8b84b2016-11-08 15:23:39504 net::CompletionCallback callback;
505 while (true) {
506 int rv = filter->Read(dest_buffer.get(), dest_buffer->size(), callback);
507 ASSERT_LE(0, rv);
508 if (rv <= 0)
509 break;
510 to_append->append(dest_buffer->data(), rv);
511 }
dbeam49dab442016-08-20 00:49:52512}
513
lunalu2ddb05a82016-09-19 19:22:07514// Queries for video input devices on the current system using the getSources
515// API.
516//
517// This does not guarantee that a getUserMedia with video will succeed, as the
518// camera could be busy for instance.
519//
520// Returns has-video-input-device to the test if there is a webcam available,
521// no-video-input-devices otherwise.
lukaszac7d6bd32017-07-11 00:19:31522const char kHasVideoInputDeviceOnSystem[] = R"(
523 (function() {
524 navigator.mediaDevices.enumerateDevices()
525 .then(function(devices) {
526 if (devices.some((device) => device.kind == 'videoinput')) {
527 window.domAutomationController.send('has-video-input-device');
528 } else {
529 window.domAutomationController.send('no-video-input-devices');
530 }
531 });
532 })()
533)";
lunalu2ddb05a82016-09-19 19:22:07534
535const char kHasVideoInputDevice[] = "has-video-input-device";
536
Charlie Reise2c2c492018-06-15 21:34:04537// Interceptor that replaces params.url with |new_url| and params.origin with
538// |new_origin| for any commits to |target_url|.
539class CommitOriginInterceptor : public DidCommitProvisionalLoadInterceptor {
540 public:
541 CommitOriginInterceptor(WebContents* web_contents,
542 const GURL& target_url,
543 const GURL& new_url,
544 const url::Origin& new_origin)
545 : DidCommitProvisionalLoadInterceptor(web_contents),
546 target_url_(target_url),
547 new_url_(new_url),
548 new_origin_(new_origin) {}
549 ~CommitOriginInterceptor() override = default;
550
551 // WebContentsObserver:
552 void WebContentsDestroyed() override { delete this; }
553
554 protected:
clamyd3bfdb02018-07-12 13:52:18555 bool WillDispatchDidCommitProvisionalLoad(
Charlie Reise2c2c492018-06-15 21:34:04556 RenderFrameHost* render_frame_host,
557 ::FrameHostMsg_DidCommitProvisionalLoad_Params* params,
558 service_manager::mojom::InterfaceProviderRequest*
559 interface_provider_request) override {
560 if (params->url == target_url_) {
561 params->url = new_url_;
562 params->origin = new_origin_;
563 }
clamyd3bfdb02018-07-12 13:52:18564 return true;
Charlie Reise2c2c492018-06-15 21:34:04565 }
566
567 private:
568 GURL target_url_;
569 GURL new_url_;
570 url::Origin new_origin_;
571
572 DISALLOW_COPY_AND_ASSIGN(CommitOriginInterceptor);
573};
574
[email protected]7d478cb2012-07-24 17:19:42575} // namespace
576
Lukasz Anforowicz637e7d6d2018-10-06 05:44:12577bool NavigateToURL(WebContents* web_contents, const GURL& url) {
578 NavigateToURLBlockUntilNavigationsComplete(web_contents, url, 1);
579 if (!IsLastCommittedEntryOfPageType(web_contents, PAGE_TYPE_NORMAL)) {
580 // TODO(crbug.com/882545) remove the following debug information:
581 {
582 NavigationEntry* last_entry =
583 web_contents->GetController().GetLastCommittedEntry();
584 if (!last_entry) {
585 DLOG(WARNING) << "No last committed entry";
586 } else {
587 DLOG(WARNING) << "Last committed entry is of type "
588 << last_entry->GetPageType();
589 }
590 }
591 return false;
592 }
593
594 // TODO(crbug.com/882545) revert this to the return statement below.
595 bool same_url = web_contents->GetLastCommittedURL() == url;
596 if (!same_url) {
597 DLOG(WARNING) << "Expected URL " << url << " but observed "
598 << web_contents->GetLastCommittedURL();
599 }
600 return same_url;
601 // return web_contents->GetLastCommittedURL() == url;
602}
603
alexmos75648bb32015-01-07 21:06:28604bool NavigateIframeToURL(WebContents* web_contents,
605 std::string iframe_id,
606 const GURL& url) {
alexmos75648bb32015-01-07 21:06:28607 std::string script = base::StringPrintf(
608 "setTimeout(\""
609 "var iframes = document.getElementById('%s');iframes.src='%s';"
610 "\",0)",
611 iframe_id.c_str(), url.spec().c_str());
creis748a2c92015-12-15 18:09:30612 TestNavigationObserver load_observer(web_contents);
alexmos75648bb32015-01-07 21:06:28613 bool result = ExecuteScript(web_contents, script);
614 load_observer.Wait();
615 return result;
616}
[email protected]71d504f2012-07-25 17:15:28617
Lukasz Anforowicz637e7d6d2018-10-06 05:44:12618void NavigateToURLBlockUntilNavigationsComplete(WebContents* web_contents,
619 const GURL& url,
620 int number_of_navigations) {
621 // Prepare for the navigation.
622 WaitForLoadStop(web_contents);
623 TestNavigationObserver same_tab_observer(web_contents, number_of_navigations);
624
625 // This mimics behavior of Shell::LoadURL...
626 NavigationController::LoadURLParams params(url);
627 params.transition_type = ui::PageTransitionFromInt(
628 ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
629 web_contents->GetController().LoadURLWithParams(params);
630 web_contents->Focus();
631
632 // Wait until the expected number of navigations finish.
633 same_tab_observer.Wait();
634 // TODO(crbug.com/882545) Delete this if statement once the problem has been
635 // identified.
636 if (!same_tab_observer.last_navigation_succeeded()) {
637 DLOG(WARNING) << "Last navigation to " << url << " failed with net error "
638 << same_tab_observer.last_net_error_code();
639 }
640}
641
[email protected]c42de732013-02-16 06:26:31642GURL GetFileUrlWithQuery(const base::FilePath& path,
[email protected]71d504f2012-07-25 17:15:28643 const std::string& query_string) {
644 GURL url = net::FilePathToFileURL(path);
645 if (!query_string.empty()) {
646 GURL::Replacements replacements;
647 replacements.SetQueryStr(query_string);
648 return url.ReplaceComponents(replacements);
649 }
650 return url;
651}
652
Xida Chenec19b702018-08-15 01:57:14653void ResetTouchAction(RenderWidgetHost* host) {
654 static_cast<InputRouterImpl*>(
655 static_cast<RenderWidgetHostImpl*>(host)->input_router())
Xida Chen0f7980b2018-10-12 12:40:53656 ->ForceResetTouchActionForTest();
Xida Chenec19b702018-08-15 01:57:14657}
658
659void ResendGestureScrollUpdateToEmbedder(WebContents* guest_web_contents,
660 const blink::WebInputEvent& event) {
Ehsan Karamadfa983e82018-11-13 01:26:42661 auto* guest_web_contents_impl =
662 static_cast<WebContentsImpl*>(guest_web_contents);
663 DCHECK(guest_web_contents_impl->GetBrowserPluginGuest());
664 guest_web_contents_impl->GetBrowserPluginGuest()->ResendEventToEmbedder(
665 event);
Xida Chenec19b702018-08-15 01:57:14666}
667
Xida Chen9658adb2018-08-17 18:38:30668void MaybeSendSyntheticTapGesture(WebContents* guest_web_contents) {
669 content::RenderWidgetHostViewGuest* rwhv =
670 static_cast<content::RenderWidgetHostViewGuest*>(
671 guest_web_contents->GetRenderWidgetHostView());
672 DCHECK(rwhv);
673 rwhv->MaybeSendSyntheticTapGestureForTest(blink::WebFloatPoint(1, 1),
674 blink::WebFloatPoint(1, 1));
675}
676
alexmos0785dd762014-11-13 19:59:38677void WaitForLoadStopWithoutSuccessCheck(WebContents* web_contents) {
[email protected]6ddc6e3f22012-07-26 01:15:35678 // In many cases, the load may have finished before we get here. Only wait if
679 // the tab still has a pending navigation.
[email protected]6b6147472014-06-27 17:37:07680 if (web_contents->IsLoading()) {
681 WindowedNotificationObserver load_stop_observer(
682 NOTIFICATION_LOAD_STOP,
683 Source<NavigationController>(&web_contents->GetController()));
684 load_stop_observer.Wait();
685 }
[email protected]6ddc6e3f22012-07-26 01:15:35686}
687
alexmos0785dd762014-11-13 19:59:38688bool WaitForLoadStop(WebContents* web_contents) {
Gennady Sushko1fbd57fa2017-10-25 20:28:17689 WebContentsDestroyedObserver observer(web_contents);
alexmos0785dd762014-11-13 19:59:38690 WaitForLoadStopWithoutSuccessCheck(web_contents);
Gennady Sushko1fbd57fa2017-10-25 20:28:17691 if (observer.IsDestroyed()) {
692 LOG(ERROR) << "WebContents was destroyed during waiting for load stop.";
693 return false;
694 }
alexmos0785dd762014-11-13 19:59:38695 return IsLastCommittedEntryOfPageType(web_contents, PAGE_TYPE_NORMAL);
696}
697
avi336125f72017-05-06 22:25:40698void PrepContentsForBeforeUnloadTest(WebContents* web_contents) {
699 for (auto* frame : web_contents->GetAllFrames()) {
700 // JavaScript onbeforeunload dialogs are ignored unless the frame received a
701 // user gesture. Make sure the frames have user gestures.
702 frame->ExecuteJavaScriptWithUserGestureForTests(base::string16());
703
704 // Disable the hang monitor, otherwise there will be a race between the
705 // beforeunload dialog and the beforeunload hang timer.
706 frame->DisableBeforeUnloadHangMonitorForTesting();
707 }
708}
709
alexmos0785dd762014-11-13 19:59:38710bool IsLastCommittedEntryOfPageType(WebContents* web_contents,
711 content::PageType page_type) {
712 NavigationEntry* last_entry =
713 web_contents->GetController().GetLastCommittedEntry();
714 if (!last_entry)
715 return false;
716 return last_entry->GetPageType() == page_type;
717}
718
Charlie Reis76147902018-04-26 01:21:07719void OverrideLastCommittedOrigin(RenderFrameHost* render_frame_host,
720 const url::Origin& origin) {
721 static_cast<RenderFrameHostImpl*>(render_frame_host)
722 ->SetLastCommittedOriginForTesting(origin);
723}
724
[email protected]e0f3e142012-07-26 03:31:34725void CrashTab(WebContents* web_contents) {
Lukasz Anforowiczf14b5452017-10-02 20:10:34726 RenderProcessHost* rph = web_contents->GetMainFrame()->GetProcess();
[email protected]8ffad4e2014-01-02 23:18:26727 RenderProcessHostWatcher watcher(
728 rph, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
Wez0abfbf512018-03-03 01:54:45729 rph->Shutdown(0);
[email protected]8ffad4e2014-01-02 23:18:26730 watcher.Wait();
[email protected]e0f3e142012-07-26 03:31:34731}
[email protected]6ddc6e3f22012-07-26 01:15:35732
Charlie Reise2c2c492018-06-15 21:34:04733void PwnCommitIPC(WebContents* web_contents,
734 const GURL& target_url,
735 const GURL& new_url,
736 const url::Origin& new_origin) {
737 // This will be cleaned up when |web_contents| is destroyed.
738 new CommitOriginInterceptor(web_contents, target_url, new_url, new_origin);
739}
740
creis0f905332017-05-01 17:07:30741void SimulateUnresponsiveRenderer(WebContents* web_contents,
742 RenderWidgetHost* widget) {
743 static_cast<WebContentsImpl*>(web_contents)
Lukasz Anforowicz52b93722018-06-20 16:11:39744 ->RendererUnresponsive(RenderWidgetHostImpl::From(widget),
745 base::DoNothing::Repeatedly());
creis0f905332017-05-01 17:07:30746}
747
[email protected]6b6147472014-06-27 17:37:07748#if defined(USE_AURA)
749bool IsResizeComplete(aura::test::WindowEventDispatcherTestApi* dispatcher_test,
750 RenderWidgetHostImpl* widget_host) {
Saman Samiac97cd02018-01-19 19:04:10751 dispatcher_test->WaitUntilPointerMovesDispatched();
Fady Samuel0b911822018-04-25 13:22:16752 widget_host->SynchronizeVisualProperties();
Fady Samuel44e5e78d2018-05-08 05:46:04753 return !widget_host->visual_properties_ack_pending_for_testing();
[email protected]6b6147472014-06-27 17:37:07754}
755
756void WaitForResizeComplete(WebContents* web_contents) {
757 aura::Window* content = web_contents->GetContentNativeView();
758 if (!content)
759 return;
760
761 aura::WindowTreeHost* window_host = content->GetHost();
762 aura::WindowEventDispatcher* dispatcher = window_host->dispatcher();
763 aura::test::WindowEventDispatcherTestApi dispatcher_test(dispatcher);
avif9ab5d942015-10-15 14:05:44764 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
765 web_contents->GetRenderViewHost()->GetWidget());
[email protected]6b6147472014-06-27 17:37:07766 if (!IsResizeComplete(&dispatcher_test, widget_host)) {
767 WindowedNotificationObserver resize_observer(
Fady Samuel44e5e78d2018-05-08 05:46:04768 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_VISUAL_PROPERTIES,
[email protected]6b6147472014-06-27 17:37:07769 base::Bind(IsResizeComplete, &dispatcher_test, widget_host));
770 resize_observer.Wait();
771 }
772}
jaekyun23d007d2015-03-11 02:24:56773#elif defined(OS_ANDROID)
774bool IsResizeComplete(RenderWidgetHostImpl* widget_host) {
Fady Samuel44e5e78d2018-05-08 05:46:04775 return !widget_host->visual_properties_ack_pending_for_testing();
jaekyun23d007d2015-03-11 02:24:56776}
777
778void WaitForResizeComplete(WebContents* web_contents) {
avif9ab5d942015-10-15 14:05:44779 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
780 web_contents->GetRenderViewHost()->GetWidget());
jaekyun23d007d2015-03-11 02:24:56781 if (!IsResizeComplete(widget_host)) {
782 WindowedNotificationObserver resize_observer(
Fady Samuel44e5e78d2018-05-08 05:46:04783 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_VISUAL_PROPERTIES,
jaekyun23d007d2015-03-11 02:24:56784 base::Bind(IsResizeComplete, widget_host));
785 resize_observer.Wait();
786 }
787}
788#endif
[email protected]6b6147472014-06-27 17:37:07789
[email protected]0f061d92012-10-24 17:30:25790void SimulateMouseClick(WebContents* web_contents,
791 int modifiers,
[email protected]180ef242013-11-07 06:50:46792 blink::WebMouseEvent::Button button) {
[email protected]fc2b46b2014-05-03 16:33:45793 int x = web_contents->GetContainerBounds().width() / 2;
794 int y = web_contents->GetContainerBounds().height() / 2;
[email protected]861f9782013-03-05 03:29:54795 SimulateMouseClickAt(web_contents, modifiers, button, gfx::Point(x, y));
796}
797
798void SimulateMouseClickAt(WebContents* web_contents,
799 int modifiers,
[email protected]180ef242013-11-07 06:50:46800 blink::WebMouseEvent::Button button,
[email protected]861f9782013-03-05 03:29:54801 const gfx::Point& point) {
Daniel Cheng224569ee2018-04-25 05:45:06802 blink::WebMouseEvent mouse_event(blink::WebInputEvent::kMouseDown, modifiers,
803 ui::EventTimeForNow());
[email protected]0f061d92012-10-24 17:30:25804 mouse_event.button = button;
Blink Reformat1c4d759e2017-04-09 16:34:54805 mouse_event.SetPositionInWidget(point.x(), point.y());
mustaqc51f3aab2017-04-05 15:43:11806 // Mac needs positionInScreen for events to plugins.
[email protected]fc2b46b2014-05-03 16:33:45807 gfx::Rect offset = web_contents->GetContainerBounds();
Blink Reformat1c4d759e2017-04-09 16:34:54808 mouse_event.SetPositionInScreen(point.x() + offset.x(),
mustaqc51f3aab2017-04-05 15:43:11809 point.y() + offset.y());
Blink Reformat1c4d759e2017-04-09 16:34:54810 mouse_event.click_count = 1;
avif9ab5d942015-10-15 14:05:44811 web_contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
812 mouse_event);
Blink Reformat1c4d759e2017-04-09 16:34:54813 mouse_event.SetType(blink::WebInputEvent::kMouseUp);
avif9ab5d942015-10-15 14:05:44814 web_contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
815 mouse_event);
[email protected]7d478cb2012-07-24 17:19:42816}
817
W. James MacLean82b029b2017-10-23 15:05:43818void SimulateRoutedMouseClickAt(WebContents* web_contents,
819 int modifiers,
820 blink::WebMouseEvent::Button button,
821 const gfx::Point& point) {
822 content::WebContentsImpl* web_contents_impl =
823 static_cast<content::WebContentsImpl*>(web_contents);
824 content::RenderWidgetHostViewBase* rwhvb =
825 static_cast<content::RenderWidgetHostViewBase*>(
826 web_contents->GetRenderWidgetHostView());
Daniel Cheng224569ee2018-04-25 05:45:06827 blink::WebMouseEvent mouse_event(blink::WebInputEvent::kMouseDown, modifiers,
828 ui::EventTimeForNow());
W. James MacLean82b029b2017-10-23 15:05:43829 mouse_event.button = button;
830 mouse_event.SetPositionInWidget(point.x(), point.y());
831 // Mac needs positionInScreen for events to plugins.
832 gfx::Rect offset = web_contents->GetContainerBounds();
833 mouse_event.SetPositionInScreen(point.x() + offset.x(),
834 point.y() + offset.y());
835 mouse_event.click_count = 1;
836 web_contents_impl->GetInputEventRouter()->RouteMouseEvent(rwhvb, &mouse_event,
837 ui::LatencyInfo());
838 mouse_event.SetType(blink::WebInputEvent::kMouseUp);
839 web_contents_impl->GetInputEventRouter()->RouteMouseEvent(rwhvb, &mouse_event,
840 ui::LatencyInfo());
841}
842
Ken Buchanand1d30d12018-10-04 22:48:04843void SendMouseDownToWidget(RenderWidgetHost* target,
844 int modifiers,
845 blink::WebMouseEvent::Button button) {
846 auto* view = static_cast<content::RenderWidgetHostImpl*>(target)->GetView();
847
848 blink::WebMouseEvent mouse_event(blink::WebInputEvent::kMouseDown, modifiers,
849 ui::EventTimeForNow());
850 mouse_event.button = button;
851 int x = view->GetViewBounds().width() / 2;
852 int y = view->GetViewBounds().height() / 2;
853 mouse_event.SetPositionInWidget(x, y);
854 mouse_event.click_count = 1;
855 target->ForwardMouseEvent(mouse_event);
856}
857
[email protected]7d478cb2012-07-24 17:19:42858void SimulateMouseEvent(WebContents* web_contents,
[email protected]180ef242013-11-07 06:50:46859 blink::WebInputEvent::Type type,
[email protected]7d478cb2012-07-24 17:19:42860 const gfx::Point& point) {
Daniel Cheng224569ee2018-04-25 05:45:06861 blink::WebMouseEvent mouse_event(type, blink::WebInputEvent::kNoModifiers,
862 ui::EventTimeForNow());
Blink Reformat1c4d759e2017-04-09 16:34:54863 mouse_event.SetPositionInWidget(point.x(), point.y());
avif9ab5d942015-10-15 14:05:44864 web_contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
865 mouse_event);
[email protected]7d478cb2012-07-24 17:19:42866}
867
W. James MacLean4263cfc2018-05-10 15:57:52868void SimulateRoutedMouseEvent(WebContents* web_contents,
869 blink::WebInputEvent::Type type,
870 const gfx::Point& point) {
871 content::WebContentsImpl* web_contents_impl =
872 static_cast<content::WebContentsImpl*>(web_contents);
873 content::RenderWidgetHostViewBase* rwhvb =
874 static_cast<content::RenderWidgetHostViewBase*>(
875 web_contents->GetRenderWidgetHostView());
876 blink::WebMouseEvent mouse_event(type, 0, ui::EventTimeForNow());
877 mouse_event.SetPositionInWidget(point.x(), point.y());
878 // Mac needs positionInScreen for events to plugins.
879 gfx::Rect offset = web_contents->GetContainerBounds();
880 mouse_event.SetPositionInScreen(point.x() + offset.x(),
881 point.y() + offset.y());
882
883 web_contents_impl->GetInputEventRouter()->RouteMouseEvent(rwhvb, &mouse_event,
884 ui::LatencyInfo());
885}
886
wjmaclean73b15a22015-09-25 15:56:40887void SimulateMouseWheelEvent(WebContents* web_contents,
888 const gfx::Point& point,
sahele2b952b2017-09-13 18:28:49889 const gfx::Vector2d& delta,
890 const blink::WebMouseWheelEvent::Phase phase) {
Daniel Cheng224569ee2018-04-25 05:45:06891 blink::WebMouseWheelEvent wheel_event(blink::WebInputEvent::kMouseWheel,
892 blink::WebInputEvent::kNoModifiers,
893 ui::EventTimeForNow());
dtapuska899ac222017-01-03 18:09:16894
Blink Reformat1c4d759e2017-04-09 16:34:54895 wheel_event.SetPositionInWidget(point.x(), point.y());
896 wheel_event.delta_x = delta.x();
897 wheel_event.delta_y = delta.y();
sahele2b952b2017-09-13 18:28:49898 wheel_event.phase = phase;
avif9ab5d942015-10-15 14:05:44899 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
900 web_contents->GetRenderViewHost()->GetWidget());
wjmaclean73b15a22015-09-25 15:56:40901 widget_host->ForwardWheelEvent(wheel_event);
902}
903
Kevin McNeebc61eb62017-11-13 20:39:14904#if !defined(OS_MACOSX)
905void SimulateMouseWheelCtrlZoomEvent(WebContents* web_contents,
906 const gfx::Point& point,
907 bool zoom_in,
908 blink::WebMouseWheelEvent::Phase phase) {
Daniel Cheng224569ee2018-04-25 05:45:06909 blink::WebMouseWheelEvent wheel_event(blink::WebInputEvent::kMouseWheel,
910 blink::WebInputEvent::kControlKey,
911 ui::EventTimeForNow());
Kevin McNeebc61eb62017-11-13 20:39:14912
913 wheel_event.SetPositionInWidget(point.x(), point.y());
914 wheel_event.delta_y =
915 (zoom_in ? 1.0 : -1.0) * ui::MouseWheelEvent::kWheelDelta;
916 wheel_event.wheel_ticks_y = (zoom_in ? 1.0 : -1.0);
917 wheel_event.has_precise_scrolling_deltas = false;
918 wheel_event.phase = phase;
919 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
920 web_contents->GetRenderViewHost()->GetWidget());
921 widget_host->ForwardWheelEvent(wheel_event);
922}
923#endif // !defined(OS_MACOSX)
924
925void SimulateGesturePinchSequence(WebContents* web_contents,
926 const gfx::Point& point,
927 float scale,
928 blink::WebGestureDevice source_device) {
929 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
930 web_contents->GetRenderViewHost()->GetWidget());
931
Daniel Cheng224569ee2018-04-25 05:45:06932 blink::WebGestureEvent pinch_begin(blink::WebInputEvent::kGesturePinchBegin,
933 blink::WebInputEvent::kNoModifiers,
934 ui::EventTimeForNow(), source_device);
Ella Ge1116059d2018-03-21 02:06:13935 pinch_begin.SetPositionInWidget(gfx::PointF(point));
936 pinch_begin.SetPositionInScreen(gfx::PointF(point));
Kevin McNee297980d2018-06-04 21:32:14937 pinch_begin.SetNeedsWheelEvent(source_device ==
938 blink::kWebGestureDeviceTouchpad);
Kevin McNeebc61eb62017-11-13 20:39:14939 widget_host->ForwardGestureEvent(pinch_begin);
940
941 blink::WebGestureEvent pinch_update(pinch_begin);
942 pinch_update.SetType(blink::WebInputEvent::kGesturePinchUpdate);
943 pinch_update.data.pinch_update.scale = scale;
Kevin McNee297980d2018-06-04 21:32:14944 pinch_update.SetNeedsWheelEvent(source_device ==
945 blink::kWebGestureDeviceTouchpad);
Kevin McNeebc61eb62017-11-13 20:39:14946 widget_host->ForwardGestureEvent(pinch_update);
947
948 blink::WebGestureEvent pinch_end(pinch_begin);
Kevin McNee297980d2018-06-04 21:32:14949 pinch_end.SetType(blink::WebInputEvent::kGesturePinchEnd);
950 pinch_end.SetNeedsWheelEvent(source_device ==
951 blink::kWebGestureDeviceTouchpad);
Kevin McNeebc61eb62017-11-13 20:39:14952 widget_host->ForwardGestureEvent(pinch_end);
953}
954
wjmaclean73b15a22015-09-25 15:56:40955void SimulateGestureScrollSequence(WebContents* web_contents,
956 const gfx::Point& point,
957 const gfx::Vector2dF& delta) {
avif9ab5d942015-10-15 14:05:44958 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
959 web_contents->GetRenderViewHost()->GetWidget());
wjmaclean73b15a22015-09-25 15:56:40960
dtapuska899ac222017-01-03 18:09:16961 blink::WebGestureEvent scroll_begin(
Blink Reformat1c4d759e2017-04-09 16:34:54962 blink::WebGestureEvent::kGestureScrollBegin,
Daniel Cheng224569ee2018-04-25 05:45:06963 blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow(),
Ella Ge1116059d2018-03-21 02:06:13964 blink::kWebGestureDeviceTouchpad);
965 scroll_begin.SetPositionInWidget(gfx::PointF(point));
Sahel Sharifydbafed52017-08-03 16:59:12966 scroll_begin.data.scroll_begin.delta_x_hint = delta.x();
967 scroll_begin.data.scroll_begin.delta_y_hint = delta.y();
wjmaclean73b15a22015-09-25 15:56:40968 widget_host->ForwardGestureEvent(scroll_begin);
969
dtapuska899ac222017-01-03 18:09:16970 blink::WebGestureEvent scroll_update(
Blink Reformat1c4d759e2017-04-09 16:34:54971 blink::WebGestureEvent::kGestureScrollUpdate,
Daniel Cheng224569ee2018-04-25 05:45:06972 blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow(),
Ella Ge1116059d2018-03-21 02:06:13973 blink::kWebGestureDeviceTouchpad);
974 scroll_update.SetPositionInWidget(gfx::PointF(point));
Blink Reformat1c4d759e2017-04-09 16:34:54975 scroll_update.data.scroll_update.delta_x = delta.x();
976 scroll_update.data.scroll_update.delta_y = delta.y();
977 scroll_update.data.scroll_update.velocity_x = 0;
978 scroll_update.data.scroll_update.velocity_y = 0;
wjmaclean73b15a22015-09-25 15:56:40979 widget_host->ForwardGestureEvent(scroll_update);
980
Daniel Cheng224569ee2018-04-25 05:45:06981 blink::WebGestureEvent scroll_end(blink::WebGestureEvent::kGestureScrollEnd,
982 blink::WebInputEvent::kNoModifiers,
983 ui::EventTimeForNow(),
984 blink::kWebGestureDeviceTouchpad);
Ella Ge1116059d2018-03-21 02:06:13985 scroll_end.SetPositionInWidget(gfx::PointF(point));
wjmaclean73b15a22015-09-25 15:56:40986 widget_host->ForwardGestureEvent(scroll_end);
987}
988
khmeld9269402016-06-04 03:59:34989void SimulateGestureFlingSequence(WebContents* web_contents,
990 const gfx::Point& point,
991 const gfx::Vector2dF& velocity) {
992 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
993 web_contents->GetRenderViewHost()->GetWidget());
994
dtapuska899ac222017-01-03 18:09:16995 blink::WebGestureEvent scroll_begin(
Blink Reformat1c4d759e2017-04-09 16:34:54996 blink::WebGestureEvent::kGestureScrollBegin,
Daniel Cheng224569ee2018-04-25 05:45:06997 blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow(),
Ella Ge1116059d2018-03-21 02:06:13998 blink::kWebGestureDeviceTouchpad);
999 scroll_begin.SetPositionInWidget(gfx::PointF(point));
khmeld9269402016-06-04 03:59:341000 widget_host->ForwardGestureEvent(scroll_begin);
1001
Daniel Cheng224569ee2018-04-25 05:45:061002 blink::WebGestureEvent scroll_end(blink::WebGestureEvent::kGestureScrollEnd,
1003 blink::WebInputEvent::kNoModifiers,
1004 ui::EventTimeForNow(),
1005 blink::kWebGestureDeviceTouchpad);
Ella Ge1116059d2018-03-21 02:06:131006 scroll_end.SetPositionInWidget(gfx::PointF(point));
khmeld9269402016-06-04 03:59:341007 widget_host->ForwardGestureEvent(scroll_end);
1008
Daniel Cheng224569ee2018-04-25 05:45:061009 blink::WebGestureEvent fling_start(blink::WebGestureEvent::kGestureFlingStart,
1010 blink::WebInputEvent::kNoModifiers,
1011 ui::EventTimeForNow(),
1012 blink::kWebGestureDeviceTouchpad);
Ella Ge1116059d2018-03-21 02:06:131013 fling_start.SetPositionInWidget(gfx::PointF(point));
Blink Reformat1c4d759e2017-04-09 16:34:541014 fling_start.data.fling_start.target_viewport = false;
1015 fling_start.data.fling_start.velocity_x = velocity.x();
1016 fling_start.data.fling_start.velocity_y = velocity.y();
khmeld9269402016-06-04 03:59:341017 widget_host->ForwardGestureEvent(fling_start);
1018}
1019
Kevin McNee08bf6de62017-11-08 15:24:481020void SimulateGestureEvent(WebContents* web_contents,
1021 const blink::WebGestureEvent& gesture_event,
1022 const ui::LatencyInfo& latency) {
1023 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
1024 web_contents->GetRenderWidgetHostView());
1025 view->ProcessGestureEvent(gesture_event, latency);
1026}
1027
Xida Chen2eec314f2018-06-07 11:42:421028void SimulateTouchGestureAt(WebContents* web_contents,
1029 const gfx::Point& point,
1030 blink::WebInputEvent::Type type) {
1031 blink::WebGestureEvent gesture(type, 0, ui::EventTimeForNow(),
1032 blink::kWebGestureDeviceTouchscreen);
1033 gesture.SetPositionInWidget(gfx::PointF(point));
avif9ab5d942015-10-15 14:05:441034 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
1035 web_contents->GetRenderViewHost()->GetWidget());
Xida Chen2eec314f2018-06-07 11:42:421036 widget_host->ForwardGestureEvent(gesture);
1037}
1038
1039void SimulateTapDownAt(WebContents* web_contents, const gfx::Point& point) {
1040 SimulateTouchGestureAt(web_contents, point,
1041 blink::WebGestureEvent::kGestureTapDown);
1042}
1043
1044void SimulateTapAt(WebContents* web_contents, const gfx::Point& point) {
1045 SimulateTouchGestureAt(web_contents, point,
1046 blink::WebGestureEvent::kGestureTap);
myid.shin8143cbe2015-03-18 17:26:101047}
1048
1049void SimulateTapWithModifiersAt(WebContents* web_contents,
1050 unsigned modifiers,
1051 const gfx::Point& point) {
Ella Ge1116059d2018-03-21 02:06:131052 blink::WebGestureEvent tap(blink::WebGestureEvent::kGestureTap, modifiers,
Daniel Cheng224569ee2018-04-25 05:45:061053 ui::EventTimeForNow(),
Ella Ge1116059d2018-03-21 02:06:131054 blink::kWebGestureDeviceTouchpad);
1055 tap.SetPositionInWidget(gfx::PointF(point));
avif9ab5d942015-10-15 14:05:441056 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
1057 web_contents->GetRenderViewHost()->GetWidget());
[email protected]709c57e2014-08-08 06:46:341058 widget_host->ForwardGestureEvent(tap);
[email protected]c8befac42014-05-22 15:13:271059}
1060
wjmacleane31234f2015-12-14 17:20:451061#if defined(USE_AURA)
wjmaclean6aefc3a2015-06-22 21:58:291062void SimulateTouchPressAt(WebContents* web_contents, const gfx::Point& point) {
lanwei64725672017-03-16 20:56:051063 ui::TouchEvent touch(
1064 ui::ET_TOUCH_PRESSED, point, base::TimeTicks(),
1065 ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
wjmacleane31234f2015-12-14 17:20:451066 static_cast<RenderWidgetHostViewAura*>(
1067 web_contents->GetRenderWidgetHostView())
1068 ->OnTouchEvent(&touch);
wjmaclean6aefc3a2015-06-22 21:58:291069}
Pedro Amaral55cc4c002017-12-20 21:33:481070
Ella Geaa4f17632018-04-04 00:05:581071void SimulateLongTapAt(WebContents* web_contents, const gfx::Point& point) {
Pedro Amaral55cc4c002017-12-20 21:33:481072 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
1073 web_contents->GetRenderWidgetHostView());
1074
1075 ui::TouchEvent touch_start(
1076 ui::ET_TOUCH_PRESSED, point, base::TimeTicks(),
1077 ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
1078 rwhva->OnTouchEvent(&touch_start);
1079
1080 ui::GestureEventDetails tap_down_details(ui::ET_GESTURE_TAP_DOWN);
1081 tap_down_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
1082 ui::GestureEvent tap_down(point.x(), point.y(), 0, ui::EventTimeForNow(),
1083 tap_down_details, touch_start.unique_event_id());
1084 rwhva->OnGestureEvent(&tap_down);
1085
1086 ui::GestureEventDetails long_press_details(ui::ET_GESTURE_LONG_PRESS);
1087 long_press_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
1088 ui::GestureEvent long_press(point.x(), point.y(), 0, ui::EventTimeForNow(),
1089 long_press_details,
1090 touch_start.unique_event_id());
1091 rwhva->OnGestureEvent(&long_press);
1092
1093 ui::TouchEvent touch_end(
1094 ui::ET_TOUCH_RELEASED, point, base::TimeTicks(),
1095 ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
1096 rwhva->OnTouchEvent(&touch_end);
Ella Geaa4f17632018-04-04 00:05:581097
1098 ui::GestureEventDetails long_tap_details(ui::ET_GESTURE_LONG_TAP);
1099 long_tap_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
1100 ui::GestureEvent long_tap(point.x(), point.y(), 0, ui::EventTimeForNow(),
1101 long_tap_details, touch_end.unique_event_id());
1102 rwhva->OnGestureEvent(&long_tap);
Pedro Amaral55cc4c002017-12-20 21:33:481103}
wjmacleane31234f2015-12-14 17:20:451104#endif
wjmaclean6aefc3a2015-06-22 21:58:291105
[email protected]26151fd2012-07-20 23:38:571106void SimulateKeyPress(WebContents* web_contents,
dtapuska8b1bdc82016-06-07 21:39:481107 ui::DomKey key,
1108 ui::DomCode code,
[email protected]6dc5a332013-09-11 01:02:101109 ui::KeyboardCode key_code,
[email protected]26151fd2012-07-20 23:38:571110 bool control,
1111 bool shift,
1112 bool alt,
1113 bool command) {
Lei Zhang6cef3262017-08-16 15:44:381114 SimulateKeyPressImpl(web_contents, key, code, key_code, control, shift, alt,
1115 command, /*send_char=*/true);
1116}
[email protected]ec8e05952013-09-19 21:45:401117
Lei Zhang6cef3262017-08-16 15:44:381118void SimulateKeyPressWithoutChar(WebContents* web_contents,
1119 ui::DomKey key,
1120 ui::DomCode code,
1121 ui::KeyboardCode key_code,
1122 bool control,
1123 bool shift,
1124 bool alt,
1125 bool command) {
1126 SimulateKeyPressImpl(web_contents, key, code, key_code, control, shift, alt,
1127 command, /*send_char=*/false);
1128}
[email protected]ec8e05952013-09-19 21:45:401129
Lei Zhang6cef3262017-08-16 15:44:381130ScopedSimulateModifierKeyPress::ScopedSimulateModifierKeyPress(
1131 WebContents* web_contents,
1132 bool control,
1133 bool shift,
1134 bool alt,
1135 bool command)
1136 : web_contents_(web_contents),
1137 modifiers_(0),
1138 control_(control),
1139 shift_(shift),
1140 alt_(alt),
1141 command_(command) {
1142 modifiers_ =
1143 SimulateModifierKeysDown(web_contents_, control_, shift_, alt_, command_);
1144}
[email protected]ec8e05952013-09-19 21:45:401145
Lei Zhang6cef3262017-08-16 15:44:381146ScopedSimulateModifierKeyPress::~ScopedSimulateModifierKeyPress() {
1147 modifiers_ = SimulateModifierKeysUp(web_contents_, control_, shift_, alt_,
1148 command_, modifiers_);
1149 DCHECK_EQ(0, modifiers_);
1150}
[email protected]ec8e05952013-09-19 21:45:401151
Lei Zhang6cef3262017-08-16 15:44:381152void ScopedSimulateModifierKeyPress::MouseClickAt(
1153 int additional_modifiers,
1154 blink::WebMouseEvent::Button button,
1155 const gfx::Point& point) {
1156 SimulateMouseClickAt(web_contents_, modifiers_ | additional_modifiers, button,
1157 point);
1158}
[email protected]ec8e05952013-09-19 21:45:401159
Lei Zhang6cef3262017-08-16 15:44:381160void ScopedSimulateModifierKeyPress::KeyPress(ui::DomKey key,
1161 ui::DomCode code,
1162 ui::KeyboardCode key_code) {
1163 SimulateKeyEvent(web_contents_, key, code, key_code, /*send_char=*/true,
1164 modifiers_);
1165}
[email protected]26151fd2012-07-20 23:38:571166
Lei Zhang6cef3262017-08-16 15:44:381167void ScopedSimulateModifierKeyPress::KeyPressWithoutChar(
1168 ui::DomKey key,
1169 ui::DomCode code,
1170 ui::KeyboardCode key_code) {
1171 SimulateKeyEvent(web_contents_, key, code, key_code, /*send_char=*/false,
1172 modifiers_);
[email protected]26151fd2012-07-20 23:38:571173}
1174
lunalu2ddb05a82016-09-19 19:22:071175bool IsWebcamAvailableOnSystem(WebContents* web_contents) {
1176 std::string result;
1177 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
1178 web_contents, kHasVideoInputDeviceOnSystem, &result));
1179 return result == kHasVideoInputDevice;
1180}
1181
nickadef4a52016-06-09 18:45:541182RenderFrameHost* ConvertToRenderFrameHost(WebContents* web_contents) {
1183 return web_contents->GetMainFrame();
[email protected]ff4657ee2014-03-15 01:08:151184}
1185
nickadef4a52016-06-09 18:45:541186RenderFrameHost* ConvertToRenderFrameHost(RenderFrameHost* render_frame_host) {
1187 return render_frame_host;
[email protected]ff4657ee2014-03-15 01:08:151188}
1189
alexmos4cf2aa32015-07-15 23:40:431190bool ExecuteScript(const ToRenderFrameHost& adapter,
[email protected]b6987e02013-01-04 18:30:431191 const std::string& script) {
lukaszac7d6bd32017-07-11 00:19:311192 return ExecuteScriptWithUserGestureControl(adapter.render_frame_host(),
1193 script, true);
vasiliib50cee4c92017-03-31 11:53:141194}
1195
1196bool ExecuteScriptWithoutUserGesture(const ToRenderFrameHost& adapter,
1197 const std::string& script) {
lukaszac7d6bd32017-07-11 00:19:311198 return ExecuteScriptWithUserGestureControl(adapter.render_frame_host(),
1199 script, false);
1200}
1201
1202void ExecuteScriptAsync(const ToRenderFrameHost& adapter,
1203 const std::string& script) {
1204 adapter.render_frame_host()->ExecuteJavaScriptWithUserGestureForTests(
1205 base::UTF8ToUTF16(script));
[email protected]b6987e02013-01-04 18:30:431206}
1207
wjmaclean64951902016-04-29 20:59:121208bool ExecuteScriptAndExtractDouble(const ToRenderFrameHost& adapter,
1209 const std::string& script, double* result) {
1210 DCHECK(result);
1211 std::unique_ptr<base::Value> value;
Nick Carterb7e71312018-08-03 23:36:131212 return ExecuteScriptHelper(adapter.render_frame_host(), script, true,
1213 ISOLATED_WORLD_ID_GLOBAL, &value) &&
1214 value && value->GetAsDouble(result);
wjmaclean64951902016-04-29 20:59:121215}
1216
alexmos4cf2aa32015-07-15 23:40:431217bool ExecuteScriptAndExtractInt(const ToRenderFrameHost& adapter,
[email protected]b6987e02013-01-04 18:30:431218 const std::string& script, int* result) {
[email protected]ff4657ee2014-03-15 01:08:151219 DCHECK(result);
dcheng6003e0b2016-04-09 18:42:341220 std::unique_ptr<base::Value> value;
Nick Carterb7e71312018-08-03 23:36:131221 return ExecuteScriptHelper(adapter.render_frame_host(), script, true,
1222 ISOLATED_WORLD_ID_GLOBAL, &value) &&
1223 value && value->GetAsInteger(result);
[email protected]b6987e02013-01-04 18:30:431224}
1225
alexmos4cf2aa32015-07-15 23:40:431226bool ExecuteScriptAndExtractBool(const ToRenderFrameHost& adapter,
[email protected]b6987e02013-01-04 18:30:431227 const std::string& script, bool* result) {
[email protected]ff4657ee2014-03-15 01:08:151228 DCHECK(result);
dcheng6003e0b2016-04-09 18:42:341229 std::unique_ptr<base::Value> value;
Nick Carterb7e71312018-08-03 23:36:131230 return ExecuteScriptHelper(adapter.render_frame_host(), script, true,
1231 ISOLATED_WORLD_ID_GLOBAL, &value) &&
1232 value && value->GetAsBoolean(result);
mdjones28f36942015-09-24 00:48:221233}
1234
alexmos4cf2aa32015-07-15 23:40:431235bool ExecuteScriptAndExtractString(const ToRenderFrameHost& adapter,
[email protected]b6987e02013-01-04 18:30:431236 const std::string& script,
1237 std::string* result) {
[email protected]ff4657ee2014-03-15 01:08:151238 DCHECK(result);
dcheng6003e0b2016-04-09 18:42:341239 std::unique_ptr<base::Value> value;
Nick Carterb7e71312018-08-03 23:36:131240 return ExecuteScriptHelper(adapter.render_frame_host(), script, true,
1241 ISOLATED_WORLD_ID_GLOBAL, &value) &&
1242 value && value->GetAsString(result);
[email protected]b6987e02013-01-04 18:30:431243}
1244
vasiliib50cee4c92017-03-31 11:53:141245bool ExecuteScriptWithoutUserGestureAndExtractDouble(
1246 const ToRenderFrameHost& adapter,
1247 const std::string& script,
1248 double* result) {
1249 DCHECK(result);
1250 std::unique_ptr<base::Value> value;
1251 return ExecuteScriptHelper(adapter.render_frame_host(), script, false,
Nick Carterb7e71312018-08-03 23:36:131252 ISOLATED_WORLD_ID_GLOBAL, &value) &&
vasiliib50cee4c92017-03-31 11:53:141253 value && value->GetAsDouble(result);
1254}
1255
1256bool ExecuteScriptWithoutUserGestureAndExtractInt(
1257 const ToRenderFrameHost& adapter,
1258 const std::string& script,
1259 int* result) {
1260 DCHECK(result);
1261 std::unique_ptr<base::Value> value;
1262 return ExecuteScriptHelper(adapter.render_frame_host(), script, false,
Nick Carterb7e71312018-08-03 23:36:131263 ISOLATED_WORLD_ID_GLOBAL, &value) &&
vasiliib50cee4c92017-03-31 11:53:141264 value && value->GetAsInteger(result);
1265}
1266
1267bool ExecuteScriptWithoutUserGestureAndExtractBool(
1268 const ToRenderFrameHost& adapter,
1269 const std::string& script,
1270 bool* result) {
1271 DCHECK(result);
1272 std::unique_ptr<base::Value> value;
1273 return ExecuteScriptHelper(adapter.render_frame_host(), script, false,
Nick Carterb7e71312018-08-03 23:36:131274 ISOLATED_WORLD_ID_GLOBAL, &value) &&
vasiliib50cee4c92017-03-31 11:53:141275 value && value->GetAsBoolean(result);
1276}
1277
1278bool ExecuteScriptWithoutUserGestureAndExtractString(
1279 const ToRenderFrameHost& adapter,
1280 const std::string& script,
1281 std::string* result) {
1282 DCHECK(result);
1283 std::unique_ptr<base::Value> value;
1284 return ExecuteScriptHelper(adapter.render_frame_host(), script, false,
Nick Carterb7e71312018-08-03 23:36:131285 ISOLATED_WORLD_ID_GLOBAL, &value) &&
vasiliib50cee4c92017-03-31 11:53:141286 value && value->GetAsString(result);
1287}
1288
Nick Carterb7e71312018-08-03 23:36:131289// EvalJsResult methods.
1290EvalJsResult::EvalJsResult(base::Value value, const std::string& error)
1291 : value(error.empty() ? std::move(value) : base::Value()), error(error) {}
1292
1293EvalJsResult::EvalJsResult(const EvalJsResult& other)
1294 : value(other.value.Clone()), error(other.error) {}
1295
1296const std::string& EvalJsResult::ExtractString() const {
1297 CHECK(error.empty())
1298 << "Can't ExtractString() because the script encountered a problem: "
1299 << error;
1300 CHECK(value.is_string()) << "Can't ExtractString() because script result: "
1301 << value << "is not a string.";
1302 return value.GetString();
1303}
1304
1305int EvalJsResult::ExtractInt() const {
1306 CHECK(error.empty())
1307 << "Can't ExtractInt() because the script encountered a problem: "
1308 << error;
1309 CHECK(value.is_int()) << "Can't ExtractInt() because script result: " << value
1310 << "is not an int.";
1311 return value.GetInt();
1312}
1313
1314bool EvalJsResult::ExtractBool() const {
1315 CHECK(error.empty())
1316 << "Can't ExtractBool() because the script encountered a problem: "
1317 << error;
1318 CHECK(value.is_bool()) << "Can't ExtractBool() because script result: "
1319 << value << "is not a bool.";
1320 return value.GetBool();
1321}
1322
1323double EvalJsResult::ExtractDouble() const {
1324 CHECK(error.empty())
1325 << "Can't ExtractDouble() because the script encountered a problem: "
1326 << error;
1327 CHECK(value.is_double() || value.is_int())
1328 << "Can't ExtractDouble() because script result: " << value
1329 << "is not a double or int.";
1330 return value.GetDouble();
1331}
1332
1333base::ListValue EvalJsResult::ExtractList() const {
1334 CHECK(error.empty())
1335 << "Can't ExtractList() because the script encountered a problem: "
1336 << error;
1337 CHECK(value.is_list()) << "Can't ExtractList() because script result: "
1338 << value << "is not a list.";
1339 return base::ListValue(value.GetList());
1340}
1341
1342void PrintTo(const EvalJsResult& bar, ::std::ostream* os) {
1343 if (!bar.error.empty()) {
1344 *os << bar.error;
1345 } else {
1346 *os << bar.value;
1347 }
1348}
1349
1350namespace {
1351
1352// Parse a JS stack trace out of |js_error|, detect frames that match
1353// |source_name|, and interleave the appropriate lines of source code from
1354// |source| into the error report. This is meant to be useful for scripts that
1355// are passed to ExecuteScript functions, and hence dynamically generated.
1356//
1357// An adjustment of |column_adjustment_for_line_one| characters is subtracted
1358// when mapping positions from line 1 of |source|. This is to offset the effect
1359// of boilerplate added by the script runner.
1360//
1361// TODO(nick): Elide snippets to 80 chars, since it is common for sources to not
1362// include newlines.
1363std::string AnnotateAndAdjustJsStackTraces(const std::string& js_error,
1364 std::string source_name,
1365 const std::string& source,
1366 int column_adjustment_for_line_one) {
1367 // Escape wildcards in |source_name| for use in MatchPattern.
1368 base::ReplaceChars(source_name, "\\", "\\\\", &source_name);
1369 base::ReplaceChars(source_name, "*", "\\*", &source_name);
1370 base::ReplaceChars(source_name, "?", "\\?", &source_name);
1371
1372 // This vector maps line numbers to the corresponding text in |source|.
1373 const std::vector<base::StringPiece> source_lines = base::SplitStringPiece(
1374 source, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
1375
1376 // |source_frame_pattern| should match any line that looks like a stack frame
1377 // from a source file named |source_name|.
1378 const std::string source_frame_pattern =
1379 base::StringPrintf(" at * (%s:*:*)", source_name.c_str());
1380
1381 // This is the amount of indentation that is applied to the lines of inserted
1382 // annotations.
1383 const std::string indent(8, ' ');
1384 const base::StringPiece elision_mark = "";
1385
1386 // Loop over each line of |js_error|, and append each to |annotated_error| --
1387 // possibly rewriting to include extra context.
1388 std::ostringstream annotated_error;
1389 for (const base::StringPiece& error_line : base::SplitStringPiece(
1390 js_error, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)) {
1391 // Does this look like a stack frame whose URL source matches |source_name|?
1392 if (base::MatchPattern(error_line, source_frame_pattern)) {
1393 // When a match occurs, annotate the stack trace with the corresponding
1394 // line from |source|, along with a ^^^ underneath, indicating the column
1395 // position.
1396 std::vector<base::StringPiece> error_line_parts = base::SplitStringPiece(
1397 error_line, ":", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
Lukasz Anforowicz637e7d6d2018-10-06 05:44:121398 CHECK_GE(error_line_parts.size(), 2u);
Nick Carterb7e71312018-08-03 23:36:131399
1400 int column_number = 0;
1401 base::StringToInt(error_line_parts.back(), &column_number);
1402 error_line_parts.pop_back();
1403 int line_number = 0;
1404 base::StringToInt(error_line_parts.back(), &line_number);
1405 error_line_parts.pop_back();
1406
1407 // Protect against out-of-range matches.
1408 if ((line_number > 0) && (column_number > 0) &&
1409 static_cast<size_t>(line_number) <= source_lines.size()) {
1410 // Apply adjustment requested by caller to columns on the first line.
1411 // This allows us to add preamble boilerplate to the script, but still
1412 // locate errors correctly.
1413 if (line_number == 1 && column_number > column_adjustment_for_line_one)
1414 column_number -= column_adjustment_for_line_one;
1415
1416 // Some source lines are huge. Elide |source_line| so that it doesn't
1417 // occupy more than one actual line.
1418 std::string source_line = source_lines[line_number - 1].as_string();
1419
1420 int max_column_number = 60 - indent.length();
1421 if (column_number > max_column_number) {
1422 source_line = source_line.substr(column_number - max_column_number);
1423 column_number = max_column_number;
1424 source_line.replace(0, elision_mark.length(), elision_mark.data(),
1425 elision_mark.length());
1426 }
1427
1428 size_t max_length = 80 - indent.length();
1429 if (source_line.length() > max_length) {
1430 source_line =
1431 source_line.substr(0, max_length - elision_mark.length());
1432 elision_mark.AppendToString(&source_line);
1433 }
1434
1435 annotated_error << base::JoinString(error_line_parts, ":") << ":"
1436 << line_number << ":" << column_number << "):\n"
1437 << indent << source_line << '\n'
1438 << indent << std::string(column_number - 1, ' ')
1439 << "^^^^^\n";
1440 continue;
1441 }
1442 }
1443 // This line was not rewritten -- just append it as-is.
1444 annotated_error << error_line << "\n";
1445 }
1446 return annotated_error.str();
1447}
1448
1449} // namespace
1450
1451testing::AssertionResult ExecJs(const ToRenderFrameHost& execution_target,
1452 const std::string& script,
1453 int options,
1454 int world_id) {
1455 CHECK(!(options & EXECUTE_SCRIPT_USE_MANUAL_REPLY))
1456 << "USE_MANUAL_REPLY does not make sense with ExecJs.";
1457
1458 // ExecJs() doesn't care about the result, so disable promise resolution.
1459 // Instead of using ExecJs() to wait for an async event, callers may use
1460 // EvalJs() with a sentinel result value like "success".
1461 options |= EXECUTE_SCRIPT_NO_RESOLVE_PROMISES;
1462
1463 // TODO(nick): Do we care enough about folks shooting themselves in the foot
1464 // here with e.g. ASSERT_TRUE(ExecJs("window == window.top")) -- when they
1465 // mean EvalJs -- to fail a CHECK() when eval_result.value.is_bool()?
1466 EvalJsResult eval_result =
1467 EvalJs(execution_target, script, options, world_id);
1468
1469 // NOTE: |eval_result.value| is intentionally ignored by ExecJs().
1470 if (!eval_result.error.empty())
1471 return testing::AssertionFailure() << eval_result.error;
1472 return testing::AssertionSuccess();
1473}
1474
1475EvalJsResult EvalJs(const ToRenderFrameHost& execution_target,
1476 const std::string& script,
1477 int options,
1478 int world_id) {
1479 // The sourceURL= parameter provides a string that replaces <anonymous> in
1480 // stack traces, if an Error is thrown. 'std::string' is meant to communicate
1481 // that this is a dynamic argument originating from C++ code.
1482 const char* kSourceURL = "__const_std::string&_script__";
1483 std::string modified_script =
1484 base::StringPrintf("%s;\n//# sourceURL=%s", script.c_str(), kSourceURL);
1485
1486 // An extra eval() indirection is used here to catch syntax errors and return
1487 // them as assertion failures. This eval() operation deliberately occurs in
1488 // the global scope, so 'var' declarations in |script| will persist for later
1489 // script executions. (As an aside: global/local scope for eval depends on
1490 // whether 'eval' is called directly or indirectly; 'window.eval()' is
1491 // indirect).
1492 //
1493 // The call to eval() itself is inside a .then() handler so that syntax errors
1494 // result in Promise rejection. Calling eval() either throws (in the event of
1495 // a SyntaxError) or returns the script's completion value.
1496 //
1497 // The result of eval() (i.e., the statement completion value of |script|) is
1498 // wrapped in an array and passed to a second .then() handler. If eval()
1499 // returned a Promise and the |resolve_promises| option is set, this handler
1500 // calls Promise.all to reply after the returned Promise resolves.
1501 //
1502 // If |script| evaluated successfully, the third.then() handler maps the
1503 // resolved |result| of eval() to a |reply| that is a one-element list
1504 // containing the value (this element can be any JSON-serializable type). If
1505 // the manual reply option is being used, no reply is emitted after successful
1506 // execution -- the script is expected to call send() itself. The call to
1507 // Promise.reject() squelches this reply, and the final .then() handler is not
1508 // called.
1509 //
1510 // If an uncaught error was thrown, or eval() returns a Promise that is
1511 // rejected, the third .then() handler maps the |error| to a |reply| that is
1512 // a string value.
1513 //
1514 // The fourth and final .then() handler passes the |reply| (whether
1515 // successful or unsuccessful) to domAutomationController.send(), so that it's
1516 // transmitted back here in browser process C++ land. A GUID token is also
1517 // included, that protects against |script| directly calling
1518 // domAutomationController.send() itself, which is disallowed in EvalJs.
1519 bool use_automatic_reply = !(options & EXECUTE_SCRIPT_USE_MANUAL_REPLY);
1520 bool resolve_promises = !(options & EXECUTE_SCRIPT_NO_RESOLVE_PROMISES);
1521
1522 std::string token = "EvalJs-" + base::GenerateGUID();
1523 std::string runner_script = JsReplace(
1524 R"(Promise.resolve($1)
1525 .then(script => [window.eval(script)])
1526 .then((result) => $2 ? Promise.all(result) : result )
1527 .then((result) => $3 ? result : Promise.reject(),
1528 (error) => 'a JavaScript error:' +
1529 (error && error.stack ? '\n' + error.stack
1530 : ' "' + error + '"'))
1531 .then((reply) => window.domAutomationController.send([$4, reply]));
1532 //# sourceURL=EvalJs-runner.js)",
1533 modified_script, resolve_promises, use_automatic_reply, token);
1534
1535 bool user_gesture = !(options & EXECUTE_SCRIPT_NO_USER_GESTURE);
1536 std::ostringstream error_stream;
1537 std::unique_ptr<base::Value> response;
1538 if (!execution_target.render_frame_host()->IsRenderFrameLive()) {
1539 error_stream << "Error: EvalJs won't work on an already-crashed frame.";
1540 } else if (!ExecuteScriptHelper(execution_target.render_frame_host(),
1541 runner_script, user_gesture, world_id,
1542 &response)) {
1543 error_stream << "Internal Error: ExecuteScriptHelper failed";
1544 } else if (!response) {
1545 error_stream << "Internal Error: no value";
1546 } else {
1547 bool is_reply_from_runner_script =
1548 response->is_list() && response->GetList().size() == 2 &&
1549 response->GetList()[0].is_string() &&
1550 response->GetList()[0].GetString() == token;
1551
1552 bool is_error =
1553 is_reply_from_runner_script && response->GetList()[1].is_string();
1554 bool is_automatic_success_reply =
1555 is_reply_from_runner_script && response->GetList()[1].is_list() &&
1556 response->GetList()[1].GetList().size() == 1;
1557
1558 if (is_error) {
1559 // This is a response generated by the error handler in our runner
1560 // script. This occurs when the script throws an exception, or when
1561 // eval throws a SyntaxError.
1562 //
1563 // Parse the stack trace here, and interleave lines of source code from
1564 // |script| to aid debugging.
1565 std::string error_text = response->GetList()[1].GetString();
1566
1567 if (base::StartsWith(error_text,
1568 "a JavaScript error:\nEvalError: Refused",
1569 base::CompareCase::SENSITIVE)) {
1570 error_text =
1571 "EvalJs encountered an EvalError, because eval() is blocked by the "
1572 "document's CSP on this page. To test content that is protected by "
1573 "CSP, consider using EvalJs with an isolated world. Details: " +
1574 error_text;
1575 }
1576
1577 CHECK(!error_text.empty());
1578 error_stream << AnnotateAndAdjustJsStackTraces(error_text, kSourceURL,
1579 script, 0);
1580 } else if (!use_automatic_reply) {
1581 // When |script| itself calls domAutomationController.send() on success,
1582 // |response| could be anything; so there's no more checking we can do:
1583 // return |response| as success, with an empty error.
1584 return EvalJsResult(std::move(*response), std::string());
1585 } else if (is_automatic_success_reply) {
1586 // Got a response from the runner script that indicates success (of the
1587 // form [token, [completion_value]]. Return the completion value, with an
1588 // empty error.
1589 return EvalJsResult(std::move(response->GetList()[1].GetList()[0]),
1590 std::string());
1591 } else {
1592 // The response was not well-formed (it failed the token match), so it's
1593 // not from our runner script. Fail with an explanation of the raw
1594 // message. This allows us to reject other calls
1595 // domAutomationController.send().
1596 error_stream
1597 << "Internal Error: expected a 2-element list of the form "
1598 << "['" << token << "', [result]]; but got instead: " << *response
1599 << " ... This is potentially because a script tried to call "
1600 "domAutomationController.send itself -- that is only allowed "
1601 "when using EvalJsWithManualReply(). When using EvalJs(), result "
1602 "values are just the result of calling eval() on the script -- "
1603 "the completion value is the value of the last executed "
1604 "statement. When using ExecJs(), there is no result value.";
1605 }
1606 }
1607
1608 // Something went wrong. Return an empty value and a non-empty error.
1609 return EvalJsResult(base::Value(), error_stream.str());
1610}
1611
1612EvalJsResult EvalJsWithManualReply(const ToRenderFrameHost& execution_target,
1613 const std::string& script,
1614 int options,
1615 int world_id) {
1616 return EvalJs(execution_target, script,
1617 options | EXECUTE_SCRIPT_USE_MANUAL_REPLY, world_id);
1618}
1619
[email protected]67048bd2014-03-18 07:32:351620namespace {
1621void AddToSetIfFrameMatchesPredicate(
1622 std::set<RenderFrameHost*>* frame_set,
1623 const base::Callback<bool(RenderFrameHost*)>& predicate,
1624 RenderFrameHost* host) {
1625 if (predicate.Run(host))
1626 frame_set->insert(host);
1627}
1628}
1629
1630RenderFrameHost* FrameMatchingPredicate(
1631 WebContents* web_contents,
1632 const base::Callback<bool(RenderFrameHost*)>& predicate) {
1633 std::set<RenderFrameHost*> frame_set;
Lei Zhangebcc6302018-01-12 19:46:451634 web_contents->ForEachFrame(base::BindRepeating(
1635 &AddToSetIfFrameMatchesPredicate, &frame_set, predicate));
lukasza424c0452017-05-03 16:08:241636 EXPECT_EQ(1U, frame_set.size());
1637 return frame_set.size() == 1 ? *frame_set.begin() : nullptr;
[email protected]67048bd2014-03-18 07:32:351638}
1639
1640bool FrameMatchesName(const std::string& name, RenderFrameHost* frame) {
1641 return frame->GetFrameName() == name;
1642}
1643
[email protected]18fb4692014-03-20 00:47:171644bool FrameIsChildOfMainFrame(RenderFrameHost* frame) {
1645 return frame->GetParent() && !frame->GetParent()->GetParent();
1646}
1647
[email protected]2f7a3992014-03-20 22:53:241648bool FrameHasSourceUrl(const GURL& url, RenderFrameHost* frame) {
1649 return frame->GetLastCommittedURL() == url;
1650}
1651
alexmosaf3efeb2016-04-12 07:17:391652RenderFrameHost* ChildFrameAt(RenderFrameHost* frame, size_t index) {
1653 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(frame);
1654 if (index >= rfh->frame_tree_node()->child_count())
1655 return nullptr;
1656 return rfh->frame_tree_node()->child_at(index)->current_frame_host();
1657}
1658
[email protected]ff4657ee2014-03-15 01:08:151659bool ExecuteWebUIResourceTest(WebContents* web_contents,
1660 const std::vector<int>& js_resource_ids) {
[email protected]c2791c1a2013-08-22 07:18:351661 // Inject WebUI test runner script first prior to other scripts required to
1662 // run the test as scripts may depend on it being declared.
1663 std::vector<int> ids;
1664 ids.push_back(IDR_WEBUI_JS_WEBUI_RESOURCE_TEST);
1665 ids.insert(ids.end(), js_resource_ids.begin(), js_resource_ids.end());
1666
1667 std::string script;
Lei Zhang0fe3176e2017-11-01 05:30:081668 for (int id : ids) {
dbeam49dab442016-08-20 00:49:521669 scoped_refptr<base::RefCountedMemory> bytes =
Lei Zhang0fe3176e2017-11-01 05:30:081670 ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes(id);
dbeam49dab442016-08-20 00:49:521671
1672 if (HasGzipHeader(*bytes))
1673 AppendGzippedResource(*bytes, &script);
1674 else
1675 script.append(bytes->front_as<char>(), bytes->size());
1676
[email protected]c2791c1a2013-08-22 07:18:351677 script.append("\n");
1678 }
lukaszac7d6bd32017-07-11 00:19:311679 ExecuteScriptAsync(web_contents, script);
[email protected]c2791c1a2013-08-22 07:18:351680
[email protected]67048bd2014-03-18 07:32:351681 DOMMessageQueue message_queue;
Luciano Pacheco034fd9d2018-09-19 01:18:401682
1683 bool should_wait_flag =
1684 base::CommandLine::ForCurrentProcess()->HasSwitch(kWaitForDebuggerWebUI);
1685
Christopher Lam4d3266c12018-12-17 01:49:441686 if (should_wait_flag) {
Luciano Pacheco034fd9d2018-09-19 01:18:401687 ExecuteScriptAsync(
1688 web_contents,
1689 "window.waitUser = true; "
1690 "window.go = function() { window.waitUser = false }; "
1691 "console.log('Waiting for debugger...'); "
1692 "console.log('Run: go() in the JS console when you are ready.');");
1693 }
1694
lukaszac7d6bd32017-07-11 00:19:311695 ExecuteScriptAsync(web_contents, "runTests()");
[email protected]c2791c1a2013-08-22 07:18:351696
1697 std::string message;
1698 do {
1699 if (!message_queue.WaitForMessage(&message))
1700 return false;
1701 } while (message.compare("\"PENDING\"") == 0);
1702
1703 return message.compare("\"SUCCESS\"") == 0;
1704}
1705
[email protected]88509ab2012-08-27 15:04:141706std::string GetCookies(BrowserContext* browser_context, const GURL& url) {
1707 std::string cookies;
Randy Smithe23356c22017-11-14 01:41:501708 base::RunLoop run_loop;
1709 network::mojom::CookieManagerPtr cookie_manager;
1710 BrowserContext::GetDefaultStoragePartition(browser_context)
1711 ->GetNetworkContext()
1712 ->GetCookieManager(mojo::MakeRequest(&cookie_manager));
1713 cookie_manager->GetCookieList(
1714 url, net::CookieOptions(),
Joshua Bell1d432be2018-06-27 19:59:481715 base::BindOnce(
1716 [](std::string* cookies_out, base::RunLoop* run_loop,
1717 const std::vector<net::CanonicalCookie>& cookies) {
1718 *cookies_out = net::CanonicalCookie::BuildCookieLine(cookies);
1719 run_loop->Quit();
1720 },
1721 &cookies, &run_loop));
1722 run_loop.Run();
1723 return cookies;
1724}
1725
1726std::vector<net::CanonicalCookie> GetCanonicalCookies(
1727 BrowserContext* browser_context,
1728 const GURL& url) {
1729 std::vector<net::CanonicalCookie> cookies;
1730 base::RunLoop run_loop;
1731 network::mojom::CookieManagerPtr cookie_manager;
1732 BrowserContext::GetDefaultStoragePartition(browser_context)
1733 ->GetNetworkContext()
1734 ->GetCookieManager(mojo::MakeRequest(&cookie_manager));
1735 cookie_manager->GetCookieList(
1736 url, net::CookieOptions(),
1737 base::BindOnce(
1738 [](base::RunLoop* run_loop,
1739 std::vector<net::CanonicalCookie>* cookies_out,
1740 const std::vector<net::CanonicalCookie>& cookies) {
1741 *cookies_out = cookies;
1742 run_loop->Quit();
1743 },
1744 &run_loop, &cookies));
Randy Smithe23356c22017-11-14 01:41:501745 run_loop.Run();
[email protected]88509ab2012-08-27 15:04:141746 return cookies;
1747}
1748
[email protected]b561aab2012-08-27 20:17:491749bool SetCookie(BrowserContext* browser_context,
1750 const GURL& url,
1751 const std::string& value) {
1752 bool result = false;
Randy Smithe23356c22017-11-14 01:41:501753 base::RunLoop run_loop;
1754 network::mojom::CookieManagerPtr cookie_manager;
1755 BrowserContext::GetDefaultStoragePartition(browser_context)
1756 ->GetNetworkContext()
1757 ->GetCookieManager(mojo::MakeRequest(&cookie_manager));
1758 std::unique_ptr<net::CanonicalCookie> cc(net::CanonicalCookie::Create(
1759 url, value, base::Time::Now(), net::CookieOptions()));
1760 DCHECK(cc.get());
[email protected]b561aab2012-08-27 20:17:491761
Randy Smithe23356c22017-11-14 01:41:501762 cookie_manager->SetCanonicalCookie(
1763 *cc.get(), true /* secure_source */, true /* modify_http_only */,
Joshua Bell1d432be2018-06-27 19:59:481764 base::BindOnce(
1765 [](bool* result, base::RunLoop* run_loop, bool success) {
1766 *result = success;
1767 run_loop->Quit();
1768 },
1769 &result, &run_loop));
Randy Smithe23356c22017-11-14 01:41:501770 run_loop.Run();
[email protected]b561aab2012-08-27 20:17:491771 return result;
1772}
1773
[email protected]e7e9c862014-08-21 22:00:381774void FetchHistogramsFromChildProcesses() {
Wezf2311d72018-06-02 02:02:181775 base::RunLoop run_loop;
[email protected]e7e9c862014-08-21 22:00:381776
1777 FetchHistogramsAsynchronously(
Wezf2311d72018-06-02 02:02:181778 base::ThreadTaskRunnerHandle::Get(), run_loop.QuitClosure(),
[email protected]e7e9c862014-08-21 22:00:381779 // If this call times out, it means that a child process is not
1780 // responding, which is something we should not ignore. The timeout is
1781 // set to be longer than the normal browser test timeout so that it will
1782 // be prempted by the normal timeout.
1783 TestTimeouts::action_max_timeout());
Wezf2311d72018-06-02 02:02:181784 run_loop.Run();
[email protected]e7e9c862014-08-21 22:00:381785}
1786
svaldezc3a9a172015-11-03 22:01:331787void SetupCrossSiteRedirector(net::EmbeddedTestServer* embedded_test_server) {
martijn2037cd72016-11-10 20:11:321788 embedded_test_server->RegisterRequestHandler(
1789 base::Bind(&CrossSiteRedirectResponseHandler, embedded_test_server));
naskob00afd82014-10-03 05:48:591790}
1791
meacerb47bc8782014-10-07 03:40:011792void WaitForInterstitialAttach(content::WebContents* web_contents) {
1793 if (web_contents->ShowingInterstitialPage())
1794 return;
Wezf2311d72018-06-02 02:02:181795 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
1796 InterstitialObserver observer(web_contents, run_loop.QuitClosure(),
1797 base::OnceClosure());
1798 run_loop.Run();
meacerb47bc8782014-10-07 03:40:011799}
1800
1801void WaitForInterstitialDetach(content::WebContents* web_contents) {
David Benjamin5f4ec142018-12-19 16:44:241802 RunTaskAndWaitForInterstitialDetach(web_contents, base::OnceClosure());
meacerb47bc8782014-10-07 03:40:011803}
1804
1805void RunTaskAndWaitForInterstitialDetach(content::WebContents* web_contents,
David Benjamin5f4ec142018-12-19 16:44:241806 base::OnceClosure task) {
meacerb47bc8782014-10-07 03:40:011807 if (!web_contents || !web_contents->ShowingInterstitialPage())
1808 return;
Wezf2311d72018-06-02 02:02:181809 base::RunLoop run_loop;
1810 InterstitialObserver observer(web_contents, base::OnceClosure(),
1811 run_loop.QuitClosure());
meacerb47bc8782014-10-07 03:40:011812 if (!task.is_null())
David Benjamin5f4ec142018-12-19 16:44:241813 std::move(task).Run();
meacerb47bc8782014-10-07 03:40:011814 // At this point, web_contents may have been deleted.
Wezf2311d72018-06-02 02:02:181815 run_loop.Run();
meacerb47bc8782014-10-07 03:40:011816}
1817
meacer8543a232015-01-23 19:58:451818bool WaitForRenderFrameReady(RenderFrameHost* rfh) {
1819 if (!rfh)
1820 return false;
Nick Carterb7e71312018-08-03 23:36:131821 // TODO(nick): This can't switch to EvalJs yet, because of hardcoded
1822 // dependencies on 'pageLoadComplete' in some interstitial implementations.
meacer8543a232015-01-23 19:58:451823 std::string result;
Nick Carterb7e71312018-08-03 23:36:131824 EXPECT_TRUE(ExecuteScriptAndExtractString(
1825 rfh,
1826 "(async function() {"
1827 " if (document.readyState != 'complete') {"
1828 " await new Promise((resolve) =>"
1829 " document.addEventListener('readystatechange', event => {"
1830 " if (document.readyState == 'complete') {"
1831 " resolve();"
1832 " }"
1833 " }));"
1834 " }"
1835 "})().then(() => {"
1836 " window.domAutomationController.send('pageLoadComplete');"
1837 "});",
1838 &result));
1839 EXPECT_EQ("pageLoadComplete", result);
1840 return "pageLoadComplete" == result;
meacer8543a232015-01-23 19:58:451841}
1842
dmazzonifdfa2e02016-03-30 01:15:431843void EnableAccessibilityForWebContents(WebContents* web_contents) {
1844 WebContentsImpl* web_contents_impl =
1845 static_cast<WebContentsImpl*>(web_contents);
Doug Turner63f3c7b2017-07-29 05:10:011846 web_contents_impl->SetAccessibilityMode(ui::kAXModeComplete);
dmazzonifdfa2e02016-03-30 01:15:431847}
1848
1849void WaitForAccessibilityFocusChange() {
Wezf2311d72018-06-02 02:02:181850 base::RunLoop run_loop;
dmazzonifdfa2e02016-03-30 01:15:431851 BrowserAccessibilityManager::SetFocusChangeCallbackForTesting(
Wezf2311d72018-06-02 02:02:181852 run_loop.QuitClosure());
1853 run_loop.Run();
dmazzonifdfa2e02016-03-30 01:15:431854}
1855
1856ui::AXNodeData GetFocusedAccessibilityNodeInfo(WebContents* web_contents) {
1857 WebContentsImpl* web_contents_impl =
1858 static_cast<WebContentsImpl*>(web_contents);
1859 BrowserAccessibilityManager* manager =
1860 web_contents_impl->GetRootBrowserAccessibilityManager();
1861 if (!manager)
1862 return ui::AXNodeData();
1863 BrowserAccessibility* focused_node = manager->GetFocus();
1864 return focused_node->GetData();
1865}
1866
dmazzoni25af8422016-06-28 20:29:541867bool AccessibilityTreeContainsNodeWithName(BrowserAccessibility* node,
1868 const std::string& name) {
Dominic Mazzonidcef1b732018-01-26 17:57:041869 if (node->GetStringAttribute(ax::mojom::StringAttribute::kName) == name)
dmazzoni25af8422016-06-28 20:29:541870 return true;
1871 for (unsigned i = 0; i < node->PlatformChildCount(); i++) {
1872 if (AccessibilityTreeContainsNodeWithName(node->PlatformGetChild(i), name))
1873 return true;
1874 }
1875 return false;
1876}
1877
dmazzoni5a0018c92016-07-18 21:45:351878bool ListenToGuestWebContents(
1879 AccessibilityNotificationWaiter* accessibility_waiter,
1880 WebContents* web_contents) {
1881 accessibility_waiter->ListenToAdditionalFrame(
1882 static_cast<RenderFrameHostImpl*>(web_contents->GetMainFrame()));
1883 return true;
1884}
1885
dmazzoni25af8422016-06-28 20:29:541886void WaitForAccessibilityTreeToContainNodeWithName(WebContents* web_contents,
1887 const std::string& name) {
1888 WebContentsImpl* web_contents_impl = static_cast<WebContentsImpl*>(
1889 web_contents);
1890 RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
1891 web_contents_impl->GetMainFrame());
1892 BrowserAccessibilityManager* main_frame_manager =
1893 main_frame->browser_accessibility_manager();
1894 FrameTree* frame_tree = web_contents_impl->GetFrameTree();
dmazzoni5a0018c92016-07-18 21:45:351895 while (!main_frame_manager || !AccessibilityTreeContainsNodeWithName(
dmazzoni25af8422016-06-28 20:29:541896 main_frame_manager->GetRoot(), name)) {
Dominic Mazzonidcef1b732018-01-26 17:57:041897 AccessibilityNotificationWaiter accessibility_waiter(
1898 main_frame, ax::mojom::Event::kNone);
dmazzoni5a0018c92016-07-18 21:45:351899 for (FrameTreeNode* node : frame_tree->Nodes()) {
dmazzoni25af8422016-06-28 20:29:541900 accessibility_waiter.ListenToAdditionalFrame(
1901 node->current_frame_host());
dmazzoni5a0018c92016-07-18 21:45:351902 }
1903
1904 content::BrowserPluginGuestManager* guest_manager =
1905 web_contents_impl->GetBrowserContext()->GetGuestManager();
1906 if (guest_manager) {
1907 guest_manager->ForEachGuest(web_contents_impl,
Mark Pilgrimd84121732018-03-22 14:12:121908 base::BindRepeating(&ListenToGuestWebContents,
1909 &accessibility_waiter));
dmazzoni5a0018c92016-07-18 21:45:351910 }
dmazzoni25af8422016-06-28 20:29:541911
1912 accessibility_waiter.WaitForNotification();
dmazzoni5a0018c92016-07-18 21:45:351913 main_frame_manager = main_frame->browser_accessibility_manager();
dmazzoni25af8422016-06-28 20:29:541914 }
1915}
1916
1917ui::AXTreeUpdate GetAccessibilityTreeSnapshot(WebContents* web_contents) {
1918 WebContentsImpl* web_contents_impl =
1919 static_cast<WebContentsImpl*>(web_contents);
1920 BrowserAccessibilityManager* manager =
1921 web_contents_impl->GetRootBrowserAccessibilityManager();
1922 if (!manager)
1923 return ui::AXTreeUpdate();
1924 return manager->SnapshotAXTreeForTesting();
1925}
1926
wjmacleanb65ea792016-07-07 22:17:071927bool IsWebContentsBrowserPluginFocused(content::WebContents* web_contents) {
1928 WebContentsImpl* web_contents_impl =
1929 static_cast<WebContentsImpl*>(web_contents);
1930 BrowserPluginGuest* browser_plugin_guest =
1931 web_contents_impl->GetBrowserPluginGuest();
1932 return browser_plugin_guest ? browser_plugin_guest->focused() : false;
1933}
1934
lfge2176fb2017-03-26 00:45:471935RenderWidgetHost* GetMouseLockWidget(WebContents* web_contents) {
1936 return static_cast<WebContentsImpl*>(web_contents)->GetMouseLockWidget();
1937}
1938
Joe Downinga7235f92018-05-30 22:40:521939RenderWidgetHost* GetKeyboardLockWidget(WebContents* web_contents) {
1940 return static_cast<WebContentsImpl*>(web_contents)->GetKeyboardLockWidget();
1941}
1942
Ken Buchanand1d30d12018-10-04 22:48:041943RenderWidgetHost* GetMouseCaptureWidget(WebContents* web_contents) {
1944 return static_cast<WebContentsImpl*>(web_contents)
1945 ->GetInputEventRouter()
1946 ->GetMouseCaptureWidgetForTests();
1947}
1948
Joe Downing899268242018-06-01 05:52:241949bool RequestKeyboardLock(WebContents* web_contents,
1950 base::Optional<base::flat_set<ui::DomCode>> codes) {
1951 DCHECK(!codes.has_value() || !codes.value().empty());
1952 WebContentsImpl* web_contents_impl =
1953 static_cast<WebContentsImpl*>(web_contents);
1954 RenderWidgetHostImpl* render_widget_host_impl =
1955 web_contents_impl->GetMainFrame()->GetRenderWidgetHost();
1956 return render_widget_host_impl->RequestKeyboardLock(std::move(codes));
1957}
1958
1959void CancelKeyboardLock(WebContents* web_contents) {
1960 WebContentsImpl* web_contents_impl =
1961 static_cast<WebContentsImpl*>(web_contents);
1962 RenderWidgetHostImpl* render_widget_host_impl =
1963 web_contents_impl->GetMainFrame()->GetRenderWidgetHost();
1964 render_widget_host_impl->CancelKeyboardLock();
1965}
1966
lfg1453e412017-04-11 00:48:501967bool IsInnerInterstitialPageConnected(InterstitialPage* interstitial_page) {
1968 InterstitialPageImpl* impl =
1969 static_cast<InterstitialPageImpl*>(interstitial_page);
1970
1971 RenderWidgetHostViewBase* rwhvb =
1972 static_cast<RenderWidgetHostViewBase*>(impl->GetView());
1973 EXPECT_TRUE(rwhvb->IsRenderWidgetHostViewChildFrame());
1974 RenderWidgetHostViewChildFrame* rwhvcf =
1975 static_cast<RenderWidgetHostViewChildFrame*>(rwhvb);
1976
1977 CrossProcessFrameConnector* frame_connector =
Ken Buchanandaef006b2017-08-17 18:32:151978 static_cast<CrossProcessFrameConnector*>(
1979 rwhvcf->FrameConnectorForTesting());
lfg1453e412017-04-11 00:48:501980
1981 WebContentsImpl* inner_web_contents =
1982 static_cast<WebContentsImpl*>(impl->GetWebContents());
1983 FrameTreeNode* outer_node = FrameTreeNode::GloballyFindByID(
1984 inner_web_contents->GetOuterDelegateFrameTreeNodeId());
1985
1986 return outer_node->current_frame_host()->GetView() ==
1987 frame_connector->GetParentRenderWidgetHostView();
1988}
1989
Evan Stadef96e8132018-10-18 18:55:381990ScreenOrientationDelegate* GetScreenOrientationDelegate() {
1991 return ScreenOrientationProvider::GetDelegateForTesting();
1992}
1993
lfg1453e412017-04-11 00:48:501994std::vector<RenderWidgetHostView*> GetInputEventRouterRenderWidgetHostViews(
1995 WebContents* web_contents) {
1996 return static_cast<WebContentsImpl*>(web_contents)
1997 ->GetInputEventRouter()
1998 ->GetRenderWidgetHostViewsForTests();
1999}
2000
2001RenderWidgetHost* GetFocusedRenderWidgetHost(WebContents* web_contents) {
2002 WebContentsImpl* web_contents_impl =
2003 static_cast<WebContentsImpl*>(web_contents);
2004 return web_contents_impl->GetFocusedRenderWidgetHost(
2005 web_contents_impl->GetMainFrame()->GetRenderWidgetHost());
2006}
2007
Lucas Furukawa Gadaniabbfa342017-08-29 19:37:572008WebContents* GetFocusedWebContents(WebContents* web_contents) {
2009 WebContentsImpl* web_contents_impl =
2010 static_cast<WebContentsImpl*>(web_contents);
2011 return web_contents_impl->GetFocusedWebContents();
2012}
2013
lfg1453e412017-04-11 00:48:502014void RouteMouseEvent(WebContents* web_contents, blink::WebMouseEvent* event) {
2015 WebContentsImpl* web_contents_impl =
2016 static_cast<WebContentsImpl*>(web_contents);
2017 web_contents_impl->GetInputEventRouter()->RouteMouseEvent(
2018 static_cast<RenderWidgetHostViewBase*>(
2019 web_contents_impl->GetMainFrame()->GetView()),
2020 event, ui::LatencyInfo());
2021}
2022
wjmacleanb65ea792016-07-07 22:17:072023#if defined(USE_AURA)
2024void SendRoutedTouchTapSequence(content::WebContents* web_contents,
2025 gfx::Point point) {
2026 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
2027 web_contents->GetRenderWidgetHostView());
lanwei64725672017-03-16 20:56:052028 ui::TouchEvent touch_start(
2029 ui::ET_TOUCH_PRESSED, point, base::TimeTicks::Now(),
2030 ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
wjmacleanb65ea792016-07-07 22:17:072031 rwhva->OnTouchEvent(&touch_start);
lanwei64725672017-03-16 20:56:052032 ui::TouchEvent touch_end(
2033 ui::ET_TOUCH_RELEASED, point, base::TimeTicks::Now(),
2034 ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
wjmacleanb65ea792016-07-07 22:17:072035 rwhva->OnTouchEvent(&touch_end);
2036}
2037
2038void SendRoutedGestureTapSequence(content::WebContents* web_contents,
2039 gfx::Point point) {
2040 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
2041 web_contents->GetRenderWidgetHostView());
2042 ui::GestureEventDetails gesture_tap_down_details(ui::ET_GESTURE_TAP_DOWN);
Xida Chen2eec314f2018-06-07 11:42:422043 gesture_tap_down_details.set_is_source_touch_event_set_non_blocking(true);
wjmacleanb65ea792016-07-07 22:17:072044 gesture_tap_down_details.set_device_type(
2045 ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
2046 ui::GestureEvent gesture_tap_down(point.x(), point.y(), 0,
2047 base::TimeTicks::Now(),
2048 gesture_tap_down_details);
2049 rwhva->OnGestureEvent(&gesture_tap_down);
2050 ui::GestureEventDetails gesture_tap_details(ui::ET_GESTURE_TAP);
Xida Chen2eec314f2018-06-07 11:42:422051 gesture_tap_details.set_is_source_touch_event_set_non_blocking(true);
wjmacleanb65ea792016-07-07 22:17:072052 gesture_tap_details.set_device_type(
2053 ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
2054 gesture_tap_details.set_tap_count(1);
2055 ui::GestureEvent gesture_tap(point.x(), point.y(), 0, base::TimeTicks::Now(),
2056 gesture_tap_details);
2057 rwhva->OnGestureEvent(&gesture_tap);
2058}
2059
kenrb66c46292017-04-03 18:47:362060#endif
2061
wjmacleanb65ea792016-07-07 22:17:072062namespace {
2063
jonross068adbc2018-05-30 18:04:472064RenderFrameMetadataProvider* RenderFrameMetadataProviderFromFrameTreeNode(
2065 FrameTreeNode* node) {
2066 DCHECK(node);
2067 DCHECK(node->current_frame_host());
2068 DCHECK(node->current_frame_host()->GetRenderWidgetHost());
2069 return node->current_frame_host()
2070 ->GetRenderWidgetHost()
2071 ->render_frame_metadata_provider();
2072}
2073
jonross36545cf2018-02-23 19:50:352074RenderFrameMetadataProvider* RenderFrameMetadataProviderFromWebContents(
2075 WebContents* web_contents) {
Eric Seckler4f0eb9fa2018-03-01 11:23:212076 DCHECK(web_contents);
2077 DCHECK(web_contents->GetRenderViewHost());
2078 DCHECK(
2079 RenderWidgetHostImpl::From(web_contents->GetRenderViewHost()->GetWidget())
2080 ->render_frame_metadata_provider());
jonross36545cf2018-02-23 19:50:352081 return RenderWidgetHostImpl::From(
2082 web_contents->GetRenderViewHost()->GetWidget())
2083 ->render_frame_metadata_provider();
2084}
2085
wjmacleanb65ea792016-07-07 22:17:072086} // namespace
2087
[email protected]35daebe02012-07-20 05:40:592088TitleWatcher::TitleWatcher(WebContents* web_contents,
[email protected]fcf75d42013-12-03 20:11:262089 const base::string16& expected_title)
ahest29276c32017-01-19 07:36:312090 : WebContentsObserver(web_contents) {
[email protected]35daebe02012-07-20 05:40:592091 expected_titles_.push_back(expected_title);
[email protected]35daebe02012-07-20 05:40:592092}
2093
[email protected]fcf75d42013-12-03 20:11:262094void TitleWatcher::AlsoWaitForTitle(const base::string16& expected_title) {
[email protected]35daebe02012-07-20 05:40:592095 expected_titles_.push_back(expected_title);
2096}
2097
2098TitleWatcher::~TitleWatcher() {
2099}
2100
[email protected]fcf75d42013-12-03 20:11:262101const base::string16& TitleWatcher::WaitAndGetTitle() {
[email protected]b17eb8e42014-02-07 01:20:372102 TestTitle();
ahest29276c32017-01-19 07:36:312103 run_loop_.Run();
[email protected]35daebe02012-07-20 05:40:592104 return observed_title_;
2105}
2106
fdegans6ce28f52015-03-19 12:52:222107void TitleWatcher::DidStopLoading() {
[email protected]66798902013-10-01 18:40:162108 // When navigating through the history, the restored NavigationEntry's title
2109 // will be used. If the entry ends up having the same title after we return
2110 // to it, as will usually be the case, then WebContentsObserver::TitleSet
2111 // will then be suppressed, since the NavigationEntry's title hasn't changed.
2112 TestTitle();
2113}
[email protected]35daebe02012-07-20 05:40:592114
Avi Drissman93002212017-09-27 03:20:522115void TitleWatcher::TitleWasSet(NavigationEntry* entry) {
[email protected]66798902013-10-01 18:40:162116 TestTitle();
2117}
2118
2119void TitleWatcher::TestTitle() {
ahest29276c32017-01-19 07:36:312120 const base::string16& current_title = web_contents()->GetTitle();
2121 if (base::ContainsValue(expected_titles_, current_title)) {
2122 observed_title_ = current_title;
2123 run_loop_.Quit();
2124 }
[email protected]35daebe02012-07-20 05:40:592125}
2126
[email protected]8ffad4e2014-01-02 23:18:262127RenderProcessHostWatcher::RenderProcessHostWatcher(
Wezf2311d72018-06-02 02:02:182128 RenderProcessHost* render_process_host,
2129 WatchType type)
[email protected]8ffad4e2014-01-02 23:18:262130 : render_process_host_(render_process_host),
2131 type_(type),
alexmos3c8c8a12015-04-13 20:51:392132 did_exit_normally_(true),
Wezf2311d72018-06-02 02:02:182133 quit_closure_(run_loop_.QuitClosure()) {
[email protected]8ffad4e2014-01-02 23:18:262134 render_process_host_->AddObserver(this);
2135}
2136
Lukasz Anforowiczf14b5452017-10-02 20:10:342137RenderProcessHostWatcher::RenderProcessHostWatcher(WebContents* web_contents,
2138 WatchType type)
Wezf2311d72018-06-02 02:02:182139 : RenderProcessHostWatcher(web_contents->GetMainFrame()->GetProcess(),
2140 type) {}
[email protected]8ffad4e2014-01-02 23:18:262141
2142RenderProcessHostWatcher::~RenderProcessHostWatcher() {
2143 if (render_process_host_)
2144 render_process_host_->RemoveObserver(this);
2145}
2146
2147void RenderProcessHostWatcher::Wait() {
Wezf2311d72018-06-02 02:02:182148 run_loop_.Run();
[email protected]8ffad4e2014-01-02 23:18:262149}
2150
2151void RenderProcessHostWatcher::RenderProcessExited(
2152 RenderProcessHost* host,
Bo Liu2a489402018-04-24 23:41:272153 const ChildProcessTerminationInfo& info) {
2154 did_exit_normally_ =
2155 info.status == base::TERMINATION_STATUS_NORMAL_TERMINATION;
[email protected]8ffad4e2014-01-02 23:18:262156 if (type_ == WATCH_FOR_PROCESS_EXIT)
Wezf2311d72018-06-02 02:02:182157 std::move(quit_closure_).Run();
[email protected]8ffad4e2014-01-02 23:18:262158}
2159
2160void RenderProcessHostWatcher::RenderProcessHostDestroyed(
2161 RenderProcessHost* host) {
Ivan Kotenkov2c0d2bb32017-11-01 15:41:282162 render_process_host_ = nullptr;
[email protected]8ffad4e2014-01-02 23:18:262163 if (type_ == WATCH_FOR_HOST_DESTRUCTION)
Wezf2311d72018-06-02 02:02:182164 std::move(quit_closure_).Run();
[email protected]8ffad4e2014-01-02 23:18:262165}
2166
[email protected]25ebc37b2014-03-24 21:34:482167DOMMessageQueue::DOMMessageQueue() {
[email protected]b5e34972012-09-26 03:50:232168 registrar_.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE,
2169 NotificationService::AllSources());
2170}
2171
lukaszaf1cf6922016-11-03 00:21:432172DOMMessageQueue::DOMMessageQueue(WebContents* web_contents)
2173 : WebContentsObserver(web_contents) {
2174 registrar_.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE,
2175 Source<WebContents>(web_contents));
2176}
2177
[email protected]b5e34972012-09-26 03:50:232178DOMMessageQueue::~DOMMessageQueue() {}
2179
2180void DOMMessageQueue::Observe(int type,
2181 const NotificationSource& source,
2182 const NotificationDetails& details) {
avi60bd4902015-09-23 20:39:242183 Details<std::string> dom_op_result(details);
2184 message_queue_.push(*dom_op_result.ptr());
Wezf2311d72018-06-02 02:02:182185 if (quit_closure_)
2186 std::move(quit_closure_).Run();
[email protected]b5e34972012-09-26 03:50:232187}
2188
lukaszaf1cf6922016-11-03 00:21:432189void DOMMessageQueue::RenderProcessGone(base::TerminationStatus status) {
vasiliib50cee4c92017-03-31 11:53:142190 VLOG(0) << "DOMMessageQueue::RenderProcessGone " << status;
lukaszaf1cf6922016-11-03 00:21:432191 switch (status) {
2192 case base::TERMINATION_STATUS_NORMAL_TERMINATION:
2193 case base::TERMINATION_STATUS_STILL_RUNNING:
2194 break;
2195 default:
lukaszac7d6bd32017-07-11 00:19:312196 renderer_crashed_ = true;
Wezf2311d72018-06-02 02:02:182197 if (quit_closure_)
2198 std::move(quit_closure_).Run();
lukaszaf1cf6922016-11-03 00:21:432199 break;
2200 }
2201}
2202
[email protected]b5e34972012-09-26 03:50:232203void DOMMessageQueue::ClearQueue() {
Brett Wilsoncc8623d2017-09-12 03:28:102204 message_queue_ = base::queue<std::string>();
[email protected]b5e34972012-09-26 03:50:232205}
2206
2207bool DOMMessageQueue::WaitForMessage(std::string* message) {
[email protected]25ebc37b2014-03-24 21:34:482208 DCHECK(message);
lukaszac7d6bd32017-07-11 00:19:312209 if (!renderer_crashed_ && message_queue_.empty()) {
[email protected]b5e34972012-09-26 03:50:232210 // This will be quit when a new message comes in.
Wezf2311d72018-06-02 02:02:182211 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
2212 quit_closure_ = run_loop.QuitClosure();
2213 run_loop.Run();
[email protected]b5e34972012-09-26 03:50:232214 }
lukaszad4d9b1032016-12-10 03:38:122215 return PopMessage(message);
2216}
2217
2218bool DOMMessageQueue::PopMessage(std::string* message) {
2219 DCHECK(message);
lukaszac7d6bd32017-07-11 00:19:312220 if (renderer_crashed_ || message_queue_.empty())
[email protected]b5e34972012-09-26 03:50:232221 return false;
[email protected]25ebc37b2014-03-24 21:34:482222 *message = message_queue_.front();
[email protected]eb6a3922013-06-21 22:03:522223 message_queue_.pop();
[email protected]b5e34972012-09-26 03:50:232224 return true;
2225}
2226
nick7bb1c5c72014-12-24 01:37:192227class WebContentsAddedObserver::RenderViewCreatedObserver
2228 : public WebContentsObserver {
2229 public:
2230 explicit RenderViewCreatedObserver(WebContents* web_contents)
2231 : WebContentsObserver(web_contents),
2232 render_view_created_called_(false),
2233 main_frame_created_called_(false) {}
2234
2235 // WebContentsObserver:
2236 void RenderViewCreated(RenderViewHost* rvh) override {
2237 render_view_created_called_ = true;
2238 }
2239
2240 void RenderFrameCreated(RenderFrameHost* rfh) override {
2241 if (rfh == web_contents()->GetMainFrame())
2242 main_frame_created_called_ = true;
2243 }
2244
2245 bool render_view_created_called_;
2246 bool main_frame_created_called_;
2247};
2248
2249WebContentsAddedObserver::WebContentsAddedObserver()
2250 : web_contents_created_callback_(
2251 base::Bind(&WebContentsAddedObserver::WebContentsCreated,
2252 base::Unretained(this))),
Ivan Kotenkov2c0d2bb32017-11-01 15:41:282253 web_contents_(nullptr) {
benwells5e7260d2017-03-20 23:36:332254 WebContentsImpl::FriendWrapper::AddCreatedCallbackForTesting(
nick7bb1c5c72014-12-24 01:37:192255 web_contents_created_callback_);
2256}
2257
2258WebContentsAddedObserver::~WebContentsAddedObserver() {
benwells5e7260d2017-03-20 23:36:332259 WebContentsImpl::FriendWrapper::RemoveCreatedCallbackForTesting(
nick7bb1c5c72014-12-24 01:37:192260 web_contents_created_callback_);
2261}
2262
2263void WebContentsAddedObserver::WebContentsCreated(WebContents* web_contents) {
2264 DCHECK(!web_contents_);
2265 web_contents_ = web_contents;
2266 child_observer_.reset(new RenderViewCreatedObserver(web_contents));
2267
Wezf2311d72018-06-02 02:02:182268 if (quit_closure_)
2269 std::move(quit_closure_).Run();
nick7bb1c5c72014-12-24 01:37:192270}
2271
2272WebContents* WebContentsAddedObserver::GetWebContents() {
2273 if (web_contents_)
2274 return web_contents_;
2275
Wezf2311d72018-06-02 02:02:182276 base::RunLoop run_loop;
2277 quit_closure_ = run_loop.QuitClosure();
2278 run_loop.Run();
nick7bb1c5c72014-12-24 01:37:192279 return web_contents_;
2280}
2281
2282bool WebContentsAddedObserver::RenderViewCreatedCalled() {
2283 if (child_observer_) {
2284 return child_observer_->render_view_created_called_ &&
2285 child_observer_->main_frame_created_called_;
2286 }
2287 return false;
2288}
2289
Gennady Sushko1fbd57fa2017-10-25 20:28:172290WebContentsDestroyedObserver::WebContentsDestroyedObserver(
2291 WebContents* web_contents)
2292 : WebContentsObserver(web_contents) {
2293 DCHECK(web_contents);
2294}
2295
2296WebContentsDestroyedObserver::~WebContentsDestroyedObserver() {}
2297
2298void WebContentsDestroyedObserver::WebContentsDestroyed() {
2299 destroyed_ = true;
2300}
2301
wjmaclean6aefc3a2015-06-22 21:58:292302bool RequestFrame(WebContents* web_contents) {
2303 DCHECK(web_contents);
avif9ab5d942015-10-15 14:05:442304 return RenderWidgetHostImpl::From(
2305 web_contents->GetRenderViewHost()->GetWidget())
Fady Samuel3798e6d52018-05-02 17:06:252306 ->RequestRepaintForTesting();
wjmaclean6aefc3a2015-06-22 21:58:292307}
2308
jonrossa2ff4f82018-02-16 17:27:462309RenderFrameSubmissionObserver::RenderFrameSubmissionObserver(
2310 RenderFrameMetadataProvider* render_frame_metadata_provider)
2311 : render_frame_metadata_provider_(render_frame_metadata_provider) {
2312 render_frame_metadata_provider_->AddObserver(this);
2313 render_frame_metadata_provider_->ReportAllFrameSubmissionsForTesting(true);
2314}
2315
jonross36545cf2018-02-23 19:50:352316RenderFrameSubmissionObserver::RenderFrameSubmissionObserver(
jonross068adbc2018-05-30 18:04:472317 FrameTreeNode* node)
2318 : RenderFrameSubmissionObserver(
2319 RenderFrameMetadataProviderFromFrameTreeNode(node)) {}
2320
2321RenderFrameSubmissionObserver::RenderFrameSubmissionObserver(
jonross36545cf2018-02-23 19:50:352322 WebContents* web_contents)
2323 : RenderFrameSubmissionObserver(
2324 RenderFrameMetadataProviderFromWebContents(web_contents)) {}
2325
jonrossa2ff4f82018-02-16 17:27:462326RenderFrameSubmissionObserver::~RenderFrameSubmissionObserver() {
2327 render_frame_metadata_provider_->RemoveObserver(this);
2328 render_frame_metadata_provider_->ReportAllFrameSubmissionsForTesting(false);
2329}
2330
jonross36545cf2018-02-23 19:50:352331void RenderFrameSubmissionObserver::WaitForAnyFrameSubmission() {
2332 break_on_any_frame_ = true;
2333 Wait();
2334 break_on_any_frame_ = false;
2335}
2336
2337void RenderFrameSubmissionObserver::WaitForMetadataChange() {
2338 Wait();
2339}
2340
W. James MacLean2a90bff2018-11-05 20:52:472341void RenderFrameSubmissionObserver::WaitForPageScaleFactor(
2342 float expected_page_scale_factor,
2343 const float tolerance) {
2344 while (std::abs(render_frame_metadata_provider_->LastRenderFrameMetadata()
2345 .page_scale_factor -
2346 expected_page_scale_factor) < tolerance) {
2347 WaitForMetadataChange();
2348 }
2349}
2350
2351void RenderFrameSubmissionObserver::WaitForExternalPageScaleFactor(
2352 float expected_external_page_scale_factor,
2353 const float tolerance) {
2354 while (std::abs(render_frame_metadata_provider_->LastRenderFrameMetadata()
2355 .external_page_scale_factor -
2356 expected_external_page_scale_factor) < tolerance) {
2357 WaitForMetadataChange();
2358 }
2359}
2360
jonross082707af42018-03-23 14:14:302361void RenderFrameSubmissionObserver::WaitForScrollOffset(
2362 const gfx::Vector2dF& expected_offset) {
2363 while (render_frame_metadata_provider_->LastRenderFrameMetadata()
2364 .root_scroll_offset != expected_offset) {
2365 WaitForMetadataChange();
2366 }
2367}
2368
yiyix5989c742018-04-06 19:13:162369void RenderFrameSubmissionObserver::WaitForScrollOffsetAtTop(
2370 bool expected_scroll_offset_at_top) {
2371 while (render_frame_metadata_provider_->LastRenderFrameMetadata()
2372 .is_scroll_offset_at_top != expected_scroll_offset_at_top) {
2373 WaitForMetadataChange();
2374 }
2375}
2376
jonross36545cf2018-02-23 19:50:352377const cc::RenderFrameMetadata&
2378RenderFrameSubmissionObserver::LastRenderFrameMetadata() const {
2379 return render_frame_metadata_provider_->LastRenderFrameMetadata();
jonrossa2ff4f82018-02-16 17:27:462380}
2381
2382void RenderFrameSubmissionObserver::Quit() {
Wezf2311d72018-06-02 02:02:182383 if (quit_closure_)
2384 std::move(quit_closure_).Run();
jonrossa2ff4f82018-02-16 17:27:462385}
2386
jonross36545cf2018-02-23 19:50:352387void RenderFrameSubmissionObserver::Wait() {
Wezf2311d72018-06-02 02:02:182388 base::RunLoop run_loop;
2389 quit_closure_ = run_loop.QuitClosure();
2390 run_loop.Run();
jonross36545cf2018-02-23 19:50:352391}
2392
Fady Samuel365f2932018-06-24 14:14:502393void RenderFrameSubmissionObserver::
2394 OnRenderFrameMetadataChangedBeforeActivation(
2395 const cc::RenderFrameMetadata& metadata) {}
2396
2397void RenderFrameSubmissionObserver::
2398 OnRenderFrameMetadataChangedAfterActivation() {
jonross36545cf2018-02-23 19:50:352399 Quit();
2400}
jonrossa2ff4f82018-02-16 17:27:462401
2402void RenderFrameSubmissionObserver::OnRenderFrameSubmission() {
Eric Seckler4f0eb9fa2018-03-01 11:23:212403 render_frame_count_++;
jonross36545cf2018-02-23 19:50:352404 if (break_on_any_frame_)
2405 Quit();
jonrossa2ff4f82018-02-16 17:27:462406}
2407
Fady Samuelca9ecb72018-05-05 05:59:272408void RenderFrameSubmissionObserver::OnLocalSurfaceIdChanged(
2409 const cc::RenderFrameMetadata& metadata) {}
2410
lfg43e08e62016-02-03 18:51:372411MainThreadFrameObserver::MainThreadFrameObserver(
2412 RenderWidgetHost* render_widget_host)
2413 : render_widget_host_(render_widget_host),
2414 routing_id_(render_widget_host_->GetProcess()->GetNextRoutingID()) {
2415 // TODO(lfg): We should look into adding a way to observe RenderWidgetHost
2416 // messages similarly to what WebContentsObserver can do with RFH and RVW.
2417 render_widget_host_->GetProcess()->AddRoute(routing_id_, this);
2418}
2419
2420MainThreadFrameObserver::~MainThreadFrameObserver() {
2421 render_widget_host_->GetProcess()->RemoveRoute(routing_id_);
2422}
2423
2424void MainThreadFrameObserver::Wait() {
2425 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Albert J. Wong3c93c182018-09-27 17:29:432426 render_widget_host_->Send(new WidgetMsg_WaitForNextFrameForTests(
lfg43e08e62016-02-03 18:51:372427 render_widget_host_->GetRoutingID(), routing_id_));
Wezf2311d72018-06-02 02:02:182428 base::RunLoop run_loop;
2429 quit_closure_ = run_loop.QuitClosure();
2430 run_loop.Run();
lfg43e08e62016-02-03 18:51:372431}
2432
2433void MainThreadFrameObserver::Quit() {
Wezf2311d72018-06-02 02:02:182434 if (quit_closure_)
2435 std::move(quit_closure_).Run();
lfg43e08e62016-02-03 18:51:372436}
2437
2438bool MainThreadFrameObserver::OnMessageReceived(const IPC::Message& msg) {
Albert J. Wong3c93c182018-09-27 17:29:432439 if (msg.type() == WidgetHostMsg_WaitForNextFrameForTests_ACK::ID &&
lfg43e08e62016-02-03 18:51:372440 msg.routing_id() == routing_id_) {
Eric Seckler8652dcd52018-09-20 10:42:282441 base::PostTaskWithTraits(
2442 FROM_HERE, {BrowserThread::UI},
tzik874190512017-08-18 01:40:202443 base::BindOnce(&MainThreadFrameObserver::Quit, base::Unretained(this)));
lfg43e08e62016-02-03 18:51:372444 }
2445 return true;
2446}
2447
dtapuska0bd451a2016-02-18 17:08:102448InputMsgWatcher::InputMsgWatcher(RenderWidgetHost* render_widget_host,
2449 blink::WebInputEvent::Type type)
Dave Tapuskab1b6faa2017-10-23 21:54:232450 : render_widget_host_(render_widget_host),
dtapuska0bd451a2016-02-18 17:08:102451 wait_for_type_(type),
dtapuska120e9972016-11-07 20:13:392452 ack_result_(INPUT_EVENT_ACK_STATE_UNKNOWN),
Dave Tapuskab1b6faa2017-10-23 21:54:232453 ack_source_(InputEventAckSource::UNKNOWN) {
2454 render_widget_host->AddInputEventObserver(this);
dtapuska0bd451a2016-02-18 17:08:102455}
2456
Dave Tapuskab1b6faa2017-10-23 21:54:232457InputMsgWatcher::~InputMsgWatcher() {
2458 render_widget_host_->RemoveInputEventObserver(this);
2459}
dtapuska0bd451a2016-02-18 17:08:102460
Dave Tapuskab1b6faa2017-10-23 21:54:232461void InputMsgWatcher::OnInputEventAck(InputEventAckSource ack_source,
2462 InputEventAckState ack_state,
2463 const blink::WebInputEvent& event) {
2464 if (event.GetType() == wait_for_type_) {
dtapuska0bd451a2016-02-18 17:08:102465 ack_result_ = ack_state;
dtapuska120e9972016-11-07 20:13:392466 ack_source_ = ack_source;
Wezf2311d72018-06-02 02:02:182467 if (quit_closure_)
2468 std::move(quit_closure_).Run();
dtapuska0bd451a2016-02-18 17:08:102469 }
2470}
2471
samuong8db76012017-01-20 06:36:082472bool InputMsgWatcher::HasReceivedAck() const {
2473 return ack_result_ != INPUT_EVENT_ACK_STATE_UNKNOWN;
2474}
2475
Dave Tapuskab1b6faa2017-10-23 21:54:232476InputEventAckState InputMsgWatcher::WaitForAck() {
dtapuska0bd451a2016-02-18 17:08:102477 DCHECK_CURRENTLY_ON(BrowserThread::UI);
dtapuska0bd451a2016-02-18 17:08:102478 base::RunLoop run_loop;
Wezf2311d72018-06-02 02:02:182479 quit_closure_ = run_loop.QuitClosure();
dtapuska0bd451a2016-02-18 17:08:102480 run_loop.Run();
2481 return ack_result_;
2482}
2483
Dave Tapuska27e3e7c2017-10-25 13:14:552484InputEventAckState InputMsgWatcher::GetAckStateWaitIfNecessary() {
2485 if (HasReceivedAck())
2486 return ack_result_;
2487 return WaitForAck();
2488}
2489
Kevin McNeecbb8687a2017-11-14 19:10:592490InputEventAckWaiter::InputEventAckWaiter(RenderWidgetHost* render_widget_host,
2491 InputEventAckPredicate predicate)
2492 : render_widget_host_(render_widget_host),
2493 predicate_(predicate),
2494 event_received_(false) {
2495 render_widget_host_->AddInputEventObserver(this);
2496}
2497
2498namespace {
2499InputEventAckWaiter::InputEventAckPredicate EventAckHasType(
2500 blink::WebInputEvent::Type type) {
2501 return base::BindRepeating(
2502 [](blink::WebInputEvent::Type expected_type, InputEventAckSource source,
2503 InputEventAckState state, const blink::WebInputEvent& event) {
2504 return event.GetType() == expected_type;
2505 },
2506 type);
2507}
2508} // namespace
2509
2510InputEventAckWaiter::InputEventAckWaiter(RenderWidgetHost* render_widget_host,
2511 blink::WebInputEvent::Type type)
2512 : InputEventAckWaiter(render_widget_host, EventAckHasType(type)) {}
2513
2514InputEventAckWaiter::~InputEventAckWaiter() {
2515 render_widget_host_->RemoveInputEventObserver(this);
2516}
2517
2518void InputEventAckWaiter::Wait() {
2519 if (!event_received_) {
2520 base::RunLoop run_loop;
Wezf2311d72018-06-02 02:02:182521 quit_closure_ = run_loop.QuitClosure();
Kevin McNeecbb8687a2017-11-14 19:10:592522 run_loop.Run();
2523 }
2524}
2525
2526void InputEventAckWaiter::Reset() {
2527 event_received_ = false;
Wezf2311d72018-06-02 02:02:182528 quit_closure_ = base::OnceClosure();
Kevin McNeecbb8687a2017-11-14 19:10:592529}
2530
2531void InputEventAckWaiter::OnInputEventAck(InputEventAckSource source,
2532 InputEventAckState state,
2533 const blink::WebInputEvent& event) {
2534 if (predicate_.Run(source, state, event)) {
2535 event_received_ = true;
Wezf2311d72018-06-02 02:02:182536 if (quit_closure_)
2537 std::move(quit_closure_).Run();
Kevin McNeecbb8687a2017-11-14 19:10:592538 }
2539}
2540
Stuart Langleye8300012017-11-24 01:16:182541// TODO(dcheng): Make the test clipboard on different threads share the
2542// same backing store. crbug.com/629765
2543// TODO(slangley): crbug.com/775830 - Cleanup BrowserTestClipboardScope now that
2544// there is no need to thread hop for Windows.
2545BrowserTestClipboardScope::BrowserTestClipboardScope() {
dominicc4d8435d2016-07-22 03:43:342546 ui::TestClipboard::CreateForCurrentThread();
2547}
2548
Stuart Langleye8300012017-11-24 01:16:182549BrowserTestClipboardScope::~BrowserTestClipboardScope() {
dominicc4d8435d2016-07-22 03:43:342550 ui::Clipboard::DestroyClipboardForCurrentThread();
2551}
2552
dominicc4d8435d2016-07-22 03:43:342553void BrowserTestClipboardScope::SetRtf(const std::string& rtf) {
dominicc4d8435d2016-07-22 03:43:342554 ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
2555 clipboard_writer.WriteRTF(rtf);
2556}
2557
2558void BrowserTestClipboardScope::SetText(const std::string& text) {
dominicc4d8435d2016-07-22 03:43:342559 ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
2560 clipboard_writer.WriteText(base::ASCIIToUTF16(text));
2561}
2562
Stuart Langleye8300012017-11-24 01:16:182563void BrowserTestClipboardScope::GetText(std::string* result) {
2564 ui::Clipboard::GetForCurrentThread()->ReadAsciiText(
2565 ui::CLIPBOARD_TYPE_COPY_PASTE, result);
2566}
2567
avallee0206f782016-07-28 18:55:332568class FrameFocusedObserver::FrameTreeNodeObserverImpl
2569 : public FrameTreeNode::Observer {
2570 public:
Wezf2311d72018-06-02 02:02:182571 explicit FrameTreeNodeObserverImpl(FrameTreeNode* owner) : owner_(owner) {
avallee0206f782016-07-28 18:55:332572 owner->AddObserver(this);
2573 }
2574 ~FrameTreeNodeObserverImpl() override { owner_->RemoveObserver(this); }
2575
Wezf2311d72018-06-02 02:02:182576 void Run() { run_loop_.Run(); }
avallee0206f782016-07-28 18:55:332577
2578 void OnFrameTreeNodeFocused(FrameTreeNode* node) override {
2579 if (node == owner_)
Wezf2311d72018-06-02 02:02:182580 run_loop_.Quit();
avallee0206f782016-07-28 18:55:332581 }
2582
2583 private:
2584 FrameTreeNode* owner_;
Wezf2311d72018-06-02 02:02:182585 base::RunLoop run_loop_;
avallee0206f782016-07-28 18:55:332586};
2587
2588FrameFocusedObserver::FrameFocusedObserver(RenderFrameHost* owner_host)
2589 : impl_(new FrameTreeNodeObserverImpl(
2590 static_cast<RenderFrameHostImpl*>(owner_host)->frame_tree_node())) {}
2591
2592FrameFocusedObserver::~FrameFocusedObserver() {}
2593
2594void FrameFocusedObserver::Wait() {
2595 impl_->Run();
2596}
2597
Ria Jiang79f58ed922018-04-10 03:30:522598class FrameDeletedObserver::FrameTreeNodeObserverImpl
2599 : public FrameTreeNode::Observer {
2600 public:
2601 explicit FrameTreeNodeObserverImpl(FrameTreeNode* owner) : owner_(owner) {
2602 owner->AddObserver(this);
2603 }
2604 ~FrameTreeNodeObserverImpl() override = default;
2605
2606 void Run() { run_loop_.Run(); }
2607
2608 private:
2609 // FrameTreeNode::Observer
2610 void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override {
2611 if (node == owner_)
2612 run_loop_.Quit();
2613 }
2614
2615 FrameTreeNode* owner_;
2616 base::RunLoop run_loop_;
2617};
2618
2619FrameDeletedObserver::FrameDeletedObserver(RenderFrameHost* owner_host)
2620 : impl_(new FrameTreeNodeObserverImpl(
2621 static_cast<RenderFrameHostImpl*>(owner_host)->frame_tree_node())) {}
2622
2623FrameDeletedObserver::~FrameDeletedObserver() = default;
2624
2625void FrameDeletedObserver::Wait() {
2626 impl_->Run();
2627}
2628
csharrison4bd8a192016-08-02 18:03:152629TestNavigationManager::TestNavigationManager(WebContents* web_contents,
2630 const GURL& url)
2631 : WebContentsObserver(web_contents),
2632 url_(url),
csharrison4bd8a192016-08-02 18:03:152633 handle_(nullptr),
clamy19f0d492016-10-13 16:53:282634 navigation_paused_(false),
2635 current_state_(NavigationState::INITIAL),
2636 desired_state_(NavigationState::STARTED),
csharrison4bd8a192016-08-02 18:03:152637 weak_factory_(this) {}
2638
2639TestNavigationManager::~TestNavigationManager() {
clamy19f0d492016-10-13 16:53:282640 if (navigation_paused_)
Charles Harrison4f2bf1a2017-07-18 20:21:212641 handle_->CallResumeForTesting();
csharrison4bd8a192016-08-02 18:03:152642}
2643
clamy19f0d492016-10-13 16:53:282644bool TestNavigationManager::WaitForRequestStart() {
2645 // This is the default desired state. In PlzNavigate, a browser-initiated
2646 // navigation can reach this state synchronously, so the TestNavigationManager
2647 // is set to always pause navigations at WillStartRequest. This ensures the
2648 // user can always call WaitForWillStartRequest.
2649 DCHECK(desired_state_ == NavigationState::STARTED);
2650 return WaitForDesiredState();
csharrison4bd8a192016-08-02 18:03:152651}
2652
arthursonzogni85a04232017-09-28 18:14:192653void TestNavigationManager::ResumeNavigation() {
2654 DCHECK(current_state_ == NavigationState::STARTED ||
2655 current_state_ == NavigationState::RESPONSE);
2656 DCHECK_EQ(current_state_, desired_state_);
2657 DCHECK(navigation_paused_);
2658 navigation_paused_ = false;
2659 handle_->CallResumeForTesting();
2660}
2661
arthursonzogni3a4ca9f2017-12-07 17:58:342662NavigationHandle* TestNavigationManager::GetNavigationHandle() {
2663 return handle_;
2664}
2665
clamy19f0d492016-10-13 16:53:282666bool TestNavigationManager::WaitForResponse() {
2667 desired_state_ = NavigationState::RESPONSE;
2668 return WaitForDesiredState();
clamyd69748c2016-10-07 22:09:442669}
2670
csharrison4bd8a192016-08-02 18:03:152671void TestNavigationManager::WaitForNavigationFinished() {
clamy19f0d492016-10-13 16:53:282672 desired_state_ = NavigationState::FINISHED;
2673 WaitForDesiredState();
csharrison4bd8a192016-08-02 18:03:152674}
2675
2676void TestNavigationManager::DidStartNavigation(NavigationHandle* handle) {
2677 if (!ShouldMonitorNavigation(handle))
2678 return;
2679
2680 handle_ = handle;
2681 std::unique_ptr<NavigationThrottle> throttle(
2682 new TestNavigationManagerThrottle(
2683 handle_, base::Bind(&TestNavigationManager::OnWillStartRequest,
clamyd69748c2016-10-07 22:09:442684 weak_factory_.GetWeakPtr()),
2685 base::Bind(&TestNavigationManager::OnWillProcessResponse,
2686 weak_factory_.GetWeakPtr())));
csharrison4bd8a192016-08-02 18:03:152687 handle_->RegisterThrottleForTesting(std::move(throttle));
2688}
2689
2690void TestNavigationManager::DidFinishNavigation(NavigationHandle* handle) {
2691 if (handle != handle_)
2692 return;
clamyb99ec532018-03-01 15:00:482693 was_successful_ = handle->HasCommitted() && !handle->IsErrorPage();
clamy19f0d492016-10-13 16:53:282694 current_state_ = NavigationState::FINISHED;
2695 navigation_paused_ = false;
csharrison4bd8a192016-08-02 18:03:152696 handle_ = nullptr;
clamy19f0d492016-10-13 16:53:282697 OnNavigationStateChanged();
csharrison4bd8a192016-08-02 18:03:152698}
2699
2700void TestNavigationManager::OnWillStartRequest() {
clamy19f0d492016-10-13 16:53:282701 current_state_ = NavigationState::STARTED;
2702 navigation_paused_ = true;
2703 OnNavigationStateChanged();
clamyd69748c2016-10-07 22:09:442704}
2705
2706void TestNavigationManager::OnWillProcessResponse() {
clamy19f0d492016-10-13 16:53:282707 current_state_ = NavigationState::RESPONSE;
2708 navigation_paused_ = true;
2709 OnNavigationStateChanged();
csharrison4bd8a192016-08-02 18:03:152710}
2711
Charles Harrison4f2bf1a2017-07-18 20:21:212712// TODO(csharrison): Remove CallResumeForTesting method calls in favor of doing
2713// it through the throttle.
clamy19f0d492016-10-13 16:53:282714bool TestNavigationManager::WaitForDesiredState() {
2715 // If the desired state has laready been reached, just return.
2716 if (current_state_ == desired_state_)
2717 return true;
2718
2719 // Resume the navigation if it was paused.
2720 if (navigation_paused_)
Charles Harrison4f2bf1a2017-07-18 20:21:212721 handle_->CallResumeForTesting();
clamy19f0d492016-10-13 16:53:282722
2723 // Wait for the desired state if needed.
2724 if (current_state_ < desired_state_) {
Wezf2311d72018-06-02 02:02:182725 DCHECK(!quit_closure_);
2726 base::RunLoop run_loop;
2727 quit_closure_ = run_loop.QuitClosure();
2728 run_loop.Run();
clamy19f0d492016-10-13 16:53:282729 }
2730
2731 // Return false if the navigation did not reach the state specified by the
2732 // user.
2733 return current_state_ == desired_state_;
2734}
2735
2736void TestNavigationManager::OnNavigationStateChanged() {
2737 // If the state the user was waiting for has been reached, exit the message
2738 // loop.
2739 if (current_state_ >= desired_state_) {
Wezf2311d72018-06-02 02:02:182740 if (quit_closure_)
2741 std::move(quit_closure_).Run();
csharrison4bd8a192016-08-02 18:03:152742 return;
clamyd69748c2016-10-07 22:09:442743 }
clamy19f0d492016-10-13 16:53:282744
2745 // Otherwise, the navigation should be resumed if it was previously paused.
2746 if (navigation_paused_)
Charles Harrison4f2bf1a2017-07-18 20:21:212747 handle_->CallResumeForTesting();
csharrison4bd8a192016-08-02 18:03:152748}
2749
2750bool TestNavigationManager::ShouldMonitorNavigation(NavigationHandle* handle) {
2751 if (handle_ || handle->GetURL() != url_)
2752 return false;
clamy19f0d492016-10-13 16:53:282753 if (current_state_ != NavigationState::INITIAL)
csharrison4bd8a192016-08-02 18:03:152754 return false;
2755 return true;
2756}
2757
nasko7058e5de2017-04-18 23:05:302758NavigationHandleCommitObserver::NavigationHandleCommitObserver(
2759 content::WebContents* web_contents,
2760 const GURL& url)
2761 : content::WebContentsObserver(web_contents),
2762 url_(url),
2763 has_committed_(false),
2764 was_same_document_(false),
2765 was_renderer_initiated_(false) {}
2766
2767void NavigationHandleCommitObserver::DidFinishNavigation(
2768 content::NavigationHandle* handle) {
2769 if (handle->GetURL() != url_)
2770 return;
2771 has_committed_ = true;
2772 was_same_document_ = handle->IsSameDocument();
2773 was_renderer_initiated_ = handle->IsRendererInitiated();
2774}
2775
robc72f59f32016-10-14 09:35:162776ConsoleObserverDelegate::ConsoleObserverDelegate(WebContents* web_contents,
2777 const std::string& filter)
Wezf2311d72018-06-02 02:02:182778 : web_contents_(web_contents), filter_(filter) {}
robc72f59f32016-10-14 09:35:162779
2780ConsoleObserverDelegate::~ConsoleObserverDelegate() {}
2781
2782void ConsoleObserverDelegate::Wait() {
Wezf2311d72018-06-02 02:02:182783 run_loop_.Run();
robc72f59f32016-10-14 09:35:162784}
2785
avia90ae4e2016-11-11 20:49:332786bool ConsoleObserverDelegate::DidAddMessageToConsole(
robc72f59f32016-10-14 09:35:162787 WebContents* source,
2788 int32_t level,
2789 const base::string16& message,
2790 int32_t line_no,
2791 const base::string16& source_id) {
2792 DCHECK(source == web_contents_);
2793
2794 std::string ascii_message = base::UTF16ToASCII(message);
2795 if (base::MatchPattern(ascii_message, filter_)) {
2796 message_ = ascii_message;
Wezf2311d72018-06-02 02:02:182797 run_loop_.Quit();
robc72f59f32016-10-14 09:35:162798 }
2799 return false;
2800}
2801
nickbfaea4ee2016-12-02 20:59:312802// static
nickbfaea4ee2016-12-02 20:59:312803void PwnMessageHelper::RegisterBlobURL(RenderProcessHost* process,
2804 GURL url,
2805 std::string uuid) {
2806 IPC::IpcSecurityTestUtil::PwnMessageReceived(
2807 process->GetChannel(), BlobHostMsg_RegisterPublicURL(url, uuid));
2808}
2809
Adithya Srinivasan0c72ff02018-08-13 19:47:292810namespace {
2811blink::mojom::FileSystemManagerPtr GetFileSystemManager(
2812 RenderProcessHost* rph) {
2813 FileSystemManagerImpl* file_system = static_cast<RenderProcessHostImpl*>(rph)
2814 ->GetFileSystemManagerForTesting();
2815 blink::mojom::FileSystemManagerPtr file_system_manager_ptr;
Eric Seckler8652dcd52018-09-20 10:42:282816 base::PostTaskWithTraits(
2817 FROM_HERE, {BrowserThread::IO},
Adithya Srinivasan0c72ff02018-08-13 19:47:292818 base::BindOnce(&FileSystemManagerImpl::BindRequest,
2819 base::Unretained(file_system),
2820 mojo::MakeRequest(&file_system_manager_ptr)));
2821 return file_system_manager_ptr;
2822}
2823} // namespace
2824
nickbfaea4ee2016-12-02 20:59:312825// static
2826void PwnMessageHelper::FileSystemCreate(RenderProcessHost* process,
2827 int request_id,
2828 GURL path,
2829 bool exclusive,
2830 bool is_directory,
2831 bool recursive) {
Adithya Srinivasan0c72ff02018-08-13 19:47:292832 TestFileapiOperationWaiter waiter;
2833 blink::mojom::FileSystemManagerPtr file_system_manager_ptr =
2834 GetFileSystemManager(process);
2835 file_system_manager_ptr->Create(
2836 path, exclusive, is_directory, recursive,
2837 base::BindOnce(&TestFileapiOperationWaiter::DidCreate,
2838 base::Unretained(&waiter)));
2839 waiter.WaitForOperationToFinish();
nickbfaea4ee2016-12-02 20:59:312840}
2841
2842// static
2843void PwnMessageHelper::FileSystemWrite(RenderProcessHost* process,
2844 int request_id,
2845 GURL file_path,
2846 std::string blob_uuid,
2847 int64_t position) {
Adithya Srinivasan0c72ff02018-08-13 19:47:292848 TestFileapiOperationWaiter waiter;
2849 blink::mojom::FileSystemManagerPtr file_system_manager_ptr =
2850 GetFileSystemManager(process);
2851 blink::mojom::FileSystemOperationListenerPtr listener_ptr;
2852 mojo::Binding<blink::mojom::FileSystemOperationListener> binding(
2853 &waiter, mojo::MakeRequest(&listener_ptr));
2854 blink::mojom::FileSystemCancellableOperationPtr op_ptr;
nickbfaea4ee2016-12-02 20:59:312855
Adithya Srinivasan0c72ff02018-08-13 19:47:292856 file_system_manager_ptr->Write(file_path, blob_uuid, position,
2857 mojo::MakeRequest(&op_ptr),
2858 std::move(listener_ptr));
2859 waiter.WaitForOperationToFinish();
nickbfaea4ee2016-12-02 20:59:312860}
2861
lfge2176fb2017-03-26 00:45:472862void PwnMessageHelper::LockMouse(RenderProcessHost* process,
2863 int routing_id,
2864 bool user_gesture,
lfge2176fb2017-03-26 00:45:472865 bool privileged) {
2866 IPC::IpcSecurityTestUtil::PwnMessageReceived(
2867 process->GetChannel(),
Albert J. Wong3c93c182018-09-27 17:29:432868 WidgetHostMsg_LockMouse(routing_id, user_gesture, privileged));
lfge2176fb2017-03-26 00:45:472869}
2870
mcnee19fd2492017-06-01 14:42:432871#if defined(USE_AURA)
2872namespace {
2873class MockOverscrollControllerImpl : public OverscrollController,
2874 public MockOverscrollController {
2875 public:
Wezf2311d72018-06-02 02:02:182876 MockOverscrollControllerImpl() : content_scrolling_(false) {}
mcnee19fd2492017-06-01 14:42:432877 ~MockOverscrollControllerImpl() override {}
2878
2879 // OverscrollController:
2880 void ReceivedEventACK(const blink::WebInputEvent& event,
2881 bool processed) override {
2882 // Since we're only mocking this one method of OverscrollController and its
2883 // other methods are non-virtual, we'll delegate to it so that it doesn't
2884 // get into an inconsistent state.
2885 OverscrollController::ReceivedEventACK(event, processed);
2886
2887 if (event.GetType() == blink::WebInputEvent::kGestureScrollUpdate &&
2888 processed) {
2889 content_scrolling_ = true;
Wezf2311d72018-06-02 02:02:182890 if (quit_closure_)
2891 std::move(quit_closure_).Run();
mcnee19fd2492017-06-01 14:42:432892 }
2893 }
2894
2895 // MockOverscrollController:
2896 void WaitForConsumedScroll() override {
Wezf2311d72018-06-02 02:02:182897 if (!content_scrolling_) {
2898 base::RunLoop run_loop;
2899 quit_closure_ = run_loop.QuitClosure();
2900 run_loop.Run();
2901 }
mcnee19fd2492017-06-01 14:42:432902 }
2903
2904 private:
2905 bool content_scrolling_;
Wezf2311d72018-06-02 02:02:182906 base::OnceClosure quit_closure_;
mcnee19fd2492017-06-01 14:42:432907
2908 DISALLOW_COPY_AND_ASSIGN(MockOverscrollControllerImpl);
2909};
2910} // namespace
2911
2912// static
2913MockOverscrollController* MockOverscrollController::Create(
2914 RenderWidgetHostView* rwhv) {
2915 std::unique_ptr<MockOverscrollControllerImpl> mock =
Jeremy Roman04f27c372017-10-27 15:20:552916 std::make_unique<MockOverscrollControllerImpl>();
mcnee19fd2492017-06-01 14:42:432917 MockOverscrollController* raw_mock = mock.get();
2918
2919 RenderWidgetHostViewAura* rwhva =
2920 static_cast<RenderWidgetHostViewAura*>(rwhv);
2921 rwhva->SetOverscrollControllerForTesting(std::move(mock));
2922
2923 return raw_mock;
2924}
2925
2926#endif // defined(USE_AURA)
2927
W. James MacLean82b029b2017-10-23 15:05:432928ContextMenuFilter::ContextMenuFilter()
2929 : content::BrowserMessageFilter(FrameMsgStart),
Wezf2311d72018-06-02 02:02:182930 run_loop_(new base::RunLoop),
2931 quit_closure_(run_loop_->QuitClosure()) {}
W. James MacLean82b029b2017-10-23 15:05:432932
2933bool ContextMenuFilter::OnMessageReceived(const IPC::Message& message) {
2934 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
2935 if (message.type() == FrameHostMsg_ContextMenu::ID) {
2936 FrameHostMsg_ContextMenu::Param params;
2937 FrameHostMsg_ContextMenu::Read(&message, &params);
2938 content::ContextMenuParams menu_params = std::get<0>(params);
Eric Seckler8652dcd52018-09-20 10:42:282939 base::PostTaskWithTraits(
2940 FROM_HERE, {content::BrowserThread::UI},
W. James MacLean82b029b2017-10-23 15:05:432941 base::BindOnce(&ContextMenuFilter::OnContextMenu, this, menu_params));
2942 }
2943 return false;
2944}
2945
2946void ContextMenuFilter::Wait() {
Wezf2311d72018-06-02 02:02:182947 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
2948 run_loop_->Run();
2949 run_loop_ = nullptr;
W. James MacLean82b029b2017-10-23 15:05:432950}
2951
2952ContextMenuFilter::~ContextMenuFilter() {}
2953
2954void ContextMenuFilter::OnContextMenu(
2955 const content::ContextMenuParams& params) {
2956 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
W. James MacLean82b029b2017-10-23 15:05:432957 last_params_ = params;
Wezf2311d72018-06-02 02:02:182958 std::move(quit_closure_).Run();
W. James MacLean82b029b2017-10-23 15:05:432959}
2960
W. James MacLeana21ff3d2017-10-28 13:04:242961WebContents* GetEmbedderForGuest(content::WebContents* guest) {
2962 CHECK(guest);
2963 return static_cast<content::WebContentsImpl*>(guest)->GetOuterWebContents();
2964}
2965
John Abd-El-Malek7c5c7e4c2018-01-11 21:36:162966bool IsNetworkServiceRunningInProcess() {
Yutaka Hiranod8789f92018-01-30 09:59:512967 return base::FeatureList::IsEnabled(network::features::kNetworkService) &&
John Abd-El-Malek7c5c7e4c2018-01-11 21:36:162968 (base::CommandLine::ForCurrentProcess()->HasSwitch(
2969 switches::kSingleProcess) ||
2970 base::FeatureList::IsEnabled(features::kNetworkServiceInProcess));
2971}
2972
John Abd-El-Malek53670dd2018-01-18 22:07:212973int LoadBasicRequest(network::mojom::NetworkContext* network_context,
John Abd-El-Malekdeec0082017-12-20 20:47:472974 const GURL& url,
2975 int process_id,
Chong Zhangfdbb7e9d2018-08-24 23:40:542976 int render_frame_id,
2977 int load_flags) {
John Abd-El-Malekb165dc52018-01-18 17:12:182978 network::mojom::URLLoaderFactoryPtr url_loader_factory;
Lukasz Anforowicz0b05f082018-05-18 23:04:002979 network::mojom::URLLoaderFactoryParamsPtr url_loader_factory_params =
2980 network::mojom::URLLoaderFactoryParams::New();
2981 url_loader_factory_params->process_id = process_id;
2982 url_loader_factory_params->is_corb_enabled = false;
John Abd-El-Malekdeec0082017-12-20 20:47:472983 network_context->CreateURLLoaderFactory(MakeRequest(&url_loader_factory),
Lukasz Anforowicz0b05f082018-05-18 23:04:002984 std::move(url_loader_factory_params));
Chong Zhangc40a6ce52017-12-10 03:00:282985 // |url_loader_factory| will receive error notification asynchronously if
2986 // |network_context| has already encountered error. However it's still false
2987 // at this point.
2988 EXPECT_FALSE(url_loader_factory.encountered_error());
2989
John Abd-El-Malek1df61792018-01-12 20:40:452990 auto request = std::make_unique<network::ResourceRequest>();
Chong Zhangc40a6ce52017-12-10 03:00:282991 request->url = url;
John Abd-El-Malekdeec0082017-12-20 20:47:472992 request->render_frame_id = render_frame_id;
Chong Zhangfdbb7e9d2018-08-24 23:40:542993 request->load_flags = load_flags;
Chong Zhangc40a6ce52017-12-10 03:00:282994
2995 content::SimpleURLLoaderTestHelper simple_loader_helper;
John Abd-El-Malekbdafede2018-02-06 15:10:362996 std::unique_ptr<network::SimpleURLLoader> simple_loader =
2997 network::SimpleURLLoader::Create(std::move(request),
Chong Zhangc40a6ce52017-12-10 03:00:282998 TRAFFIC_ANNOTATION_FOR_TESTS);
2999
3000 simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
3001 url_loader_factory.get(), simple_loader_helper.GetCallback());
3002 simple_loader_helper.WaitForCallback();
3003
3004 return simple_loader->NetError();
3005}
3006
John Abd-El-Malekcc0b2a62018-03-20 19:32:503007void EnsureCookiesFlushed(BrowserContext* browser_context) {
3008 BrowserContext::ForEachStoragePartition(
3009 browser_context, base::BindRepeating([](StoragePartition* partition) {
3010 base::RunLoop run_loop;
3011 partition->GetCookieManagerForBrowserProcess()->FlushCookieStore(
3012 run_loop.QuitClosure());
3013 run_loop.Run();
3014 }));
3015}
3016
Jay Civellifd2d7f912018-01-26 21:51:393017bool HasValidProcessForProcessGroup(const std::string& process_group_name) {
3018 return ServiceManagerContext::HasValidProcessForProcessGroup(
3019 process_group_name);
James Cook6929b872018-01-03 17:56:563020}
3021
Chris Blume12a26462018-04-22 02:00:123022bool TestChildOrGuestAutoresize(bool is_guest,
3023 RenderProcessHost* embedder_rph,
3024 RenderWidgetHost* guest_rwh) {
3025 RenderProcessHostImpl* embedder_rph_impl =
3026 static_cast<RenderProcessHostImpl*>(embedder_rph);
3027 RenderWidgetHostImpl* guest_rwh_impl =
3028 static_cast<RenderWidgetHostImpl*>(guest_rwh);
3029
Fady Samuel799e72192018-04-25 21:16:573030 scoped_refptr<SynchronizeVisualPropertiesMessageFilter> filter(
3031 new SynchronizeVisualPropertiesMessageFilter());
Chris Blume12a26462018-04-22 02:00:123032
3033 // Register the message filter for the guest or child. For guest, we must use
3034 // a special hook, as there are already message filters installed which will
3035 // supercede us.
3036 if (is_guest) {
3037 embedder_rph_impl->SetBrowserPluginMessageFilterSubFilterForTesting(
3038 filter.get());
3039 } else {
3040 embedder_rph_impl->AddFilter(filter.get());
3041 }
3042
Fady Samuel84d8a1f72018-11-08 00:26:173043 viz::LocalSurfaceId current_id = guest_rwh_impl->GetView()
3044 ->GetLocalSurfaceIdAllocation()
3045 .local_surface_id();
Eric Karl2a4b17a2018-04-22 11:00:293046 // The guest may not yet be fully attached / initted. If not, |current_id|
3047 // will be invalid, and we should wait for an ID before proceeding.
3048 if (!current_id.is_valid())
3049 current_id = filter->WaitForSurfaceId();
3050
Chris Blume12a26462018-04-22 02:00:123051 // Enable auto-resize.
Eric Karl7fdf2af2018-04-24 21:21:303052 gfx::Size min_size(10, 10);
3053 gfx::Size max_size(100, 100);
3054 guest_rwh_impl->SetAutoResize(true, min_size, max_size);
3055 guest_rwh_impl->GetView()->EnableAutoResize(min_size, max_size);
3056
3057 // Enabling auto resize generates a surface ID, wait for it.
3058 current_id = filter->WaitForSurfaceId();
Chris Blume12a26462018-04-22 02:00:123059
3060 // Fake an auto-resize update.
Fady Samueleeab73952018-05-08 03:00:003061 viz::LocalSurfaceId local_surface_id(current_id.parent_sequence_number(),
3062 current_id.child_sequence_number() + 1,
3063 current_id.embed_token());
Fady Samuele392fd52018-05-11 17:16:433064 cc::RenderFrameMetadata metadata;
3065 metadata.viewport_size_in_pixels = gfx::Size(75, 75);
Fady Samuelb655f452018-11-06 00:48:343066 metadata.local_surface_id_allocation =
3067 viz::LocalSurfaceIdAllocation(local_surface_id, base::TimeTicks::Now());
Fady Samuele392fd52018-05-11 17:16:433068 guest_rwh_impl->DidUpdateVisualProperties(metadata);
Eric Karl7fdf2af2018-04-24 21:21:303069
3070 // This won't generate a response, as we short-circuit auto-resizes, so cause
3071 // an additional update by disabling auto-resize.
Fady Samueleeab73952018-05-08 03:00:003072 guest_rwh_impl->GetView()->DisableAutoResize(gfx::Size(75, 75));
Eric Karl7fdf2af2018-04-24 21:21:303073
Chris Blume12a26462018-04-22 02:00:123074 // Get the first delivered surface id and ensure it has the surface id which
3075 // we expect.
Eric Karl7fdf2af2018-04-24 21:21:303076 return filter->WaitForSurfaceId() ==
3077 viz::LocalSurfaceId(current_id.parent_sequence_number() + 1,
3078 current_id.child_sequence_number() + 1,
3079 current_id.embed_token());
Chris Blume12a26462018-04-22 02:00:123080}
3081
Fady Samuel799e72192018-04-25 21:16:573082const uint32_t
3083 SynchronizeVisualPropertiesMessageFilter::kMessageClassesToFilter[2] = {
3084 FrameMsgStart, BrowserPluginMsgStart};
Chris Blume12a26462018-04-22 02:00:123085
Fady Samuel799e72192018-04-25 21:16:573086SynchronizeVisualPropertiesMessageFilter::
3087 SynchronizeVisualPropertiesMessageFilter()
Chris Blume12a26462018-04-22 02:00:123088 : content::BrowserMessageFilter(kMessageClassesToFilter,
Avi Drissman9d3ded92018-12-25 20:50:213089 base::size(kMessageClassesToFilter)),
Chris Blume12a26462018-04-22 02:00:123090 screen_space_rect_run_loop_(std::make_unique<base::RunLoop>()),
3091 screen_space_rect_received_(false) {}
3092
Fady Samuel799e72192018-04-25 21:16:573093void SynchronizeVisualPropertiesMessageFilter::WaitForRect() {
Chris Blume12a26462018-04-22 02:00:123094 screen_space_rect_run_loop_->Run();
3095}
3096
Fady Samuel799e72192018-04-25 21:16:573097void SynchronizeVisualPropertiesMessageFilter::ResetRectRunLoop() {
Chris Blume12a26462018-04-22 02:00:123098 last_rect_ = gfx::Rect();
3099 screen_space_rect_run_loop_.reset(new base::RunLoop);
3100 screen_space_rect_received_ = false;
3101}
3102
Fady Samuel799e72192018-04-25 21:16:573103viz::FrameSinkId SynchronizeVisualPropertiesMessageFilter::GetOrWaitForId() {
Chris Blume12a26462018-04-22 02:00:123104 // No-op if already quit.
3105 frame_sink_id_run_loop_.Run();
3106 return frame_sink_id_;
3107}
3108
Fady Samuel799e72192018-04-25 21:16:573109viz::LocalSurfaceId
3110SynchronizeVisualPropertiesMessageFilter::WaitForSurfaceId() {
Chris Blume12a26462018-04-22 02:00:123111 surface_id_run_loop_.reset(new base::RunLoop);
3112 surface_id_run_loop_->Run();
3113 return last_surface_id_;
3114}
3115
Fady Samuel799e72192018-04-25 21:16:573116SynchronizeVisualPropertiesMessageFilter::
3117 ~SynchronizeVisualPropertiesMessageFilter() {}
Chris Blume12a26462018-04-22 02:00:123118
Fady Samuel799e72192018-04-25 21:16:573119void SynchronizeVisualPropertiesMessageFilter::
3120 OnSynchronizeFrameHostVisualProperties(
Fady Samuelb6b52ea2018-11-08 20:34:493121 const viz::FrameSinkId& frame_sink_id,
3122 const FrameVisualProperties& visual_properties) {
3123 OnSynchronizeVisualProperties(frame_sink_id, visual_properties);
Chris Blume12a26462018-04-22 02:00:123124}
3125
Fady Samuel799e72192018-04-25 21:16:573126void SynchronizeVisualPropertiesMessageFilter::
3127 OnSynchronizeBrowserPluginVisualProperties(
3128 int browser_plugin_guest_instance_id,
Fady Samuelb6b52ea2018-11-08 20:34:493129 FrameVisualProperties visual_properties) {
3130 OnSynchronizeVisualProperties(viz::FrameSinkId(), visual_properties);
Chris Blume12a26462018-04-22 02:00:123131}
3132
Fady Samuel799e72192018-04-25 21:16:573133void SynchronizeVisualPropertiesMessageFilter::OnSynchronizeVisualProperties(
Chris Blume12a26462018-04-22 02:00:123134 const viz::FrameSinkId& frame_sink_id,
Fady Samuelb6b52ea2018-11-08 20:34:493135 const FrameVisualProperties& visual_properties) {
3136 gfx::Rect screen_space_rect_in_dip = visual_properties.screen_space_rect;
Chris Blume12a26462018-04-22 02:00:123137 if (IsUseZoomForDSFEnabled()) {
3138 screen_space_rect_in_dip =
3139 gfx::Rect(gfx::ScaleToFlooredPoint(
Fady Samuelb6b52ea2018-11-08 20:34:493140 visual_properties.screen_space_rect.origin(),
3141 1.f / visual_properties.screen_info.device_scale_factor),
Chris Blume12a26462018-04-22 02:00:123142 gfx::ScaleToCeiledSize(
Fady Samuelb6b52ea2018-11-08 20:34:493143 visual_properties.screen_space_rect.size(),
3144 1.f / visual_properties.screen_info.device_scale_factor));
Chris Blume12a26462018-04-22 02:00:123145 }
3146 // Track each rect updates.
Eric Seckler8652dcd52018-09-20 10:42:283147 base::PostTaskWithTraits(
3148 FROM_HERE, {content::BrowserThread::UI},
Fady Samuel799e72192018-04-25 21:16:573149 base::BindOnce(
3150 &SynchronizeVisualPropertiesMessageFilter::OnUpdatedFrameRectOnUI,
3151 this, screen_space_rect_in_dip));
Chris Blume12a26462018-04-22 02:00:123152
3153 // Track each surface id update.
Eric Seckler8652dcd52018-09-20 10:42:283154 base::PostTaskWithTraits(
3155 FROM_HERE, {content::BrowserThread::UI},
Fady Samuel799e72192018-04-25 21:16:573156 base::BindOnce(
3157 &SynchronizeVisualPropertiesMessageFilter::OnUpdatedSurfaceIdOnUI,
Fady Samuelb6b52ea2018-11-08 20:34:493158 this,
3159 visual_properties.local_surface_id_allocation.local_surface_id()));
Chris Blume12a26462018-04-22 02:00:123160
3161 // Record the received value. We cannot check the current state of the child
3162 // frame, as it can only be processed on the UI thread, and we cannot block
3163 // here.
3164 frame_sink_id_ = frame_sink_id;
3165
3166 // There can be several updates before a valid viz::FrameSinkId is ready. Do
3167 // not quit |run_loop_| until after we receive a valid one.
3168 if (!frame_sink_id_.is_valid())
3169 return;
3170
3171 // We can't nest on the IO thread. So tests will wait on the UI thread, so
3172 // post there to exit the nesting.
Eric Seckler8652dcd52018-09-20 10:42:283173 base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI})
Chris Blume12a26462018-04-22 02:00:123174 ->PostTask(FROM_HERE,
Fady Samuel799e72192018-04-25 21:16:573175 base::BindOnce(&SynchronizeVisualPropertiesMessageFilter::
3176 OnUpdatedFrameSinkIdOnUI,
3177 this));
Chris Blume12a26462018-04-22 02:00:123178}
3179
Fady Samuel799e72192018-04-25 21:16:573180void SynchronizeVisualPropertiesMessageFilter::OnUpdatedFrameRectOnUI(
Chris Blume12a26462018-04-22 02:00:123181 const gfx::Rect& rect) {
3182 last_rect_ = rect;
3183 if (!screen_space_rect_received_) {
3184 screen_space_rect_received_ = true;
3185 // Tests looking at the rect currently expect all received input to finish
3186 // processing before the test continutes.
3187 screen_space_rect_run_loop_->QuitWhenIdle();
3188 }
3189}
3190
Fady Samuel799e72192018-04-25 21:16:573191void SynchronizeVisualPropertiesMessageFilter::OnUpdatedFrameSinkIdOnUI() {
Chris Blume12a26462018-04-22 02:00:123192 frame_sink_id_run_loop_.Quit();
3193}
3194
Fady Samuel799e72192018-04-25 21:16:573195void SynchronizeVisualPropertiesMessageFilter::OnUpdatedSurfaceIdOnUI(
Chris Blume12a26462018-04-22 02:00:123196 viz::LocalSurfaceId surface_id) {
3197 last_surface_id_ = surface_id;
3198 if (surface_id_run_loop_) {
3199 surface_id_run_loop_->QuitWhenIdle();
3200 }
3201}
3202
Fady Samuel799e72192018-04-25 21:16:573203bool SynchronizeVisualPropertiesMessageFilter::OnMessageReceived(
Chris Blume12a26462018-04-22 02:00:123204 const IPC::Message& message) {
Fady Samuel799e72192018-04-25 21:16:573205 IPC_BEGIN_MESSAGE_MAP(SynchronizeVisualPropertiesMessageFilter, message)
3206 IPC_MESSAGE_HANDLER(FrameHostMsg_SynchronizeVisualProperties,
3207 OnSynchronizeFrameHostVisualProperties)
3208 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SynchronizeVisualProperties,
3209 OnSynchronizeBrowserPluginVisualProperties)
Chris Blume12a26462018-04-22 02:00:123210 IPC_END_MESSAGE_MAP()
3211
3212 // We do not consume the message, so that we can verify the effects of it
3213 // being processed.
3214 return false;
3215}
3216
[email protected]78089f02012-07-19 06:11:283217} // namespace content