1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/public/test/browser_test_utils.h"
6
7 #include <stddef.h>
8
9 #include <set>
10 #include <tuple>
11 #include <utility>
12
13 #include "base/bind.h"
14 #include "base/callback_helpers.h"
15 #include "base/command_line.h"
16 #include "base/files/file_util.h"
17 #include "base/guid.h"
18 #include "base/json/json_reader.h"
19 #include "base/process/kill.h"
20 #include "base/run_loop.h"
21 #include "base/stl_util.h"
22 #include "base/strings/pattern.h"
23 #include "base/strings/strcat.h"
24 #include "base/strings/string_number_conversions.h"
25 #include "base/strings/string_piece.h"
26 #include "base/strings/stringprintf.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/synchronization/waitable_event.h"
29 #include "base/task/post_task.h"
30 #include "base/test/bind.h"
31 #include "base/test/test_switches.h"
32 #include "base/test/test_timeouts.h"
33 #include "base/threading/thread_task_runner_handle.h"
34 #include "base/values.h"
35 #include "build/build_config.h"
36 #include "cc/test/pixel_test_utils.h"
37 #include "components/viz/client/frame_evictor.h"
38 #include "content/browser/accessibility/browser_accessibility.h"
39 #include "content/browser/accessibility/browser_accessibility_manager.h"
40 #include "content/browser/file_system/file_system_manager_impl.h"
41 #include "content/browser/renderer_host/cross_process_frame_connector.h"
42 #include "content/browser/renderer_host/frame_tree_node.h"
43 #include "content/browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.h"
44 #include "content/browser/renderer_host/navigation_request.h"
45 #include "content/browser/renderer_host/render_frame_host_impl.h"
46 #include "content/browser/renderer_host/render_frame_metadata_provider_impl.h"
47 #include "content/browser/renderer_host/render_frame_proxy_host.h"
48 #include "content/browser/renderer_host/render_process_host_impl.h"
49 #include "content/browser/renderer_host/render_widget_host_impl.h"
50 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
51 #include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
52 #include "content/browser/screen_orientation/screen_orientation_provider.h"
53 #include "content/browser/service_manager/service_manager_context.h"
54 #include "content/browser/storage_partition_impl.h"
55 #include "content/browser/web_contents/web_contents_impl.h"
56 #include "content/browser/web_contents/web_contents_view.h"
57 #include "content/common/frame.mojom.h"
58 #include "content/common/frame_messages.h"
59 #include "content/common/input_messages.h"
60 #include "content/public/browser/browser_context.h"
61 #include "content/public/browser/browser_task_traits.h"
62 #include "content/public/browser/browser_thread.h"
63 #include "content/public/browser/child_process_termination_info.h"
64 #include "content/public/browser/histogram_fetcher.h"
65 #include "content/public/browser/navigation_entry.h"
66 #include "content/public/browser/navigation_handle.h"
67 #include "content/public/browser/navigation_throttle.h"
68 #include "content/public/browser/network_service_instance.h"
69 #include "content/public/browser/notification_service.h"
70 #include "content/public/browser/notification_types.h"
71 #include "content/public/browser/render_frame_host.h"
72 #include "content/public/browser/render_process_host.h"
73 #include "content/public/browser/render_view_host.h"
74 #include "content/public/browser/storage_partition.h"
75 #include "content/public/browser/web_contents.h"
76 #include "content/public/common/content_features.h"
77 #include "content/public/common/content_switches.h"
78 #include "content/public/common/service_names.mojom.h"
79 #include "content/public/common/use_zoom_for_dsf_policy.h"
80 #include "content/public/test/accessibility_notification_waiter.h"
81 #include "content/public/test/no_renderer_crashes_assertion.h"
82 #include "content/public/test/simple_url_loader_test_helper.h"
83 #include "content/public/test/test_fileapi_operation_waiter.h"
84 #include "content/public/test/test_frame_navigation_observer.h"
85 #include "content/public/test/test_launcher.h"
86 #include "content/public/test/test_navigation_observer.h"
87 #include "content/public/test/test_utils.h"
88 #include "content/test/did_commit_navigation_interceptor.h"
89 #include "ipc/ipc_security_test_util.h"
90 #include "mojo/public/cpp/bindings/pending_remote.h"
91 #include "mojo/public/cpp/bindings/receiver.h"
92 #include "mojo/public/cpp/bindings/remote.h"
93 #include "net/base/completion_once_callback.h"
94 #include "net/base/filename_util.h"
95 #include "net/base/io_buffer.h"
96 #include "net/cookies/canonical_cookie.h"
97 #include "net/cookies/cookie_access_result.h"
98 #include "net/cookies/cookie_util.h"
99 #include "net/filter/gzip_header.h"
100 #include "net/filter/gzip_source_stream.h"
101 #include "net/filter/mock_source_stream.h"
102 #include "net/test/embedded_test_server/embedded_test_server.h"
103 #include "net/test/embedded_test_server/http_request.h"
104 #include "net/test/embedded_test_server/http_response.h"
105 #include "net/test/python_utils.h"
106 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
107 #include "services/network/public/cpp/features.h"
108 #include "services/network/public/cpp/simple_url_loader.h"
109 #include "services/network/public/mojom/cookie_manager.mojom.h"
110 #include "services/network/public/mojom/network_service.mojom.h"
111 #include "services/network/public/mojom/network_service_test.mojom.h"
112 #include "services/service_manager/public/cpp/connector.h"
113 #include "storage/browser/file_system/file_system_context.h"
114 #include "testing/gmock/include/gmock/gmock-matchers.h"
115 #include "testing/gtest/include/gtest/gtest.h"
116 #include "third_party/blink/public/common/frame/frame_visual_properties.h"
117 #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h"
118 #include "third_party/blink/public/mojom/filesystem/file_system.mojom.h"
119 #include "third_party/skia/include/core/SkBitmap.h"
120 #include "ui/base/clipboard/clipboard.h"
121 #include "ui/base/clipboard/scoped_clipboard_writer.h"
122 #include "ui/base/clipboard/test/test_clipboard.h"
123 #include "ui/base/resource/resource_bundle.h"
124 #include "ui/compositor/test/draw_waiter_for_test.h"
125 #include "ui/events/base_event_utils.h"
126 #include "ui/events/gesture_detection/gesture_configuration.h"
127 #include "ui/events/keycodes/dom/dom_code.h"
128 #include "ui/events/keycodes/dom/keycode_converter.h"
129 #include "ui/latency/latency_info.h"
130 #include "ui/resources/grit/webui_generated_resources.h"
131
132 #if defined(OS_WIN)
133 #include <uiautomation.h>
134 #include <wrl/client.h>
135 #include "base/win/scoped_safearray.h"
136 #include "base/win/scoped_variant.h"
137 #endif
138
139 #if defined(USE_AURA)
140 #include "content/browser/renderer_host/delegated_frame_host.h"
141 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
142 #include "ui/aura/test/window_event_dispatcher_test_api.h"
143 #include "ui/aura/window.h"
144 #include "ui/aura/window_event_dispatcher.h"
145 #include "ui/aura/window_tree_host.h"
146 #include "ui/events/event.h"
147 #endif // USE_AURA
148
149 namespace content {
150 namespace {
151
152 // Specifying a prototype so that we can add the WARN_UNUSED_RESULT attribute.
153 bool ExecuteScriptHelper(RenderFrameHost* render_frame_host,
154 const std::string& script,
155 bool user_gesture,
156 int32_t world_id,
157 std::unique_ptr<base::Value>* result)
158 WARN_UNUSED_RESULT;
159
160 // Executes the passed |script| in the frame specified by |render_frame_host|.
161 // If |result| is not NULL, stores the value that the evaluation of the script
162 // in |result|. Returns true on success.
ExecuteScriptHelper(RenderFrameHost * render_frame_host,const std::string & script,bool user_gesture,int32_t world_id,std::unique_ptr<base::Value> * result)163 bool ExecuteScriptHelper(RenderFrameHost* render_frame_host,
164 const std::string& script,
165 bool user_gesture,
166 int32_t world_id,
167 std::unique_ptr<base::Value>* result) {
168 // TODO(lukasza): Only get messages from the specific |render_frame_host|.
169 DOMMessageQueue dom_message_queue(render_frame_host);
170
171 base::string16 script16 = base::UTF8ToUTF16(script);
172 if (world_id == ISOLATED_WORLD_ID_GLOBAL && user_gesture) {
173 render_frame_host->ExecuteJavaScriptWithUserGestureForTests(script16,
174 world_id);
175 } else {
176 // Note that |user_gesture| here is ignored when the world is not main. We
177 // allow a value of |true| because it's the default, but in blink, the
178 // execution will occur with no user gesture.
179 render_frame_host->ExecuteJavaScriptForTests(script16, base::NullCallback(),
180 world_id);
181 }
182
183 std::string json;
184 if (!dom_message_queue.WaitForMessage(&json)) {
185 DLOG(ERROR) << "Cannot communicate with DOMMessageQueue.";
186 return false;
187 }
188
189 // Nothing more to do for callers that ignore the returned JS value.
190 if (!result)
191 return true;
192
193 base::JSONReader::ValueWithError parsed_json =
194 base::JSONReader::ReadAndReturnValueWithError(
195 json, base::JSON_ALLOW_TRAILING_COMMAS);
196 if (!parsed_json.value) {
197 *result = nullptr;
198 DLOG(ERROR) << parsed_json.error_message;
199 return false;
200 }
201 *result = base::Value::ToUniquePtrValue(std::move(*parsed_json.value));
202
203 return true;
204 }
205
ExecuteScriptWithUserGestureControl(RenderFrameHost * frame,const std::string & script,bool user_gesture)206 bool ExecuteScriptWithUserGestureControl(RenderFrameHost* frame,
207 const std::string& script,
208 bool user_gesture) {
209 // TODO(lukasza): ExecuteScript should just call
210 // ExecuteJavaScriptWithUserGestureForTests and avoid modifying the original
211 // script (and at that point we should merge it with and remove
212 // ExecuteScriptAsync). This is difficult to change, because many tests
213 // depend on the message loop pumping done by ExecuteScriptHelper below (this
214 // is fragile - these tests should wait on a more specific thing instead).
215
216 // TODO(nick): This function can't be replaced with a call to ExecJs(), since
217 // ExecJs calls eval() which might be blocked by the page's CSP.
218 std::string expected_response = "ExecuteScript-" + base::GenerateGUID();
219 std::string new_script = base::StringPrintf(
220 R"( %s; // Original script.
221 window.domAutomationController.send('%s'); )",
222 script.c_str(), expected_response.c_str());
223
224 std::unique_ptr<base::Value> value;
225 if (!ExecuteScriptHelper(frame, new_script, user_gesture,
226 ISOLATED_WORLD_ID_GLOBAL, &value) ||
227 !value.get()) {
228 return false;
229 }
230
231 DCHECK_EQ(base::Value::Type::STRING, value->type());
232 std::string actual_response;
233 if (value->GetAsString(&actual_response))
234 DCHECK_EQ(expected_response, actual_response);
235
236 return true;
237 }
238
BuildSimpleWebKeyEvent(blink::WebInputEvent::Type type,ui::DomKey key,ui::DomCode code,ui::KeyboardCode key_code,NativeWebKeyboardEvent * event)239 void BuildSimpleWebKeyEvent(blink::WebInputEvent::Type type,
240 ui::DomKey key,
241 ui::DomCode code,
242 ui::KeyboardCode key_code,
243 NativeWebKeyboardEvent* event) {
244 event->dom_key = key;
245 event->dom_code = static_cast<int>(code);
246 event->native_key_code = ui::KeycodeConverter::DomCodeToNativeKeycode(code);
247 event->windows_key_code = key_code;
248 event->is_system_key = false;
249 event->skip_in_browser = true;
250
251 if (type == blink::WebInputEvent::Type::kChar ||
252 type == blink::WebInputEvent::Type::kRawKeyDown) {
253 // |key| is the only parameter that contains information about the case of
254 // the character. Use it to be able to generate lower case input.
255 if (key.IsCharacter()) {
256 event->text[0] = key.ToCharacter();
257 event->unmodified_text[0] = key.ToCharacter();
258 } else {
259 event->text[0] = key_code;
260 event->unmodified_text[0] = key_code;
261 }
262 }
263 }
264
InjectRawKeyEvent(WebContents * web_contents,blink::WebInputEvent::Type type,ui::DomKey key,ui::DomCode code,ui::KeyboardCode key_code,int modifiers)265 void InjectRawKeyEvent(WebContents* web_contents,
266 blink::WebInputEvent::Type type,
267 ui::DomKey key,
268 ui::DomCode code,
269 ui::KeyboardCode key_code,
270 int modifiers) {
271 NativeWebKeyboardEvent event(type, modifiers, base::TimeTicks::Now());
272 BuildSimpleWebKeyEvent(type, key, code, key_code, &event);
273 WebContentsImpl* web_contents_impl =
274 static_cast<WebContentsImpl*>(web_contents);
275 RenderWidgetHostImpl* main_frame_rwh =
276 web_contents_impl->GetMainFrame()->GetRenderWidgetHost();
277 web_contents_impl->GetFocusedRenderWidgetHost(main_frame_rwh)
278 ->ForwardKeyboardEvent(event);
279 }
280
SimulateModifierKeysDown(WebContents * web_contents,bool control,bool shift,bool alt,bool command)281 int SimulateModifierKeysDown(WebContents* web_contents,
282 bool control,
283 bool shift,
284 bool alt,
285 bool command) {
286 int modifiers = 0;
287
288 // The order of these key down events shouldn't matter for our simulation.
289 // For our simulation we can use either the left keys or the right keys.
290 if (control) {
291 modifiers |= blink::WebInputEvent::kControlKey;
292 InjectRawKeyEvent(web_contents, blink::WebInputEvent::Type::kRawKeyDown,
293 ui::DomKey::CONTROL, ui::DomCode::CONTROL_LEFT,
294 ui::VKEY_CONTROL, modifiers);
295 }
296 if (shift) {
297 modifiers |= blink::WebInputEvent::kShiftKey;
298 InjectRawKeyEvent(web_contents, blink::WebInputEvent::Type::kRawKeyDown,
299 ui::DomKey::SHIFT, ui::DomCode::SHIFT_LEFT,
300 ui::VKEY_SHIFT, modifiers);
301 }
302 if (alt) {
303 modifiers |= blink::WebInputEvent::kAltKey;
304 InjectRawKeyEvent(web_contents, blink::WebInputEvent::Type::kRawKeyDown,
305 ui::DomKey::ALT, ui::DomCode::ALT_LEFT, ui::VKEY_MENU,
306 modifiers);
307 }
308 if (command) {
309 modifiers |= blink::WebInputEvent::kMetaKey;
310 InjectRawKeyEvent(web_contents, blink::WebInputEvent::Type::kRawKeyDown,
311 ui::DomKey::META, ui::DomCode::META_LEFT,
312 ui::VKEY_COMMAND, modifiers);
313 }
314 return modifiers;
315 }
316
SimulateModifierKeysUp(WebContents * web_contents,bool control,bool shift,bool alt,bool command,int modifiers)317 int SimulateModifierKeysUp(WebContents* web_contents,
318 bool control,
319 bool shift,
320 bool alt,
321 bool command,
322 int modifiers) {
323 // The order of these key releases shouldn't matter for our simulation.
324 if (control) {
325 modifiers &= ~blink::WebInputEvent::kControlKey;
326 InjectRawKeyEvent(web_contents, blink::WebInputEvent::Type::kKeyUp,
327 ui::DomKey::CONTROL, ui::DomCode::CONTROL_LEFT,
328 ui::VKEY_CONTROL, modifiers);
329 }
330
331 if (shift) {
332 modifiers &= ~blink::WebInputEvent::kShiftKey;
333 InjectRawKeyEvent(web_contents, blink::WebInputEvent::Type::kKeyUp,
334 ui::DomKey::SHIFT, ui::DomCode::SHIFT_LEFT,
335 ui::VKEY_SHIFT, modifiers);
336 }
337
338 if (alt) {
339 modifiers &= ~blink::WebInputEvent::kAltKey;
340 InjectRawKeyEvent(web_contents, blink::WebInputEvent::Type::kKeyUp,
341 ui::DomKey::ALT, ui::DomCode::ALT_LEFT, ui::VKEY_MENU,
342 modifiers);
343 }
344
345 if (command) {
346 modifiers &= ~blink::WebInputEvent::kMetaKey;
347 InjectRawKeyEvent(web_contents, blink::WebInputEvent::Type::kKeyUp,
348 ui::DomKey::META, ui::DomCode::META_LEFT,
349 ui::VKEY_COMMAND, modifiers);
350 }
351 return modifiers;
352 }
353
SimulateKeyEvent(WebContents * web_contents,ui::DomKey key,ui::DomCode code,ui::KeyboardCode key_code,bool send_char,int modifiers)354 void SimulateKeyEvent(WebContents* web_contents,
355 ui::DomKey key,
356 ui::DomCode code,
357 ui::KeyboardCode key_code,
358 bool send_char,
359 int modifiers) {
360 InjectRawKeyEvent(web_contents, blink::WebInputEvent::Type::kRawKeyDown, key,
361 code, key_code, modifiers);
362 if (send_char) {
363 InjectRawKeyEvent(web_contents, blink::WebInputEvent::Type::kChar, key,
364 code, key_code, modifiers);
365 }
366 InjectRawKeyEvent(web_contents, blink::WebInputEvent::Type::kKeyUp, key, code,
367 key_code, modifiers);
368 }
369
SimulateKeyPressImpl(WebContents * web_contents,ui::DomKey key,ui::DomCode code,ui::KeyboardCode key_code,bool control,bool shift,bool alt,bool command,bool send_char)370 void SimulateKeyPressImpl(WebContents* web_contents,
371 ui::DomKey key,
372 ui::DomCode code,
373 ui::KeyboardCode key_code,
374 bool control,
375 bool shift,
376 bool alt,
377 bool command,
378 bool send_char) {
379 int modifiers =
380 SimulateModifierKeysDown(web_contents, control, shift, alt, command);
381 SimulateKeyEvent(web_contents, key, code, key_code, send_char, modifiers);
382 modifiers = SimulateModifierKeysUp(web_contents, control, shift, alt, command,
383 modifiers);
384 ASSERT_EQ(modifiers, 0);
385 }
386
387 std::unique_ptr<net::test_server::HttpResponse>
CrossSiteRedirectResponseHandler(const net::EmbeddedTestServer * test_server,const net::test_server::HttpRequest & request)388 CrossSiteRedirectResponseHandler(const net::EmbeddedTestServer* test_server,
389 const net::test_server::HttpRequest& request) {
390 net::HttpStatusCode http_status_code;
391
392 // Inspect the prefix and extract the remainder of the url into |params|.
393 size_t length_of_chosen_prefix;
394 std::string prefix_302("/cross-site/");
395 std::string prefix_307("/cross-site-307/");
396 if (base::StartsWith(request.relative_url, prefix_302,
397 base::CompareCase::SENSITIVE)) {
398 http_status_code = net::HTTP_MOVED_PERMANENTLY;
399 length_of_chosen_prefix = prefix_302.length();
400 } else if (base::StartsWith(request.relative_url, prefix_307,
401 base::CompareCase::SENSITIVE)) {
402 http_status_code = net::HTTP_TEMPORARY_REDIRECT;
403 length_of_chosen_prefix = prefix_307.length();
404 } else {
405 // Unrecognized prefix - let somebody else handle this request.
406 return std::unique_ptr<net::test_server::HttpResponse>();
407 }
408 std::string params = request.relative_url.substr(length_of_chosen_prefix);
409
410 // A hostname to redirect to must be included in the URL, therefore at least
411 // one '/' character is expected.
412 size_t slash = params.find('/');
413 if (slash == std::string::npos)
414 return std::unique_ptr<net::test_server::HttpResponse>();
415
416 // Replace the host of the URL with the one passed in the URL.
417 GURL::Replacements replace_host;
418 replace_host.SetHostStr(base::StringPiece(params).substr(0, slash));
419 GURL redirect_server =
420 test_server->base_url().ReplaceComponents(replace_host);
421
422 // Append the real part of the path to the new URL.
423 std::string path = params.substr(slash + 1);
424 GURL redirect_target(redirect_server.Resolve(path));
425 DCHECK(redirect_target.is_valid());
426
427 auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
428 http_response->set_code(http_status_code);
429 http_response->AddCustomHeader("Location", redirect_target.spec());
430 return std::move(http_response);
431 }
432
433 // Helper class used by the TestNavigationManager to pause navigations.
434 // Note: the throttle should be added to the *end* of the list of throttles,
435 // so all NavigationThrottles that should be attached observe the
436 // WillStartRequest callback. RegisterThrottleForTesting has this behavior.
437 class TestNavigationManagerThrottle : public NavigationThrottle {
438 public:
TestNavigationManagerThrottle(NavigationHandle * handle,base::OnceClosure on_will_start_request_closure,base::OnceClosure on_will_process_response_closure)439 TestNavigationManagerThrottle(
440 NavigationHandle* handle,
441 base::OnceClosure on_will_start_request_closure,
442 base::OnceClosure on_will_process_response_closure)
443 : NavigationThrottle(handle),
444 on_will_start_request_closure_(
445 std::move(on_will_start_request_closure)),
446 on_will_process_response_closure_(
447 std::move(on_will_process_response_closure)) {}
~TestNavigationManagerThrottle()448 ~TestNavigationManagerThrottle() override {}
449
GetNameForLogging()450 const char* GetNameForLogging() override {
451 return "TestNavigationManagerThrottle";
452 }
453
454 private:
455 // NavigationThrottle:
WillStartRequest()456 NavigationThrottle::ThrottleCheckResult WillStartRequest() override {
457 DCHECK(on_will_start_request_closure_);
458 GetUIThreadTaskRunner({})->PostTask(
459 FROM_HERE, std::move(on_will_start_request_closure_));
460 return NavigationThrottle::DEFER;
461 }
462
WillProcessResponse()463 NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
464 DCHECK(on_will_process_response_closure_);
465 GetUIThreadTaskRunner({})->PostTask(
466 FROM_HERE, std::move(on_will_process_response_closure_));
467 return NavigationThrottle::DEFER;
468 }
469
470 base::OnceClosure on_will_start_request_closure_;
471 base::OnceClosure on_will_process_response_closure_;
472 };
473
HasGzipHeader(const base::RefCountedMemory & maybe_gzipped)474 bool HasGzipHeader(const base::RefCountedMemory& maybe_gzipped) {
475 net::GZipHeader header;
476 net::GZipHeader::Status header_status = net::GZipHeader::INCOMPLETE_HEADER;
477 const char* header_end = nullptr;
478 while (header_status == net::GZipHeader::INCOMPLETE_HEADER) {
479 header_status = header.ReadMore(maybe_gzipped.front_as<char>(),
480 maybe_gzipped.size(),
481 &header_end);
482 }
483 return header_status == net::GZipHeader::COMPLETE_HEADER;
484 }
485
AppendGzippedResource(const base::RefCountedMemory & encoded,std::string * to_append)486 void AppendGzippedResource(const base::RefCountedMemory& encoded,
487 std::string* to_append) {
488 auto source_stream = std::make_unique<net::MockSourceStream>();
489 source_stream->AddReadResult(encoded.front_as<char>(), encoded.size(),
490 net::OK, net::MockSourceStream::SYNC);
491 // Add an EOF.
492 source_stream->AddReadResult(encoded.front_as<char>() + encoded.size(), 0,
493 net::OK, net::MockSourceStream::SYNC);
494 std::unique_ptr<net::GzipSourceStream> filter = net::GzipSourceStream::Create(
495 std::move(source_stream), net::SourceStream::TYPE_GZIP);
496 scoped_refptr<net::IOBufferWithSize> dest_buffer =
497 base::MakeRefCounted<net::IOBufferWithSize>(4096);
498 while (true) {
499 int rv = filter->Read(dest_buffer.get(), dest_buffer->size(),
500 net::CompletionOnceCallback());
501 ASSERT_LE(0, rv);
502 if (rv <= 0)
503 break;
504 to_append->append(dest_buffer->data(), rv);
505 }
506 }
507
508 // Queries for video input devices on the current system using the getSources
509 // API.
510 //
511 // This does not guarantee that a getUserMedia with video will succeed, as the
512 // camera could be busy for instance.
513 //
514 // Returns has-video-input-device to the test if there is a webcam available,
515 // no-video-input-devices otherwise.
516 const char kHasVideoInputDeviceOnSystem[] = R"(
517 (function() {
518 navigator.mediaDevices.enumerateDevices()
519 .then(function(devices) {
520 if (devices.some((device) => device.kind == 'videoinput')) {
521 window.domAutomationController.send('has-video-input-device');
522 } else {
523 window.domAutomationController.send('no-video-input-devices');
524 }
525 });
526 })()
527 )";
528
529 const char kHasVideoInputDevice[] = "has-video-input-device";
530
531 // Interceptor that replaces params.url with |new_url| and params.origin with
532 // |new_origin| for any commits to |target_url|.
533 class CommitOriginInterceptor : public DidCommitNavigationInterceptor {
534 public:
CommitOriginInterceptor(WebContents * web_contents,const GURL & target_url,const GURL & new_url,const url::Origin & new_origin)535 CommitOriginInterceptor(WebContents* web_contents,
536 const GURL& target_url,
537 const GURL& new_url,
538 const url::Origin& new_origin)
539 : DidCommitNavigationInterceptor(web_contents),
540 target_url_(target_url),
541 new_url_(new_url),
542 new_origin_(new_origin) {}
543 ~CommitOriginInterceptor() override = default;
544
545 // WebContentsObserver:
WebContentsDestroyed()546 void WebContentsDestroyed() override { delete this; }
547
548 protected:
WillProcessDidCommitNavigation(RenderFrameHost * render_frame_host,NavigationRequest * navigation_request,::FrameHostMsg_DidCommitProvisionalLoad_Params * params,mojom::DidCommitProvisionalLoadInterfaceParamsPtr * interface_params)549 bool WillProcessDidCommitNavigation(
550 RenderFrameHost* render_frame_host,
551 NavigationRequest* navigation_request,
552 ::FrameHostMsg_DidCommitProvisionalLoad_Params* params,
553 mojom::DidCommitProvisionalLoadInterfaceParamsPtr* interface_params)
554 override {
555 if (params->url == target_url_) {
556 params->url = new_url_;
557 params->origin = new_origin_;
558 }
559 return true;
560 }
561
562 private:
563 GURL target_url_;
564 GURL new_url_;
565 url::Origin new_origin_;
566
567 DISALLOW_COPY_AND_ASSIGN(CommitOriginInterceptor);
568 };
569
570 } // namespace
571
NavigateToURL(WebContents * web_contents,const GURL & url)572 bool NavigateToURL(WebContents* web_contents, const GURL& url) {
573 return NavigateToURL(web_contents, url, url);
574 }
575
NavigateToURL(WebContents * web_contents,const GURL & url,const GURL & expected_commit_url)576 bool NavigateToURL(WebContents* web_contents,
577 const GURL& url,
578 const GURL& expected_commit_url) {
579 NavigateToURLBlockUntilNavigationsComplete(web_contents, url, 1);
580 if (!IsLastCommittedEntryOfPageType(web_contents, PAGE_TYPE_NORMAL))
581 return false;
582
583 bool is_same_url = web_contents->GetLastCommittedURL() == expected_commit_url;
584 if (!is_same_url) {
585 DLOG(WARNING) << "Expected URL " << expected_commit_url << " but observed "
586 << web_contents->GetLastCommittedURL();
587 }
588 return is_same_url;
589 }
590
NavigateToURLFromRenderer(const ToRenderFrameHost & adapter,const GURL & url)591 bool NavigateToURLFromRenderer(const ToRenderFrameHost& adapter,
592 const GURL& url) {
593 return NavigateToURLFromRenderer(adapter, url, url);
594 }
595
NavigateToURLFromRenderer(const ToRenderFrameHost & adapter,const GURL & url,const GURL & expected_commit_url)596 bool NavigateToURLFromRenderer(const ToRenderFrameHost& adapter,
597 const GURL& url,
598 const GURL& expected_commit_url) {
599 RenderFrameHost* rfh = adapter.render_frame_host();
600 TestFrameNavigationObserver nav_observer(rfh);
601 if (!ExecJs(rfh, JsReplace("location = $1", url)))
602 return false;
603 nav_observer.Wait();
604 return nav_observer.last_committed_url() == expected_commit_url &&
605 nav_observer.last_navigation_succeeded();
606 }
607
NavigateToURLFromRendererWithoutUserGesture(const ToRenderFrameHost & adapter,const GURL & url)608 bool NavigateToURLFromRendererWithoutUserGesture(
609 const ToRenderFrameHost& adapter,
610 const GURL& url) {
611 RenderFrameHost* rfh = adapter.render_frame_host();
612 TestFrameNavigationObserver nav_observer(rfh);
613 if (!ExecJs(rfh, JsReplace("location = $1", url),
614 EXECUTE_SCRIPT_NO_USER_GESTURE)) {
615 return false;
616 }
617 nav_observer.Wait();
618 return nav_observer.last_committed_url() == url;
619 }
620
NavigateIframeToURL(WebContents * web_contents,const std::string & iframe_id,const GURL & url)621 bool NavigateIframeToURL(WebContents* web_contents,
622 const std::string& iframe_id,
623 const GURL& url) {
624 TestNavigationObserver load_observer(web_contents);
625 bool result = BeginNavigateIframeToURL(web_contents, iframe_id, url);
626 load_observer.Wait();
627 return result;
628 }
629
BeginNavigateIframeToURL(WebContents * web_contents,const std::string & iframe_id,const GURL & url)630 bool BeginNavigateIframeToURL(WebContents* web_contents,
631 const std::string& iframe_id,
632 const GURL& url) {
633 std::string script = base::StringPrintf(
634 "setTimeout(\""
635 "var iframes = document.getElementById('%s');iframes.src='%s';"
636 "\",0)",
637 iframe_id.c_str(), url.spec().c_str());
638 return ExecuteScript(web_contents, script);
639 }
640
NavigateToURLBlockUntilNavigationsComplete(WebContents * web_contents,const GURL & url,int number_of_navigations)641 void NavigateToURLBlockUntilNavigationsComplete(WebContents* web_contents,
642 const GURL& url,
643 int number_of_navigations) {
644 // Prepare for the navigation.
645 WaitForLoadStop(web_contents);
646 TestNavigationObserver same_tab_observer(web_contents, number_of_navigations);
647
648 // This mimics behavior of Shell::LoadURL...
649 NavigationController::LoadURLParams params(url);
650 params.transition_type = ui::PageTransitionFromInt(
651 ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
652 web_contents->GetController().LoadURLWithParams(params);
653 web_contents->Focus();
654
655 // Wait until the expected number of navigations finish.
656 same_tab_observer.Wait();
657 }
658
GetFileUrlWithQuery(const base::FilePath & path,const std::string & query_string)659 GURL GetFileUrlWithQuery(const base::FilePath& path,
660 const std::string& query_string) {
661 GURL url = net::FilePathToFileURL(path);
662 if (!query_string.empty()) {
663 GURL::Replacements replacements;
664 replacements.SetQueryStr(query_string);
665 return url.ReplaceComponents(replacements);
666 }
667 return url;
668 }
669
ResetTouchAction(RenderWidgetHost * host)670 void ResetTouchAction(RenderWidgetHost* host) {
671 static_cast<InputRouterImpl*>(
672 static_cast<RenderWidgetHostImpl*>(host)->input_router())
673 ->ForceResetTouchActionForTest();
674 }
675
RequestMouseLock(RenderWidgetHost * host,bool user_gesture,bool request_unadjusted_movement)676 void RequestMouseLock(RenderWidgetHost* host,
677 bool user_gesture,
678 bool request_unadjusted_movement) {
679 static_cast<RenderWidgetHostImpl*>(host)->RequestMouseLock(
680 user_gesture, request_unadjusted_movement,
681 /*response=*/base::DoNothing());
682 }
683
RunUntilInputProcessed(RenderWidgetHost * host)684 void RunUntilInputProcessed(RenderWidgetHost* host) {
685 base::RunLoop run_loop;
686 RenderWidgetHostImpl::From(host)->WaitForInputProcessed(
687 run_loop.QuitClosure());
688 run_loop.Run();
689 }
690
ReferrerPolicyToString(network::mojom::ReferrerPolicy referrer_policy)691 std::string ReferrerPolicyToString(
692 network::mojom::ReferrerPolicy referrer_policy) {
693 switch (referrer_policy) {
694 case network::mojom::ReferrerPolicy::kDefault:
695 return "no-meta";
696 case network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade:
697 return "no-referrer-when-downgrade";
698 case network::mojom::ReferrerPolicy::kOrigin:
699 return "origin";
700 case network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin:
701 return "origin-when-crossorigin";
702 case network::mojom::ReferrerPolicy::kSameOrigin:
703 return "same-origin";
704 case network::mojom::ReferrerPolicy::kStrictOrigin:
705 return "strict-origin";
706 case network::mojom::ReferrerPolicy::kAlways:
707 return "always";
708 case network::mojom::ReferrerPolicy::kNever:
709 return "never";
710 case network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin:
711 return "strict-origin-when-cross-origin";
712 }
713 NOTREACHED();
714 return "";
715 }
716
717 mojo::PendingAssociatedReceiver<blink::mojom::FrameWidget>
BindFakeFrameWidgetInterfaces(RenderFrameHost * frame)718 BindFakeFrameWidgetInterfaces(RenderFrameHost* frame) {
719 RenderWidgetHostImpl* render_widget_host_impl =
720 static_cast<RenderFrameHostImpl*>(frame)->GetRenderWidgetHost();
721
722 mojo::AssociatedRemote<blink::mojom::FrameWidgetHost> blink_frame_widget_host;
723 auto blink_frame_widget_host_receiver =
724 blink_frame_widget_host.BindNewEndpointAndPassDedicatedReceiver();
725
726 mojo::AssociatedRemote<blink::mojom::FrameWidget> blink_frame_widget;
727 auto blink_frame_widget_receiver =
728 blink_frame_widget.BindNewEndpointAndPassDedicatedReceiver();
729
730 render_widget_host_impl->BindFrameWidgetInterfaces(
731 std::move(blink_frame_widget_host_receiver), blink_frame_widget.Unbind());
732
733 return blink_frame_widget_receiver;
734 }
735
SimulateActiveStateForWidget(RenderFrameHost * frame,bool active)736 void SimulateActiveStateForWidget(RenderFrameHost* frame, bool active) {
737 static_cast<RenderFrameHostImpl*>(frame)->GetRenderWidgetHost()->SetActive(
738 active);
739 }
740
WaitForLoadStopWithoutSuccessCheck(WebContents * web_contents)741 void WaitForLoadStopWithoutSuccessCheck(WebContents* web_contents) {
742 // In many cases, the load may have finished before we get here. Only wait if
743 // the tab still has a pending navigation.
744 if (web_contents->IsLoading()) {
745 WindowedNotificationObserver load_stop_observer(
746 NOTIFICATION_LOAD_STOP,
747 Source<NavigationController>(&web_contents->GetController()));
748 load_stop_observer.Wait();
749 }
750 }
751
WaitForLoadStop(WebContents * web_contents)752 bool WaitForLoadStop(WebContents* web_contents) {
753 WebContentsDestroyedWatcher watcher(web_contents);
754 WaitForLoadStopWithoutSuccessCheck(web_contents);
755 if (watcher.IsDestroyed()) {
756 LOG(ERROR) << "WebContents was destroyed during waiting for load stop.";
757 return false;
758 }
759 bool is_page_normal =
760 IsLastCommittedEntryOfPageType(web_contents, PAGE_TYPE_NORMAL);
761 if (!is_page_normal) {
762 NavigationEntry* last_entry =
763 web_contents->GetController().GetLastCommittedEntry();
764 if (last_entry) {
765 LOG(ERROR) << "Http status code = " << last_entry->GetHttpStatusCode()
766 << ", page type = " << last_entry->GetPageType();
767 } else {
768 LOG(ERROR) << "No committed entry.";
769 }
770 }
771 return is_page_normal;
772 }
773
PrepContentsForBeforeUnloadTest(WebContents * web_contents,bool trigger_user_activation)774 void PrepContentsForBeforeUnloadTest(WebContents* web_contents,
775 bool trigger_user_activation) {
776 for (auto* frame : web_contents->GetAllFrames()) {
777 if (trigger_user_activation)
778 frame->ExecuteJavaScriptWithUserGestureForTests(base::string16());
779
780 // Disable the hang monitor, otherwise there will be a race between the
781 // beforeunload dialog and the beforeunload hang timer.
782 frame->DisableBeforeUnloadHangMonitorForTesting();
783 }
784 }
785
IsLastCommittedEntryOfPageType(WebContents * web_contents,content::PageType page_type)786 bool IsLastCommittedEntryOfPageType(WebContents* web_contents,
787 content::PageType page_type) {
788 NavigationEntry* last_entry =
789 web_contents->GetController().GetLastCommittedEntry();
790 return last_entry && last_entry->GetPageType() == page_type;
791 }
792
OverrideLastCommittedOrigin(RenderFrameHost * render_frame_host,const url::Origin & origin)793 void OverrideLastCommittedOrigin(RenderFrameHost* render_frame_host,
794 const url::Origin& origin) {
795 static_cast<RenderFrameHostImpl*>(render_frame_host)
796 ->SetLastCommittedOriginForTesting(origin);
797 }
798
CrashTab(WebContents * web_contents)799 void CrashTab(WebContents* web_contents) {
800 RenderProcessHost* rph = web_contents->GetMainFrame()->GetProcess();
801 RenderProcessHostWatcher watcher(
802 rph, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
803 EXPECT_TRUE(rph->Shutdown(RESULT_CODE_KILLED));
804 watcher.Wait();
805 EXPECT_FALSE(watcher.did_exit_normally());
806 EXPECT_TRUE(web_contents->IsCrashed());
807 }
808
PwnCommitIPC(WebContents * web_contents,const GURL & target_url,const GURL & new_url,const url::Origin & new_origin)809 void PwnCommitIPC(WebContents* web_contents,
810 const GURL& target_url,
811 const GURL& new_url,
812 const url::Origin& new_origin) {
813 // This will be cleaned up when |web_contents| is destroyed.
814 new CommitOriginInterceptor(web_contents, target_url, new_url, new_origin);
815 }
816
SimulateUnresponsiveRenderer(WebContents * web_contents,RenderWidgetHost * widget)817 void SimulateUnresponsiveRenderer(WebContents* web_contents,
818 RenderWidgetHost* widget) {
819 static_cast<WebContentsImpl*>(web_contents)
820 ->RendererUnresponsive(RenderWidgetHostImpl::From(widget),
821 base::DoNothing::Repeatedly());
822 }
823
824 #if defined(USE_AURA)
IsResizeComplete(aura::test::WindowEventDispatcherTestApi * dispatcher_test,RenderWidgetHostImpl * widget_host)825 bool IsResizeComplete(aura::test::WindowEventDispatcherTestApi* dispatcher_test,
826 RenderWidgetHostImpl* widget_host) {
827 dispatcher_test->WaitUntilPointerMovesDispatched();
828 widget_host->SynchronizeVisualProperties();
829 return !widget_host->visual_properties_ack_pending_for_testing();
830 }
831
WaitForResizeComplete(WebContents * web_contents)832 void WaitForResizeComplete(WebContents* web_contents) {
833 aura::Window* content = web_contents->GetContentNativeView();
834 if (!content)
835 return;
836
837 aura::WindowTreeHost* window_host = content->GetHost();
838 aura::WindowEventDispatcher* dispatcher = window_host->dispatcher();
839 aura::test::WindowEventDispatcherTestApi dispatcher_test(dispatcher);
840 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
841 web_contents->GetMainFrame()->GetRenderViewHost()->GetWidget());
842 if (!IsResizeComplete(&dispatcher_test, widget_host)) {
843 WindowedNotificationObserver resize_observer(
844 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_VISUAL_PROPERTIES,
845 base::BindRepeating(IsResizeComplete, &dispatcher_test, widget_host));
846 resize_observer.Wait();
847 }
848 }
849 #elif defined(OS_ANDROID)
IsResizeComplete(RenderWidgetHostImpl * widget_host)850 bool IsResizeComplete(RenderWidgetHostImpl* widget_host) {
851 return !widget_host->visual_properties_ack_pending_for_testing();
852 }
853
WaitForResizeComplete(WebContents * web_contents)854 void WaitForResizeComplete(WebContents* web_contents) {
855 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
856 web_contents->GetRenderViewHost()->GetWidget());
857 if (!IsResizeComplete(widget_host)) {
858 WindowedNotificationObserver resize_observer(
859 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_VISUAL_PROPERTIES,
860 base::BindRepeating(IsResizeComplete, widget_host));
861 resize_observer.Wait();
862 }
863 }
864 #endif
865
SimulateMouseClick(WebContents * web_contents,int modifiers,blink::WebMouseEvent::Button button)866 void SimulateMouseClick(WebContents* web_contents,
867 int modifiers,
868 blink::WebMouseEvent::Button button) {
869 int x = web_contents->GetContainerBounds().width() / 2;
870 int y = web_contents->GetContainerBounds().height() / 2;
871 SimulateMouseClickAt(web_contents, modifiers, button, gfx::Point(x, y));
872 }
873
SimulateMouseClickAt(WebContents * web_contents,int modifiers,blink::WebMouseEvent::Button button,const gfx::Point & point)874 void SimulateMouseClickAt(WebContents* web_contents,
875 int modifiers,
876 blink::WebMouseEvent::Button button,
877 const gfx::Point& point) {
878 auto* web_contents_impl = static_cast<WebContentsImpl*>(web_contents);
879 auto* rwhvb = static_cast<RenderWidgetHostViewBase*>(
880 web_contents->GetRenderWidgetHostView());
881 blink::WebMouseEvent mouse_event(blink::WebInputEvent::Type::kMouseDown,
882 modifiers, ui::EventTimeForNow());
883 mouse_event.button = button;
884 mouse_event.SetPositionInWidget(point.x(), point.y());
885 // Mac needs positionInScreen for events to plugins.
886 gfx::Rect offset = web_contents->GetContainerBounds();
887 mouse_event.SetPositionInScreen(point.x() + offset.x(),
888 point.y() + offset.y());
889 mouse_event.click_count = 1;
890 web_contents_impl->GetInputEventRouter()->RouteMouseEvent(rwhvb, &mouse_event,
891 ui::LatencyInfo());
892 mouse_event.SetType(blink::WebInputEvent::Type::kMouseUp);
893 web_contents_impl->GetInputEventRouter()->RouteMouseEvent(rwhvb, &mouse_event,
894 ui::LatencyInfo());
895 }
896
SimulateMouseClickOrTapElementWithId(content::WebContents * web_contents,const std::string & id)897 void SimulateMouseClickOrTapElementWithId(content::WebContents* web_contents,
898 const std::string& id) {
899 // Get the center coordinates of the DOM element.
900 const int x = EvalJs(web_contents,
901 JsReplace("const bounds = "
902 "document.getElementById($1)."
903 "getBoundingClientRect();"
904 "Math.floor(bounds.left + bounds.width / 2)",
905 id))
906 .ExtractInt();
907 const int y = EvalJs(web_contents,
908 JsReplace("const bounds = "
909 "document.getElementById($1)."
910 "getBoundingClientRect();"
911 "Math.floor(bounds.top + bounds.height / 2)",
912 id))
913 .ExtractInt();
914 #if defined(OS_ANDROID)
915 SimulateTapDownAt(web_contents, gfx::Point(x, y));
916 SimulateTapAt(web_contents, gfx::Point(x, y));
917 #else
918 SimulateMouseClickAt(web_contents, 0, blink::WebMouseEvent::Button::kLeft,
919 gfx::Point(x, y));
920 #endif // defined(OS_ANDROID)
921 }
922
SendMouseDownToWidget(RenderWidgetHost * target,int modifiers,blink::WebMouseEvent::Button button)923 void SendMouseDownToWidget(RenderWidgetHost* target,
924 int modifiers,
925 blink::WebMouseEvent::Button button) {
926 auto* view = static_cast<RenderWidgetHostImpl*>(target)->GetView();
927
928 blink::WebMouseEvent mouse_event(blink::WebInputEvent::Type::kMouseDown,
929 modifiers, ui::EventTimeForNow());
930 mouse_event.button = button;
931 int x = view->GetViewBounds().width() / 2;
932 int y = view->GetViewBounds().height() / 2;
933 mouse_event.SetPositionInWidget(x, y);
934 mouse_event.click_count = 1;
935 target->ForwardMouseEvent(mouse_event);
936 }
937
SimulateMouseEvent(WebContents * web_contents,blink::WebInputEvent::Type type,const gfx::Point & point)938 void SimulateMouseEvent(WebContents* web_contents,
939 blink::WebInputEvent::Type type,
940 const gfx::Point& point) {
941 SimulateMouseEvent(web_contents, type,
942 blink::WebMouseEvent::Button::kNoButton, point);
943 }
944
SimulateMouseEvent(WebContents * web_contents,blink::WebInputEvent::Type type,blink::WebMouseEvent::Button button,const gfx::Point & point)945 void SimulateMouseEvent(WebContents* web_contents,
946 blink::WebInputEvent::Type type,
947 blink::WebMouseEvent::Button button,
948 const gfx::Point& point) {
949 auto* web_contents_impl = static_cast<WebContentsImpl*>(web_contents);
950 auto* rwhvb = static_cast<RenderWidgetHostViewBase*>(
951 web_contents->GetRenderWidgetHostView());
952 blink::WebMouseEvent mouse_event(type, 0, ui::EventTimeForNow());
953 mouse_event.button = button;
954 mouse_event.SetPositionInWidget(point.x(), point.y());
955 // Mac needs positionInScreen for events to plugins.
956 gfx::Rect offset = web_contents->GetContainerBounds();
957 mouse_event.SetPositionInScreen(point.x() + offset.x(),
958 point.y() + offset.y());
959
960 web_contents_impl->GetInputEventRouter()->RouteMouseEvent(rwhvb, &mouse_event,
961 ui::LatencyInfo());
962 }
963
SimulateMouseWheelEvent(WebContents * web_contents,const gfx::Point & point,const gfx::Vector2d & delta,const blink::WebMouseWheelEvent::Phase phase)964 void SimulateMouseWheelEvent(WebContents* web_contents,
965 const gfx::Point& point,
966 const gfx::Vector2d& delta,
967 const blink::WebMouseWheelEvent::Phase phase) {
968 blink::WebMouseWheelEvent wheel_event(blink::WebInputEvent::Type::kMouseWheel,
969 blink::WebInputEvent::kNoModifiers,
970 ui::EventTimeForNow());
971
972 wheel_event.SetPositionInWidget(point.x(), point.y());
973 wheel_event.delta_x = delta.x();
974 wheel_event.delta_y = delta.y();
975 wheel_event.phase = phase;
976 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
977 web_contents->GetMainFrame()->GetRenderViewHost()->GetWidget());
978 widget_host->ForwardWheelEvent(wheel_event);
979 }
980
981 #if !defined(OS_MAC)
SimulateMouseWheelCtrlZoomEvent(WebContents * web_contents,const gfx::Point & point,bool zoom_in,blink::WebMouseWheelEvent::Phase phase)982 void SimulateMouseWheelCtrlZoomEvent(WebContents* web_contents,
983 const gfx::Point& point,
984 bool zoom_in,
985 blink::WebMouseWheelEvent::Phase phase) {
986 blink::WebMouseWheelEvent wheel_event(blink::WebInputEvent::Type::kMouseWheel,
987 blink::WebInputEvent::kControlKey,
988 ui::EventTimeForNow());
989
990 wheel_event.SetPositionInWidget(point.x(), point.y());
991 wheel_event.delta_units = ui::ScrollGranularity::kScrollByPrecisePixel;
992 wheel_event.delta_y =
993 (zoom_in ? 1.0 : -1.0) * ui::MouseWheelEvent::kWheelDelta;
994 wheel_event.wheel_ticks_y = (zoom_in ? 1.0 : -1.0);
995 wheel_event.phase = phase;
996 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
997 web_contents->GetMainFrame()->GetRenderViewHost()->GetWidget());
998 widget_host->ForwardWheelEvent(wheel_event);
999 }
1000
SimulateTouchscreenPinch(WebContents * web_contents,const gfx::PointF & anchor,float scale_change,base::OnceClosure on_complete)1001 void SimulateTouchscreenPinch(WebContents* web_contents,
1002 const gfx::PointF& anchor,
1003 float scale_change,
1004 base::OnceClosure on_complete) {
1005 SyntheticPinchGestureParams params;
1006 params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT;
1007 params.scale_factor = scale_change;
1008 params.anchor = anchor;
1009
1010 auto pinch_gesture =
1011 std::make_unique<SyntheticTouchscreenPinchGesture>(params);
1012 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
1013 web_contents->GetTopLevelRenderWidgetHostView()->GetRenderWidgetHost());
1014 widget_host->QueueSyntheticGesture(
1015 std::move(pinch_gesture),
1016 base::BindOnce(
1017 [](base::OnceClosure on_complete, SyntheticGesture::Result result) {
1018 std::move(on_complete).Run();
1019 },
1020 std::move(on_complete)));
1021 }
1022
1023 #endif // !defined(OS_MAC)
1024
SimulateGesturePinchSequence(WebContents * web_contents,const gfx::Point & point,float scale,blink::WebGestureDevice source_device)1025 void SimulateGesturePinchSequence(WebContents* web_contents,
1026 const gfx::Point& point,
1027 float scale,
1028 blink::WebGestureDevice source_device) {
1029 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
1030 web_contents->GetMainFrame()->GetRenderViewHost()->GetWidget());
1031
1032 blink::WebGestureEvent pinch_begin(
1033 blink::WebInputEvent::Type::kGesturePinchBegin,
1034 blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow(), source_device);
1035 pinch_begin.SetPositionInWidget(gfx::PointF(point));
1036 pinch_begin.SetPositionInScreen(gfx::PointF(point));
1037 pinch_begin.SetNeedsWheelEvent(source_device ==
1038 blink::WebGestureDevice::kTouchpad);
1039 widget_host->ForwardGestureEvent(pinch_begin);
1040
1041 blink::WebGestureEvent pinch_update(pinch_begin);
1042 pinch_update.SetType(blink::WebInputEvent::Type::kGesturePinchUpdate);
1043 pinch_update.data.pinch_update.scale = scale;
1044 pinch_update.SetNeedsWheelEvent(source_device ==
1045 blink::WebGestureDevice::kTouchpad);
1046 widget_host->ForwardGestureEvent(pinch_update);
1047
1048 blink::WebGestureEvent pinch_end(pinch_begin);
1049 pinch_end.SetType(blink::WebInputEvent::Type::kGesturePinchEnd);
1050 pinch_end.SetNeedsWheelEvent(source_device ==
1051 blink::WebGestureDevice::kTouchpad);
1052 widget_host->ForwardGestureEvent(pinch_end);
1053 }
1054
SimulateGestureScrollSequence(WebContents * web_contents,const gfx::Point & point,const gfx::Vector2dF & delta)1055 void SimulateGestureScrollSequence(WebContents* web_contents,
1056 const gfx::Point& point,
1057 const gfx::Vector2dF& delta) {
1058 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
1059 web_contents->GetMainFrame()->GetRenderViewHost()->GetWidget());
1060
1061 blink::WebGestureEvent scroll_begin(
1062 blink::WebGestureEvent::Type::kGestureScrollBegin,
1063 blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow(),
1064 blink::WebGestureDevice::kTouchpad);
1065 scroll_begin.SetPositionInWidget(gfx::PointF(point));
1066 scroll_begin.data.scroll_begin.delta_x_hint = delta.x();
1067 scroll_begin.data.scroll_begin.delta_y_hint = delta.y();
1068 widget_host->ForwardGestureEvent(scroll_begin);
1069
1070 blink::WebGestureEvent scroll_update(
1071 blink::WebGestureEvent::Type::kGestureScrollUpdate,
1072 blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow(),
1073 blink::WebGestureDevice::kTouchpad);
1074 scroll_update.SetPositionInWidget(gfx::PointF(point));
1075 scroll_update.data.scroll_update.delta_x = delta.x();
1076 scroll_update.data.scroll_update.delta_y = delta.y();
1077 scroll_update.data.scroll_update.velocity_x = 0;
1078 scroll_update.data.scroll_update.velocity_y = 0;
1079 widget_host->ForwardGestureEvent(scroll_update);
1080
1081 blink::WebGestureEvent scroll_end(
1082 blink::WebGestureEvent::Type::kGestureScrollEnd,
1083 blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow(),
1084 blink::WebGestureDevice::kTouchpad);
1085 scroll_end.SetPositionInWidget(gfx::PointF(point));
1086 widget_host->ForwardGestureEvent(scroll_end);
1087 }
1088
SimulateGestureFlingSequence(WebContents * web_contents,const gfx::Point & point,const gfx::Vector2dF & velocity)1089 void SimulateGestureFlingSequence(WebContents* web_contents,
1090 const gfx::Point& point,
1091 const gfx::Vector2dF& velocity) {
1092 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
1093 web_contents->GetMainFrame()->GetRenderViewHost()->GetWidget());
1094
1095 blink::WebGestureEvent scroll_begin(
1096 blink::WebGestureEvent::Type::kGestureScrollBegin,
1097 blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow(),
1098 blink::WebGestureDevice::kTouchpad);
1099 scroll_begin.SetPositionInWidget(gfx::PointF(point));
1100 widget_host->ForwardGestureEvent(scroll_begin);
1101
1102 blink::WebGestureEvent scroll_end(
1103 blink::WebGestureEvent::Type::kGestureScrollEnd,
1104 blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow(),
1105 blink::WebGestureDevice::kTouchpad);
1106 scroll_end.SetPositionInWidget(gfx::PointF(point));
1107 widget_host->ForwardGestureEvent(scroll_end);
1108
1109 blink::WebGestureEvent fling_start(
1110 blink::WebGestureEvent::Type::kGestureFlingStart,
1111 blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow(),
1112 blink::WebGestureDevice::kTouchpad);
1113 fling_start.SetPositionInWidget(gfx::PointF(point));
1114 fling_start.data.fling_start.target_viewport = false;
1115 fling_start.data.fling_start.velocity_x = velocity.x();
1116 fling_start.data.fling_start.velocity_y = velocity.y();
1117 widget_host->ForwardGestureEvent(fling_start);
1118 }
1119
SimulateGestureEvent(WebContents * web_contents,const blink::WebGestureEvent & gesture_event,const ui::LatencyInfo & latency)1120 void SimulateGestureEvent(WebContents* web_contents,
1121 const blink::WebGestureEvent& gesture_event,
1122 const ui::LatencyInfo& latency) {
1123 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
1124 web_contents->GetRenderWidgetHostView());
1125 view->ProcessGestureEvent(gesture_event, latency);
1126 }
1127
SimulateTouchGestureAt(WebContents * web_contents,const gfx::Point & point,blink::WebInputEvent::Type type)1128 void SimulateTouchGestureAt(WebContents* web_contents,
1129 const gfx::Point& point,
1130 blink::WebInputEvent::Type type) {
1131 blink::WebGestureEvent gesture(type, 0, ui::EventTimeForNow(),
1132 blink::WebGestureDevice::kTouchscreen);
1133 gesture.SetPositionInWidget(gfx::PointF(point));
1134 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
1135 web_contents->GetMainFrame()->GetRenderViewHost()->GetWidget());
1136 widget_host->ForwardGestureEvent(gesture);
1137 }
1138
SimulateTapDownAt(WebContents * web_contents,const gfx::Point & point)1139 void SimulateTapDownAt(WebContents* web_contents, const gfx::Point& point) {
1140 SimulateTouchGestureAt(web_contents, point,
1141 blink::WebGestureEvent::Type::kGestureTapDown);
1142 }
1143
SimulateTapAt(WebContents * web_contents,const gfx::Point & point)1144 void SimulateTapAt(WebContents* web_contents, const gfx::Point& point) {
1145 SimulateTouchGestureAt(web_contents, point,
1146 blink::WebGestureEvent::Type::kGestureTap);
1147 }
1148
SimulateTapWithModifiersAt(WebContents * web_contents,unsigned modifiers,const gfx::Point & point)1149 void SimulateTapWithModifiersAt(WebContents* web_contents,
1150 unsigned modifiers,
1151 const gfx::Point& point) {
1152 blink::WebGestureEvent tap(blink::WebGestureEvent::Type::kGestureTap,
1153 modifiers, ui::EventTimeForNow(),
1154 blink::WebGestureDevice::kTouchpad);
1155 tap.SetPositionInWidget(gfx::PointF(point));
1156 RenderWidgetHostImpl* widget_host = RenderWidgetHostImpl::From(
1157 web_contents->GetMainFrame()->GetRenderViewHost()->GetWidget());
1158 widget_host->ForwardGestureEvent(tap);
1159 }
1160
1161 #if defined(USE_AURA)
SimulateTouchEventAt(WebContents * web_contents,ui::EventType event_type,const gfx::Point & point)1162 void SimulateTouchEventAt(WebContents* web_contents,
1163 ui::EventType event_type,
1164 const gfx::Point& point) {
1165 ui::TouchEvent touch(event_type, point, base::TimeTicks(),
1166 ui::PointerDetails(ui::EventPointerType::kTouch, 0));
1167 static_cast<RenderWidgetHostViewAura*>(
1168 web_contents->GetRenderWidgetHostView())
1169 ->OnTouchEvent(&touch);
1170 }
1171
SimulateLongTapAt(WebContents * web_contents,const gfx::Point & point)1172 void SimulateLongTapAt(WebContents* web_contents, const gfx::Point& point) {
1173 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
1174 web_contents->GetRenderWidgetHostView());
1175
1176 ui::TouchEvent touch_start(
1177 ui::ET_TOUCH_PRESSED, point, base::TimeTicks(),
1178 ui::PointerDetails(ui::EventPointerType::kTouch, 0));
1179 rwhva->OnTouchEvent(&touch_start);
1180
1181 ui::GestureEventDetails tap_down_details(ui::ET_GESTURE_TAP_DOWN);
1182 tap_down_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
1183 ui::GestureEvent tap_down(point.x(), point.y(), 0, ui::EventTimeForNow(),
1184 tap_down_details, touch_start.unique_event_id());
1185 rwhva->OnGestureEvent(&tap_down);
1186
1187 ui::GestureEventDetails long_press_details(ui::ET_GESTURE_LONG_PRESS);
1188 long_press_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
1189 ui::GestureEvent long_press(point.x(), point.y(), 0, ui::EventTimeForNow(),
1190 long_press_details,
1191 touch_start.unique_event_id());
1192 rwhva->OnGestureEvent(&long_press);
1193
1194 ui::TouchEvent touch_end(ui::ET_TOUCH_RELEASED, point, base::TimeTicks(),
1195 ui::PointerDetails(ui::EventPointerType::kTouch, 0));
1196 rwhva->OnTouchEvent(&touch_end);
1197
1198 ui::GestureEventDetails long_tap_details(ui::ET_GESTURE_LONG_TAP);
1199 long_tap_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
1200 ui::GestureEvent long_tap(point.x(), point.y(), 0, ui::EventTimeForNow(),
1201 long_tap_details, touch_end.unique_event_id());
1202 rwhva->OnGestureEvent(&long_tap);
1203 }
1204 #endif
1205
SimulateKeyPress(WebContents * web_contents,ui::DomKey key,ui::DomCode code,ui::KeyboardCode key_code,bool control,bool shift,bool alt,bool command)1206 void SimulateKeyPress(WebContents* web_contents,
1207 ui::DomKey key,
1208 ui::DomCode code,
1209 ui::KeyboardCode key_code,
1210 bool control,
1211 bool shift,
1212 bool alt,
1213 bool command) {
1214 SimulateKeyPressImpl(web_contents, key, code, key_code, control, shift, alt,
1215 command, /*send_char=*/true);
1216 }
1217
SimulateKeyPressWithoutChar(WebContents * web_contents,ui::DomKey key,ui::DomCode code,ui::KeyboardCode key_code,bool control,bool shift,bool alt,bool command)1218 void SimulateKeyPressWithoutChar(WebContents* web_contents,
1219 ui::DomKey key,
1220 ui::DomCode code,
1221 ui::KeyboardCode key_code,
1222 bool control,
1223 bool shift,
1224 bool alt,
1225 bool command) {
1226 SimulateKeyPressImpl(web_contents, key, code, key_code, control, shift, alt,
1227 command, /*send_char=*/false);
1228 }
1229
ScopedSimulateModifierKeyPress(WebContents * web_contents,bool control,bool shift,bool alt,bool command)1230 ScopedSimulateModifierKeyPress::ScopedSimulateModifierKeyPress(
1231 WebContents* web_contents,
1232 bool control,
1233 bool shift,
1234 bool alt,
1235 bool command)
1236 : web_contents_(web_contents),
1237 modifiers_(0),
1238 control_(control),
1239 shift_(shift),
1240 alt_(alt),
1241 command_(command) {
1242 modifiers_ =
1243 SimulateModifierKeysDown(web_contents_, control_, shift_, alt_, command_);
1244 }
1245
~ScopedSimulateModifierKeyPress()1246 ScopedSimulateModifierKeyPress::~ScopedSimulateModifierKeyPress() {
1247 modifiers_ = SimulateModifierKeysUp(web_contents_, control_, shift_, alt_,
1248 command_, modifiers_);
1249 DCHECK_EQ(0, modifiers_);
1250 }
1251
MouseClickAt(int additional_modifiers,blink::WebMouseEvent::Button button,const gfx::Point & point)1252 void ScopedSimulateModifierKeyPress::MouseClickAt(
1253 int additional_modifiers,
1254 blink::WebMouseEvent::Button button,
1255 const gfx::Point& point) {
1256 SimulateMouseClickAt(web_contents_, modifiers_ | additional_modifiers, button,
1257 point);
1258 }
1259
KeyPress(ui::DomKey key,ui::DomCode code,ui::KeyboardCode key_code)1260 void ScopedSimulateModifierKeyPress::KeyPress(ui::DomKey key,
1261 ui::DomCode code,
1262 ui::KeyboardCode key_code) {
1263 SimulateKeyEvent(web_contents_, key, code, key_code, /*send_char=*/true,
1264 modifiers_);
1265 }
1266
KeyPressWithoutChar(ui::DomKey key,ui::DomCode code,ui::KeyboardCode key_code)1267 void ScopedSimulateModifierKeyPress::KeyPressWithoutChar(
1268 ui::DomKey key,
1269 ui::DomCode code,
1270 ui::KeyboardCode key_code) {
1271 SimulateKeyEvent(web_contents_, key, code, key_code, /*send_char=*/false,
1272 modifiers_);
1273 }
1274
IsWebcamAvailableOnSystem(WebContents * web_contents)1275 bool IsWebcamAvailableOnSystem(WebContents* web_contents) {
1276 std::string result;
1277 EXPECT_TRUE(ExecuteScriptAndExtractString(
1278 web_contents, kHasVideoInputDeviceOnSystem, &result));
1279 return result == kHasVideoInputDevice;
1280 }
1281
ConvertToRenderFrameHost(WebContents * web_contents)1282 RenderFrameHost* ConvertToRenderFrameHost(WebContents* web_contents) {
1283 return web_contents->GetMainFrame();
1284 }
1285
ConvertToRenderFrameHost(RenderFrameHost * render_frame_host)1286 RenderFrameHost* ConvertToRenderFrameHost(RenderFrameHost* render_frame_host) {
1287 return render_frame_host;
1288 }
1289
ExecuteScript(const ToRenderFrameHost & adapter,const std::string & script)1290 bool ExecuteScript(const ToRenderFrameHost& adapter,
1291 const std::string& script) {
1292 return ExecuteScriptWithUserGestureControl(adapter.render_frame_host(),
1293 script, true);
1294 }
1295
ExecuteScriptWithoutUserGesture(const ToRenderFrameHost & adapter,const std::string & script)1296 bool ExecuteScriptWithoutUserGesture(const ToRenderFrameHost& adapter,
1297 const std::string& script) {
1298 return ExecuteScriptWithUserGestureControl(adapter.render_frame_host(),
1299 script, false);
1300 }
1301
ExecuteScriptAsync(const ToRenderFrameHost & adapter,const std::string & script)1302 void ExecuteScriptAsync(const ToRenderFrameHost& adapter,
1303 const std::string& script) {
1304 adapter.render_frame_host()->ExecuteJavaScriptWithUserGestureForTests(
1305 base::UTF8ToUTF16(script));
1306 }
1307
ExecuteScriptAndExtractDouble(const ToRenderFrameHost & adapter,const std::string & script,double * result)1308 bool ExecuteScriptAndExtractDouble(const ToRenderFrameHost& adapter,
1309 const std::string& script, double* result) {
1310 DCHECK(result);
1311 std::unique_ptr<base::Value> value;
1312 return ExecuteScriptHelper(adapter.render_frame_host(), script, true,
1313 ISOLATED_WORLD_ID_GLOBAL, &value) &&
1314 value && value->GetAsDouble(result);
1315 }
1316
ExecuteScriptAndExtractInt(const ToRenderFrameHost & adapter,const std::string & script,int * result)1317 bool ExecuteScriptAndExtractInt(const ToRenderFrameHost& adapter,
1318 const std::string& script, int* result) {
1319 DCHECK(result);
1320 std::unique_ptr<base::Value> value;
1321 return ExecuteScriptHelper(adapter.render_frame_host(), script, true,
1322 ISOLATED_WORLD_ID_GLOBAL, &value) &&
1323 value && value->GetAsInteger(result);
1324 }
1325
ExecuteScriptAndExtractBool(const ToRenderFrameHost & adapter,const std::string & script,bool * result)1326 bool ExecuteScriptAndExtractBool(const ToRenderFrameHost& adapter,
1327 const std::string& script, bool* result) {
1328 DCHECK(result);
1329 std::unique_ptr<base::Value> value;
1330 return ExecuteScriptHelper(adapter.render_frame_host(), script, true,
1331 ISOLATED_WORLD_ID_GLOBAL, &value) &&
1332 value && value->GetAsBoolean(result);
1333 }
1334
ExecuteScriptAndExtractString(const ToRenderFrameHost & adapter,const std::string & script,std::string * result)1335 bool ExecuteScriptAndExtractString(const ToRenderFrameHost& adapter,
1336 const std::string& script,
1337 std::string* result) {
1338 DCHECK(result);
1339 std::unique_ptr<base::Value> value;
1340 return ExecuteScriptHelper(adapter.render_frame_host(), script, true,
1341 ISOLATED_WORLD_ID_GLOBAL, &value) &&
1342 value && value->GetAsString(result);
1343 }
1344
ExecuteScriptWithoutUserGestureAndExtractDouble(const ToRenderFrameHost & adapter,const std::string & script,double * result)1345 bool ExecuteScriptWithoutUserGestureAndExtractDouble(
1346 const ToRenderFrameHost& adapter,
1347 const std::string& script,
1348 double* result) {
1349 DCHECK(result);
1350 std::unique_ptr<base::Value> value;
1351 return ExecuteScriptHelper(adapter.render_frame_host(), script, false,
1352 ISOLATED_WORLD_ID_GLOBAL, &value) &&
1353 value && value->GetAsDouble(result);
1354 }
1355
ExecuteScriptWithoutUserGestureAndExtractInt(const ToRenderFrameHost & adapter,const std::string & script,int * result)1356 bool ExecuteScriptWithoutUserGestureAndExtractInt(
1357 const ToRenderFrameHost& adapter,
1358 const std::string& script,
1359 int* result) {
1360 DCHECK(result);
1361 std::unique_ptr<base::Value> value;
1362 return ExecuteScriptHelper(adapter.render_frame_host(), script, false,
1363 ISOLATED_WORLD_ID_GLOBAL, &value) &&
1364 value && value->GetAsInteger(result);
1365 }
1366
ExecuteScriptWithoutUserGestureAndExtractBool(const ToRenderFrameHost & adapter,const std::string & script,bool * result)1367 bool ExecuteScriptWithoutUserGestureAndExtractBool(
1368 const ToRenderFrameHost& adapter,
1369 const std::string& script,
1370 bool* result) {
1371 DCHECK(result);
1372 std::unique_ptr<base::Value> value;
1373 return ExecuteScriptHelper(adapter.render_frame_host(), script, false,
1374 ISOLATED_WORLD_ID_GLOBAL, &value) &&
1375 value && value->GetAsBoolean(result);
1376 }
1377
ExecuteScriptWithoutUserGestureAndExtractString(const ToRenderFrameHost & adapter,const std::string & script,std::string * result)1378 bool ExecuteScriptWithoutUserGestureAndExtractString(
1379 const ToRenderFrameHost& adapter,
1380 const std::string& script,
1381 std::string* result) {
1382 DCHECK(result);
1383 std::unique_ptr<base::Value> value;
1384 return ExecuteScriptHelper(adapter.render_frame_host(), script, false,
1385 ISOLATED_WORLD_ID_GLOBAL, &value) &&
1386 value && value->GetAsString(result);
1387 }
1388
1389 // EvalJsResult methods.
EvalJsResult(base::Value value,const std::string & error)1390 EvalJsResult::EvalJsResult(base::Value value, const std::string& error)
1391 : value(error.empty() ? std::move(value) : base::Value()), error(error) {}
1392
EvalJsResult(const EvalJsResult & other)1393 EvalJsResult::EvalJsResult(const EvalJsResult& other)
1394 : value(other.value.Clone()), error(other.error) {}
1395
ExtractString() const1396 const std::string& EvalJsResult::ExtractString() const {
1397 CHECK(error.empty())
1398 << "Can't ExtractString() because the script encountered a problem: "
1399 << error;
1400 CHECK(value.is_string()) << "Can't ExtractString() because script result: "
1401 << value << "is not a string.";
1402 return value.GetString();
1403 }
1404
ExtractInt() const1405 int EvalJsResult::ExtractInt() const {
1406 CHECK(error.empty())
1407 << "Can't ExtractInt() because the script encountered a problem: "
1408 << error;
1409 CHECK(value.is_int()) << "Can't ExtractInt() because script result: " << value
1410 << "is not an int.";
1411 return value.GetInt();
1412 }
1413
ExtractBool() const1414 bool EvalJsResult::ExtractBool() const {
1415 CHECK(error.empty())
1416 << "Can't ExtractBool() because the script encountered a problem: "
1417 << error;
1418 CHECK(value.is_bool()) << "Can't ExtractBool() because script result: "
1419 << value << "is not a bool.";
1420 return value.GetBool();
1421 }
1422
ExtractDouble() const1423 double EvalJsResult::ExtractDouble() const {
1424 CHECK(error.empty())
1425 << "Can't ExtractDouble() because the script encountered a problem: "
1426 << error;
1427 CHECK(value.is_double() || value.is_int())
1428 << "Can't ExtractDouble() because script result: " << value
1429 << "is not a double or int.";
1430 return value.GetDouble();
1431 }
1432
ExtractList() const1433 base::ListValue EvalJsResult::ExtractList() const {
1434 CHECK(error.empty())
1435 << "Can't ExtractList() because the script encountered a problem: "
1436 << error;
1437 CHECK(value.is_list()) << "Can't ExtractList() because script result: "
1438 << value << "is not a list.";
1439 return base::ListValue(value.GetList());
1440 }
1441
PrintTo(const EvalJsResult & bar,::std::ostream * os)1442 void PrintTo(const EvalJsResult& bar, ::std::ostream* os) {
1443 if (!bar.error.empty()) {
1444 *os << bar.error;
1445 } else {
1446 *os << bar.value;
1447 }
1448 }
1449
1450 namespace {
1451
1452 // Parse a JS stack trace out of |js_error|, detect frames that match
1453 // |source_name|, and interleave the appropriate lines of source code from
1454 // |source| into the error report. This is meant to be useful for scripts that
1455 // are passed to ExecuteScript functions, and hence dynamically generated.
1456 //
1457 // An adjustment of |column_adjustment_for_line_one| characters is subtracted
1458 // when mapping positions from line 1 of |source|. This is to offset the effect
1459 // of boilerplate added by the script runner.
1460 //
1461 // TODO(nick): Elide snippets to 80 chars, since it is common for sources to not
1462 // include newlines.
AnnotateAndAdjustJsStackTraces(const std::string & js_error,std::string source_name,const std::string & source,int column_adjustment_for_line_one)1463 std::string AnnotateAndAdjustJsStackTraces(const std::string& js_error,
1464 std::string source_name,
1465 const std::string& source,
1466 int column_adjustment_for_line_one) {
1467 // Escape wildcards in |source_name| for use in MatchPattern.
1468 base::ReplaceChars(source_name, "\\", "\\\\", &source_name);
1469 base::ReplaceChars(source_name, "*", "\\*", &source_name);
1470 base::ReplaceChars(source_name, "?", "\\?", &source_name);
1471
1472 // This vector maps line numbers to the corresponding text in |source|.
1473 const std::vector<base::StringPiece> source_lines = base::SplitStringPiece(
1474 source, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
1475
1476 // |source_frame_pattern| should match any line that looks like a stack frame
1477 // from a source file named |source_name|.
1478 const std::string source_frame_pattern =
1479 base::StringPrintf(" at * (%s:*:*)", source_name.c_str());
1480
1481 // This is the amount of indentation that is applied to the lines of inserted
1482 // annotations.
1483 const std::string indent(8, ' ');
1484 const base::StringPiece elision_mark = "";
1485
1486 // Loop over each line of |js_error|, and append each to |annotated_error| --
1487 // possibly rewriting to include extra context.
1488 std::ostringstream annotated_error;
1489 for (const base::StringPiece& error_line : base::SplitStringPiece(
1490 js_error, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)) {
1491 // Does this look like a stack frame whose URL source matches |source_name|?
1492 if (base::MatchPattern(error_line, source_frame_pattern)) {
1493 // When a match occurs, annotate the stack trace with the corresponding
1494 // line from |source|, along with a ^^^ underneath, indicating the column
1495 // position.
1496 std::vector<base::StringPiece> error_line_parts = base::SplitStringPiece(
1497 error_line, ":", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
1498 CHECK_GE(error_line_parts.size(), 2u);
1499
1500 int column_number = 0;
1501 base::StringToInt(error_line_parts.back(), &column_number);
1502 error_line_parts.pop_back();
1503 int line_number = 0;
1504 base::StringToInt(error_line_parts.back(), &line_number);
1505 error_line_parts.pop_back();
1506
1507 // Protect against out-of-range matches.
1508 if ((line_number > 0) && (column_number > 0) &&
1509 static_cast<size_t>(line_number) <= source_lines.size()) {
1510 // Apply adjustment requested by caller to columns on the first line.
1511 // This allows us to add preamble boilerplate to the script, but still
1512 // locate errors correctly.
1513 if (line_number == 1 && column_number > column_adjustment_for_line_one)
1514 column_number -= column_adjustment_for_line_one;
1515
1516 // Some source lines are huge. Elide |source_line| so that it doesn't
1517 // occupy more than one actual line.
1518 std::string source_line = source_lines[line_number - 1].as_string();
1519
1520 int max_column_number = 60 - indent.length();
1521 if (column_number > max_column_number) {
1522 source_line = source_line.substr(column_number - max_column_number);
1523 column_number = max_column_number;
1524 source_line.replace(0, elision_mark.length(), elision_mark.data(),
1525 elision_mark.length());
1526 }
1527
1528 size_t max_length = 80 - indent.length();
1529 if (source_line.length() > max_length) {
1530 source_line = base::StrCat(
1531 {source_line.substr(0, max_length - elision_mark.length()),
1532 elision_mark});
1533 }
1534
1535 annotated_error << base::JoinString(error_line_parts, ":") << ":"
1536 << line_number << ":" << column_number << "):\n"
1537 << indent << source_line << '\n'
1538 << indent << std::string(column_number - 1, ' ')
1539 << "^^^^^\n";
1540 continue;
1541 }
1542 }
1543 // This line was not rewritten -- just append it as-is.
1544 annotated_error << error_line << "\n";
1545 }
1546 return annotated_error.str();
1547 }
1548
EvalRunnerScript(const ToRenderFrameHost & execution_target,const std::string & script,int options,int32_t world_id,const std::string & token)1549 EvalJsResult EvalRunnerScript(const ToRenderFrameHost& execution_target,
1550 const std::string& script,
1551 int options,
1552 int32_t world_id,
1553 const std::string& token) {
1554 const char* kSourceURL = "__const_std::string&_script__";
1555 bool use_automatic_reply = !(options & EXECUTE_SCRIPT_USE_MANUAL_REPLY);
1556 bool user_gesture = !(options & EXECUTE_SCRIPT_NO_USER_GESTURE);
1557 std::ostringstream error_stream;
1558 std::unique_ptr<base::Value> response;
1559 if (!execution_target.render_frame_host()->IsRenderFrameLive()) {
1560 error_stream << "Error: EvalJs won't work on an already-crashed frame.";
1561 } else if (!ExecuteScriptHelper(execution_target.render_frame_host(), script,
1562 user_gesture, world_id, &response)) {
1563 error_stream << "Internal Error: ExecuteScriptHelper failed";
1564 } else if (!response) {
1565 error_stream << "Internal Error: no value";
1566 } else {
1567 bool is_reply_from_script = response->is_list() &&
1568 response->GetList().size() == 2 &&
1569 response->GetList()[0].is_string() &&
1570 response->GetList()[0].GetString() == token;
1571
1572 bool is_error = is_reply_from_script && response->GetList()[1].is_string();
1573 bool is_automatic_success_reply =
1574 is_reply_from_script && response->GetList()[1].is_list() &&
1575 response->GetList()[1].GetList().size() == 1;
1576
1577 if (is_error) {
1578 // This is a response generated by the error handler in our runner
1579 // script. This occurs when the script throws an exception, or when
1580 // eval throws a SyntaxError.
1581 //
1582 // Parse the stack trace here, and interleave lines of source code from
1583 // |script| to aid debugging.
1584 std::string error_text = response->GetList()[1].GetString();
1585
1586 if (base::StartsWith(error_text,
1587 "a JavaScript error:\nEvalError: Refused",
1588 base::CompareCase::SENSITIVE)) {
1589 error_text =
1590 "EvalJs encountered an EvalError, because eval() is blocked by the "
1591 "document's CSP on this page. To test content that is protected by "
1592 "CSP, consider using EvalJs with an isolated world. Details: " +
1593 error_text;
1594 }
1595
1596 CHECK(!error_text.empty());
1597 error_stream << AnnotateAndAdjustJsStackTraces(error_text, kSourceURL,
1598 script, 0);
1599 } else if (!use_automatic_reply) {
1600 // When |script| itself calls domAutomationController.send() on success,
1601 // |response| could be anything; so there's no more checking we can do:
1602 // return |response| as success, with an empty error.
1603 return EvalJsResult(std::move(*response), std::string());
1604 } else if (is_automatic_success_reply) {
1605 // Got a response from the runner script that indicates success (of the
1606 // form [token, [completion_value]]. Return the completion value, with an
1607 // empty error.
1608 return EvalJsResult(std::move(response->GetList()[1].GetList()[0]),
1609 std::string());
1610 } else {
1611 // The response was not well-formed (it failed the token match), so it's
1612 // not from our runner script. Fail with an explanation of the raw
1613 // message. This allows us to reject other calls
1614 // domAutomationController.send().
1615 error_stream
1616 << "Internal Error: expected a 2-element list of the form "
1617 << "['" << token << "', [result]]; but got instead: " << *response
1618 << " ... This is potentially because a script tried to call "
1619 "domAutomationController.send itself -- that is only allowed "
1620 "when using EvalJsWithManualReply(). When using EvalJs(), result "
1621 "values are just the result of calling eval() on the script -- "
1622 "the completion value is the value of the last executed "
1623 "statement. When using ExecJs(), there is no result value.";
1624 }
1625 }
1626
1627 // Something went wrong. Return an empty value and a non-empty error.
1628 return EvalJsResult(base::Value(), error_stream.str());
1629 }
1630
1631 } // namespace
1632
ExecJs(const ToRenderFrameHost & execution_target,const std::string & script,int options,int32_t world_id)1633 testing::AssertionResult ExecJs(const ToRenderFrameHost& execution_target,
1634 const std::string& script,
1635 int options,
1636 int32_t world_id) {
1637 CHECK(!(options & EXECUTE_SCRIPT_USE_MANUAL_REPLY))
1638 << "USE_MANUAL_REPLY does not make sense with ExecJs.";
1639
1640 // ExecJs() doesn't care about the result, so disable promise resolution.
1641 // Instead of using ExecJs() to wait for an async event, callers may use
1642 // EvalJs() with a sentinel result value like "success".
1643 options |= EXECUTE_SCRIPT_NO_RESOLVE_PROMISES;
1644
1645 // TODO(nick): Do we care enough about folks shooting themselves in the foot
1646 // here with e.g. ASSERT_TRUE(ExecJs("window == window.top")) -- when they
1647 // mean EvalJs -- to fail a CHECK() when eval_result.value.is_bool()?
1648 EvalJsResult eval_result =
1649 EvalJs(execution_target, script, options, world_id);
1650
1651 // NOTE: |eval_result.value| is intentionally ignored by ExecJs().
1652 if (!eval_result.error.empty())
1653 return testing::AssertionFailure() << eval_result.error;
1654 return testing::AssertionSuccess();
1655 }
1656
EvalJs(const ToRenderFrameHost & execution_target,const std::string & script,int options,int32_t world_id)1657 EvalJsResult EvalJs(const ToRenderFrameHost& execution_target,
1658 const std::string& script,
1659 int options,
1660 int32_t world_id) {
1661 // The sourceURL= parameter provides a string that replaces <anonymous> in
1662 // stack traces, if an Error is thrown. 'std::string' is meant to communicate
1663 // that this is a dynamic argument originating from C++ code.
1664 const char* kSourceURL = "__const_std::string&_script__";
1665 std::string modified_script =
1666 base::StringPrintf("%s;\n//# sourceURL=%s", script.c_str(), kSourceURL);
1667
1668 // An extra eval() indirection is used here to catch syntax errors and return
1669 // them as assertion failures. This eval() operation deliberately occurs in
1670 // the global scope, so 'var' declarations in |script| will persist for later
1671 // script executions. (As an aside: global/local scope for eval depends on
1672 // whether 'eval' is called directly or indirectly; 'window.eval()' is
1673 // indirect).
1674 //
1675 // The call to eval() itself is inside a .then() handler so that syntax errors
1676 // result in Promise rejection. Calling eval() either throws (in the event of
1677 // a SyntaxError) or returns the script's completion value.
1678 //
1679 // The result of eval() (i.e., the statement completion value of |script|) is
1680 // wrapped in an array and passed to a second .then() handler. If eval()
1681 // returned a Promise and the |resolve_promises| option is set, this handler
1682 // calls Promise.all to reply after the returned Promise resolves.
1683 //
1684 // If |script| evaluated successfully, the third.then() handler maps the
1685 // resolved |result| of eval() to a |reply| that is a one-element list
1686 // containing the value (this element can be any JSON-serializable type). If
1687 // the manual reply option is being used, no reply is emitted after successful
1688 // execution -- the script is expected to call send() itself. The call to
1689 // Promise.reject() squelches this reply, and the final .then() handler is not
1690 // called.
1691 //
1692 // If an uncaught error was thrown, or eval() returns a Promise that is
1693 // rejected, the third .then() handler maps the |error| to a |reply| that is
1694 // a string value.
1695 //
1696 // The fourth and final .then() handler passes the |reply| (whether
1697 // successful or unsuccessful) to domAutomationController.send(), so that it's
1698 // transmitted back here in browser process C++ land. A GUID token is also
1699 // included, that protects against |script| directly calling
1700 // domAutomationController.send() itself, which is disallowed in EvalJs.
1701 bool use_automatic_reply = !(options & EXECUTE_SCRIPT_USE_MANUAL_REPLY);
1702 bool resolve_promises = !(options & EXECUTE_SCRIPT_NO_RESOLVE_PROMISES);
1703
1704 std::string token = "EvalJs-" + base::GenerateGUID();
1705 std::string runner_script = JsReplace(
1706 R"(Promise.resolve($1)
1707 .then(script => [window.eval(script)])
1708 .then((result) => $2 ? Promise.all(result) : result )
1709 .then((result) => $3 ? result : Promise.reject(),
1710 (error) => 'a JavaScript error:' +
1711 (error && error.stack ? '\n' + error.stack
1712 : ' "' + error + '"'))
1713 .then((reply) => window.domAutomationController.send([$4, reply]));
1714 //# sourceURL=EvalJs-runner.js)",
1715 modified_script, resolve_promises, use_automatic_reply, token);
1716
1717 return EvalRunnerScript(execution_target, runner_script, options, world_id,
1718 token);
1719 }
1720
EvalJsWithManualReply(const ToRenderFrameHost & execution_target,const std::string & script,int options,int32_t world_id)1721 EvalJsResult EvalJsWithManualReply(const ToRenderFrameHost& execution_target,
1722 const std::string& script,
1723 int options,
1724 int32_t world_id) {
1725 return EvalJs(execution_target, script,
1726 options | EXECUTE_SCRIPT_USE_MANUAL_REPLY, world_id);
1727 }
1728
EvalJsAfterLifecycleUpdate(const ToRenderFrameHost & execution_target,const std::string & raf_script,const std::string & script,int options,int32_t world_id)1729 EvalJsResult EvalJsAfterLifecycleUpdate(
1730 const ToRenderFrameHost& execution_target,
1731 const std::string& raf_script,
1732 const std::string& script,
1733 int options,
1734 int32_t world_id) {
1735 bool use_automatic_reply = !(options & EXECUTE_SCRIPT_USE_MANUAL_REPLY);
1736 bool resolve_promises = !(options & EXECUTE_SCRIPT_NO_RESOLVE_PROMISES);
1737 std::string token = "EvalJs-" + base::GenerateGUID();
1738 const char* kSourceURL = "__const_std::string&_script__";
1739 std::string modified_raf_script;
1740 if (raf_script.length()) {
1741 modified_raf_script = base::StringPrintf("%s;\n//# sourceURL=%s",
1742 raf_script.c_str(), kSourceURL);
1743 }
1744 std::string modified_script =
1745 base::StringPrintf("%s;\n//# sourceURL=%s", script.c_str(), kSourceURL);
1746
1747 // This runner_script is very similar to that used by EvalJs, except that
1748 // this one delays running the argument script until just before
1749 // (|raf_script|) and after (|script|) a rendering update.
1750 std::string runner_script = JsReplace(
1751 R"(Promise.all([$1, $2])
1752 .then(scripts => new Promise((resolve, reject) => {
1753 requestAnimationFrame(() => {
1754 window.eval(scripts[0]);
1755 setTimeout(() => {
1756 resolve([window.eval(scripts[1])])
1757 }) }) }) )
1758 .then((result) => $3 ? Promise.all(result) : result )
1759 .then((result) => $4 ? result : Promise.reject(),
1760 (error) => 'a JavaScript error:' +
1761 (error && error.stack ? '\n' + error.stack
1762 : ' "' + error + '"'))
1763 .then((reply) => window.domAutomationController.send([$5, reply]));
1764 //# sourceURL=EvalJs-runner.js)",
1765 modified_raf_script, modified_script, resolve_promises,
1766 use_automatic_reply, token);
1767
1768 return EvalRunnerScript(execution_target, runner_script, options, world_id,
1769 token);
1770 }
1771
1772 namespace {
AddToSetIfFrameMatchesPredicate(std::set<RenderFrameHost * > * frame_set,base::OnceCallback<bool (RenderFrameHost *)> predicate,RenderFrameHost * host)1773 void AddToSetIfFrameMatchesPredicate(
1774 std::set<RenderFrameHost*>* frame_set,
1775 base::OnceCallback<bool(RenderFrameHost*)> predicate,
1776 RenderFrameHost* host) {
1777 if (std::move(predicate).Run(host))
1778 frame_set->insert(host);
1779 }
1780 }
1781
FrameMatchingPredicate(WebContents * web_contents,base::RepeatingCallback<bool (RenderFrameHost *)> predicate)1782 RenderFrameHost* FrameMatchingPredicate(
1783 WebContents* web_contents,
1784 base::RepeatingCallback<bool(RenderFrameHost*)> predicate) {
1785 std::set<RenderFrameHost*> frame_set;
1786 web_contents->ForEachFrame(base::BindRepeating(
1787 &AddToSetIfFrameMatchesPredicate, &frame_set, predicate));
1788 EXPECT_EQ(1U, frame_set.size());
1789 return frame_set.size() == 1 ? *frame_set.begin() : nullptr;
1790 }
1791
FrameMatchesName(const std::string & name,RenderFrameHost * frame)1792 bool FrameMatchesName(const std::string& name, RenderFrameHost* frame) {
1793 return frame->GetFrameName() == name;
1794 }
1795
FrameIsChildOfMainFrame(RenderFrameHost * frame)1796 bool FrameIsChildOfMainFrame(RenderFrameHost* frame) {
1797 return frame->GetParent() && !frame->GetParent()->GetParent();
1798 }
1799
FrameHasSourceUrl(const GURL & url,RenderFrameHost * frame)1800 bool FrameHasSourceUrl(const GURL& url, RenderFrameHost* frame) {
1801 return frame->GetLastCommittedURL() == url;
1802 }
1803
ChildFrameAt(RenderFrameHost * frame,size_t index)1804 RenderFrameHost* ChildFrameAt(RenderFrameHost* frame, size_t index) {
1805 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(frame);
1806 if (index >= rfh->frame_tree_node()->child_count())
1807 return nullptr;
1808 return rfh->frame_tree_node()->child_at(index)->current_frame_host();
1809 }
1810
ExecuteWebUIResourceTest(WebContents * web_contents,const std::vector<int> & js_resource_ids)1811 bool ExecuteWebUIResourceTest(WebContents* web_contents,
1812 const std::vector<int>& js_resource_ids) {
1813 // Inject WebUI test runner script first prior to other scripts required to
1814 // run the test as scripts may depend on it being declared.
1815 std::vector<int> ids;
1816 ids.push_back(IDR_WEBUI_JS_WEBUI_RESOURCE_TEST_JS);
1817 ids.insert(ids.end(), js_resource_ids.begin(), js_resource_ids.end());
1818
1819 std::string script;
1820 for (int id : ids) {
1821 scoped_refptr<base::RefCountedMemory> bytes =
1822 ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes(id);
1823
1824 if (HasGzipHeader(*bytes))
1825 AppendGzippedResource(*bytes, &script);
1826 else
1827 script.append(bytes->front_as<char>(), bytes->size());
1828
1829 script.append("\n");
1830 }
1831 ExecuteScriptAsync(web_contents, script);
1832
1833 DOMMessageQueue message_queue;
1834
1835 bool should_wait_flag = base::CommandLine::ForCurrentProcess()->HasSwitch(
1836 switches::kWaitForDebuggerWebUI);
1837
1838 if (should_wait_flag) {
1839 ExecuteScriptAsync(
1840 web_contents,
1841 "window.waitUser = true; "
1842 "window.go = function() { window.waitUser = false }; "
1843 "console.log('Waiting for debugger...'); "
1844 "console.log('Run: go() in the JS console when you are ready.');");
1845 }
1846
1847 ExecuteScriptAsync(web_contents, "runTests()");
1848
1849 std::string message;
1850 do {
1851 if (!message_queue.WaitForMessage(&message))
1852 return false;
1853 } while (message.compare("\"PENDING\"") == 0);
1854
1855 return message.compare("\"SUCCESS\"") == 0;
1856 }
1857
GetCookies(BrowserContext * browser_context,const GURL & url,net::CookieOptions::SameSiteCookieContext context)1858 std::string GetCookies(BrowserContext* browser_context,
1859 const GURL& url,
1860 net::CookieOptions::SameSiteCookieContext context) {
1861 std::string cookies;
1862 base::RunLoop run_loop;
1863 mojo::Remote<network::mojom::CookieManager> cookie_manager;
1864 BrowserContext::GetDefaultStoragePartition(browser_context)
1865 ->GetNetworkContext()
1866 ->GetCookieManager(cookie_manager.BindNewPipeAndPassReceiver());
1867 net::CookieOptions options;
1868 options.set_same_site_cookie_context(context);
1869 cookie_manager->GetCookieList(
1870 url, options,
1871 base::BindOnce(
1872 [](std::string* cookies_out, base::RunLoop* run_loop,
1873 const net::CookieAccessResultList& cookies,
1874 const net::CookieAccessResultList& excluded_cookies) {
1875 *cookies_out = net::CanonicalCookie::BuildCookieLine(cookies);
1876 run_loop->Quit();
1877 },
1878 &cookies, &run_loop));
1879 run_loop.Run();
1880 return cookies;
1881 }
1882
GetCanonicalCookies(BrowserContext * browser_context,const GURL & url)1883 std::vector<net::CanonicalCookie> GetCanonicalCookies(
1884 BrowserContext* browser_context,
1885 const GURL& url) {
1886 std::vector<net::CanonicalCookie> cookies;
1887 base::RunLoop run_loop;
1888 mojo::Remote<network::mojom::CookieManager> cookie_manager;
1889 BrowserContext::GetDefaultStoragePartition(browser_context)
1890 ->GetNetworkContext()
1891 ->GetCookieManager(cookie_manager.BindNewPipeAndPassReceiver());
1892 // Allow access to SameSite cookies in tests.
1893 net::CookieOptions options;
1894 options.set_same_site_cookie_context(
1895 net::CookieOptions::SameSiteCookieContext::MakeInclusive());
1896 cookie_manager->GetCookieList(
1897 url, options,
1898 base::BindOnce(
1899 [](base::RunLoop* run_loop,
1900 std::vector<net::CanonicalCookie>* cookies_out,
1901 const net::CookieAccessResultList& cookies,
1902 const net::CookieAccessResultList& excluded_cookies) {
1903 *cookies_out = net::cookie_util::StripAccessResults(cookies);
1904 run_loop->Quit();
1905 },
1906 &run_loop, &cookies));
1907 run_loop.Run();
1908 return cookies;
1909 }
1910
SetCookie(BrowserContext * browser_context,const GURL & url,const std::string & value,net::CookieOptions::SameSiteCookieContext context)1911 bool SetCookie(BrowserContext* browser_context,
1912 const GURL& url,
1913 const std::string& value,
1914 net::CookieOptions::SameSiteCookieContext context) {
1915 bool result = false;
1916 base::RunLoop run_loop;
1917 mojo::Remote<network::mojom::CookieManager> cookie_manager;
1918 BrowserContext::GetDefaultStoragePartition(browser_context)
1919 ->GetNetworkContext()
1920 ->GetCookieManager(cookie_manager.BindNewPipeAndPassReceiver());
1921 std::unique_ptr<net::CanonicalCookie> cc(net::CanonicalCookie::Create(
1922 url, value, base::Time::Now(), base::nullopt /* server_time */));
1923 DCHECK(cc.get());
1924
1925 net::CookieOptions options;
1926 options.set_include_httponly();
1927 options.set_same_site_cookie_context(context);
1928 cookie_manager->SetCanonicalCookie(
1929 *cc.get(), url, options,
1930 base::BindOnce(
1931 [](bool* result, base::RunLoop* run_loop,
1932 net::CookieAccessResult set_cookie_access_result) {
1933 *result = set_cookie_access_result.status.IsInclude();
1934 run_loop->Quit();
1935 },
1936 &result, &run_loop));
1937 run_loop.Run();
1938 return result;
1939 }
1940
FetchHistogramsFromChildProcesses()1941 void FetchHistogramsFromChildProcesses() {
1942 // Wait for all the renderer processes to be initialized before fetching
1943 // histograms for the first time.
1944 for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
1945 !it.IsAtEnd(); it.Advance()) {
1946 if (!it.GetCurrentValue()->IsReady()) {
1947 RenderProcessHost* render_process_host = it.GetCurrentValue();
1948 RenderProcessHostWatcher ready_watcher(
1949 render_process_host,
1950 RenderProcessHostWatcher::WATCH_FOR_PROCESS_READY);
1951 ready_watcher.Wait();
1952 }
1953 }
1954
1955 base::RunLoop run_loop;
1956
1957 FetchHistogramsAsynchronously(
1958 base::ThreadTaskRunnerHandle::Get(), run_loop.QuitClosure(),
1959 // If this call times out, it means that a child process is not
1960 // responding, which is something we should not ignore. The timeout is
1961 // set to be longer than the normal browser test timeout so that it will
1962 // be prempted by the normal timeout.
1963 TestTimeouts::action_max_timeout());
1964 run_loop.Run();
1965 }
1966
SetupCrossSiteRedirector(net::EmbeddedTestServer * embedded_test_server)1967 void SetupCrossSiteRedirector(net::EmbeddedTestServer* embedded_test_server) {
1968 embedded_test_server->RegisterRequestHandler(base::BindRepeating(
1969 &CrossSiteRedirectResponseHandler, embedded_test_server));
1970 }
1971
WaitForRenderFrameReady(RenderFrameHost * rfh)1972 bool WaitForRenderFrameReady(RenderFrameHost* rfh) {
1973 if (!rfh)
1974 return false;
1975 // TODO(nick): This can't switch to EvalJs yet, because of hardcoded
1976 // dependencies on 'pageLoadComplete' in some interstitial implementations.
1977 std::string result;
1978 EXPECT_TRUE(ExecuteScriptAndExtractString(
1979 rfh,
1980 "(async function() {"
1981 " if (document.readyState != 'complete') {"
1982 " await new Promise((resolve) =>"
1983 " document.addEventListener('readystatechange', event => {"
1984 " if (document.readyState == 'complete') {"
1985 " resolve();"
1986 " }"
1987 " }));"
1988 " }"
1989 "})().then(() => {"
1990 " window.domAutomationController.send('pageLoadComplete');"
1991 "});",
1992 &result));
1993 EXPECT_EQ("pageLoadComplete", result);
1994 return "pageLoadComplete" == result;
1995 }
1996
RemoveWebContentsReceiverSet(WebContents * web_contents,const std::string & interface_name)1997 void RemoveWebContentsReceiverSet(WebContents* web_contents,
1998 const std::string& interface_name) {
1999 static_cast<WebContentsImpl*>(web_contents)
2000 ->RemoveReceiverSetForTesting(interface_name);
2001 }
2002
EnableAccessibilityForWebContents(WebContents * web_contents)2003 void EnableAccessibilityForWebContents(WebContents* web_contents) {
2004 WebContentsImpl* web_contents_impl =
2005 static_cast<WebContentsImpl*>(web_contents);
2006 web_contents_impl->SetAccessibilityMode(ui::kAXModeComplete);
2007 }
2008
WaitForAccessibilityFocusChange()2009 void WaitForAccessibilityFocusChange() {
2010 base::RunLoop run_loop;
2011 BrowserAccessibilityManager::SetFocusChangeCallbackForTesting(
2012 run_loop.QuitClosure());
2013 run_loop.Run();
2014 }
2015
GetFocusedAccessibilityNodeInfo(WebContents * web_contents)2016 ui::AXNodeData GetFocusedAccessibilityNodeInfo(WebContents* web_contents) {
2017 WebContentsImpl* web_contents_impl =
2018 static_cast<WebContentsImpl*>(web_contents);
2019 BrowserAccessibilityManager* manager =
2020 web_contents_impl->GetRootBrowserAccessibilityManager();
2021 if (!manager)
2022 return ui::AXNodeData();
2023 BrowserAccessibility* focused_node = manager->GetFocus();
2024 return focused_node->GetData();
2025 }
2026
AccessibilityTreeContainsNodeWithName(BrowserAccessibility * node,const std::string & name)2027 bool AccessibilityTreeContainsNodeWithName(BrowserAccessibility* node,
2028 const std::string& name) {
2029 // If an image annotation is set, it plays the same role as a name, so it
2030 // makes sense to check both in the same test helper.
2031 if (node->GetStringAttribute(ax::mojom::StringAttribute::kName) == name ||
2032 node->GetStringAttribute(ax::mojom::StringAttribute::kImageAnnotation) ==
2033 name)
2034 return true;
2035 for (unsigned i = 0; i < node->PlatformChildCount(); i++) {
2036 if (AccessibilityTreeContainsNodeWithName(node->PlatformGetChild(i), name))
2037 return true;
2038 }
2039 return false;
2040 }
2041
WaitForAccessibilityTreeToChange(WebContents * web_contents)2042 void WaitForAccessibilityTreeToChange(WebContents* web_contents) {
2043 AccessibilityNotificationWaiter accessibility_waiter(
2044 web_contents, ui::AXMode(), ax::mojom::Event::kNone);
2045 accessibility_waiter.WaitForNotification();
2046 }
2047
WaitForAccessibilityTreeToContainNodeWithName(WebContents * web_contents,const std::string & name)2048 void WaitForAccessibilityTreeToContainNodeWithName(WebContents* web_contents,
2049 const std::string& name) {
2050 WebContentsImpl* web_contents_impl = static_cast<WebContentsImpl*>(
2051 web_contents);
2052 RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
2053 web_contents_impl->GetMainFrame());
2054 BrowserAccessibilityManager* main_frame_manager =
2055 main_frame->browser_accessibility_manager();
2056 while (!main_frame_manager || !AccessibilityTreeContainsNodeWithName(
2057 main_frame_manager->GetRoot(), name)) {
2058 WaitForAccessibilityTreeToChange(web_contents);
2059 main_frame_manager = main_frame->browser_accessibility_manager();
2060 }
2061 }
2062
GetAccessibilityTreeSnapshot(WebContents * web_contents)2063 ui::AXTreeUpdate GetAccessibilityTreeSnapshot(WebContents* web_contents) {
2064 WebContentsImpl* web_contents_impl =
2065 static_cast<WebContentsImpl*>(web_contents);
2066 BrowserAccessibilityManager* manager =
2067 web_contents_impl->GetRootBrowserAccessibilityManager();
2068 if (!manager)
2069 return ui::AXTreeUpdate();
2070 return manager->SnapshotAXTreeForTesting();
2071 }
2072
GetRootAccessibilityNode(WebContents * web_contents)2073 ui::AXPlatformNodeDelegate* GetRootAccessibilityNode(
2074 WebContents* web_contents) {
2075 WebContentsImpl* web_contents_impl =
2076 static_cast<WebContentsImpl*>(web_contents);
2077 BrowserAccessibilityManager* manager =
2078 web_contents_impl->GetRootBrowserAccessibilityManager();
2079 return manager ? manager->GetRoot() : nullptr;
2080 }
2081
2082 FindAccessibilityNodeCriteria::FindAccessibilityNodeCriteria() = default;
2083
2084 FindAccessibilityNodeCriteria::~FindAccessibilityNodeCriteria() = default;
2085
FindAccessibilityNode(WebContents * web_contents,const FindAccessibilityNodeCriteria & criteria)2086 ui::AXPlatformNodeDelegate* FindAccessibilityNode(
2087 WebContents* web_contents,
2088 const FindAccessibilityNodeCriteria& criteria) {
2089 ui::AXPlatformNodeDelegate* root = GetRootAccessibilityNode(web_contents);
2090 CHECK(root);
2091 return FindAccessibilityNodeInSubtree(root, criteria);
2092 }
2093
FindAccessibilityNodeInSubtree(ui::AXPlatformNodeDelegate * node,const FindAccessibilityNodeCriteria & criteria)2094 ui::AXPlatformNodeDelegate* FindAccessibilityNodeInSubtree(
2095 ui::AXPlatformNodeDelegate* node,
2096 const FindAccessibilityNodeCriteria& criteria) {
2097 auto* node_internal = BrowserAccessibility::FromAXPlatformNodeDelegate(node);
2098 DCHECK(node_internal);
2099 if ((!criteria.name ||
2100 node_internal->GetStringAttribute(ax::mojom::StringAttribute::kName) ==
2101 criteria.name.value()) &&
2102 (!criteria.role || node_internal->GetRole() == criteria.role.value())) {
2103 return node;
2104 }
2105
2106 for (unsigned int i = 0; i < node_internal->PlatformChildCount(); ++i) {
2107 BrowserAccessibility* child = node_internal->PlatformGetChild(i);
2108 ui::AXPlatformNodeDelegate* result =
2109 FindAccessibilityNodeInSubtree(child, criteria);
2110 if (result)
2111 return result;
2112 }
2113 return nullptr;
2114 }
2115
2116 #if defined(OS_WIN)
2117 template <typename T>
QueryInterfaceFromNode(ui::AXPlatformNodeDelegate * node)2118 Microsoft::WRL::ComPtr<T> QueryInterfaceFromNode(
2119 ui::AXPlatformNodeDelegate* node) {
2120 Microsoft::WRL::ComPtr<T> result;
2121 EXPECT_HRESULT_SUCCEEDED(
2122 node->GetNativeViewAccessible()->QueryInterface(__uuidof(T), &result));
2123 return result;
2124 }
2125
UiaGetPropertyValueVtArrayVtUnknownValidate(PROPERTYID property_id,ui::AXPlatformNodeDelegate * target_node,const std::vector<std::string> & expected_names)2126 void UiaGetPropertyValueVtArrayVtUnknownValidate(
2127 PROPERTYID property_id,
2128 ui::AXPlatformNodeDelegate* target_node,
2129 const std::vector<std::string>& expected_names) {
2130 ASSERT_TRUE(target_node);
2131
2132 base::win::ScopedVariant result_variant;
2133 Microsoft::WRL::ComPtr<IRawElementProviderSimple> node_provider =
2134 QueryInterfaceFromNode<IRawElementProviderSimple>(target_node);
2135
2136 node_provider->GetPropertyValue(property_id, result_variant.Receive());
2137 ASSERT_EQ(VT_ARRAY | VT_UNKNOWN, result_variant.type());
2138 ASSERT_EQ(1u, SafeArrayGetDim(V_ARRAY(result_variant.ptr())));
2139
2140 LONG lower_bound, upper_bound, size;
2141 ASSERT_HRESULT_SUCCEEDED(
2142 SafeArrayGetLBound(V_ARRAY(result_variant.ptr()), 1, &lower_bound));
2143 ASSERT_HRESULT_SUCCEEDED(
2144 SafeArrayGetUBound(V_ARRAY(result_variant.ptr()), 1, &upper_bound));
2145 size = upper_bound - lower_bound + 1;
2146 ASSERT_EQ(static_cast<LONG>(expected_names.size()), size);
2147
2148 std::vector<std::string> names;
2149 for (LONG i = 0; i < size; ++i) {
2150 Microsoft::WRL::ComPtr<IUnknown> unknown_element;
2151 ASSERT_HRESULT_SUCCEEDED(
2152 SafeArrayGetElement(V_ARRAY(result_variant.ptr()), &i,
2153 static_cast<void**>(&unknown_element)));
2154 ASSERT_NE(nullptr, unknown_element);
2155
2156 Microsoft::WRL::ComPtr<IRawElementProviderSimple>
2157 raw_element_provider_simple;
2158 ASSERT_HRESULT_SUCCEEDED(unknown_element.As(&raw_element_provider_simple));
2159 ASSERT_NE(nullptr, raw_element_provider_simple);
2160
2161 base::win::ScopedVariant name;
2162 ASSERT_HRESULT_SUCCEEDED(raw_element_provider_simple->GetPropertyValue(
2163 UIA_NamePropertyId, name.Receive()));
2164 ASSERT_EQ(VT_BSTR, name.type());
2165 names.push_back(base::UTF16ToUTF8(
2166 base::string16(V_BSTR(name.ptr()), SysStringLen(V_BSTR(name.ptr())))));
2167 }
2168
2169 ASSERT_THAT(names, testing::UnorderedElementsAreArray(expected_names));
2170 }
2171 #endif
2172
GetMouseLockWidget(WebContents * web_contents)2173 RenderWidgetHost* GetMouseLockWidget(WebContents* web_contents) {
2174 return static_cast<WebContentsImpl*>(web_contents)->GetMouseLockWidget();
2175 }
2176
GetKeyboardLockWidget(WebContents * web_contents)2177 RenderWidgetHost* GetKeyboardLockWidget(WebContents* web_contents) {
2178 return static_cast<WebContentsImpl*>(web_contents)->GetKeyboardLockWidget();
2179 }
2180
GetMouseCaptureWidget(WebContents * web_contents)2181 RenderWidgetHost* GetMouseCaptureWidget(WebContents* web_contents) {
2182 return static_cast<WebContentsImpl*>(web_contents)
2183 ->GetInputEventRouter()
2184 ->GetMouseCaptureWidgetForTests();
2185 }
2186
RequestKeyboardLock(WebContents * web_contents,base::Optional<base::flat_set<ui::DomCode>> codes)2187 bool RequestKeyboardLock(WebContents* web_contents,
2188 base::Optional<base::flat_set<ui::DomCode>> codes) {
2189 DCHECK(!codes.has_value() || !codes.value().empty());
2190 WebContentsImpl* web_contents_impl =
2191 static_cast<WebContentsImpl*>(web_contents);
2192 RenderWidgetHostImpl* render_widget_host_impl =
2193 web_contents_impl->GetMainFrame()->GetRenderWidgetHost();
2194 return render_widget_host_impl->RequestKeyboardLock(std::move(codes));
2195 }
2196
CancelKeyboardLock(WebContents * web_contents)2197 void CancelKeyboardLock(WebContents* web_contents) {
2198 WebContentsImpl* web_contents_impl =
2199 static_cast<WebContentsImpl*>(web_contents);
2200 RenderWidgetHostImpl* render_widget_host_impl =
2201 web_contents_impl->GetMainFrame()->GetRenderWidgetHost();
2202 render_widget_host_impl->CancelKeyboardLock();
2203 }
2204
GetScreenOrientationDelegate()2205 ScreenOrientationDelegate* GetScreenOrientationDelegate() {
2206 return ScreenOrientationProvider::GetDelegateForTesting();
2207 }
2208
GetInputEventRouterRenderWidgetHostViews(WebContents * web_contents)2209 std::vector<RenderWidgetHostView*> GetInputEventRouterRenderWidgetHostViews(
2210 WebContents* web_contents) {
2211 return static_cast<WebContentsImpl*>(web_contents)
2212 ->GetInputEventRouter()
2213 ->GetRenderWidgetHostViewsForTests();
2214 }
2215
GetFocusedRenderWidgetHost(WebContents * web_contents)2216 RenderWidgetHost* GetFocusedRenderWidgetHost(WebContents* web_contents) {
2217 WebContentsImpl* web_contents_impl =
2218 static_cast<WebContentsImpl*>(web_contents);
2219 return web_contents_impl->GetFocusedRenderWidgetHost(
2220 web_contents_impl->GetMainFrame()->GetRenderWidgetHost());
2221 }
2222
IsRenderWidgetHostFocused(const RenderWidgetHost * host)2223 bool IsRenderWidgetHostFocused(const RenderWidgetHost* host) {
2224 return static_cast<const RenderWidgetHostImpl*>(host)->is_focused();
2225 }
2226
GetFocusedWebContents(WebContents * web_contents)2227 WebContents* GetFocusedWebContents(WebContents* web_contents) {
2228 WebContentsImpl* web_contents_impl =
2229 static_cast<WebContentsImpl*>(web_contents);
2230 return web_contents_impl->GetFocusedWebContents();
2231 }
2232
2233 namespace {
2234
RenderFrameMetadataProviderFromFrameTreeNode(FrameTreeNode * node)2235 RenderFrameMetadataProviderImpl* RenderFrameMetadataProviderFromFrameTreeNode(
2236 FrameTreeNode* node) {
2237 DCHECK(node);
2238 DCHECK(node->current_frame_host());
2239 DCHECK(node->current_frame_host()->GetRenderWidgetHost());
2240 return node->current_frame_host()
2241 ->GetRenderWidgetHost()
2242 ->render_frame_metadata_provider();
2243 }
2244
RenderFrameMetadataProviderFromWebContents(WebContents * web_contents)2245 RenderFrameMetadataProviderImpl* RenderFrameMetadataProviderFromWebContents(
2246 WebContents* web_contents) {
2247 DCHECK(web_contents);
2248 DCHECK(web_contents->GetMainFrame()->GetRenderViewHost());
2249 DCHECK(RenderWidgetHostImpl::From(
2250 web_contents->GetMainFrame()->GetRenderViewHost()->GetWidget())
2251 ->render_frame_metadata_provider());
2252 return RenderWidgetHostImpl::From(
2253 web_contents->GetMainFrame()->GetRenderViewHost()->GetWidget())
2254 ->render_frame_metadata_provider();
2255 }
2256
2257 } // namespace
2258
TitleWatcher(WebContents * web_contents,const base::string16 & expected_title)2259 TitleWatcher::TitleWatcher(WebContents* web_contents,
2260 const base::string16& expected_title)
2261 : WebContentsObserver(web_contents) {
2262 expected_titles_.push_back(expected_title);
2263 }
2264
AlsoWaitForTitle(const base::string16 & expected_title)2265 void TitleWatcher::AlsoWaitForTitle(const base::string16& expected_title) {
2266 expected_titles_.push_back(expected_title);
2267 }
2268
2269 TitleWatcher::~TitleWatcher() = default;
2270
WaitAndGetTitle()2271 const base::string16& TitleWatcher::WaitAndGetTitle() {
2272 TestTitle();
2273 run_loop_.Run();
2274 return observed_title_;
2275 }
2276
DidStopLoading()2277 void TitleWatcher::DidStopLoading() {
2278 // When navigating through the history, the restored NavigationEntry's title
2279 // will be used. If the entry ends up having the same title after we return
2280 // to it, as will usually be the case, then WebContentsObserver::TitleSet
2281 // will then be suppressed, since the NavigationEntry's title hasn't changed.
2282 TestTitle();
2283 }
2284
TitleWasSet(NavigationEntry * entry)2285 void TitleWatcher::TitleWasSet(NavigationEntry* entry) {
2286 TestTitle();
2287 }
2288
TestTitle()2289 void TitleWatcher::TestTitle() {
2290 const base::string16& current_title = web_contents()->GetTitle();
2291 if (base::Contains(expected_titles_, current_title)) {
2292 observed_title_ = current_title;
2293 run_loop_.Quit();
2294 }
2295 }
2296
RenderProcessHostWatcher(RenderProcessHost * render_process_host,WatchType type)2297 RenderProcessHostWatcher::RenderProcessHostWatcher(
2298 RenderProcessHost* render_process_host,
2299 WatchType type)
2300 : render_process_host_(render_process_host),
2301 type_(type),
2302 did_exit_normally_(true),
2303 allow_renderer_crashes_(
2304 std::make_unique<ScopedAllowRendererCrashes>(render_process_host)),
2305 quit_closure_(run_loop_.QuitClosure()) {
2306 render_process_host_->AddObserver(this);
2307 }
2308
RenderProcessHostWatcher(WebContents * web_contents,WatchType type)2309 RenderProcessHostWatcher::RenderProcessHostWatcher(WebContents* web_contents,
2310 WatchType type)
2311 : RenderProcessHostWatcher(web_contents->GetMainFrame()->GetProcess(),
2312 type) {}
2313
~RenderProcessHostWatcher()2314 RenderProcessHostWatcher::~RenderProcessHostWatcher() {
2315 ClearProcessHost();
2316 }
2317
ClearProcessHost()2318 void RenderProcessHostWatcher::ClearProcessHost() {
2319 // Although we would like to make it so that from here on, renderer crashes
2320 // cause test failures, resetting ScopedAllowRendererCrashes inside the RPH
2321 // observers is too soon. The current crash is notified to the testing
2322 // framework *after* the observers run and we need this one to be ignored.
2323 if (render_process_host_)
2324 render_process_host_->RemoveObserver(this);
2325 render_process_host_ = nullptr;
2326 }
2327
Wait()2328 void RenderProcessHostWatcher::Wait() {
2329 run_loop_.Run();
2330
2331 DCHECK(allow_renderer_crashes_)
2332 << "RenderProcessHostWatcher::Wait() may only be called once";
2333 allow_renderer_crashes_.reset();
2334 // Call this here just in case something else quits the RunLoop.
2335 ClearProcessHost();
2336 }
2337
QuitRunLoop()2338 void RenderProcessHostWatcher::QuitRunLoop() {
2339 std::move(quit_closure_).Run();
2340 ClearProcessHost();
2341 }
2342
RenderProcessReady(RenderProcessHost * host)2343 void RenderProcessHostWatcher::RenderProcessReady(RenderProcessHost* host) {
2344 if (type_ == WATCH_FOR_PROCESS_READY)
2345 QuitRunLoop();
2346 }
2347
RenderProcessExited(RenderProcessHost * host,const ChildProcessTerminationInfo & info)2348 void RenderProcessHostWatcher::RenderProcessExited(
2349 RenderProcessHost* host,
2350 const ChildProcessTerminationInfo& info) {
2351 did_exit_normally_ =
2352 info.status == base::TERMINATION_STATUS_NORMAL_TERMINATION;
2353 if (type_ == WATCH_FOR_PROCESS_EXIT)
2354 QuitRunLoop();
2355 }
2356
RenderProcessHostDestroyed(RenderProcessHost * host)2357 void RenderProcessHostWatcher::RenderProcessHostDestroyed(
2358 RenderProcessHost* host) {
2359 render_process_host_ = nullptr;
2360 if (type_ == WATCH_FOR_HOST_DESTRUCTION)
2361 QuitRunLoop();
2362 }
2363
RenderProcessHostKillWaiter(RenderProcessHost * render_process_host,const std::string & uma_name)2364 RenderProcessHostKillWaiter::RenderProcessHostKillWaiter(
2365 RenderProcessHost* render_process_host,
2366 const std::string& uma_name)
2367 : exit_watcher_(render_process_host,
2368 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT),
2369 uma_name_(uma_name) {}
2370
Wait()2371 base::Optional<int> RenderProcessHostKillWaiter::Wait() {
2372 base::Optional<bad_message::BadMessageReason> result;
2373
2374 // Wait for the renderer kill.
2375 exit_watcher_.Wait();
2376 #if !defined(OS_ANDROID)
2377 // Getting termination status on android is not reliable. To avoid flakiness,
2378 // we can skip this check and just check bad message. On other platforms we
2379 // want to verify that the renderer got killed, rather than exiting normally.
2380 if (exit_watcher_.did_exit_normally()) {
2381 LOG(ERROR) << "Renderer unexpectedly exited normally.";
2382 return result;
2383 }
2384 #endif
2385
2386 // Find the logged UMA data (if present).
2387 std::vector<base::Bucket> uma_samples =
2388 histogram_tester_.GetAllSamples(uma_name_);
2389 // No UMA will be present if the kill was not triggered by the //content layer
2390 // (e.g. if it was triggered by bad_message::ReceivedBadMessage from //chrome
2391 // layer or from somewhere in the //components layer).
2392 if (uma_samples.empty()) {
2393 LOG(ERROR) << "Unexpectedly found no '" << uma_name_ << "' samples.";
2394 return result;
2395 }
2396 const base::Bucket& bucket = uma_samples.back();
2397 // Assuming that user of RenderProcessHostKillWatcher makes sure that only one
2398 // kill can happen while using the class.
2399 DCHECK_EQ(1u, uma_samples.size())
2400 << "Multiple renderer kills are unsupported";
2401
2402 return bucket.min;
2403 }
2404
RenderProcessHostBadMojoMessageWaiter(RenderProcessHost * render_process_host)2405 RenderProcessHostBadMojoMessageWaiter::RenderProcessHostBadMojoMessageWaiter(
2406 RenderProcessHost* render_process_host)
2407 : monitored_render_process_id_(render_process_host->GetID()),
2408 kill_waiter_(render_process_host,
2409 "Stability.BadMessageTerminated.Content") {
2410 // base::Unretained is safe below, because the destructor unregisters the
2411 // callback.
2412 RenderProcessHostImpl::SetBadMojoMessageCallbackForTesting(
2413 base::BindRepeating(
2414 &RenderProcessHostBadMojoMessageWaiter::OnBadMojoMessage,
2415 base::Unretained(this)));
2416 }
2417
2418 RenderProcessHostBadMojoMessageWaiter::
~RenderProcessHostBadMojoMessageWaiter()2419 ~RenderProcessHostBadMojoMessageWaiter() {
2420 RenderProcessHostImpl::SetBadMojoMessageCallbackForTesting(
2421 RenderProcessHostImpl::BadMojoMessageCallbackForTesting());
2422 }
2423
Wait()2424 base::Optional<std::string> RenderProcessHostBadMojoMessageWaiter::Wait() {
2425 base::Optional<int> bad_message_reason = kill_waiter_.Wait();
2426 if (!bad_message_reason.has_value())
2427 return base::nullopt;
2428 if (bad_message_reason.value() != bad_message::RPH_MOJO_PROCESS_ERROR) {
2429 LOG(ERROR) << "Unexpected |bad_message_reason|: "
2430 << bad_message_reason.value();
2431 return base::nullopt;
2432 }
2433
2434 return observed_mojo_error_;
2435 }
2436
OnBadMojoMessage(int render_process_id,const std::string & error)2437 void RenderProcessHostBadMojoMessageWaiter::OnBadMojoMessage(
2438 int render_process_id,
2439 const std::string& error) {
2440 if (render_process_id == monitored_render_process_id_)
2441 observed_mojo_error_ = error;
2442 }
2443
DOMMessageQueue()2444 DOMMessageQueue::DOMMessageQueue() {
2445 registrar_.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE,
2446 NotificationService::AllSources());
2447 }
2448
DOMMessageQueue(WebContents * web_contents)2449 DOMMessageQueue::DOMMessageQueue(WebContents* web_contents)
2450 : WebContentsObserver(web_contents) {
2451 registrar_.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE,
2452 Source<WebContents>(web_contents));
2453 }
2454
DOMMessageQueue(RenderFrameHost * render_frame_host)2455 DOMMessageQueue::DOMMessageQueue(RenderFrameHost* render_frame_host)
2456 : DOMMessageQueue(WebContents::FromRenderFrameHost(render_frame_host)) {
2457 render_frame_host_ = render_frame_host;
2458 }
2459
2460 DOMMessageQueue::~DOMMessageQueue() = default;
2461
Observe(int type,const NotificationSource & source,const NotificationDetails & details)2462 void DOMMessageQueue::Observe(int type,
2463 const NotificationSource& source,
2464 const NotificationDetails& details) {
2465 Details<std::string> dom_op_result(details);
2466 message_queue_.push(*dom_op_result.ptr());
2467 if (quit_closure_)
2468 std::move(quit_closure_).Run();
2469 }
2470
RenderProcessGone(base::TerminationStatus status)2471 void DOMMessageQueue::RenderProcessGone(base::TerminationStatus status) {
2472 VLOG(0) << "DOMMessageQueue::RenderProcessGone " << status;
2473 switch (status) {
2474 case base::TERMINATION_STATUS_NORMAL_TERMINATION:
2475 case base::TERMINATION_STATUS_STILL_RUNNING:
2476 break;
2477 default:
2478 renderer_crashed_ = true;
2479 if (quit_closure_)
2480 std::move(quit_closure_).Run();
2481 break;
2482 }
2483 }
2484
RenderFrameDeleted(RenderFrameHost * render_frame_host)2485 void DOMMessageQueue::RenderFrameDeleted(RenderFrameHost* render_frame_host) {
2486 if (!render_frame_host_)
2487 return;
2488 if (render_frame_host_ != render_frame_host)
2489 return;
2490 if (quit_closure_)
2491 std::move(quit_closure_).Run();
2492 }
2493
ClearQueue()2494 void DOMMessageQueue::ClearQueue() {
2495 message_queue_ = base::queue<std::string>();
2496 }
2497
WaitForMessage(std::string * message)2498 bool DOMMessageQueue::WaitForMessage(std::string* message) {
2499 DCHECK(message);
2500 if (!renderer_crashed_ && message_queue_.empty()) {
2501 // This will be quit when a new message comes in.
2502 base::RunLoop run_loop{base::RunLoop::Type::kNestableTasksAllowed};
2503 quit_closure_ = run_loop.QuitClosure();
2504 run_loop.Run();
2505 }
2506 return PopMessage(message);
2507 }
2508
PopMessage(std::string * message)2509 bool DOMMessageQueue::PopMessage(std::string* message) {
2510 DCHECK(message);
2511 if (renderer_crashed_ || message_queue_.empty())
2512 return false;
2513 *message = message_queue_.front();
2514 message_queue_.pop();
2515 return true;
2516 }
2517
2518 class WebContentsAddedObserver::RenderViewCreatedObserver
2519 : public WebContentsObserver {
2520 public:
RenderViewCreatedObserver(WebContents * web_contents)2521 explicit RenderViewCreatedObserver(WebContents* web_contents)
2522 : WebContentsObserver(web_contents),
2523 render_view_created_called_(false),
2524 main_frame_created_called_(false) {}
2525
2526 // WebContentsObserver:
RenderViewCreated(RenderViewHost * rvh)2527 void RenderViewCreated(RenderViewHost* rvh) override {
2528 render_view_created_called_ = true;
2529 }
2530
RenderFrameCreated(RenderFrameHost * rfh)2531 void RenderFrameCreated(RenderFrameHost* rfh) override {
2532 if (rfh == web_contents()->GetMainFrame())
2533 main_frame_created_called_ = true;
2534 }
2535
2536 bool render_view_created_called_;
2537 bool main_frame_created_called_;
2538 };
2539
WebContentsAddedObserver()2540 WebContentsAddedObserver::WebContentsAddedObserver()
2541 : web_contents_created_callback_(
2542 base::BindRepeating(&WebContentsAddedObserver::WebContentsCreated,
2543 base::Unretained(this))),
2544 web_contents_(nullptr) {
2545 WebContentsImpl::FriendWrapper::AddCreatedCallbackForTesting(
2546 web_contents_created_callback_);
2547 }
2548
~WebContentsAddedObserver()2549 WebContentsAddedObserver::~WebContentsAddedObserver() {
2550 WebContentsImpl::FriendWrapper::RemoveCreatedCallbackForTesting(
2551 web_contents_created_callback_);
2552 }
2553
WebContentsCreated(WebContents * web_contents)2554 void WebContentsAddedObserver::WebContentsCreated(WebContents* web_contents) {
2555 DCHECK(!web_contents_);
2556 web_contents_ = web_contents;
2557 child_observer_ = std::make_unique<RenderViewCreatedObserver>(web_contents);
2558
2559 if (quit_closure_)
2560 std::move(quit_closure_).Run();
2561 }
2562
GetWebContents()2563 WebContents* WebContentsAddedObserver::GetWebContents() {
2564 if (web_contents_)
2565 return web_contents_;
2566
2567 base::RunLoop run_loop;
2568 quit_closure_ = run_loop.QuitClosure();
2569 run_loop.Run();
2570 return web_contents_;
2571 }
2572
RenderViewCreatedCalled()2573 bool WebContentsAddedObserver::RenderViewCreatedCalled() {
2574 if (child_observer_) {
2575 return child_observer_->render_view_created_called_ &&
2576 child_observer_->main_frame_created_called_;
2577 }
2578 return false;
2579 }
2580
RequestFrame(WebContents * web_contents)2581 bool RequestFrame(WebContents* web_contents) {
2582 DCHECK(web_contents);
2583 return RenderWidgetHostImpl::From(
2584 web_contents->GetMainFrame()->GetRenderViewHost()->GetWidget())
2585 ->RequestRepaintForTesting();
2586 }
2587
RenderFrameSubmissionObserver(RenderFrameMetadataProviderImpl * render_frame_metadata_provider)2588 RenderFrameSubmissionObserver::RenderFrameSubmissionObserver(
2589 RenderFrameMetadataProviderImpl* render_frame_metadata_provider)
2590 : render_frame_metadata_provider_(render_frame_metadata_provider) {
2591 render_frame_metadata_provider_->AddObserver(this);
2592 render_frame_metadata_provider_->ReportAllFrameSubmissionsForTesting(true);
2593 }
2594
RenderFrameSubmissionObserver(FrameTreeNode * node)2595 RenderFrameSubmissionObserver::RenderFrameSubmissionObserver(
2596 FrameTreeNode* node)
2597 : RenderFrameSubmissionObserver(
2598 RenderFrameMetadataProviderFromFrameTreeNode(node)) {}
2599
RenderFrameSubmissionObserver(WebContents * web_contents)2600 RenderFrameSubmissionObserver::RenderFrameSubmissionObserver(
2601 WebContents* web_contents)
2602 : RenderFrameSubmissionObserver(
2603 RenderFrameMetadataProviderFromWebContents(web_contents)) {}
2604
~RenderFrameSubmissionObserver()2605 RenderFrameSubmissionObserver::~RenderFrameSubmissionObserver() {
2606 render_frame_metadata_provider_->RemoveObserver(this);
2607 render_frame_metadata_provider_->ReportAllFrameSubmissionsForTesting(false);
2608 }
2609
WaitForAnyFrameSubmission()2610 void RenderFrameSubmissionObserver::WaitForAnyFrameSubmission() {
2611 break_on_any_frame_ = true;
2612 Wait();
2613 break_on_any_frame_ = false;
2614 }
2615
WaitForMetadataChange()2616 void RenderFrameSubmissionObserver::WaitForMetadataChange() {
2617 Wait();
2618 }
2619
WaitForPageScaleFactor(float expected_page_scale_factor,const float tolerance)2620 void RenderFrameSubmissionObserver::WaitForPageScaleFactor(
2621 float expected_page_scale_factor,
2622 const float tolerance) {
2623 while (std::abs(render_frame_metadata_provider_->LastRenderFrameMetadata()
2624 .page_scale_factor -
2625 expected_page_scale_factor) > tolerance) {
2626 WaitForMetadataChange();
2627 }
2628 }
2629
WaitForExternalPageScaleFactor(float expected_external_page_scale_factor,const float tolerance)2630 void RenderFrameSubmissionObserver::WaitForExternalPageScaleFactor(
2631 float expected_external_page_scale_factor,
2632 const float tolerance) {
2633 while (std::abs(render_frame_metadata_provider_->LastRenderFrameMetadata()
2634 .external_page_scale_factor -
2635 expected_external_page_scale_factor) > tolerance) {
2636 WaitForMetadataChange();
2637 }
2638 }
2639
WaitForScrollOffset(const gfx::Vector2dF & expected_offset)2640 void RenderFrameSubmissionObserver::WaitForScrollOffset(
2641 const gfx::Vector2dF& expected_offset) {
2642 while (render_frame_metadata_provider_->LastRenderFrameMetadata()
2643 .root_scroll_offset != expected_offset) {
2644 const auto& offset =
2645 render_frame_metadata_provider_->LastRenderFrameMetadata()
2646 .root_scroll_offset;
2647 constexpr float kEpsilon = 0.01f;
2648 if (offset.has_value()) {
2649 const auto diff = expected_offset - *offset;
2650 if (std::abs(diff.x()) <= kEpsilon && std::abs(diff.y()) <= kEpsilon) {
2651 break;
2652 }
2653 }
2654 WaitForMetadataChange();
2655 }
2656 }
2657
WaitForScrollOffsetAtTop(bool expected_scroll_offset_at_top)2658 void RenderFrameSubmissionObserver::WaitForScrollOffsetAtTop(
2659 bool expected_scroll_offset_at_top) {
2660 while (render_frame_metadata_provider_->LastRenderFrameMetadata()
2661 .is_scroll_offset_at_top != expected_scroll_offset_at_top) {
2662 WaitForMetadataChange();
2663 }
2664 }
2665
2666 const cc::RenderFrameMetadata&
LastRenderFrameMetadata() const2667 RenderFrameSubmissionObserver::LastRenderFrameMetadata() const {
2668 return render_frame_metadata_provider_->LastRenderFrameMetadata();
2669 }
2670
NotifyOnNextMetadataChange(base::OnceClosure closure)2671 void RenderFrameSubmissionObserver::NotifyOnNextMetadataChange(
2672 base::OnceClosure closure) {
2673 DCHECK(closure);
2674 DCHECK(metadata_change_closure_.is_null());
2675 metadata_change_closure_ = std::move(closure);
2676 }
2677
Quit()2678 void RenderFrameSubmissionObserver::Quit() {
2679 if (quit_closure_)
2680 std::move(quit_closure_).Run();
2681 }
2682
Wait()2683 void RenderFrameSubmissionObserver::Wait() {
2684 base::RunLoop run_loop{base::RunLoop::Type::kNestableTasksAllowed};
2685 quit_closure_ = run_loop.QuitClosure();
2686 run_loop.Run();
2687 }
2688
2689 void RenderFrameSubmissionObserver::
OnRenderFrameMetadataChangedBeforeActivation(const cc::RenderFrameMetadata & metadata)2690 OnRenderFrameMetadataChangedBeforeActivation(
2691 const cc::RenderFrameMetadata& metadata) {}
2692
2693 void RenderFrameSubmissionObserver::
OnRenderFrameMetadataChangedAfterActivation()2694 OnRenderFrameMetadataChangedAfterActivation() {
2695 Quit();
2696 if (metadata_change_closure_)
2697 std::move(metadata_change_closure_).Run();
2698 }
2699
OnRenderFrameSubmission()2700 void RenderFrameSubmissionObserver::OnRenderFrameSubmission() {
2701 render_frame_count_++;
2702 if (break_on_any_frame_)
2703 Quit();
2704 }
2705
OnLocalSurfaceIdChanged(const cc::RenderFrameMetadata & metadata)2706 void RenderFrameSubmissionObserver::OnLocalSurfaceIdChanged(
2707 const cc::RenderFrameMetadata& metadata) {}
2708
MainThreadFrameObserver(RenderWidgetHost * render_widget_host)2709 MainThreadFrameObserver::MainThreadFrameObserver(
2710 RenderWidgetHost* render_widget_host)
2711 : render_widget_host_(render_widget_host),
2712 routing_id_(render_widget_host_->GetProcess()->GetNextRoutingID()) {}
2713
2714 MainThreadFrameObserver::~MainThreadFrameObserver() = default;
2715
Wait()2716 void MainThreadFrameObserver::Wait() {
2717 DCHECK_CURRENTLY_ON(BrowserThread::UI);
2718 static_cast<RenderWidgetHostImpl*>(render_widget_host_)
2719 ->InsertVisualStateCallback(base::BindOnce(&MainThreadFrameObserver::Quit,
2720 base::Unretained(this)));
2721 base::RunLoop run_loop;
2722 quit_closure_ = run_loop.QuitClosure();
2723 run_loop.Run();
2724 }
2725
Quit(bool)2726 void MainThreadFrameObserver::Quit(bool) {
2727 if (quit_closure_)
2728 std::move(quit_closure_).Run();
2729 }
2730
InputMsgWatcher(RenderWidgetHost * render_widget_host,blink::WebInputEvent::Type type)2731 InputMsgWatcher::InputMsgWatcher(RenderWidgetHost* render_widget_host,
2732 blink::WebInputEvent::Type type)
2733 : render_widget_host_(render_widget_host),
2734 wait_for_type_(type),
2735 ack_result_(blink::mojom::InputEventResultState::kUnknown),
2736 ack_source_(blink::mojom::InputEventResultSource::kUnknown) {
2737 render_widget_host->AddInputEventObserver(this);
2738 }
2739
~InputMsgWatcher()2740 InputMsgWatcher::~InputMsgWatcher() {
2741 render_widget_host_->RemoveInputEventObserver(this);
2742 }
2743
OnInputEventAck(blink::mojom::InputEventResultSource ack_source,blink::mojom::InputEventResultState ack_state,const blink::WebInputEvent & event)2744 void InputMsgWatcher::OnInputEventAck(
2745 blink::mojom::InputEventResultSource ack_source,
2746 blink::mojom::InputEventResultState ack_state,
2747 const blink::WebInputEvent& event) {
2748 if (event.GetType() == wait_for_type_) {
2749 ack_result_ = ack_state;
2750 ack_source_ = ack_source;
2751 if (quit_closure_)
2752 std::move(quit_closure_).Run();
2753 }
2754 }
2755
HasReceivedAck() const2756 bool InputMsgWatcher::HasReceivedAck() const {
2757 return ack_result_ != blink::mojom::InputEventResultState::kUnknown;
2758 }
2759
WaitForAck()2760 blink::mojom::InputEventResultState InputMsgWatcher::WaitForAck() {
2761 DCHECK_CURRENTLY_ON(BrowserThread::UI);
2762 base::RunLoop run_loop;
2763 quit_closure_ = run_loop.QuitClosure();
2764 run_loop.Run();
2765 return ack_result_;
2766 }
2767
2768 blink::mojom::InputEventResultState
GetAckStateWaitIfNecessary()2769 InputMsgWatcher::GetAckStateWaitIfNecessary() {
2770 if (HasReceivedAck())
2771 return ack_result_;
2772 return WaitForAck();
2773 }
2774
InputEventAckWaiter(RenderWidgetHost * render_widget_host,InputEventAckPredicate predicate)2775 InputEventAckWaiter::InputEventAckWaiter(RenderWidgetHost* render_widget_host,
2776 InputEventAckPredicate predicate)
2777 : render_widget_host_(render_widget_host),
2778 predicate_(predicate),
2779 event_received_(false) {
2780 render_widget_host_->AddInputEventObserver(this);
2781 }
2782
2783 namespace {
EventAckHasType(blink::WebInputEvent::Type type)2784 InputEventAckWaiter::InputEventAckPredicate EventAckHasType(
2785 blink::WebInputEvent::Type type) {
2786 return base::BindRepeating(
2787 [](blink::WebInputEvent::Type expected_type,
2788 blink::mojom::InputEventResultSource source,
2789 blink::mojom::InputEventResultState state,
2790 const blink::WebInputEvent& event) {
2791 return event.GetType() == expected_type;
2792 },
2793 type);
2794 }
2795 } // namespace
2796
InputEventAckWaiter(RenderWidgetHost * render_widget_host,blink::WebInputEvent::Type type)2797 InputEventAckWaiter::InputEventAckWaiter(RenderWidgetHost* render_widget_host,
2798 blink::WebInputEvent::Type type)
2799 : InputEventAckWaiter(render_widget_host, EventAckHasType(type)) {}
2800
~InputEventAckWaiter()2801 InputEventAckWaiter::~InputEventAckWaiter() {
2802 render_widget_host_->RemoveInputEventObserver(this);
2803 }
2804
Wait()2805 void InputEventAckWaiter::Wait() {
2806 if (!event_received_) {
2807 base::RunLoop run_loop;
2808 quit_closure_ = run_loop.QuitClosure();
2809 run_loop.Run();
2810 }
2811 }
2812
Reset()2813 void InputEventAckWaiter::Reset() {
2814 event_received_ = false;
2815 quit_closure_ = base::OnceClosure();
2816 }
2817
OnInputEventAck(blink::mojom::InputEventResultSource source,blink::mojom::InputEventResultState state,const blink::WebInputEvent & event)2818 void InputEventAckWaiter::OnInputEventAck(
2819 blink::mojom::InputEventResultSource source,
2820 blink::mojom::InputEventResultState state,
2821 const blink::WebInputEvent& event) {
2822 if (predicate_.Run(source, state, event)) {
2823 event_received_ = true;
2824 if (quit_closure_)
2825 std::move(quit_closure_).Run();
2826 }
2827 }
2828
2829 // TODO(dcheng): Make the test clipboard on different threads share the
2830 // same backing store. crbug.com/629765
2831 // TODO(slangley): crbug.com/775830 - Cleanup BrowserTestClipboardScope now that
2832 // there is no need to thread hop for Windows.
BrowserTestClipboardScope()2833 BrowserTestClipboardScope::BrowserTestClipboardScope() {
2834 ui::TestClipboard::CreateForCurrentThread();
2835 }
2836
~BrowserTestClipboardScope()2837 BrowserTestClipboardScope::~BrowserTestClipboardScope() {
2838 ui::Clipboard::DestroyClipboardForCurrentThread();
2839 }
2840
SetRtf(const std::string & rtf)2841 void BrowserTestClipboardScope::SetRtf(const std::string& rtf) {
2842 ui::ScopedClipboardWriter clipboard_writer(ui::ClipboardBuffer::kCopyPaste);
2843 clipboard_writer.WriteRTF(rtf);
2844 }
2845
SetText(const std::string & text)2846 void BrowserTestClipboardScope::SetText(const std::string& text) {
2847 ui::ScopedClipboardWriter clipboard_writer(ui::ClipboardBuffer::kCopyPaste);
2848 clipboard_writer.WriteText(base::ASCIIToUTF16(text));
2849 }
2850
GetText(std::string * result)2851 void BrowserTestClipboardScope::GetText(std::string* result) {
2852 ui::Clipboard::GetForCurrentThread()->ReadAsciiText(
2853 ui::ClipboardBuffer::kCopyPaste, /* data_dst = */ nullptr, result);
2854 }
2855
2856 class FrameFocusedObserver::FrameTreeNodeObserverImpl
2857 : public FrameTreeNode::Observer {
2858 public:
FrameTreeNodeObserverImpl(FrameTreeNode * owner)2859 explicit FrameTreeNodeObserverImpl(FrameTreeNode* owner) : owner_(owner) {
2860 owner->AddObserver(this);
2861 }
~FrameTreeNodeObserverImpl()2862 ~FrameTreeNodeObserverImpl() override { owner_->RemoveObserver(this); }
2863
Run()2864 void Run() { run_loop_.Run(); }
2865
OnFrameTreeNodeFocused(FrameTreeNode * node)2866 void OnFrameTreeNodeFocused(FrameTreeNode* node) override {
2867 if (node == owner_)
2868 run_loop_.Quit();
2869 }
2870
2871 private:
2872 FrameTreeNode* owner_;
2873 base::RunLoop run_loop_;
2874 };
2875
FrameFocusedObserver(RenderFrameHost * owner_host)2876 FrameFocusedObserver::FrameFocusedObserver(RenderFrameHost* owner_host)
2877 : impl_(std::make_unique<FrameTreeNodeObserverImpl>(
2878 static_cast<RenderFrameHostImpl*>(owner_host)->frame_tree_node())) {}
2879
2880 FrameFocusedObserver::~FrameFocusedObserver() = default;
2881
Wait()2882 void FrameFocusedObserver::Wait() {
2883 impl_->Run();
2884 }
2885
2886 class FrameDeletedObserver::FrameTreeNodeObserverImpl
2887 : public FrameTreeNode::Observer {
2888 public:
FrameTreeNodeObserverImpl(FrameTreeNode * owner)2889 explicit FrameTreeNodeObserverImpl(FrameTreeNode* owner) : owner_(owner) {
2890 owner->AddObserver(this);
2891 }
2892 ~FrameTreeNodeObserverImpl() override = default;
2893
Run()2894 void Run() { run_loop_.Run(); }
2895
2896 private:
2897 // FrameTreeNode::Observer
OnFrameTreeNodeDestroyed(FrameTreeNode * node)2898 void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override {
2899 if (node == owner_)
2900 run_loop_.Quit();
2901 }
2902
2903 FrameTreeNode* owner_;
2904 base::RunLoop run_loop_;
2905 };
2906
FrameDeletedObserver(RenderFrameHost * owner_host)2907 FrameDeletedObserver::FrameDeletedObserver(RenderFrameHost* owner_host)
2908 : impl_(std::make_unique<FrameTreeNodeObserverImpl>(
2909 static_cast<RenderFrameHostImpl*>(owner_host)->frame_tree_node())) {}
2910
2911 FrameDeletedObserver::~FrameDeletedObserver() = default;
2912
Wait()2913 void FrameDeletedObserver::Wait() {
2914 impl_->Run();
2915 }
2916
TestNavigationManager(WebContents * web_contents,const GURL & url)2917 TestNavigationManager::TestNavigationManager(WebContents* web_contents,
2918 const GURL& url)
2919 : WebContentsObserver(web_contents),
2920 url_(url),
2921 request_(nullptr),
2922 navigation_paused_(false),
2923 current_state_(NavigationState::INITIAL),
2924 desired_state_(NavigationState::STARTED) {}
2925
~TestNavigationManager()2926 TestNavigationManager::~TestNavigationManager() {
2927 if (navigation_paused_)
2928 request_->GetNavigationThrottleRunnerForTesting()->CallResumeForTesting();
2929 }
2930
WaitForRequestStart()2931 bool TestNavigationManager::WaitForRequestStart() {
2932 // This is the default desired state. A browser-initiated navigation can reach
2933 // this state synchronously, so the TestNavigationManager is set to always
2934 // pause navigations at WillStartRequest. This ensures the user can always
2935 // call WaitForWillStartRequest.
2936 DCHECK(desired_state_ == NavigationState::STARTED);
2937 return WaitForDesiredState();
2938 }
2939
ResumeNavigation()2940 void TestNavigationManager::ResumeNavigation() {
2941 DCHECK(current_state_ == NavigationState::STARTED ||
2942 current_state_ == NavigationState::RESPONSE);
2943 DCHECK_EQ(current_state_, desired_state_);
2944 DCHECK(navigation_paused_);
2945 navigation_paused_ = false;
2946 request_->GetNavigationThrottleRunnerForTesting()->CallResumeForTesting();
2947 }
2948
GetNavigationHandle()2949 NavigationHandle* TestNavigationManager::GetNavigationHandle() {
2950 return request_;
2951 }
2952
WaitForResponse()2953 bool TestNavigationManager::WaitForResponse() {
2954 desired_state_ = NavigationState::RESPONSE;
2955 return WaitForDesiredState();
2956 }
2957
WaitForNavigationFinished()2958 void TestNavigationManager::WaitForNavigationFinished() {
2959 desired_state_ = NavigationState::FINISHED;
2960 WaitForDesiredState();
2961 }
2962
DidStartNavigation(NavigationHandle * handle)2963 void TestNavigationManager::DidStartNavigation(NavigationHandle* handle) {
2964 if (!ShouldMonitorNavigation(handle))
2965 return;
2966
2967 request_ = NavigationRequest::From(handle);
2968 auto throttle = std::make_unique<TestNavigationManagerThrottle>(
2969 request_,
2970 base::BindOnce(&TestNavigationManager::OnWillStartRequest,
2971 weak_factory_.GetWeakPtr()),
2972 base::BindOnce(&TestNavigationManager::OnWillProcessResponse,
2973 weak_factory_.GetWeakPtr()));
2974 request_->RegisterThrottleForTesting(std::move(throttle));
2975 }
2976
DidFinishNavigation(NavigationHandle * handle)2977 void TestNavigationManager::DidFinishNavigation(NavigationHandle* handle) {
2978 if (handle != request_)
2979 return;
2980 was_committed_ = handle->HasCommitted();
2981 was_successful_ = was_committed_ && !handle->IsErrorPage();
2982 current_state_ = NavigationState::FINISHED;
2983 navigation_paused_ = false;
2984 request_ = nullptr;
2985 OnNavigationStateChanged();
2986 }
2987
OnWillStartRequest()2988 void TestNavigationManager::OnWillStartRequest() {
2989 current_state_ = NavigationState::STARTED;
2990 navigation_paused_ = true;
2991 OnNavigationStateChanged();
2992 }
2993
OnWillProcessResponse()2994 void TestNavigationManager::OnWillProcessResponse() {
2995 current_state_ = NavigationState::RESPONSE;
2996 navigation_paused_ = true;
2997 OnNavigationStateChanged();
2998 }
2999
3000 // TODO(csharrison): Remove CallResumeForTesting method calls in favor of doing
3001 // it through the throttle.
WaitForDesiredState()3002 bool TestNavigationManager::WaitForDesiredState() {
3003 // If the desired state has laready been reached, just return.
3004 if (current_state_ == desired_state_)
3005 return true;
3006
3007 // Resume the navigation if it was paused.
3008 if (navigation_paused_)
3009 request_->GetNavigationThrottleRunnerForTesting()->CallResumeForTesting();
3010
3011 // Wait for the desired state if needed.
3012 if (current_state_ < desired_state_) {
3013 DCHECK(!quit_closure_);
3014 base::RunLoop run_loop(message_loop_type_);
3015 quit_closure_ = run_loop.QuitClosure();
3016 run_loop.Run();
3017 }
3018
3019 // Return false if the navigation did not reach the state specified by the
3020 // user.
3021 return current_state_ == desired_state_;
3022 }
3023
OnNavigationStateChanged()3024 void TestNavigationManager::OnNavigationStateChanged() {
3025 // If the state the user was waiting for has been reached, exit the message
3026 // loop.
3027 if (current_state_ >= desired_state_) {
3028 if (quit_closure_)
3029 std::move(quit_closure_).Run();
3030 return;
3031 }
3032
3033 // Otherwise, the navigation should be resumed if it was previously paused.
3034 if (navigation_paused_)
3035 request_->GetNavigationThrottleRunnerForTesting()->CallResumeForTesting();
3036 }
3037
ShouldMonitorNavigation(NavigationHandle * handle)3038 bool TestNavigationManager::ShouldMonitorNavigation(NavigationHandle* handle) {
3039 if (request_ || handle->GetURL() != url_)
3040 return false;
3041 if (current_state_ != NavigationState::INITIAL)
3042 return false;
3043 return true;
3044 }
3045
AllowNestableTasks()3046 void TestNavigationManager::AllowNestableTasks() {
3047 message_loop_type_ = base::RunLoop::Type::kNestableTasksAllowed;
3048 }
3049
NavigationHandleCommitObserver(content::WebContents * web_contents,const GURL & url)3050 NavigationHandleCommitObserver::NavigationHandleCommitObserver(
3051 content::WebContents* web_contents,
3052 const GURL& url)
3053 : WebContentsObserver(web_contents),
3054 url_(url),
3055 has_committed_(false),
3056 was_same_document_(false),
3057 was_renderer_initiated_(false) {}
3058
DidFinishNavigation(content::NavigationHandle * handle)3059 void NavigationHandleCommitObserver::DidFinishNavigation(
3060 content::NavigationHandle* handle) {
3061 if (handle->GetURL() != url_)
3062 return;
3063 has_committed_ = true;
3064 was_same_document_ = handle->IsSameDocument();
3065 was_renderer_initiated_ = handle->IsRendererInitiated();
3066 }
3067
WebContentsConsoleObserver(content::WebContents * web_contents)3068 WebContentsConsoleObserver::WebContentsConsoleObserver(
3069 content::WebContents* web_contents)
3070 : WebContentsObserver(web_contents) {}
3071 WebContentsConsoleObserver::~WebContentsConsoleObserver() = default;
3072
Wait()3073 void WebContentsConsoleObserver::Wait() {
3074 run_loop_.Run();
3075 }
3076
SetFilter(Filter filter)3077 void WebContentsConsoleObserver::SetFilter(Filter filter) {
3078 filter_ = std::move(filter);
3079 }
3080
SetPattern(std::string pattern)3081 void WebContentsConsoleObserver::SetPattern(std::string pattern) {
3082 DCHECK(!pattern.empty()) << "An empty pattern will never match.";
3083 pattern_ = std::move(pattern);
3084 }
3085
GetMessageAt(size_t index) const3086 std::string WebContentsConsoleObserver::GetMessageAt(size_t index) const {
3087 if (index >= messages_.size()) {
3088 ADD_FAILURE() << "Tried to retrieve a non-existent message at index: "
3089 << index;
3090 return std::string();
3091 }
3092 return base::UTF16ToUTF8(messages_[index].message);
3093 }
3094
OnDidAddMessageToConsole(RenderFrameHost * source_frame,blink::mojom::ConsoleMessageLevel log_level,const base::string16 & message_contents,int32_t line_no,const base::string16 & source_id)3095 void WebContentsConsoleObserver::OnDidAddMessageToConsole(
3096 RenderFrameHost* source_frame,
3097 blink::mojom::ConsoleMessageLevel log_level,
3098 const base::string16& message_contents,
3099 int32_t line_no,
3100 const base::string16& source_id) {
3101 Message message(
3102 {source_frame, log_level, message_contents, line_no, source_id});
3103 if (filter_ && !filter_.Run(message))
3104 return;
3105
3106 if (!pattern_.empty() &&
3107 !base::MatchPattern(base::UTF16ToUTF8(message_contents), pattern_)) {
3108 return;
3109 }
3110
3111 messages_.push_back(std::move(message));
3112 run_loop_.Quit();
3113 }
3114
3115 namespace {
GetFileSystemManager(RenderProcessHost * rph)3116 mojo::Remote<blink::mojom::FileSystemManager> GetFileSystemManager(
3117 RenderProcessHost* rph) {
3118 FileSystemManagerImpl* file_system = static_cast<RenderProcessHostImpl*>(rph)
3119 ->GetFileSystemManagerForTesting();
3120 mojo::Remote<blink::mojom::FileSystemManager> file_system_manager_remote;
3121 GetIOThreadTaskRunner({})->PostTask(
3122 FROM_HERE,
3123 base::BindOnce(&FileSystemManagerImpl::BindReceiver,
3124 base::Unretained(file_system),
3125 file_system_manager_remote.BindNewPipeAndPassReceiver()));
3126 return file_system_manager_remote;
3127 }
3128 } // namespace
3129
3130 // static
FileSystemCreate(RenderProcessHost * process,int request_id,GURL path,bool exclusive,bool is_directory,bool recursive)3131 void PwnMessageHelper::FileSystemCreate(RenderProcessHost* process,
3132 int request_id,
3133 GURL path,
3134 bool exclusive,
3135 bool is_directory,
3136 bool recursive) {
3137 TestFileapiOperationWaiter waiter;
3138 mojo::Remote<blink::mojom::FileSystemManager> file_system_manager =
3139 GetFileSystemManager(process);
3140 file_system_manager->Create(
3141 path, exclusive, is_directory, recursive,
3142 base::BindOnce(&TestFileapiOperationWaiter::DidCreate,
3143 base::Unretained(&waiter)));
3144 waiter.WaitForOperationToFinish();
3145 }
3146
3147 // static
FileSystemWrite(RenderProcessHost * process,int request_id,GURL file_path,std::string blob_uuid,int64_t position)3148 void PwnMessageHelper::FileSystemWrite(RenderProcessHost* process,
3149 int request_id,
3150 GURL file_path,
3151 std::string blob_uuid,
3152 int64_t position) {
3153 TestFileapiOperationWaiter waiter;
3154 mojo::Remote<blink::mojom::FileSystemManager> file_system_manager =
3155 GetFileSystemManager(process);
3156 mojo::PendingRemote<blink::mojom::FileSystemOperationListener> listener;
3157 mojo::Receiver<blink::mojom::FileSystemOperationListener> receiver(
3158 &waiter, listener.InitWithNewPipeAndPassReceiver());
3159 mojo::Remote<blink::mojom::FileSystemCancellableOperation> op;
3160
3161 file_system_manager->Write(file_path, blob_uuid, position,
3162 op.BindNewPipeAndPassReceiver(),
3163 std::move(listener));
3164 waiter.WaitForOperationToFinish();
3165 }
3166
OpenURL(RenderFrameHost * render_frame_host,const GURL & url)3167 void PwnMessageHelper::OpenURL(RenderFrameHost* render_frame_host,
3168 const GURL& url) {
3169 auto params = content::mojom::OpenURLParams::New();
3170 params->url = url;
3171 params->disposition = WindowOpenDisposition::CURRENT_TAB;
3172 params->should_replace_current_entry = false;
3173 params->user_gesture = true;
3174 static_cast<mojom::FrameHost*>(
3175 static_cast<RenderFrameHostImpl*>(render_frame_host))
3176 ->OpenURL(std::move(params));
3177 }
3178
3179 #if defined(USE_AURA)
3180 namespace {
3181
3182 // This class interacts with the internals of the DelegatedFrameHost without
3183 // exposing them in the header.
3184 class EvictionStateWaiter : public DelegatedFrameHost::Observer {
3185 public:
EvictionStateWaiter(DelegatedFrameHost * delegated_frame_host)3186 explicit EvictionStateWaiter(DelegatedFrameHost* delegated_frame_host)
3187 : delegated_frame_host_(delegated_frame_host) {
3188 delegated_frame_host_->AddObserverForTesting(this);
3189 }
3190
~EvictionStateWaiter()3191 ~EvictionStateWaiter() override {
3192 delegated_frame_host_->RemoveObserverForTesting(this);
3193 }
3194
WaitForEvictionState(DelegatedFrameHost::FrameEvictionState state)3195 void WaitForEvictionState(DelegatedFrameHost::FrameEvictionState state) {
3196 if (delegated_frame_host_->frame_eviction_state() == state)
3197 return;
3198
3199 waited_eviction_state_ = state;
3200 base::RunLoop run_loop;
3201 quit_closure_ = run_loop.QuitClosure();
3202 run_loop.Run();
3203 }
3204
3205 // DelegatedFrameHost::Observer:
OnFrameEvictionStateChanged(DelegatedFrameHost::FrameEvictionState new_state)3206 void OnFrameEvictionStateChanged(
3207 DelegatedFrameHost::FrameEvictionState new_state) override {
3208 if (!quit_closure_.is_null() && (new_state == waited_eviction_state_))
3209 std::move(quit_closure_).Run();
3210 }
3211
3212 private:
3213 DelegatedFrameHost* delegated_frame_host_;
3214 DelegatedFrameHost::FrameEvictionState waited_eviction_state_;
3215 base::OnceClosure quit_closure_;
3216
3217 DISALLOW_COPY_AND_ASSIGN(EvictionStateWaiter);
3218 };
3219
3220 } // namespace
3221
VerifyStaleContentOnFrameEviction(RenderWidgetHostView * render_widget_host_view)3222 void VerifyStaleContentOnFrameEviction(
3223 RenderWidgetHostView* render_widget_host_view) {
3224 auto* render_widget_host_view_aura =
3225 static_cast<RenderWidgetHostViewAura*>(render_widget_host_view);
3226 DelegatedFrameHost* delegated_frame_host =
3227 render_widget_host_view_aura->GetDelegatedFrameHost();
3228
3229 // Initially there should be no stale content set.
3230 EXPECT_FALSE(
3231 delegated_frame_host->stale_content_layer()->has_external_content());
3232 EXPECT_EQ(delegated_frame_host->frame_eviction_state(),
3233 DelegatedFrameHost::FrameEvictionState::kNotStarted);
3234
3235 // Hide the view and evict the frame, and expect that stale content will be
3236 // set.
3237 EvictionStateWaiter waiter{delegated_frame_host};
3238 render_widget_host_view_aura->WasOccluded();
3239 static_cast<viz::FrameEvictorClient*>(delegated_frame_host)
3240 ->EvictDelegatedFrame();
3241 EXPECT_EQ(delegated_frame_host->frame_eviction_state(),
3242 DelegatedFrameHost::FrameEvictionState::kPendingEvictionRequests);
3243 // Wait until the stale frame content is copied and set onto the layer, i.e.
3244 // the eviction state changes from kPendingEvictionRequests back to
3245 // kNotStarted.
3246 waiter.WaitForEvictionState(
3247 DelegatedFrameHost::FrameEvictionState::kNotStarted);
3248 EXPECT_TRUE(
3249 delegated_frame_host->stale_content_layer()->has_external_content());
3250 }
3251
3252 #endif // defined(USE_AURA)
3253
ContextMenuFilter(ShowBehavior behavior)3254 ContextMenuFilter::ContextMenuFilter(ShowBehavior behavior)
3255 : BrowserMessageFilter(FrameMsgStart),
3256 run_loop_(std::make_unique<base::RunLoop>()),
3257 quit_closure_(run_loop_->QuitClosure()),
3258 show_behavior_(behavior) {}
3259
OnMessageReceived(const IPC::Message & message)3260 bool ContextMenuFilter::OnMessageReceived(const IPC::Message& message) {
3261 DCHECK_CURRENTLY_ON(BrowserThread::IO);
3262 if (message.type() == FrameHostMsg_ContextMenu::ID) {
3263 FrameHostMsg_ContextMenu::Param params;
3264 FrameHostMsg_ContextMenu::Read(&message, ¶ms);
3265 UntrustworthyContextMenuParams menu_params = std::get<0>(params);
3266 GetUIThreadTaskRunner({})->PostTask(
3267 FROM_HERE,
3268 base::BindOnce(&ContextMenuFilter::OnContextMenu, this, menu_params));
3269 // Returning true here blocks the default action for this message, which
3270 // means that the menu will not be shown.
3271 return show_behavior_ == ShowBehavior::kPreventShow;
3272 }
3273 return false;
3274 }
3275
Wait()3276 void ContextMenuFilter::Wait() {
3277 DCHECK_CURRENTLY_ON(BrowserThread::UI);
3278 run_loop_->Run();
3279 run_loop_ = nullptr;
3280 }
3281
Reset()3282 void ContextMenuFilter::Reset() {
3283 ASSERT_EQ(run_loop_, nullptr);
3284 run_loop_ = std::make_unique<base::RunLoop>();
3285 quit_closure_ = run_loop_->QuitClosure();
3286 }
3287
3288 ContextMenuFilter::~ContextMenuFilter() = default;
3289
OnContextMenu(const content::UntrustworthyContextMenuParams & params)3290 void ContextMenuFilter::OnContextMenu(
3291 const content::UntrustworthyContextMenuParams& params) {
3292 DCHECK_CURRENTLY_ON(BrowserThread::UI);
3293 last_params_ = params;
3294 std::move(quit_closure_).Run();
3295 }
3296
3297 UpdateUserActivationStateInterceptor::UpdateUserActivationStateInterceptor() =
3298 default;
3299
3300 UpdateUserActivationStateInterceptor::~UpdateUserActivationStateInterceptor() =
3301 default;
3302
Init(content::RenderFrameHost * render_frame_host)3303 void UpdateUserActivationStateInterceptor::Init(
3304 content::RenderFrameHost* render_frame_host) {
3305 render_frame_host_ = render_frame_host;
3306 impl_ = static_cast<RenderFrameHostImpl*>(render_frame_host_)
3307 ->local_frame_host_receiver_for_testing()
3308 .SwapImplForTesting(this);
3309 }
3310
set_quit_handler(base::OnceClosure handler)3311 void UpdateUserActivationStateInterceptor::set_quit_handler(
3312 base::OnceClosure handler) {
3313 quit_handler_ = std::move(handler);
3314 }
3315
3316 blink::mojom::LocalFrameHost*
GetForwardingInterface()3317 UpdateUserActivationStateInterceptor::GetForwardingInterface() {
3318 return impl_;
3319 }
3320
UpdateUserActivationState(blink::mojom::UserActivationUpdateType update_type,blink::mojom::UserActivationNotificationType notification_type)3321 void UpdateUserActivationStateInterceptor::UpdateUserActivationState(
3322 blink::mojom::UserActivationUpdateType update_type,
3323 blink::mojom::UserActivationNotificationType notification_type) {
3324 update_user_activation_state_ = true;
3325 if (quit_handler_)
3326 std::move(quit_handler_).Run();
3327 GetForwardingInterface()->UpdateUserActivationState(update_type,
3328 notification_type);
3329 }
3330
GetEmbedderForGuest(content::WebContents * guest)3331 WebContents* GetEmbedderForGuest(content::WebContents* guest) {
3332 CHECK(guest);
3333 return static_cast<WebContentsImpl*>(guest)->GetOuterWebContents();
3334 }
3335
3336 namespace {
3337
LoadBasicRequest(network::mojom::URLLoaderFactory * url_loader_factory,const GURL & url,int load_flags,const base::Optional<url::Origin> & request_initiator=base::nullopt,int render_frame_id=MSG_ROUTING_NONE)3338 int LoadBasicRequest(
3339 network::mojom::URLLoaderFactory* url_loader_factory,
3340 const GURL& url,
3341 int load_flags,
3342 const base::Optional<url::Origin>& request_initiator = base::nullopt,
3343 int render_frame_id = MSG_ROUTING_NONE) {
3344 auto request = std::make_unique<network::ResourceRequest>();
3345 request->url = url;
3346 request->load_flags = load_flags;
3347 request->request_initiator = request_initiator;
3348 request->render_frame_id = render_frame_id;
3349 // Allow access to SameSite cookies in tests.
3350 request->site_for_cookies = net::SiteForCookies::FromUrl(url);
3351
3352 SimpleURLLoaderTestHelper simple_loader_helper;
3353 std::unique_ptr<network::SimpleURLLoader> simple_loader =
3354 network::SimpleURLLoader::Create(std::move(request),
3355 TRAFFIC_ANNOTATION_FOR_TESTS);
3356
3357 simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
3358 url_loader_factory, simple_loader_helper.GetCallback());
3359 simple_loader_helper.WaitForCallback();
3360
3361 return simple_loader->NetError();
3362 }
3363
3364 } // namespace
3365
LoadBasicRequest(network::mojom::NetworkContext * network_context,const GURL & url,int load_flags)3366 int LoadBasicRequest(network::mojom::NetworkContext* network_context,
3367 const GURL& url,
3368 int load_flags) {
3369 mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory;
3370 network::mojom::URLLoaderFactoryParamsPtr url_loader_factory_params =
3371 network::mojom::URLLoaderFactoryParams::New();
3372 url_loader_factory_params->process_id = network::mojom::kBrowserProcessId;
3373 url_loader_factory_params->is_corb_enabled = false;
3374 url::Origin origin = url::Origin::Create(url);
3375 url_loader_factory_params->isolation_info =
3376 net::IsolationInfo::CreateForInternalRequest(origin);
3377 network_context->CreateURLLoaderFactory(
3378 url_loader_factory.BindNewPipeAndPassReceiver(),
3379 std::move(url_loader_factory_params));
3380 // |url_loader_factory| will receive disconnect notification asynchronously if
3381 // |network_context| is already disconnected. However it's still false
3382 // at this point.
3383 EXPECT_TRUE(url_loader_factory.is_connected());
3384
3385 return LoadBasicRequest(url_loader_factory.get(), url, load_flags);
3386 }
3387
LoadBasicRequest(RenderFrameHost * frame,const GURL & url)3388 int LoadBasicRequest(RenderFrameHost* frame, const GURL& url) {
3389 mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory;
3390 frame->CreateNetworkServiceDefaultFactory(
3391 url_loader_factory.BindNewPipeAndPassReceiver());
3392 return LoadBasicRequest(
3393 url_loader_factory.get(), url, 0 /* load_flags */,
3394 frame->GetLastCommittedOrigin() /* request_initiator */,
3395 frame->GetRoutingID());
3396 }
3397
EnsureCookiesFlushed(BrowserContext * browser_context)3398 void EnsureCookiesFlushed(BrowserContext* browser_context) {
3399 BrowserContext::ForEachStoragePartition(
3400 browser_context, base::BindRepeating([](StoragePartition* partition) {
3401 base::RunLoop run_loop;
3402 partition->GetCookieManagerForBrowserProcess()->FlushCookieStore(
3403 run_loop.QuitClosure());
3404 run_loop.Run();
3405 }));
3406 }
3407
HasValidProcessForProcessGroup(const std::string & process_group_name)3408 bool HasValidProcessForProcessGroup(const std::string& process_group_name) {
3409 return ServiceManagerContext::HasValidProcessForProcessGroup(
3410 process_group_name);
3411 }
3412
TestGuestAutoresize(RenderProcessHost * embedder_rph,RenderWidgetHost * guest_rwh)3413 bool TestGuestAutoresize(RenderProcessHost* embedder_rph,
3414 RenderWidgetHost* guest_rwh) {
3415 RenderProcessHostImpl* embedder_rph_impl =
3416 static_cast<RenderProcessHostImpl*>(embedder_rph);
3417 RenderWidgetHostImpl* guest_rwh_impl =
3418 static_cast<RenderWidgetHostImpl*>(guest_rwh);
3419
3420 auto filter =
3421 base::MakeRefCounted<SynchronizeVisualPropertiesMessageFilter>();
3422
3423 embedder_rph_impl->AddFilter(filter.get());
3424
3425 viz::LocalSurfaceId current_id =
3426 guest_rwh_impl->GetView()->GetLocalSurfaceId();
3427 // The guest may not yet be fully attached / initted. If not, |current_id|
3428 // will be invalid, and we should wait for an ID before proceeding.
3429 if (!current_id.is_valid())
3430 current_id = filter->WaitForSurfaceId();
3431
3432 // Enable auto-resize.
3433 gfx::Size min_size(10, 10);
3434 gfx::Size max_size(100, 100);
3435 guest_rwh_impl->SetAutoResize(true, min_size, max_size);
3436 guest_rwh_impl->GetView()->EnableAutoResize(min_size, max_size);
3437
3438 // Enabling auto resize generates a surface ID, wait for it.
3439 current_id = filter->WaitForSurfaceId();
3440
3441 // Fake an auto-resize update.
3442 viz::LocalSurfaceId local_surface_id(current_id.parent_sequence_number(),
3443 current_id.child_sequence_number() + 1,
3444 current_id.embed_token());
3445 cc::RenderFrameMetadata metadata;
3446 metadata.viewport_size_in_pixels = gfx::Size(75, 75);
3447 metadata.local_surface_id = local_surface_id;
3448 guest_rwh_impl->OnLocalSurfaceIdChanged(metadata);
3449
3450 // This won't generate a response, as we short-circuit auto-resizes, so cause
3451 // an additional update by disabling auto-resize.
3452 guest_rwh_impl->GetView()->DisableAutoResize(gfx::Size(75, 75));
3453
3454 // Get the first delivered surface id and ensure it has the surface id which
3455 // we expect.
3456 return filter->WaitForSurfaceId() ==
3457 viz::LocalSurfaceId(current_id.parent_sequence_number() + 1,
3458 current_id.child_sequence_number() + 1,
3459 current_id.embed_token());
3460 }
3461
3462 SynchronizeVisualPropertiesMessageFilter::
SynchronizeVisualPropertiesMessageFilter()3463 SynchronizeVisualPropertiesMessageFilter()
3464 : BrowserMessageFilter(FrameMsgStart),
3465 screen_space_rect_run_loop_(std::make_unique<base::RunLoop>()),
3466 screen_space_rect_received_(false),
3467 pinch_gesture_active_set_(false),
3468 pinch_gesture_active_cleared_(false),
3469 last_pinch_gesture_active_(false) {}
3470
WaitForRect()3471 void SynchronizeVisualPropertiesMessageFilter::WaitForRect() {
3472 screen_space_rect_run_loop_->Run();
3473 }
3474
ResetRectRunLoop()3475 void SynchronizeVisualPropertiesMessageFilter::ResetRectRunLoop() {
3476 last_rect_ = gfx::Rect();
3477 screen_space_rect_run_loop_ = std::make_unique<base::RunLoop>();
3478 screen_space_rect_received_ = false;
3479 }
3480
3481 viz::LocalSurfaceId
WaitForSurfaceId()3482 SynchronizeVisualPropertiesMessageFilter::WaitForSurfaceId() {
3483 surface_id_run_loop_ = std::make_unique<base::RunLoop>();
3484 surface_id_run_loop_->Run();
3485 return last_surface_id_;
3486 }
3487
3488 SynchronizeVisualPropertiesMessageFilter::
~SynchronizeVisualPropertiesMessageFilter()3489 ~SynchronizeVisualPropertiesMessageFilter() {}
3490
3491 void SynchronizeVisualPropertiesMessageFilter::
OnSynchronizeFrameHostVisualProperties(const blink::FrameVisualProperties & visual_properties)3492 OnSynchronizeFrameHostVisualProperties(
3493 const blink::FrameVisualProperties& visual_properties) {
3494 OnSynchronizeVisualProperties(visual_properties);
3495 }
3496
OnSynchronizeVisualProperties(const blink::FrameVisualProperties & visual_properties)3497 void SynchronizeVisualPropertiesMessageFilter::OnSynchronizeVisualProperties(
3498 const blink::FrameVisualProperties& visual_properties) {
3499 // Monitor |is_pinch_gesture_active| to determine when pinch gestures begin
3500 // and end.
3501 if (visual_properties.is_pinch_gesture_active &&
3502 !last_pinch_gesture_active_) {
3503 pinch_gesture_active_set_ = true;
3504 }
3505 if (!visual_properties.is_pinch_gesture_active &&
3506 last_pinch_gesture_active_) {
3507 pinch_gesture_active_cleared_ = true;
3508 if (pinch_end_run_loop_)
3509 pinch_end_run_loop_->Quit();
3510 }
3511 last_pinch_gesture_active_ = visual_properties.is_pinch_gesture_active;
3512
3513 gfx::Rect screen_space_rect_in_dip = visual_properties.screen_space_rect;
3514 if (IsUseZoomForDSFEnabled()) {
3515 screen_space_rect_in_dip =
3516 gfx::Rect(gfx::ScaleToFlooredPoint(
3517 visual_properties.screen_space_rect.origin(),
3518 1.f / visual_properties.screen_info.device_scale_factor),
3519 gfx::ScaleToCeiledSize(
3520 visual_properties.screen_space_rect.size(),
3521 1.f / visual_properties.screen_info.device_scale_factor));
3522 }
3523 // Track each rect updates.
3524 GetUIThreadTaskRunner({})->PostTask(
3525 FROM_HERE,
3526 base::BindOnce(
3527 &SynchronizeVisualPropertiesMessageFilter::OnUpdatedFrameRectOnUI,
3528 this, screen_space_rect_in_dip));
3529
3530 // Track each surface id update.
3531 GetUIThreadTaskRunner({})->PostTask(
3532 FROM_HERE,
3533 base::BindOnce(
3534 &SynchronizeVisualPropertiesMessageFilter::OnUpdatedSurfaceIdOnUI,
3535 this, visual_properties.local_surface_id));
3536
3537 // We can't nest on the IO thread. So tests will wait on the UI thread, so
3538 // post there to exit the nesting.
3539 GetUIThreadTaskRunner({})->PostTask(
3540 FROM_HERE,
3541 base::BindOnce(
3542 &SynchronizeVisualPropertiesMessageFilter::OnUpdatedFrameSinkIdOnUI,
3543 this));
3544 }
3545
OnUpdatedFrameRectOnUI(const gfx::Rect & rect)3546 void SynchronizeVisualPropertiesMessageFilter::OnUpdatedFrameRectOnUI(
3547 const gfx::Rect& rect) {
3548 last_rect_ = rect;
3549 if (!screen_space_rect_received_) {
3550 screen_space_rect_received_ = true;
3551 // Tests looking at the rect currently expect all received input to finish
3552 // processing before the test continutes.
3553 screen_space_rect_run_loop_->QuitWhenIdle();
3554 }
3555 }
3556
OnUpdatedFrameSinkIdOnUI()3557 void SynchronizeVisualPropertiesMessageFilter::OnUpdatedFrameSinkIdOnUI() {
3558 run_loop_.Quit();
3559 }
3560
OnUpdatedSurfaceIdOnUI(viz::LocalSurfaceId surface_id)3561 void SynchronizeVisualPropertiesMessageFilter::OnUpdatedSurfaceIdOnUI(
3562 viz::LocalSurfaceId surface_id) {
3563 last_surface_id_ = surface_id;
3564 if (surface_id_run_loop_) {
3565 surface_id_run_loop_->QuitWhenIdle();
3566 }
3567 }
3568
OnMessageReceived(const IPC::Message & message)3569 bool SynchronizeVisualPropertiesMessageFilter::OnMessageReceived(
3570 const IPC::Message& message) {
3571 IPC_BEGIN_MESSAGE_MAP(SynchronizeVisualPropertiesMessageFilter, message)
3572 IPC_MESSAGE_HANDLER(FrameHostMsg_SynchronizeVisualProperties,
3573 OnSynchronizeFrameHostVisualProperties)
3574 IPC_END_MESSAGE_MAP()
3575
3576 // We do not consume the message, so that we can verify the effects of it
3577 // being processed.
3578 return false;
3579 }
3580
WaitForPinchGestureEnd()3581 void SynchronizeVisualPropertiesMessageFilter::WaitForPinchGestureEnd() {
3582 if (pinch_gesture_active_cleared_)
3583 return;
3584 DCHECK(!pinch_end_run_loop_);
3585 pinch_end_run_loop_ = std::make_unique<base::RunLoop>();
3586 pinch_end_run_loop_->Run();
3587 }
3588
RenderWidgetHostMouseEventMonitor(RenderWidgetHost * host)3589 RenderWidgetHostMouseEventMonitor::RenderWidgetHostMouseEventMonitor(
3590 RenderWidgetHost* host)
3591 : host_(host), event_received_(false) {
3592 mouse_callback_ = base::BindRepeating(
3593 &RenderWidgetHostMouseEventMonitor::MouseEventCallback,
3594 base::Unretained(this));
3595 host_->AddMouseEventCallback(mouse_callback_);
3596 }
3597
~RenderWidgetHostMouseEventMonitor()3598 RenderWidgetHostMouseEventMonitor::~RenderWidgetHostMouseEventMonitor() {
3599 host_->RemoveMouseEventCallback(mouse_callback_);
3600 }
3601
DidStartNavigationObserver(WebContents * contents)3602 DidStartNavigationObserver::DidStartNavigationObserver(WebContents* contents)
3603 : WebContentsObserver(contents) {}
3604 DidStartNavigationObserver::~DidStartNavigationObserver() = default;
3605
DidStartNavigation(NavigationHandle * handle)3606 void DidStartNavigationObserver::DidStartNavigation(NavigationHandle* handle) {
3607 if (observed_)
3608 return;
3609 observed_ = true;
3610 navigation_handle_ = handle;
3611 run_loop_.Quit();
3612 }
3613
DidFinishNavigation(NavigationHandle * handle)3614 void DidStartNavigationObserver::DidFinishNavigation(NavigationHandle* handle) {
3615 if (navigation_handle_ == handle)
3616 navigation_handle_ = nullptr;
3617 }
3618
ProxyDSFObserver()3619 ProxyDSFObserver::ProxyDSFObserver() {
3620 RenderFrameProxyHost::SetCreatedCallbackForTesting(base::BindRepeating(
3621 &ProxyDSFObserver::OnCreation, base::Unretained(this)));
3622 }
3623
~ProxyDSFObserver()3624 ProxyDSFObserver::~ProxyDSFObserver() {
3625 RenderFrameProxyHost::SetCreatedCallbackForTesting(
3626 RenderFrameProxyHost::CreatedCallback());
3627 }
3628
WaitForOneProxyHostCreation()3629 void ProxyDSFObserver::WaitForOneProxyHostCreation() {
3630 if (!proxy_host_created_dsf_.empty())
3631 return;
3632 runner_ = std::make_unique<base::RunLoop>();
3633 runner_->Run();
3634 }
3635
OnCreation(RenderFrameProxyHost * rfph)3636 void ProxyDSFObserver::OnCreation(RenderFrameProxyHost* rfph) {
3637 // Not all RenderFrameProxyHosts will be created with a
3638 // CrossProcessFrameConnector. We're only interested in the ones that do.
3639 if (auto* cpfc = rfph->cross_process_frame_connector()) {
3640 proxy_host_created_dsf_.push_back(cpfc->screen_info().device_scale_factor);
3641 }
3642 if (runner_)
3643 runner_->Quit();
3644 }
3645
CompareWebContentsOutputToReference(WebContents * web_contents,const base::FilePath & expected_path,const gfx::Size & snapshot_size,const cc::PixelComparator & comparator)3646 bool CompareWebContentsOutputToReference(
3647 WebContents* web_contents,
3648 const base::FilePath& expected_path,
3649 const gfx::Size& snapshot_size,
3650 const cc::PixelComparator& comparator) {
3651 // Produce a frame of output first to ensure the system is in a consistent,
3652 // known state.
3653 {
3654 base::RunLoop run_loop;
3655 web_contents->GetMainFrame()->InsertVisualStateCallback(
3656 base::BindLambdaForTesting([&](bool visual_state_updated) {
3657 ASSERT_TRUE(visual_state_updated);
3658 run_loop.Quit();
3659 }));
3660 run_loop.Run();
3661 }
3662
3663 auto* rwh = RenderWidgetHostImpl::From(
3664 web_contents->GetMainFrame()->GetRenderViewHost()->GetWidget());
3665
3666 if (!rwh->GetView() || !rwh->GetView()->IsSurfaceAvailableForCopy()) {
3667 ADD_FAILURE() << "RWHV surface not available for copy.";
3668 return false;
3669 }
3670
3671 bool snapshot_matches = false;
3672 {
3673 base::RunLoop run_loop;
3674 rwh->GetView()->CopyFromSurface(
3675 gfx::Rect(), gfx::Size(),
3676 base::BindLambdaForTesting([&](const SkBitmap& bitmap) {
3677 base::ScopedAllowBlockingForTesting allow_blocking;
3678 ASSERT_FALSE(bitmap.drawsNothing());
3679
3680 SkBitmap clipped_bitmap;
3681 bitmap.extractSubset(
3682 &clipped_bitmap,
3683 SkIRect::MakeWH(snapshot_size.width(), snapshot_size.height()));
3684
3685 snapshot_matches =
3686 cc::MatchesPNGFile(clipped_bitmap, expected_path, comparator);
3687
3688 // When rebaselining the pixel test, the test may fail. However, the
3689 // reference file will still be overwritten.
3690 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
3691 switches::kRebaselinePixelTests)) {
3692 ASSERT_TRUE(cc::WritePNGFile(clipped_bitmap, expected_path,
3693 /*discard_transparency=*/false));
3694 }
3695
3696 run_loop.Quit();
3697 }));
3698 run_loop.Run();
3699 }
3700
3701 return snapshot_matches;
3702 }
3703
RenderFrameHostChangedCallbackRunner(WebContents * content,RenderFrameHostChangedCallback callback)3704 RenderFrameHostChangedCallbackRunner::RenderFrameHostChangedCallbackRunner(
3705 WebContents* content,
3706 RenderFrameHostChangedCallback callback)
3707 : WebContentsObserver(content), callback_(std::move(callback)) {}
3708
3709 RenderFrameHostChangedCallbackRunner::~RenderFrameHostChangedCallbackRunner() =
3710 default;
3711
RenderFrameHostChanged(RenderFrameHost * old_host,RenderFrameHost * new_host)3712 void RenderFrameHostChangedCallbackRunner::RenderFrameHostChanged(
3713 RenderFrameHost* old_host,
3714 RenderFrameHost* new_host) {
3715 if (callback_)
3716 std::move(callback_).Run(old_host, new_host);
3717 }
3718
3719 } // namespace content
3720