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, &params);
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