#include "content/web_test/renderer/test_runner.h"
#include <stddef.h>
#include <algorithm>
#include <clocale>
#include <limits>
#include <string_view>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/containers/contains.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "build/build_config.h"
#include "cc/paint/paint_canvas.h"
#include "cc/paint/skia_paint_canvas.h"
#include "components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h"
#include "components/subresource_filter/core/common/memory_mapped_ruleset.h"
#include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/isolated_world_ids.h"
#include "content/public/renderer/render_frame_observer.h"
#include "content/renderer/render_thread_impl.h"
#include "content/web_test/common/web_test_constants.h"
#include "content/web_test/common/web_test_string_util.h"
#include "content/web_test/renderer/app_banner_service.h"
#include "content/web_test/renderer/blink_test_helpers.h"
#include "content/web_test/renderer/spell_check_client.h"
#include "content/web_test/renderer/test_preferences.h"
#include "content/web_test/renderer/test_runner_utils.h"
#include "content/web_test/renderer/web_frame_test_proxy.h"
#include "crypto/obsolete/md5.h"
#include "gin/arguments.h"
#include "gin/array_buffer.h"
#include "gin/dictionary.h"
#include "gin/object_template_builder.h"
#include "gin/public/wrappable_pointer_tags.h"
#include "gin/wrappable.h"
#include "mojo/public/mojom/base/text_direction.mojom-forward.h"
#include "net/base/filename_util.h"
#include "printing/metafile_skia.h"
#include "printing/mojom/print.mojom.h"
#include "printing/page_number.h"
#include "printing/page_range.h"
#include "printing/print_settings.h"
#include "services/network/public/mojom/cors.mojom.h"
#include "third_party/abseil-cpp/absl/numeric/int128.h"
#include "third_party/blink/public/common/page/page_zoom.h"
#include "third_party/blink/public/common/permissions/permission_utils.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "third_party/blink/public/mojom/app_banner/app_banner.mojom.h"
#include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h"
#include "third_party/blink/public/platform/file_path_conversion.h"
#include "third_party/blink/public/platform/web_cache.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_isolated_world_info.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/public/test/frame_widget_test_helper.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/public/web/web_array_buffer.h"
#include "third_party/blink/public/web/web_array_buffer_converter.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_document_loader.h"
#include "third_party/blink/public/web/web_element_collection.h"
#include "third_party/blink/public/web/web_frame.h"
#include "third_party/blink/public/web/web_frame_widget.h"
#include "third_party/blink/public/web/web_input_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_manifest_manager.h"
#include "third_party/blink/public/web/web_print_params.h"
#include "third_party/blink/public/web/web_render_theme.h"
#include "third_party/blink/public/web/web_script_source.h"
#include "third_party/blink/public/web/web_security_policy.h"
#include "third_party/blink/public/web/web_serialized_script_value.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/public/web/web_testing_support.h"
#include "third_party/blink/public/web/web_view.h"
#include "third_party/blink/public/web/web_view_observer.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/test/icc_profiles.h"
#include "v8/include/cppgc/allocation.h"
#include "v8/include/cppgc/prefinalizer.h"
#include "v8/include/v8-cppgc.h"
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
#include "third_party/blink/public/platform/web_font_render_style.h"
#endif
namespace content {
namespace {
const int kWPTPrintWidth = 5 * 96;
const int kWPTPrintHeight = 3 * 96;
const int kWPTPrintMargins = 96 / 2;
using BoundV8Callback =
base::OnceCallback<void(const v8::LocalVector<v8::Value>&)>;
v8::LocalVector<v8::Value> NoV8Args(v8::Isolate* isolate) {
return v8::LocalVector<v8::Value>(isolate);
}
v8::LocalVector<v8::Value> ConvertBitmapToV8(
v8::Isolate* isolate,
const v8::Context::Scope& context_scope,
const SkBitmap& bitmap) {
v8::LocalVector<v8::Value> args(isolate);
args.push_back(v8::Number::New(isolate, bitmap.info().width()));
args.push_back(v8::Number::New(isolate, bitmap.info().height()));
if (bitmap.isNull()) {
return args;
}
SkImageInfo info = bitmap.info().makeColorType(kRGBA_8888_SkColorType);
size_t row_bytes = info.minRowBytes();
blink::WebArrayBuffer buffer =
blink::WebArrayBuffer::Create(info.computeByteSize(row_bytes), 1);
bool read = bitmap.readPixels(info, buffer.Data(), row_bytes, 0, 0);
CHECK(read);
args.push_back(blink::WebArrayBufferConverter::ToV8Value(&buffer, isolate));
return args;
}
void ConvertAndSet(gin::Arguments* args, int* set_param) {
v8::Local<v8::Value> value = args->PeekNext();
v8::Maybe<int> result = value->Int32Value(args->GetHolderCreationContext());
if (result.IsNothing()) {
args->Skip();
args->ThrowError();
return;
}
*set_param = result.ToChecked();
}
void ConvertAndSet(gin::Arguments* args, bool* set_param) {
v8::Local<v8::Value> value = args->PeekNext();
*set_param = value->BooleanValue(args->isolate());
}
void ConvertAndSet(gin::Arguments* args, blink::WebString* set_param) {
v8::Local<v8::Value> value = args->PeekNext();
v8::MaybeLocal<v8::String> result =
value->ToString(args->GetHolderCreationContext());
if (result.IsEmpty()) {
args->Skip();
args->ThrowError();
return;
}
*set_param = web_test_string_util::V8StringToWebString(
args->isolate(), result.ToLocalChecked());
}
}
class TestRunnerBindings final : public gin::Wrappable<TestRunnerBindings> {
CPPGC_USING_PRE_FINALIZER(TestRunnerBindings, Dispose);
public:
static constexpr gin::WrapperInfo kWrapperInfo = {{gin::kEmbedderNativeGin},
gin::kTestRunnerBindings};
const gin::WrapperInfo* wrapper_info() const override {
return &kWrapperInfo;
}
TestRunnerBindings(const TestRunnerBindings&) = delete;
TestRunnerBindings& operator=(const TestRunnerBindings&) = delete;
static void Install(TestRunner* test_runner,
WebFrameTestProxy* frame,
SpellCheckClient* spell_check,
bool is_wpt_reftest,
bool is_main_test_window);
void Dispose();
BoundV8Callback WrapV8Callback(v8::Local<v8::Function> v8_callback);
BoundV8Callback WrapV8Callback(v8::Local<v8::Function> v8_callback,
v8::LocalVector<v8::Value> args_to_bind);
base::OnceClosure WrapV8Closure(v8::Local<v8::Function> v8_callback);
base::OnceClosure WrapV8Closure(v8::Local<v8::Function> v8_callback,
v8::LocalVector<v8::Value> args_to_bind);
void PostV8Callback(v8::Local<v8::Function> v8_callback);
void PostV8Callback(v8::Local<v8::Function> v8_callback,
v8::LocalVector<v8::Value> args);
blink::WebLocalFrame* GetWebFrame() {
CHECK(frame_);
return frame_->GetWebFrame();
}
explicit TestRunnerBindings(TestRunner* test_runner,
WebFrameTestProxy* frame,
SpellCheckClient* spell_check);
private:
class TestRunnerBindingsRenderFrameObserver : public RenderFrameObserver {
public:
TestRunnerBindingsRenderFrameObserver(TestRunnerBindings* bindings,
RenderFrame* frame)
: RenderFrameObserver(frame), bindings_(bindings) {}
void OnDestruct() override { bindings_->OnFrameDestroyed(); }
private:
const raw_ptr<TestRunnerBindings> bindings_;
};
gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
void AddOriginAccessAllowListEntry(const std::string& source_origin,
const std::string& destination_protocol,
const std::string& destination_host,
bool allow_destination_subdomains);
void AddWebPageOverlay();
void AllowPointerLock();
void SetHighlightAds();
#if BUILDFLAG(ENABLE_PRINTING)
void CapturePrintingPixelsThen(v8::Local<v8::Function> callback);
#endif
void CheckForLeakedWindows();
void ClearTrustTokenState(v8::Local<v8::Function> callback);
void CopyImageThen(int x, int y, v8::Local<v8::Function> callback);
void DisableMockScreenOrientation();
void DispatchBeforeInstallPromptEvent(
const std::vector<std::string>& event_platforms,
v8::Local<v8::Function> callback);
void DropPointerLock();
void DumpAsMarkup();
void DumpAsText();
void DumpAsTextWithPixelResults();
void DumpAsLayout();
void DumpAsLayoutWithPixelResults();
void DumpChildFrames();
void DumpBackForwardList();
void DumpCreateView();
void DumpDragImage();
void DumpEditingCallbacks();
void DumpFrameLoadCallbacks();
void DumpIconChanges();
void DumpNavigationPolicy();
void DumpPermissionClientCallbacks();
void DumpPingLoaderCallbacks();
void DumpSelectionRect();
void DumpTitleChanges();
void DumpUserGestureInFrameLoadCallbacks();
void EvaluateScriptInIsolatedWorld(int world_id, const std::string& script);
void EvaluateScriptInOwnTask(const std::string& script,
const std::string& source_url,
v8::Local<v8::Function> v8_callback);
void ExecCommand(gin::Arguments* args);
void TriggerTestInspectorIssue(gin::Arguments* args);
void FocusDevtoolsSecondaryWindow();
void ForceNextDrawingBufferCreationToFail();
void ForceNextWebGLContextCreationToFail();
void GetBluetoothManualChooserEvents(v8::Local<v8::Function> callback);
void GetManifestThen(v8::Local<v8::Function> callback);
std::string GetWritableDirectory();
void InsertStyleSheet(const std::string& source_code);
void UpdateAllLifecyclePhasesAndComposite();
void UpdateAllLifecyclePhasesAndCompositeThen(
v8::Local<v8::Function> callback);
void SetAnimationRequiresRaster(bool do_raster);
void LogToStderr(const std::string& output);
void NotImplemented(const gin::Arguments& args);
void NotifyDone();
void OverridePreference(gin::Arguments* args);
void QueueBackNavigation(int how_far_back);
void QueueForwardNavigation(int how_far_forward);
void QueueLoad(gin::Arguments* args);
void QueueLoadingScript(const std::string& script);
void QueueNonLoadingScript(const std::string& script);
void QueueReload();
void RemoveSpellCheckResolvedCallback();
void RemoveWebPageOverlay();
void ResolveBeforeInstallPromptPromise(const std::string& platform);
void SendBluetoothManualChooserEvent(const std::string& event,
const std::string& argument);
void SetAcceptLanguages(const std::string& accept_languages);
void SetAllowFileAccessFromFileURLs(bool allow);
void SetAllowRunningOfInsecureContent(bool allowed);
void SetBlockThirdPartyCookies(bool block);
void SetAudioData(const gin::ArrayBufferView& view);
void SetBackingScaleFactor(double value, v8::Local<v8::Function> callback);
void SetBluetoothFakeAdapter(const std::string& adapter_name,
v8::Local<v8::Function> callback);
void SetBluetoothManualChooser(bool enable);
void SetBrowserHandlesFocus(bool enable);
void SetCaretBrowsingEnabled();
void SetColorProfile(const std::string& name,
v8::Local<v8::Function> callback);
void SetCustomPolicyDelegate(gin::Arguments* args);
void SetCustomTextOutput(const std::string& output);
void SetDisallowedSubresourcePathSuffixes(std::vector<std::string> suffixes,
bool block_subresources);
void SetDomainRelaxationForbiddenForURLScheme(bool forbidden,
const std::string& scheme);
void SetDumpConsoleMessages(bool value);
void SetDumpJavaScriptDialogs(bool value);
void SetEffectiveConnectionType(const std::string& connection_type);
void SetFilePathForMockFileDialog(const std::string& path);
void SetMockSpellCheckerEnabled(bool enabled);
void SetIsolatedWorldInfo(int world_id,
v8::Local<v8::Value> security_origin,
v8::Local<v8::Value> content_security_policy);
void SetJavaScriptCanAccessClipboard(bool can_access);
void SetMockScreenOrientation(const std::string& orientation);
void SetPOSIXLocale(const std::string& locale);
void SetMainWindowHidden(bool hidden);
void SetFrameWindowHidden(bool hidden);
void SetWindowRect(const gin::Dictionary& rect);
void SetPermission(const std::string& name,
const std::string& value,
const std::string& origin,
const std::string& embedding_origin);
void SetPluginsAllowed(bool allowed);
void SetPluginsEnabled(bool enabled);
void SetPointerLockWillFail();
void SetPointerLockWillRespondAsynchronously();
void SetPopupBlockingEnabled(bool block_popups);
void SetPrinting();
void SetPrintingForFrame(const std::string& frame_name);
void SetPrintingSize(int width, int height);
void SetPrintingMargin(int);
void SetSafePrintableInset(int);
void SetShouldCenterAndShrinkToFitPaper(bool);
void SetPrintingScaleFactor(float);
void SetShouldGeneratePixelResults(bool);
void SetShouldStayOnPageAfterHandlingBeforeUnload(bool value);
void SetSpellCheckResolvedCallback(v8::Local<v8::Function> callback);
void SetStorageAllowed(bool allowed);
void SetTabKeyCyclesThroughElements(bool tab_key_cycles_through_elements);
void SetTextDirection(const std::string& direction_name);
void SetTextSubpixelPositioning(bool value);
void SetTrustTokenKeyCommitments(const std::string& raw_commitments,
v8::Local<v8::Function> callback);
void SetWillSendRequestClearHeader(const std::string& header);
void SetWillSendRequestClearReferrer();
void SetRphRegistrationMode(gin::Arguments* args);
void SimulateBrowserWindowFocus(bool value);
void NavigateSecondaryWindow(const std::string& url);
void InspectSecondaryWindow();
void SimulateWebNotificationClick(gin::Arguments* args);
void SimulateWebNotificationClose(const std::string& title, bool by_user);
void SimulateWebContentIndexDelete(const std::string& id);
void WaitForPolicyDelegate();
void WaitUntilDone();
void WaitUntilExternalURLLoad();
void DisableAutoResizeMode(int new_width, int new_height);
void EnableAutoResizeMode(int min_width,
int min_height,
int max_width,
int max_height);
void DisableAutomaticDragDrop();
void GoToOffset(int offset);
v8::Local<v8::Value> EvaluateScriptInIsolatedWorldAndReturnValue(
int world_id,
const std::string& script);
bool FindString(const std::string& search_text,
const std::vector<std::string>& options_array);
bool IsCommandEnabled(const std::string& command);
std::string PathToLocalResource(const std::string& path);
std::string PlatformName();
std::string SelectionAsMarkup();
void TextZoomIn();
void TextZoomOut();
void ZoomPageIn();
void ZoomPageOut();
void SetPageZoomFactor(double factor);
std::string TooltipText();
int WebHistoryItemCount();
int WindowCount();
void InvokeV8Callback(v8::UniquePersistent<v8::Function> callback,
std::vector<v8::UniquePersistent<v8::Value>> bound_args,
const v8::LocalVector<v8::Value>& runtime_args);
void OnFrameDestroyed() { frame_ = nullptr; }
TestRunnerBindingsRenderFrameObserver frame_observer_;
raw_ptr<TestRunner, DanglingUntriaged> runner_;
raw_ptr<WebFrameTestProxy, DanglingUntriaged> frame_;
const raw_ptr<SpellCheckClient, DanglingUntriaged> spell_check_;
TestPreferences prefs_;
std::unique_ptr<AppBannerService> app_banner_service_;
base::WeakPtrFactory<TestRunnerBindings> weak_ptr_factory_{this};
};
void TestRunnerBindings::Install(TestRunner* test_runner,
WebFrameTestProxy* frame,
SpellCheckClient* spell_check,
bool is_wpt_test,
bool is_main_test_window) {
blink::WebLocalFrame* web_frame = frame->GetWebFrame();
v8::Isolate* isolate = web_frame->GetAgentGroupScheduler()->Isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = web_frame->MainWorldScriptContext();
CHECK(!context.IsEmpty());
v8::Context::Scope context_scope(context);
auto* bindings = cppgc::MakeGarbageCollected<TestRunnerBindings>(
isolate->GetCppHeap()->GetAllocationHandle(), test_runner, frame,
spell_check);
v8::Local<v8::Object> wrapper =
bindings->GetWrapper(isolate).ToLocalChecked();
v8::Local<v8::Object> global = context->Global();
global->Set(context, gin::StringToV8(isolate, "testRunner"), wrapper).Check();
if (is_wpt_test && is_main_test_window && !web_frame->Parent() &&
!web_frame->Opener()) {
web_frame->ExecuteScript(blink::WebScriptSource(blink::WebString(
R"(if (!window.testRunner._wpt_reftest_setup) {
window.testRunner._wpt_reftest_setup = true;
function observeRefTestFinished() {
if (window.assert_equals) // In case of a testharness test.
return;
window.testRunner.waitUntilDone();
const target = document.documentElement;
if (target != null &&
(target.classList.contains('reftest-wait') ||
target.classList.contains('test-wait'))) {
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (!target.classList.contains('reftest-wait') &&
!target.classList.contains('test-wait')) {
// This is the same as https://github.com/web-platform-tests/wpt/blob/master/tools/wptrunner/wptrunner/executors/test-wait.js
requestAnimationFrame(() => {
requestAnimationFrame(() => {
window.testRunner.notifyDone();
});
});
}
});
});
const config = {attributes: true};
observer.observe(target, config);
var event = new Event('TestRendered', {bubbles: true});
target.dispatchEvent(event);
} else {
document.fonts.ready.then(() => window.testRunner.notifyDone());
}
};
window.addEventListener('load', () => {
if (document.prerendering) {
document.addEventListener('prerenderingchange',
observeRefTestFinished);
} else {
observeRefTestFinished();
}
});
})")));
}
}
void TestRunnerBindings::Dispose() {
weak_ptr_factory_.InvalidateWeakPtrsAndDoom();
app_banner_service_.reset();
frame_observer_.Dispose();
}
TestRunnerBindings::TestRunnerBindings(TestRunner* runner,
WebFrameTestProxy* frame,
SpellCheckClient* spell_check)
: frame_observer_(this, frame),
runner_(runner),
frame_(frame),
spell_check_(spell_check) {}
gin::ObjectTemplateBuilder TestRunnerBindings::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return gin::Wrappable<TestRunnerBindings>::GetObjectTemplateBuilder(isolate)
.SetMethod("abortModal", &TestRunnerBindings::NotImplemented)
.SetMethod("addDisallowedURL", &TestRunnerBindings::NotImplemented)
.SetMethod("addOriginAccessAllowListEntry",
&TestRunnerBindings::AddOriginAccessAllowListEntry)
.SetMethod("addWebPageOverlay", &TestRunnerBindings::AddWebPageOverlay)
#if BUILDFLAG(ENABLE_PRINTING)
.SetMethod("capturePrintingPixelsThen",
&TestRunnerBindings::CapturePrintingPixelsThen)
#endif
.SetMethod("checkForLeakedWindows",
&TestRunnerBindings::CheckForLeakedWindows)
.SetMethod("clearBackForwardList", &TestRunnerBindings::NotImplemented)
.SetMethod("clearTrustTokenState",
&TestRunnerBindings::ClearTrustTokenState)
.SetMethod("copyImageThen", &TestRunnerBindings::CopyImageThen)
.SetMethod("dropPointerLock", &TestRunnerBindings::DropPointerLock)
.SetMethod("allowPointerLock", &TestRunnerBindings::AllowPointerLock)
.SetMethod("setPointerLockWillFail",
&TestRunnerBindings::SetPointerLockWillFail)
.SetMethod("setPointerLockWillRespondAsynchronously",
&TestRunnerBindings::SetPointerLockWillRespondAsynchronously)
.SetMethod("disableAutoResizeMode",
&TestRunnerBindings::DisableAutoResizeMode)
.SetMethod("disableMockScreenOrientation",
&TestRunnerBindings::DisableMockScreenOrientation)
.SetMethod("setDisallowedSubresourcePathSuffixes",
&TestRunnerBindings::SetDisallowedSubresourcePathSuffixes)
.SetMethod("dispatchBeforeInstallPromptEvent",
&TestRunnerBindings::DispatchBeforeInstallPromptEvent)
.SetMethod("dumpAsMarkup", &TestRunnerBindings::DumpAsMarkup)
.SetMethod("dumpAsText", &TestRunnerBindings::DumpAsText)
.SetMethod("dumpAsTextWithPixelResults",
&TestRunnerBindings::DumpAsTextWithPixelResults)
.SetMethod("dumpAsLayout", &TestRunnerBindings::DumpAsLayout)
.SetMethod("dumpAsLayoutWithPixelResults",
&TestRunnerBindings::DumpAsLayoutWithPixelResults)
.SetMethod("dumpBackForwardList",
&TestRunnerBindings::DumpBackForwardList)
.SetMethod("dumpChildFrames", &TestRunnerBindings::DumpChildFrames)
.SetMethod("dumpDatabaseCallbacks", &TestRunnerBindings::NotImplemented)
.SetMethod("dumpDragImage", &TestRunnerBindings::DumpDragImage)
.SetMethod("dumpEditingCallbacks",
&TestRunnerBindings::DumpEditingCallbacks)
.SetMethod("dumpFrameLoadCallbacks",
&TestRunnerBindings::DumpFrameLoadCallbacks)
.SetMethod("dumpIconChanges", &TestRunnerBindings::DumpIconChanges)
.SetMethod("dumpNavigationPolicy",
&TestRunnerBindings::DumpNavigationPolicy)
.SetMethod("dumpPermissionClientCallbacks",
&TestRunnerBindings::DumpPermissionClientCallbacks)
.SetMethod("dumpPingLoaderCallbacks",
&TestRunnerBindings::DumpPingLoaderCallbacks)
.SetMethod("dumpSelectionRect", &TestRunnerBindings::DumpSelectionRect)
.SetMethod("dumpTitleChanges", &TestRunnerBindings::DumpTitleChanges)
.SetMethod("dumpUserGestureInFrameLoadCallbacks",
&TestRunnerBindings::DumpUserGestureInFrameLoadCallbacks)
.SetMethod("enableAutoResizeMode",
&TestRunnerBindings::EnableAutoResizeMode)
.SetMethod("evaluateScriptInIsolatedWorld",
&TestRunnerBindings::EvaluateScriptInIsolatedWorld)
.SetMethod("evaluateScriptInOwnTask",
&TestRunnerBindings::EvaluateScriptInOwnTask)
.SetMethod(
"evaluateScriptInIsolatedWorldAndReturnValue",
&TestRunnerBindings::EvaluateScriptInIsolatedWorldAndReturnValue)
.SetMethod("execCommand", &TestRunnerBindings::ExecCommand)
.SetMethod("triggerTestInspectorIssue",
&TestRunnerBindings::TriggerTestInspectorIssue)
.SetMethod("findString", &TestRunnerBindings::FindString)
.SetMethod("focusDevtoolsSecondaryWindow",
&TestRunnerBindings::FocusDevtoolsSecondaryWindow)
.SetMethod("forceNextDrawingBufferCreationToFail",
&TestRunnerBindings::ForceNextDrawingBufferCreationToFail)
.SetMethod("forceNextWebGLContextCreationToFail",
&TestRunnerBindings::ForceNextWebGLContextCreationToFail)
.SetMethod("getBluetoothManualChooserEvents",
&TestRunnerBindings::GetBluetoothManualChooserEvents)
.SetMethod("getManifestThen", &TestRunnerBindings::GetManifestThen)
.SetMethod("getWritableDirectory",
&TestRunnerBindings::GetWritableDirectory)
.SetMethod("insertStyleSheet", &TestRunnerBindings::InsertStyleSheet)
.SetMethod("isCommandEnabled", &TestRunnerBindings::IsCommandEnabled)
.SetMethod("keepWebHistory", &TestRunnerBindings::NotImplemented)
.SetMethod("updateAllLifecyclePhasesAndComposite",
&TestRunnerBindings::UpdateAllLifecyclePhasesAndComposite)
.SetMethod("updateAllLifecyclePhasesAndCompositeThen",
&TestRunnerBindings::UpdateAllLifecyclePhasesAndCompositeThen)
.SetMethod("setAnimationRequiresRaster",
&TestRunnerBindings::SetAnimationRequiresRaster)
.SetMethod("logToStderr", &TestRunnerBindings::LogToStderr)
.SetMethod("notifyDone", &TestRunnerBindings::NotifyDone)
.SetMethod("overridePreference", &TestRunnerBindings::OverridePreference)
.SetMethod("pathToLocalResource",
&TestRunnerBindings::PathToLocalResource)
.SetProperty("platformName", &TestRunnerBindings::PlatformName)
.SetMethod("queueBackNavigation",
&TestRunnerBindings::QueueBackNavigation)
.SetMethod("queueForwardNavigation",
&TestRunnerBindings::QueueForwardNavigation)
.SetMethod("queueLoad", &TestRunnerBindings::QueueLoad)
.SetMethod("queueLoadingScript", &TestRunnerBindings::QueueLoadingScript)
.SetMethod("queueNonLoadingScript",
&TestRunnerBindings::QueueNonLoadingScript)
.SetMethod("queueReload", &TestRunnerBindings::QueueReload)
.SetMethod("removeSpellCheckResolvedCallback",
&TestRunnerBindings::RemoveSpellCheckResolvedCallback)
.SetMethod("removeWebPageOverlay",
&TestRunnerBindings::RemoveWebPageOverlay)
.SetMethod("resolveBeforeInstallPromptPromise",
&TestRunnerBindings::ResolveBeforeInstallPromptPromise)
.SetMethod("selectionAsMarkup", &TestRunnerBindings::SelectionAsMarkup)
.SetMethod("sendBluetoothManualChooserEvent",
&TestRunnerBindings::SendBluetoothManualChooserEvent)
.SetMethod("setAcceptLanguages", &TestRunnerBindings::SetAcceptLanguages)
.SetMethod("setAllowFileAccessFromFileURLs",
&TestRunnerBindings::SetAllowFileAccessFromFileURLs)
.SetMethod("setAllowRunningOfInsecureContent",
&TestRunnerBindings::SetAllowRunningOfInsecureContent)
.SetMethod("setBlockThirdPartyCookies",
&TestRunnerBindings::SetBlockThirdPartyCookies)
.SetMethod("setAudioData", &TestRunnerBindings::SetAudioData)
.SetMethod("setBackingScaleFactor",
&TestRunnerBindings::SetBackingScaleFactor)
.SetMethod("setBluetoothFakeAdapter",
&TestRunnerBindings::SetBluetoothFakeAdapter)
.SetMethod("setBluetoothManualChooser",
&TestRunnerBindings::SetBluetoothManualChooser)
.SetMethod("setBrowserHandlesFocus",
&TestRunnerBindings::SetBrowserHandlesFocus)
.SetMethod("setCallCloseOnWebViews", &TestRunnerBindings::NotImplemented)
.SetMethod("setCaretBrowsingEnabled",
&TestRunnerBindings::SetCaretBrowsingEnabled)
.SetMethod("setColorProfile", &TestRunnerBindings::SetColorProfile)
.SetMethod("setCustomPolicyDelegate",
&TestRunnerBindings::SetCustomPolicyDelegate)
.SetMethod("setCustomTextOutput",
&TestRunnerBindings::SetCustomTextOutput)
.SetMethod("setDomainRelaxationForbiddenForURLScheme",
&TestRunnerBindings::SetDomainRelaxationForbiddenForURLScheme)
.SetMethod("setDumpConsoleMessages",
&TestRunnerBindings::SetDumpConsoleMessages)
.SetMethod("setDumpJavaScriptDialogs",
&TestRunnerBindings::SetDumpJavaScriptDialogs)
.SetMethod("setEffectiveConnectionType",
&TestRunnerBindings::SetEffectiveConnectionType)
.SetMethod("setFilePathForMockFileDialog",
&TestRunnerBindings::SetFilePathForMockFileDialog)
.SetMethod("setHighlightAds", &TestRunnerBindings::SetHighlightAds)
.SetMethod("setMockSpellCheckerEnabled",
&TestRunnerBindings::SetMockSpellCheckerEnabled)
.SetMethod("setIconDatabaseEnabled", &TestRunnerBindings::NotImplemented)
.SetMethod("setIsolatedWorldInfo",
&TestRunnerBindings::SetIsolatedWorldInfo)
.SetMethod("setJavaScriptCanAccessClipboard",
&TestRunnerBindings::SetJavaScriptCanAccessClipboard)
.SetMethod("setMainFrameIsFirstResponder",
&TestRunnerBindings::NotImplemented)
.SetMethod("setMockScreenOrientation",
&TestRunnerBindings::SetMockScreenOrientation)
.SetMethod("setPOSIXLocale", &TestRunnerBindings::SetPOSIXLocale)
.SetMethod("setMainWindowHidden",
&TestRunnerBindings::SetMainWindowHidden)
.SetMethod("setFrameWindowHidden",
&TestRunnerBindings::SetFrameWindowHidden)
.SetMethod("setWindowRect", &TestRunnerBindings::SetWindowRect)
.SetMethod("setPermission", &TestRunnerBindings::SetPermission)
.SetMethod("setPluginsAllowed", &TestRunnerBindings::SetPluginsAllowed)
.SetMethod("setPluginsEnabled", &TestRunnerBindings::SetPluginsEnabled)
.SetMethod("setPopupBlockingEnabled",
&TestRunnerBindings::SetPopupBlockingEnabled)
.SetMethod("setPrinting", &TestRunnerBindings::SetPrinting)
.SetMethod("setPrintingForFrame",
&TestRunnerBindings::SetPrintingForFrame)
.SetMethod("setPrintingSize", &TestRunnerBindings::SetPrintingSize)
.SetMethod("setPrintingMargin", &TestRunnerBindings::SetPrintingMargin)
.SetMethod("setSafePrintableInset",
&TestRunnerBindings::SetSafePrintableInset)
.SetMethod("setShouldCenterAndShrinkToFitPaper",
&TestRunnerBindings::SetShouldCenterAndShrinkToFitPaper)
.SetMethod("setPrintingScaleFactor",
&TestRunnerBindings::SetPrintingScaleFactor)
.SetMethod("setRphRegistrationMode",
&TestRunnerBindings::SetRphRegistrationMode)
.SetMethod("setScrollbarPolicy", &TestRunnerBindings::NotImplemented)
.SetMethod("setShouldGeneratePixelResults",
&TestRunnerBindings::SetShouldGeneratePixelResults)
.SetMethod(
"setShouldStayOnPageAfterHandlingBeforeUnload",
&TestRunnerBindings::SetShouldStayOnPageAfterHandlingBeforeUnload)
.SetMethod("setSpellCheckResolvedCallback",
&TestRunnerBindings::SetSpellCheckResolvedCallback)
.SetMethod("setStorageAllowed", &TestRunnerBindings::SetStorageAllowed)
.SetMethod("setTabKeyCyclesThroughElements",
&TestRunnerBindings::SetTabKeyCyclesThroughElements)
.SetMethod("setTextDirection", &TestRunnerBindings::SetTextDirection)
.SetMethod("setTextSubpixelPositioning",
&TestRunnerBindings::SetTextSubpixelPositioning)
.SetMethod("setTrustTokenKeyCommitments",
&TestRunnerBindings::SetTrustTokenKeyCommitments)
.SetMethod("setUseDashboardCompatibilityMode",
&TestRunnerBindings::NotImplemented)
.SetMethod("setWillSendRequestClearHeader",
&TestRunnerBindings::SetWillSendRequestClearHeader)
.SetMethod("setWillSendRequestClearReferrer",
&TestRunnerBindings::SetWillSendRequestClearReferrer)
.SetMethod("setWindowFocus",
&TestRunnerBindings::SimulateBrowserWindowFocus)
.SetMethod("simulateWebNotificationClick",
&TestRunnerBindings::SimulateWebNotificationClick)
.SetMethod("simulateWebNotificationClose",
&TestRunnerBindings::SimulateWebNotificationClose)
.SetMethod("simulateWebContentIndexDelete",
&TestRunnerBindings::SimulateWebContentIndexDelete)
.SetMethod("textZoomIn", &TestRunnerBindings::TextZoomIn)
.SetMethod("textZoomOut", &TestRunnerBindings::TextZoomOut)
.SetMethod("zoomPageIn", &TestRunnerBindings::ZoomPageIn)
.SetMethod("zoomPageOut", &TestRunnerBindings::ZoomPageOut)
.SetMethod("setPageZoomFactor", &TestRunnerBindings::SetPageZoomFactor)
.SetProperty("tooltipText", &TestRunnerBindings::TooltipText)
.SetMethod("waitForPolicyDelegate",
&TestRunnerBindings::WaitForPolicyDelegate)
.SetMethod("waitUntilDone", &TestRunnerBindings::WaitUntilDone)
.SetMethod("waitUntilExternalURLLoad",
&TestRunnerBindings::WaitUntilExternalURLLoad)
.SetProperty("webHistoryItemCount",
&TestRunnerBindings::WebHistoryItemCount)
.SetMethod("windowCount", &TestRunnerBindings::WindowCount)
.SetMethod("disableAutomaticDragDrop",
&TestRunnerBindings::DisableAutomaticDragDrop)
.SetMethod("goToOffset", &TestRunnerBindings::GoToOffset);
}
BoundV8Callback TestRunnerBindings::WrapV8Callback(
v8::Local<v8::Function> v8_callback) {
v8::Isolate* isolate = GetWebFrame()->GetAgentGroupScheduler()->Isolate();
return WrapV8Callback(v8_callback, NoV8Args(isolate));
}
BoundV8Callback TestRunnerBindings::WrapV8Callback(
v8::Local<v8::Function> v8_callback,
v8::LocalVector<v8::Value> args_to_bind) {
v8::Isolate* isolate = GetWebFrame()->GetAgentGroupScheduler()->Isolate();
auto persistent_callback =
v8::UniquePersistent<v8::Function>(isolate, std::move(v8_callback));
std::vector<v8::UniquePersistent<v8::Value>> persistent_args;
persistent_args.reserve(args_to_bind.size());
for (auto& arg : args_to_bind)
persistent_args.emplace_back(isolate, std::move(arg));
return base::BindOnce(
&TestRunnerBindings::InvokeV8Callback, weak_ptr_factory_.GetWeakPtr(),
std::move(persistent_callback), std::move(persistent_args));
}
base::OnceClosure TestRunnerBindings::WrapV8Closure(
v8::Local<v8::Function> v8_callback) {
v8::Isolate* isolate = GetWebFrame()->GetAgentGroupScheduler()->Isolate();
return WrapV8Closure(v8_callback, NoV8Args(isolate));
}
base::OnceClosure TestRunnerBindings::WrapV8Closure(
v8::Local<v8::Function> v8_callback,
v8::LocalVector<v8::Value> args_to_bind) {
v8::Isolate* isolate = GetWebFrame()->GetAgentGroupScheduler()->Isolate();
return base::BindOnce(
WrapV8Callback(std::move(v8_callback), std::move(args_to_bind)),
NoV8Args(isolate));
}
void TestRunnerBindings::PostV8Callback(v8::Local<v8::Function> v8_callback) {
v8::Isolate* isolate = GetWebFrame()->GetAgentGroupScheduler()->Isolate();
return PostV8Callback(v8_callback, NoV8Args(isolate));
}
void TestRunnerBindings::PostV8Callback(v8::Local<v8::Function> v8_callback,
v8::LocalVector<v8::Value> args) {
if (!frame_) {
return;
}
const auto& task_runner =
GetWebFrame()->GetTaskRunner(blink::TaskType::kInternalTest);
task_runner->PostTask(FROM_HERE,
WrapV8Closure(std::move(v8_callback), std::move(args)));
}
void TestRunnerBindings::InvokeV8Callback(
v8::UniquePersistent<v8::Function> callback,
std::vector<v8::UniquePersistent<v8::Value>> bound_args,
const v8::LocalVector<v8::Value>& runtime_args) {
if (!frame_) {
return;
}
blink::WebLocalFrame* web_frame = GetWebFrame();
v8::Isolate* isolate = web_frame->GetAgentGroupScheduler()->Isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = web_frame->MainWorldScriptContext();
CHECK(!context.IsEmpty());
v8::Context::Scope context_scope(context);
v8::LocalVector<v8::Value> local_args(isolate);
for (auto& arg : bound_args)
local_args.push_back(v8::Local<v8::Value>::New(isolate, std::move(arg)));
for (const auto& arg : runtime_args)
local_args.push_back(arg);
web_frame->CallFunctionEvenIfScriptDisabled(
v8::Local<v8::Function>::New(isolate, std::move(callback)),
context->Global(), local_args.size(), local_args.data());
}
void TestRunnerBindings::LogToStderr(const std::string& output) {
if (!frame_) {
return;
}
TRACE_EVENT1("shell", "TestRunner::LogToStderr", "output", output);
LOG(ERROR) << output;
}
void TestRunnerBindings::NotifyDone() {
if (!frame_) {
return;
}
runner_->NotifyDone(*frame_);
}
void TestRunnerBindings::WaitUntilDone() {
if (!frame_) {
return;
}
runner_->WaitUntilDone(*frame_);
}
void TestRunnerBindings::QueueBackNavigation(int how_far_back) {
if (!frame_) {
return;
}
runner_->QueueBackNavigation(how_far_back, *frame_);
}
void TestRunnerBindings::QueueForwardNavigation(int how_far_forward) {
if (!frame_) {
return;
}
runner_->QueueForwardNavigation(how_far_forward, *frame_);
}
void TestRunnerBindings::QueueReload() {
if (!frame_) {
return;
}
runner_->QueueReload(*frame_);
}
void TestRunnerBindings::QueueLoadingScript(const std::string& script) {
if (!frame_) {
return;
}
runner_->QueueLoadingScript(script, *frame_);
}
void TestRunnerBindings::QueueNonLoadingScript(const std::string& script) {
if (!frame_) {
return;
}
runner_->QueueNonLoadingScript(script, *frame_);
}
void TestRunnerBindings::QueueLoad(gin::Arguments* args) {
if (!frame_) {
return;
}
std::string url;
std::string target;
args->GetNext(&url);
args->GetNext(&target);
runner_->QueueLoad(GURL(GetWebFrame()->GetDocument().Url()), url, target,
*frame_);
}
void TestRunnerBindings::SetCustomPolicyDelegate(gin::Arguments* args) {
if (!frame_) {
return;
}
runner_->SetCustomPolicyDelegate(args, *frame_);
}
void TestRunnerBindings::WaitForPolicyDelegate() {
if (!frame_) {
return;
}
runner_->WaitForPolicyDelegate(*frame_);
}
int TestRunnerBindings::WindowCount() {
if (!frame_) {
return 0;
}
return runner_->InProcessWindowCount();
}
void TestRunnerBindings::SetTabKeyCyclesThroughElements(
bool tab_key_cycles_through_elements) {
if (!frame_) {
return;
}
blink::WebView* web_view = GetWebFrame()->View();
web_view->SetTabKeyCyclesThroughElements(tab_key_cycles_through_elements);
}
void TestRunnerBindings::ExecCommand(gin::Arguments* args) {
if (!frame_) {
return;
}
std::string command;
args->GetNext(&command);
std::string value;
if (args->Length() >= 3) {
args->Skip();
args->GetNext(&value);
}
GetWebFrame()->ExecuteCommand(blink::WebString::FromUTF8(command),
blink::WebString::FromUTF8(value));
}
void TestRunnerBindings::TriggerTestInspectorIssue(gin::Arguments* args) {
if (!frame_) {
return;
}
GetWebFrame()->AddInspectorIssue(
blink::mojom::InspectorIssueCode::kCookieIssue);
}
bool TestRunnerBindings::IsCommandEnabled(const std::string& command) {
if (!frame_) {
return false;
}
return GetWebFrame()->IsCommandEnabled(blink::WebString::FromUTF8(command));
}
void TestRunnerBindings::SetDomainRelaxationForbiddenForURLScheme(
bool forbidden,
const std::string& scheme) {
if (!frame_) {
return;
}
blink::SetDomainRelaxationForbiddenForTest(
forbidden, blink::WebString::FromUTF8(scheme));
}
void TestRunnerBindings::SetDumpConsoleMessages(bool enabled) {
if (!frame_) {
return;
}
runner_->SetDumpConsoleMessages(enabled, *frame_);
}
void TestRunnerBindings::SetDumpJavaScriptDialogs(bool enabled) {
if (!frame_) {
return;
}
runner_->SetDumpJavaScriptDialogs(enabled, *frame_);
}
void TestRunnerBindings::SetEffectiveConnectionType(
const std::string& connection_type) {
if (!frame_) {
return;
}
blink::WebEffectiveConnectionType web_type =
blink::WebEffectiveConnectionType::kTypeUnknown;
if (connection_type == "TypeUnknown")
web_type = blink::WebEffectiveConnectionType::kTypeUnknown;
else if (connection_type == "TypeOffline")
web_type = blink::WebEffectiveConnectionType::kTypeOffline;
else if (connection_type == "TypeSlow2G")
web_type = blink::WebEffectiveConnectionType::kTypeSlow2G;
else if (connection_type == "Type2G")
web_type = blink::WebEffectiveConnectionType::kType2G;
else if (connection_type == "Type3G")
web_type = blink::WebEffectiveConnectionType::kType3G;
else if (connection_type == "Type4G")
web_type = blink::WebEffectiveConnectionType::kType4G;
else
NOTREACHED();
if (runner_)
runner_->SetEffectiveConnectionType(web_type);
}
std::string TestRunnerBindings::GetWritableDirectory() {
if (!frame_) {
return {};
}
base::FilePath result;
frame_->GetWebTestControlHostRemote()->GetWritableDirectory(&result);
return result.AsUTF8Unsafe();
}
void TestRunnerBindings::SetFilePathForMockFileDialog(const std::string& path) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->SetFilePathForMockFileDialog(
base::FilePath::FromUTF8Unsafe(path));
}
void TestRunnerBindings::SetMockSpellCheckerEnabled(bool enabled) {
if (!frame_) {
return;
}
spell_check_->SetEnabled(enabled);
}
void TestRunnerBindings::SetSpellCheckResolvedCallback(
v8::Local<v8::Function> callback) {
if (!frame_) {
return;
}
spell_check_->SetSpellCheckResolvedCallback(callback);
}
void TestRunnerBindings::RemoveSpellCheckResolvedCallback() {
if (!frame_) {
return;
}
spell_check_->RemoveSpellCheckResolvedCallback();
}
v8::Local<v8::Value>
TestRunnerBindings::EvaluateScriptInIsolatedWorldAndReturnValue(
int world_id,
const std::string& script) {
if (!frame_ || world_id <= 0 || world_id >= (1 << 29)) {
return {};
}
blink::WebScriptSource source(blink::WebString::FromUTF8(script));
return GetWebFrame()->ExecuteScriptInIsolatedWorldAndReturnValue(
world_id, source, blink::BackForwardCacheAware::kAllow);
}
void TestRunnerBindings::EvaluateScriptInIsolatedWorld(
int world_id,
const std::string& script) {
if (!frame_ || world_id <= 0 || world_id >= (1 << 29)) {
return;
}
blink::WebScriptSource source(blink::WebString::FromUTF8(script));
GetWebFrame()->ExecuteScriptInIsolatedWorld(
world_id, source, blink::BackForwardCacheAware::kAllow);
}
void TestRunnerBindings::EvaluateScriptInOwnTask(
const std::string& script,
const std::string& url,
v8::Local<v8::Function> v8_callback) {
if (!frame_) {
return;
}
blink::WebScriptSource source(blink::WebString::FromUTF8(script),
blink::WebURL(GURL(url)));
GetWebFrame()
->GetTaskRunner(blink::TaskType::kInternalTest)
->PostTask(
FROM_HERE,
base::BindOnce(
[](base::WeakPtr<TestRunnerBindings> weak_this,
blink::WebScriptSource source, base::OnceClosure closure) {
if (!weak_this || !weak_this->frame_) {
return;
}
weak_this->GetWebFrame()->ExecuteScript(source);
std::move(closure).Run();
},
weak_ptr_factory_.GetWeakPtr(), std::move(source),
WrapV8Closure(v8_callback)));
}
void TestRunnerBindings::SetIsolatedWorldInfo(
int world_id,
v8::Local<v8::Value> security_origin,
v8::Local<v8::Value> content_security_policy) {
if (!frame_) {
return;
}
if (world_id <= content::ISOLATED_WORLD_ID_GLOBAL ||
blink::IsEqualOrExceedEmbedderWorldIdLimit(world_id)) {
return;
}
if (!security_origin->IsString() && !security_origin->IsNull()) {
return;
}
if (!content_security_policy->IsString() &&
!content_security_policy->IsNull()) {
return;
}
if (content_security_policy->IsString() && security_origin->IsNull()) {
return;
}
blink::WebLocalFrame* web_frame = GetWebFrame();
blink::WebIsolatedWorldInfo info;
if (security_origin->IsString()) {
info.security_origin = blink::WebSecurityOrigin::CreateFromString(
web_test_string_util::V8StringToWebString(
web_frame->GetAgentGroupScheduler()->Isolate(),
security_origin.As<v8::String>()));
}
if (content_security_policy->IsString()) {
info.content_security_policy = web_test_string_util::V8StringToWebString(
web_frame->GetAgentGroupScheduler()->Isolate(),
content_security_policy.As<v8::String>());
}
GetWebFrame()->ClearIsolatedWorldCSPForTesting(world_id);
blink::SetIsolatedWorldInfo(world_id, info);
}
void TestRunnerBindings::AddOriginAccessAllowListEntry(
const std::string& source_origin,
const std::string& destination_protocol,
const std::string& destination_host,
bool allow_destination_subdomains) {
if (!frame_) {
return;
}
GURL url(source_origin);
DCHECK(url.is_valid());
DCHECK(url.has_scheme());
DCHECK(url.has_host());
runner_->AddOriginAccessAllowListEntry(source_origin, destination_protocol,
destination_host,
allow_destination_subdomains);
}
void TestRunnerBindings::InsertStyleSheet(const std::string& source_code) {
if (!frame_) {
return;
}
GetWebFrame()->GetDocument().InsertStyleSheet(
blink::WebString::FromUTF8(source_code));
}
bool TestRunnerBindings::FindString(
const std::string& search_text,
const std::vector<std::string>& options_array) {
if (!frame_) {
return false;
}
bool match_case = true;
bool forward = true;
bool new_session = false;
bool wrap_around = false;
bool async = false;
for (const auto& option : options_array) {
if (option == "CaseInsensitive")
match_case = false;
else if (option == "Backwards")
forward = false;
else if (option == "StartInSelection")
new_session = true;
else if (option == "WrapAround")
wrap_around = true;
else if (option == "Async")
async = true;
}
const bool find_result = GetWebFrame()->FindForTesting(
0, blink::WebString::FromUTF8(search_text), match_case, forward,
new_session, false , wrap_around, async);
return find_result;
}
std::string TestRunnerBindings::SelectionAsMarkup() {
if (!frame_) {
return {};
}
return GetWebFrame()->SelectionAsMarkup().Utf8();
}
void TestRunnerBindings::SetTextSubpixelPositioning(bool value) {
if (!frame_) {
return;
}
runner_->SetTextSubpixelPositioning(value);
}
void TestRunnerBindings::SetTrustTokenKeyCommitments(
const std::string& raw_commitments,
v8::Local<v8::Function> v8_callback) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->SetTrustTokenKeyCommitments(
raw_commitments, WrapV8Closure(std::move(v8_callback)));
}
void TestRunnerBindings::SetMainWindowHidden(bool hidden) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->SetMainWindowHidden(hidden);
}
void TestRunnerBindings::SetFrameWindowHidden(bool hidden) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->SetFrameWindowHidden(
frame_->GetWebFrame()->GetLocalFrameToken(), hidden);
}
void TestRunnerBindings::SetWindowRect(const gin::Dictionary& bounds) {
if (!frame_) {
return;
}
gfx::Rect rect = frame_->GetLocalRootWebFrameWidget()->WindowRect();
int x, y, width, height;
if (const_cast<gin::Dictionary&>(bounds).Get("x", &x) &&
const_cast<gin::Dictionary&>(bounds).Get("y", &y)) {
rect.set_origin({x, y});
}
if (const_cast<gin::Dictionary&>(bounds).Get("width", &width) &&
const_cast<gin::Dictionary&>(bounds).Get("height", &height)) {
rect.set_size({width, height});
}
GetWebFrame()->View()->SetWindowRectSynchronouslyForTesting(rect);
}
void TestRunnerBindings::SetTextDirection(const std::string& direction_name) {
if (!frame_) {
return;
}
base::i18n::TextDirection direction;
if (direction_name == "auto") {
direction = base::i18n::TextDirection::UNKNOWN_DIRECTION;
} else if (direction_name == "rtl") {
direction = base::i18n::TextDirection::RIGHT_TO_LEFT;
} else if (direction_name == "ltr") {
direction = base::i18n::TextDirection::LEFT_TO_RIGHT;
} else {
return;
}
GetWebFrame()->SetTextDirectionForTesting(direction);
}
void TestRunnerBindings::EnableAutoResizeMode(int min_width,
int min_height,
int max_width,
int max_height) {
if (!frame_) {
return;
}
if (!frame_->IsMainFrame()) {
return;
}
if (max_width <= 0 || max_height <= 0) {
return;
}
gfx::Size min_size(min_width, min_height);
gfx::Size max_size(max_width, max_height);
frame_->GetWebTestControlHostRemote()->EnableAutoResize(min_size, max_size);
}
void TestRunnerBindings::DisableAutoResizeMode(int new_width, int new_height) {
if (!frame_) {
return;
}
if (!frame_->IsMainFrame()) {
return;
}
if (new_width <= 0 || new_height <= 0) {
return;
}
gfx::Size new_size(new_width, new_height);
frame_->GetWebTestControlHostRemote()->DisableAutoResize(new_size);
}
void TestRunnerBindings::SetMockScreenOrientation(
const std::string& orientation) {
if (!frame_) {
return;
}
runner_->SetMockScreenOrientation(orientation, *frame_);
}
void TestRunnerBindings::DisableMockScreenOrientation() {
if (!frame_) {
return;
}
runner_->DisableMockScreenOrientation(GetWebFrame()->View());
}
void TestRunnerBindings::SetDisallowedSubresourcePathSuffixes(
std::vector<std::string> suffixes,
bool block_subresources) {
if (!frame_) {
return;
}
base::File ruleset_file;
frame_->GetWebTestControlHostRemote()->CreateSubresourceFilterRulesetFile(
suffixes, &ruleset_file);
scoped_refptr<subresource_filter::MemoryMappedRuleset> ruleset =
subresource_filter::MemoryMappedRuleset::CreateAndInitialize(
std::move(ruleset_file));
subresource_filter::mojom::ActivationLevel activation_level =
block_subresources ? subresource_filter::mojom::ActivationLevel::kEnabled
: subresource_filter::mojom::ActivationLevel::kDryRun;
subresource_filter::mojom::ActivationState activation_state(
activation_level,
subresource_filter::mojom::SubresourceFilterDisabledReason::kUnknown,
false,
false,
false,
true,
false);
GetWebFrame()->GetDocumentLoader()->SetSubresourceFilter(
new subresource_filter::WebDocumentSubresourceFilterImpl(
url::Origin::Create(GetWebFrame()->GetDocumentLoader()->GetUrl()),
activation_state, std::move(ruleset),
base::DoNothing()));
}
void TestRunnerBindings::SetPopupBlockingEnabled(bool block_popups) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->SetPopupBlockingEnabled(block_popups);
}
void TestRunnerBindings::SetJavaScriptCanAccessClipboard(bool can_access) {
if (!frame_) {
return;
}
if (!frame_->IsMainFrame()) {
return;
}
prefs_.java_script_can_access_clipboard = can_access;
runner_->OnTestPreferencesChanged(prefs_, *frame_);
}
void TestRunnerBindings::SetAllowFileAccessFromFileURLs(bool allow) {
if (!frame_) {
return;
}
if (!frame_->IsMainFrame()) {
return;
}
prefs_.allow_file_access_from_file_urls = allow;
runner_->OnTestPreferencesChanged(prefs_, *frame_);
}
void TestRunnerBindings::OverridePreference(gin::Arguments* args) {
if (!frame_) {
return;
}
if (args->Length() != 2) {
args->ThrowTypeError("overridePreference expects 2 arguments");
return;
}
std::string key;
if (!args->GetNext(&key)) {
args->ThrowError();
return;
}
if (key == "WebKitDefaultFontSize") {
ConvertAndSet(args, &prefs_.default_font_size);
} else if (key == "WebKitMinimumFontSize") {
ConvertAndSet(args, &prefs_.minimum_font_size);
} else if (key == "WebKitDefaultTextEncodingName") {
ConvertAndSet(args, &prefs_.default_text_encoding_name);
} else if (key == "WebKitJavaScriptEnabled") {
ConvertAndSet(args, &prefs_.java_script_enabled);
} else if (key == "WebKitSupportsMultipleWindows") {
ConvertAndSet(args, &prefs_.supports_multiple_windows);
} else if (key == "WebKitDisplayImagesKey") {
ConvertAndSet(args, &prefs_.loads_images_automatically);
} else if (key == "WebKitPluginsEnabled") {
ConvertAndSet(args, &prefs_.plugins_enabled);
} else if (key == "WebKitTabToLinksPreferenceKey") {
ConvertAndSet(args, &prefs_.tabs_to_links);
} else if (key == "WebKitCSSGridLayoutEnabled") {
ConvertAndSet(args, &prefs_.experimental_css_grid_layout_enabled);
} else if (key == "WebKitHyperlinkAuditingEnabled") {
ConvertAndSet(args, &prefs_.hyperlink_auditing_enabled);
} else if (key == "WebKitEnableCaretBrowsing") {
ConvertAndSet(args, &prefs_.caret_browsing_enabled);
} else if (key == "WebKitAllowRunningInsecureContent") {
ConvertAndSet(args, &prefs_.allow_running_of_insecure_content);
} else if (key == "WebKitDisableReadingFromCanvas") {
ConvertAndSet(args, &prefs_.disable_reading_from_canvas);
} else if (key == "WebKitStrictMixedContentChecking") {
ConvertAndSet(args, &prefs_.strict_mixed_content_checking);
} else if (key == "WebKitStrictPowerfulFeatureRestrictions") {
ConvertAndSet(args, &prefs_.strict_powerful_feature_restrictions);
} else if (key == "WebKitWebSecurityEnabled") {
ConvertAndSet(args, &prefs_.web_security_enabled);
} else if (key == "WebKitSpatialNavigationEnabled") {
ConvertAndSet(args, &prefs_.spatial_navigation_enabled);
} else {
args->ThrowTypeError("Invalid name for preference: " + key);
}
runner_->OnTestPreferencesChanged(prefs_, *frame_);
}
void TestRunnerBindings::SetAcceptLanguages(
const std::string& accept_languages) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->SetAcceptLanguages(accept_languages);
}
void TestRunnerBindings::SetPluginsEnabled(bool enabled) {
if (!frame_) {
return;
}
if (!frame_->IsMainFrame()) {
return;
}
prefs_.plugins_enabled = enabled;
runner_->OnTestPreferencesChanged(prefs_, *frame_);
}
void TestRunnerBindings::DumpEditingCallbacks() {
if (!frame_) {
return;
}
runner_->DumpEditingCallbacks(*frame_);
}
void TestRunnerBindings::DumpAsMarkup() {
if (!frame_) {
return;
}
runner_->DumpAsMarkup(*frame_);
}
void TestRunnerBindings::DumpAsText() {
if (!frame_) {
return;
}
runner_->DumpAsText(*frame_);
}
void TestRunnerBindings::DumpAsTextWithPixelResults() {
if (!frame_) {
return;
}
runner_->DumpAsTextWithPixelResults(*frame_);
}
void TestRunnerBindings::DumpAsLayout() {
if (!frame_) {
return;
}
runner_->DumpAsLayout(*frame_);
}
void TestRunnerBindings::DumpAsLayoutWithPixelResults() {
if (!frame_) {
return;
}
runner_->DumpAsLayoutWithPixelResults(*frame_);
}
void TestRunnerBindings::DumpChildFrames() {
if (!frame_) {
return;
}
runner_->DumpChildFrames(*frame_);
}
void TestRunnerBindings::DumpIconChanges() {
if (!frame_) {
return;
}
runner_->DumpIconChanges(*frame_);
}
void TestRunnerBindings::SetAudioData(const gin::ArrayBufferView& view) {
if (!frame_) {
return;
}
runner_->SetAudioData(view);
}
void TestRunnerBindings::DumpFrameLoadCallbacks() {
if (!frame_) {
return;
}
runner_->DumpFrameLoadCallbacks(*frame_);
}
void TestRunnerBindings::DumpPingLoaderCallbacks() {
if (!frame_) {
return;
}
runner_->DumpPingLoaderCallbacks(*frame_);
}
void TestRunnerBindings::DumpUserGestureInFrameLoadCallbacks() {
if (!frame_) {
return;
}
runner_->DumpUserGestureInFrameLoadCallbacks(*frame_);
}
void TestRunnerBindings::DumpTitleChanges() {
if (!frame_) {
return;
}
runner_->DumpTitleChanges(*frame_);
}
void TestRunnerBindings::SetCaretBrowsingEnabled() {
if (!frame_) {
return;
}
blink::WebView* web_view = GetWebFrame()->View();
web_view->GetSettings()->SetCaretBrowsingEnabled(true);
}
void TestRunnerBindings::SetStorageAllowed(bool allowed) {
if (!frame_) {
return;
}
runner_->SetStorageAllowed(allowed, *frame_);
}
void TestRunnerBindings::SetPluginsAllowed(bool allowed) {
if (!frame_) {
return;
}
blink::WebView* web_view = GetWebFrame()->View();
web_view->GetSettings()->SetPluginsEnabled(allowed);
}
void TestRunnerBindings::SetAllowRunningOfInsecureContent(bool allowed) {
if (!frame_) {
return;
}
runner_->SetAllowRunningOfInsecureContent(allowed, *frame_);
}
void TestRunnerBindings::DumpPermissionClientCallbacks() {
if (!frame_) {
return;
}
runner_->DumpPermissionClientCallbacks(*frame_);
}
void TestRunnerBindings::DumpBackForwardList() {
if (!frame_) {
return;
}
runner_->DumpBackForwardList();
}
void TestRunnerBindings::DumpSelectionRect() {
if (!frame_) {
return;
}
runner_->DumpSelectionRect(*frame_);
}
void TestRunnerBindings::SetPrinting() {
if (!frame_) {
return;
}
runner_->SetPrinting(*frame_);
}
void TestRunnerBindings::SetPrintingForFrame(const std::string& frame_name) {
if (!frame_) {
return;
}
runner_->SetPrintingForFrame(frame_name, *frame_);
}
void TestRunnerBindings::SetPrintingSize(int width, int height) {
if (!frame_) {
return;
}
runner_->SetPrintingSize(width, height, *frame_);
}
void TestRunnerBindings::SetPrintingMargin(int margin) {
if (!frame_) {
return;
}
runner_->SetPrintingMargin(margin, *frame_);
}
void TestRunnerBindings::SetSafePrintableInset(int inset) {
if (!frame_) {
return;
}
runner_->SetSafePrintableInset(inset, *frame_);
}
void TestRunnerBindings::SetShouldCenterAndShrinkToFitPaper(bool b) {
if (!frame_) {
return;
}
runner_->SetShouldCenterAndShrinkToFitPaper(b);
}
void TestRunnerBindings::SetPrintingScaleFactor(float factor) {
if (!frame_) {
return;
}
runner_->SetPrintingScaleFactor(factor);
}
void TestRunnerBindings::ClearTrustTokenState(
v8::Local<v8::Function> v8_callback) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->ClearTrustTokenState(
WrapV8Closure(std::move(v8_callback)));
}
void TestRunnerBindings::SetShouldGeneratePixelResults(bool value) {
if (!frame_) {
return;
}
runner_->SetShouldGeneratePixelResults(value, *frame_);
}
void TestRunnerBindings::SetShouldStayOnPageAfterHandlingBeforeUnload(
bool value) {
if (!frame_) {
return;
}
runner_->SetShouldStayOnPageAfterHandlingBeforeUnload(value, *frame_);
}
void TestRunnerBindings::SetWillSendRequestClearHeader(
const std::string& header) {
if (!frame_) {
return;
}
runner_->SetWillSendRequestClearHeader(header);
}
void TestRunnerBindings::SetWillSendRequestClearReferrer() {
if (!frame_) {
return;
}
runner_->SetWillSendRequestClearReferrer();
}
void TestRunnerBindings::WaitUntilExternalURLLoad() {
if (!frame_) {
return;
}
runner_->WaitUntilExternalURLLoad(*frame_);
}
void TestRunnerBindings::DumpDragImage() {
if (!frame_) {
return;
}
runner_->DumpDragImage(*frame_);
}
void TestRunnerBindings::DumpNavigationPolicy() {
if (!frame_) {
return;
}
runner_->DumpNavigationPolicy(*frame_);
}
void TestRunnerBindings::SetBlockThirdPartyCookies(bool block) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->BlockThirdPartyCookies(block);
}
void TestRunnerBindings::SimulateBrowserWindowFocus(bool value) {
if (!frame_) {
return;
}
if (!frame_->IsMainFrame()) {
return;
}
runner_->FocusWindow(frame_, value);
}
std::string TestRunnerBindings::PathToLocalResource(const std::string& path) {
if (!frame_) {
return {};
}
return RewriteFileURLToLocalResource(path).GetString().Utf8();
}
void TestRunnerBindings::SetBackingScaleFactor(
double value,
v8::Local<v8::Function> v8_callback) {
if (!frame_) {
return;
}
double limited_value = fmin(15, value);
frame_->GetLocalRootWebFrameWidget()->SetDeviceScaleFactorForTesting(
limited_value);
v8::Isolate* isolate = GetWebFrame()->GetAgentGroupScheduler()->Isolate();
v8::HandleScope handle_scope(isolate);
WrapV8Closure(std::move(v8_callback)).Run();
}
void TestRunnerBindings::SetColorProfile(const std::string& name,
v8::Local<v8::Function> v8_callback) {
if (!frame_) {
return;
}
gfx::ColorSpace color_space;
if (name == "genericRGB") {
color_space = gfx::ICCProfileForTestingGenericRGB().GetColorSpace();
} else if (name == "sRGB") {
color_space = gfx::ColorSpace::CreateSRGB();
} else if (name == "colorSpin") {
color_space = gfx::ICCProfileForTestingColorSpin().GetColorSpace();
} else if (name == "adobeRGB") {
color_space = gfx::ICCProfileForTestingAdobeRGB().GetColorSpace();
}
GetWebFrame()->View()->SetDeviceColorSpaceForTesting(color_space);
WrapV8Closure(std::move(v8_callback)).Run();
}
void TestRunnerBindings::SetBluetoothFakeAdapter(
const std::string& adapter_name,
v8::Local<v8::Function> v8_callback) {
if (!frame_) {
return;
}
runner_->GetBluetoothFakeAdapterSetter().Set(
adapter_name, WrapV8Closure(std::move(v8_callback)));
}
void TestRunnerBindings::SetBluetoothManualChooser(bool enable) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->SetBluetoothManualChooser(enable);
}
static void GetBluetoothManualChooserEventsReply(
base::WeakPtr<TestRunnerBindings> test_runner,
blink::WebLocalFrame* frame,
BoundV8Callback callback,
const std::vector<std::string>& events) {
if (!test_runner)
return;
v8::Isolate* isolate = frame->GetAgentGroupScheduler()->Isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = frame->MainWorldScriptContext();
CHECK(!context.IsEmpty());
v8::Context::Scope context_scope(context);
v8::Local<v8::Value> arg;
bool converted = gin::TryConvertToV8(isolate, events, &arg);
CHECK(converted);
std::move(callback).Run(v8::LocalVector<v8::Value>(isolate, {
arg,
}));
}
void TestRunnerBindings::GetBluetoothManualChooserEvents(
v8::Local<v8::Function> callback) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->GetBluetoothManualChooserEvents(
base::BindOnce(&GetBluetoothManualChooserEventsReply,
weak_ptr_factory_.GetWeakPtr(), GetWebFrame(),
WrapV8Callback(std::move(callback))));
}
void TestRunnerBindings::SetBrowserHandlesFocus(bool enable) {
if (!frame_) {
return;
}
blink::SetBrowserCanHandleFocusForWebTest(enable);
}
void TestRunnerBindings::SendBluetoothManualChooserEvent(
const std::string& event,
const std::string& argument) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->SendBluetoothManualChooserEvent(
event, argument);
}
void TestRunnerBindings::SetPOSIXLocale(const std::string& locale) {
if (!frame_) {
return;
}
setlocale(LC_ALL, locale.c_str());
setlocale(LC_NUMERIC, "C");
}
void TestRunnerBindings::SimulateWebNotificationClick(gin::Arguments* args) {
if (!frame_) {
return;
}
DCHECK_GE(args->Length(), 1);
std::string title;
int action_index = std::numeric_limits<int32_t>::min();
std::optional<std::u16string> reply;
if (!args->GetNext(&title)) {
args->ThrowError();
return;
}
if (args->Length() >= 2) {
if (!args->GetNext(&action_index)) {
args->ThrowError();
return;
}
}
if (args->Length() >= 3) {
std::string reply_string;
if (!args->GetNext(&reply_string)) {
args->ThrowError();
return;
}
reply = base::UTF8ToUTF16(reply_string);
}
frame_->GetWebTestControlHostRemote()->SimulateWebNotificationClick(
title, action_index, reply);
}
void TestRunnerBindings::SimulateWebNotificationClose(const std::string& title,
bool by_user) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->SimulateWebNotificationClose(title,
by_user);
}
void TestRunnerBindings::SimulateWebContentIndexDelete(const std::string& id) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->SimulateWebContentIndexDelete(id);
}
void TestRunnerBindings::SetHighlightAds() {
if (!frame_) {
return;
}
blink::WebView* web_view = GetWebFrame()->View();
web_view->GetSettings()->SetHighlightAds(true);
}
void TestRunnerBindings::AddWebPageOverlay() {
if (!frame_) {
return;
}
if (!frame_->IsMainFrame())
return;
frame_->GetLocalRootWebFrameWidget()->SetMainFrameOverlayColor(SK_ColorCYAN);
}
void TestRunnerBindings::RemoveWebPageOverlay() {
if (!frame_) {
return;
}
if (!frame_->IsMainFrame())
return;
frame_->GetLocalRootWebFrameWidget()->SetMainFrameOverlayColor(
SK_ColorTRANSPARENT);
}
void TestRunnerBindings::UpdateAllLifecyclePhasesAndComposite() {
if (!frame_) {
return;
}
frame_->GetLocalRootFrameWidgetTestHelper()
->UpdateAllLifecyclePhasesAndComposite(base::DoNothing());
}
void TestRunnerBindings::UpdateAllLifecyclePhasesAndCompositeThen(
v8::Local<v8::Function> v8_callback) {
if (!frame_) {
return;
}
frame_->GetLocalRootFrameWidgetTestHelper()
->UpdateAllLifecyclePhasesAndComposite(
WrapV8Closure(std::move(v8_callback)));
}
void TestRunnerBindings::SetAnimationRequiresRaster(bool do_raster) {
if (!frame_) {
return;
}
runner_->SetAnimationRequiresRaster(do_raster);
}
static void GetManifestReply(v8::Isolate* isolate,
BoundV8Callback callback,
const blink::WebURL& manifest_url) {
std::move(callback).Run(NoV8Args(isolate));
}
void TestRunnerBindings::GetManifestThen(v8::Local<v8::Function> v8_callback) {
if (!frame_) {
return;
}
v8::Isolate* isolate = GetWebFrame()->GetAgentGroupScheduler()->Isolate();
blink::WebManifestManager::RequestManifestForTesting(
GetWebFrame(), base::BindOnce(GetManifestReply, isolate,
WrapV8Callback(std::move(v8_callback))));
}
#if BUILDFLAG(ENABLE_PRINTING)
void TestRunnerBindings::CapturePrintingPixelsThen(
v8::Local<v8::Function> v8_callback) {
if (!frame_) {
return;
}
blink::WebLocalFrame* frame = GetWebFrame();
SkBitmap bitmap = runner_->PrintFrameToBitmap(frame);
v8::Isolate* isolate = frame->GetAgentGroupScheduler()->Isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = frame->MainWorldScriptContext();
CHECK(!context.IsEmpty());
v8::Context::Scope context_scope(context);
WrapV8Callback(std::move(v8_callback))
.Run(ConvertBitmapToV8(isolate, context_scope, bitmap));
}
#endif
void TestRunnerBindings::CheckForLeakedWindows() {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->CheckForLeakedWindows();
}
void TestRunnerBindings::CopyImageThen(int x,
int y,
v8::Local<v8::Function> v8_callback) {
if (!frame_) {
return;
}
mojo::Remote<blink::mojom::ClipboardHost> remote_clipboard;
frame_->GetBrowserInterfaceBroker().GetInterface(
remote_clipboard.BindNewPipeAndPassReceiver());
absl::uint128 sequence_number_before;
CHECK(remote_clipboard->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste,
&sequence_number_before));
GetWebFrame()->CopyImageAtForTesting(gfx::Point(x, y));
auto sequence_number_after = sequence_number_before;
while (sequence_number_before == sequence_number_after) {
remote_clipboard->GetSequenceNumber(ui::ClipboardBuffer::kCopyPaste,
&sequence_number_after);
}
mojo_base::BigBuffer png_data;
remote_clipboard->ReadPng(ui::ClipboardBuffer::kCopyPaste, &png_data);
SkBitmap bitmap = gfx::PNGCodec::Decode(png_data);
blink::WebLocalFrame* web_frame = GetWebFrame();
v8::Isolate* isolate = web_frame->GetAgentGroupScheduler()->Isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = web_frame->MainWorldScriptContext();
CHECK(!context.IsEmpty());
v8::Context::Scope context_scope(context);
WrapV8Callback(std::move(v8_callback))
.Run(ConvertBitmapToV8(isolate, context_scope, std::move(bitmap)));
}
void TestRunnerBindings::DropPointerLock() {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->DropPointerLock();
}
void TestRunnerBindings::SetPointerLockWillFail() {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->SetPointerLockWillFail();
}
void TestRunnerBindings::SetPointerLockWillRespondAsynchronously() {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()
->SetPointerLockWillRespondAsynchronously();
}
void TestRunnerBindings::AllowPointerLock() {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->AllowPointerLock();
}
void TestRunnerBindings::SetCustomTextOutput(const std::string& output) {
if (!frame_) {
return;
}
runner_->SetCustomTextOutput(output, *frame_);
}
void TestRunnerBindings::SetPermission(const std::string& name,
const std::string& value,
const std::string& origin,
const std::string& embedding_origin) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->SetPermission(
name, blink::ToPermissionStatus(value), GURL(origin),
GURL(embedding_origin));
}
static void DispatchBeforeInstallPromptEventReply(v8::Isolate* isolate,
BoundV8Callback callback,
bool cancelled) {
v8::HandleScope handle_scope(isolate);
std::move(callback).Run(v8::LocalVector<v8::Value>(
isolate, {
v8::Boolean::New(isolate, cancelled),
}));
}
void TestRunnerBindings::DispatchBeforeInstallPromptEvent(
const std::vector<std::string>& event_platforms,
v8::Local<v8::Function> v8_callback) {
if (!frame_) {
return;
}
app_banner_service_ = std::make_unique<AppBannerService>();
frame_->BindLocalInterface(blink::mojom::AppBannerController::Name_,
app_banner_service_->controller()
.BindNewPipeAndPassReceiver()
.PassPipe());
app_banner_service_->SendBannerPromptRequest(
event_platforms,
base::BindOnce(
&DispatchBeforeInstallPromptEventReply,
base::Unretained(GetWebFrame()->GetAgentGroupScheduler()->Isolate()),
WrapV8Callback(std::move(v8_callback))));
}
void TestRunnerBindings::ResolveBeforeInstallPromptPromise(
const std::string& platform) {
if (!frame_) {
return;
}
if (app_banner_service_) {
app_banner_service_->ResolvePromise(platform);
app_banner_service_.reset();
}
}
std::string TestRunnerBindings::PlatformName() {
if (!frame_) {
return {};
}
return runner_->platform_name_;
}
void TestRunnerBindings::TextZoomIn() {
if (!frame_) {
return;
}
if (!frame_->IsMainFrame())
return;
blink::WebFrameWidget* widget = frame_->GetLocalRootWebFrameWidget();
widget->SetTextZoomFactor(widget->TextZoomFactor() * 1.2f);
}
void TestRunnerBindings::TextZoomOut() {
if (!frame_) {
return;
}
if (!frame_->IsMainFrame()) {
return;
}
blink::WebFrameWidget* widget = frame_->GetLocalRootWebFrameWidget();
widget->SetTextZoomFactor(widget->TextZoomFactor() / 1.2f);
}
void TestRunnerBindings::ZoomPageIn() {
if (!frame_) {
return;
}
if (!frame_->IsMainFrame()) {
return;
}
blink::WebFrameWidget* web_frame_widget =
frame_->GetLocalRootWebFrameWidget();
web_frame_widget->SetZoomLevelForTesting(web_frame_widget->GetZoomLevel() +
1);
}
void TestRunnerBindings::ZoomPageOut() {
if (!frame_) {
return;
}
if (!frame_->IsMainFrame())
return;
blink::WebFrameWidget* web_frame_widget =
frame_->GetLocalRootWebFrameWidget();
web_frame_widget->SetZoomLevelForTesting(web_frame_widget->GetZoomLevel() -
1);
}
void TestRunnerBindings::SetPageZoomFactor(double zoom_factor) {
if (!frame_) {
return;
}
if (!frame_->IsMainFrame()) {
return;
}
frame_->GetLocalRootWebFrameWidget()->SetZoomLevelForTesting(
blink::ZoomFactorToZoomLevel(zoom_factor));
}
std::string TestRunnerBindings::TooltipText() {
if (!frame_) {
return {};
}
blink::WebString tooltip_text =
frame_->GetLocalRootWebFrameWidget()->GetLastToolTipTextForTesting();
return tooltip_text.Utf8();
}
int TestRunnerBindings::WebHistoryItemCount() {
if (!frame_) {
return 0;
}
return frame_->GetWebFrame()->View()->HistoryBackListCount() +
frame_->GetWebFrame()->View()->HistoryForwardListCount() + 1;
}
void TestRunnerBindings::ForceNextWebGLContextCreationToFail() {
if (!frame_) {
return;
}
blink::ForceNextWebGLContextCreationToFailForTest();
}
void TestRunnerBindings::FocusDevtoolsSecondaryWindow() {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->FocusDevtoolsSecondaryWindow();
}
void TestRunnerBindings::ForceNextDrawingBufferCreationToFail() {
if (!frame_) {
return;
}
blink::ForceNextDrawingBufferCreationToFailForTest();
}
void TestRunnerBindings::DisableAutomaticDragDrop() {
if (!frame_) {
return;
}
runner_->DisableAutomaticDragDrop(*frame_);
}
void TestRunnerBindings::GoToOffset(int offset) {
if (!frame_) {
return;
}
frame_->GetWebTestControlHostRemote()->GoToOffset(offset);
}
void TestRunnerBindings::SetRphRegistrationMode(gin::Arguments* args) {
if (!frame_) {
return;
}
if (args->Length() != 1) {
args->ThrowTypeError("setRphRegistrationMode expects 1 argument");
return;
}
std::string arg;
if (!args->GetNext(&arg)) {
args->ThrowError();
return;
}
auto mode = mojom::WebTestControlHost::AutoResponseMode::kNone;
if (arg == "autoAccept") {
mode = mojom::WebTestControlHost::AutoResponseMode::kAutoAccept;
} else if (arg == "autoReject") {
mode = mojom::WebTestControlHost::AutoResponseMode::kAutoReject;
} else if (arg != "none") {
args->ThrowTypeError(
"setRphRegistrationMode called with an invalid 'mode' argument");
return;
}
frame_->GetWebTestControlHostRemote()->SetRegisterProtocolHandlerMode(mode);
}
void TestRunnerBindings::NotImplemented(const gin::Arguments& args) {}
class TestRunner::MainWindowTracker : public blink::WebViewObserver {
public:
MainWindowTracker(blink::WebView* view, TestRunner* test_runner)
: blink::WebViewObserver(view), test_runner_(test_runner) {}
void OnDestruct() override {
std::erase_if(test_runner_->main_windows_, base::MatchesUniquePtr(this));
}
private:
const raw_ptr<TestRunner> test_runner_;
};
TestRunner::WorkQueue::WorkQueue(TestRunner* controller)
: controller_(controller) {}
void TestRunner::WorkQueue::Reset() {
set_frozen(false);
set_has_items(false);
states_.ResetChangeTracking();
set_loading(true);
}
void TestRunner::WorkQueue::AddWork(mojom::WorkItemPtr work_item,
WebFrameTestProxy& source) {
if (is_frozen())
return;
source.GetWebTestControlHostRemote()->WorkItemAdded(std::move(work_item));
set_has_items(true);
OnStatesChanged(source);
}
void TestRunner::WorkQueue::RequestWork(WebFrameTestProxy& source) {
source.GetWebTestControlHostRemote()->RequestWorkItem();
}
void TestRunner::WorkQueue::ProcessWorkItem(mojom::WorkItemPtr work_item,
WebFrameTestProxy& source) {
set_loading(true);
bool started_load = ProcessWorkItemInternal(std::move(work_item), source);
if (started_load) {
if (loading_)
controller_->frame_will_start_load_ = true;
return;
}
RequestWork(source);
}
bool TestRunner::WorkQueue::ProcessWorkItemInternal(
mojom::WorkItemPtr work_item,
WebFrameTestProxy& source) {
switch (work_item->which()) {
case mojom::WorkItem::Tag::kBackForward: {
mojom::WorkItemBackForwardPtr& item_back_forward =
work_item->get_back_forward();
source.GetWebTestControlHostRemote()->GoToOffset(
item_back_forward->distance);
return true;
}
case mojom::WorkItem::Tag::kLoadingScript: {
mojom::WorkItemLoadingScriptPtr& item_loading_script =
work_item->get_loading_script();
WebFrameTestProxy* main_frame =
controller_->FindInProcessMainWindowMainFrame();
DCHECK(main_frame);
main_frame->GetWebFrame()->ExecuteScript(blink::WebScriptSource(
blink::WebString::FromUTF8(item_loading_script->script)));
return true;
}
case mojom::WorkItem::Tag::kNonLoadingScript: {
mojom::WorkItemNonLoadingScriptPtr& item_non_loading_script =
work_item->get_non_loading_script();
WebFrameTestProxy* main_frame =
controller_->FindInProcessMainWindowMainFrame();
DCHECK(main_frame);
main_frame->GetWebFrame()->ExecuteScript(blink::WebScriptSource(
blink::WebString::FromUTF8(item_non_loading_script->script)));
return false;
}
case mojom::WorkItem::Tag::kLoad: {
mojom::WorkItemLoadPtr& item_load = work_item->get_load();
source.GetWebTestControlHostRemote()->LoadURLForFrame(
GURL(item_load->url), item_load->target);
return true;
}
case mojom::WorkItem::Tag::kReload:
source.GetWebTestControlHostRemote()->Reload();
return true;
}
NOTREACHED();
}
void TestRunner::WorkQueue::ReplicateStates(const base::Value::Dict& values,
WebFrameTestProxy& source) {
states_.ApplyUntrackedChanges(values);
if (!has_items())
controller_->FinishTestIfReady(source);
}
void TestRunner::WorkQueue::OnStatesChanged(WebFrameTestProxy& source) {
if (states_.changed_values().empty())
return;
source.GetWebTestControlHostRemote()->WorkQueueStatesChanged(
states_.changed_values().Clone());
states_.ResetChangeTracking();
}
TestRunner::TestRunner() : work_queue_(this) {
blink::WebTestingSupport::SaveRuntimeFeatures();
Reset();
}
TestRunner::~TestRunner() = default;
void TestRunner::Install(WebFrameTestProxy* frame,
SpellCheckClient* spell_check) {
bool is_main_test_window = IsFrameInMainWindow(frame->GetWebFrame());
TestRunnerBindings::Install(this, frame, spell_check,
IsWebPlatformTestsMode(), is_main_test_window);
fake_screen_orientation_impl_.OverrideAssociatedInterfaceProviderForFrame(
frame->GetWebFrame());
gamepad_controller_.Install(frame);
frame->GetWebFrame()->View()->SetScreenOrientationOverrideForTesting(
fake_screen_orientation_impl_.CurrentOrientationType());
}
void TestRunner::Reset() {
loading_frames_.clear();
web_test_runtime_flags_.Reset();
fake_screen_orientation_impl_.ResetData();
gamepad_controller_.Reset();
drag_image_.reset();
blink::WebTestingSupport::ResetRuntimeFeatures();
blink::WebCache::Clear();
blink::WebSecurityPolicy::ClearOriginAccessList();
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
blink::WebFontRenderStyle::SetSubpixelPositioning(false);
#endif
blink::ResetDomainRelaxationForTest();
blink::SetBrowserCanHandleFocusForWebTest(false);
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C");
dump_as_audio_ = false;
dump_back_forward_list_ = false;
test_repaint_ = false;
sweep_horizontally_ = false;
animation_requires_raster_ = false;
main_frame_loaded_ = false;
frame_will_start_load_ = false;
did_notify_done_ = false;
http_headers_to_clear_.clear();
clear_referrer_ = false;
platform_name_ = "chromium";
weak_factory_.InvalidateWeakPtrs();
work_queue_.Reset();
}
void TestRunner::ResetWebView(blink::WebView* web_view) {
web_view->SetTabKeyCyclesThroughElements(true);
web_view->GetSettings()->SetHighlightAds(false);
web_view->GetSettings()->SetCaretBrowsingEnabled(false);
web_view->DisableAutoResizeForTesting(gfx::Size());
web_view->SetScreenOrientationOverrideForTesting(
fake_screen_orientation_impl_.CurrentOrientationType());
}
void TestRunner::ResetWebFrameWidget(blink::WebFrameWidget* web_frame_widget) {
web_frame_widget->SetDeviceScaleFactorForTesting(0);
web_frame_widget->ReleaseMouseLockAndPointerCaptureForTesting();
if (!web_frame_widget->LocalRoot()->Parent()) {
web_frame_widget->ResetZoomLevelForTesting();
web_frame_widget->SetMainFrameOverlayColor(SK_ColorTRANSPARENT);
web_frame_widget->SetTextZoomFactor(1);
}
}
void TestRunner::SetTestIsRunning(bool running) {
test_is_running_ = running;
}
bool TestRunner::ShouldDumpSelectionRect() const {
return web_test_runtime_flags_.dump_selection_rect();
}
bool TestRunner::ShouldDumpEditingCallbacks() const {
return web_test_runtime_flags_.dump_editting_callbacks();
}
void TestRunner::SetShouldDumpAsLayout(bool value, WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_as_layout(value);
OnWebTestRuntimeFlagsChanged(source);
}
bool TestRunner::ShouldDumpAsCustomText() const {
return web_test_runtime_flags_.has_custom_text_output();
}
std::string TestRunner::CustomDumpText() const {
return web_test_runtime_flags_.custom_text_output();
}
void TestRunner::SetCustomTextOutput(const std::string& text,
WebFrameTestProxy& source) {
web_test_runtime_flags_.set_custom_text_output(text);
web_test_runtime_flags_.set_has_custom_text_output(true);
OnWebTestRuntimeFlagsChanged(source);
}
bool TestRunner::ShouldGeneratePixelResults() {
return web_test_runtime_flags_.generate_pixel_results();
}
TextResultType TestRunner::ShouldGenerateTextResults() {
if (web_test_runtime_flags_.dump_as_text()) {
return TextResultType::kText;
} else if (web_test_runtime_flags_.dump_as_markup()) {
DCHECK(!web_test_runtime_flags_.is_printing());
return TextResultType::kMarkup;
} else if (web_test_runtime_flags_.dump_as_layout()) {
if (web_test_runtime_flags_.is_printing())
return TextResultType::kLayoutAsPrinting;
return TextResultType::kLayout;
}
return TextResultType::kEmpty;
}
bool TestRunner::ShouldStayOnPageAfterHandlingBeforeUnload() const {
return web_test_runtime_flags_.stay_on_page_after_handling_before_unload();
}
void TestRunner::SetShouldGeneratePixelResults(bool value,
WebFrameTestProxy& source) {
web_test_runtime_flags_.set_generate_pixel_results(value);
OnWebTestRuntimeFlagsChanged(source);
}
bool TestRunner::ShouldDumpAsAudio() const {
return dump_as_audio_;
}
const std::vector<uint8_t>& TestRunner::GetAudioData() const {
return audio_data_;
}
bool TestRunner::IsRecursiveLayoutDumpRequested() {
return web_test_runtime_flags_.dump_child_frames();
}
bool TestRunner::CanDumpPixelsFromRenderer() const {
return web_test_runtime_flags_.dump_drag_image() ||
web_test_runtime_flags_.is_printing();
}
bool TestRunner::IsPrinting() const {
return web_test_runtime_flags_.is_printing();
}
#if BUILDFLAG(ENABLE_PRINTING)
gfx::Size TestRunner::GetPrintingPageSize(blink::WebLocalFrame* frame) const {
const int printing_width = web_test_runtime_flags_.printing_width();
const int printing_height = web_test_runtime_flags_.printing_height();
if (printing_width > 0 && printing_height > 0) {
return gfx::Size(printing_width, printing_height);
}
blink::WebFrameWidget* widget = frame->LocalRoot()->FrameWidget();
widget->UpdateAllLifecyclePhases(blink::DocumentUpdateReason::kTest);
return widget->Size();
}
int TestRunner::GetPrintingMargin() const {
return web_test_runtime_flags_.printing_margin();
}
int TestRunner::GetSafePrintableInset() const {
return web_test_runtime_flags_.safe_printable_inset();
}
static std::string GetPageRangesStringFromMetadata(
blink::WebLocalFrame* frame) {
blink::WebElementCollection meta_iter =
frame->GetDocument().GetElementsByHTMLTagName("meta");
std::string result = "-";
if (!meta_iter.IsNull()) {
for (blink::WebElement meta = meta_iter.FirstItem(); !meta.IsNull();
meta = meta_iter.NextItem()) {
if (meta.GetAttribute("name") == "reftest-pages") {
blink::WebString pages = meta.GetAttribute("content");
if (!pages.IsNull()) {
result = pages.Ascii();
}
break;
}
}
}
return result;
}
printing::PageRanges TestRunner::GetPrintingPageRanges(
blink::WebLocalFrame* frame) const {
const std::string page_ranges_string = GetPageRangesStringFromMetadata(frame);
const std::vector<std::string_view> range_strings =
base::SplitStringPiece(page_ranges_string, ",", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
printing::PageRanges result;
for (std::string_view range_string : range_strings) {
const std::vector<std::string_view> page_strings = base::SplitStringPiece(
range_string, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
bool invalid = false;
if (page_strings.size() == 1) {
uint32_t page;
if (base::StringToUint(range_string, &page)) {
result.push_back(printing::PageRange{.from = page - 1, .to = page - 1});
} else {
invalid = true;
}
} else if (page_strings.size() > 2) {
invalid = true;
} else {
std::array<uint32_t, 2> page_nums{0, printing::PageRange::kMaxPage};
for (const int i : {0, 1}) {
if (!page_strings[i].empty()) {
if (base::StringToUint(page_strings[i], &page_nums[i])) {
--page_nums[i];
} else {
invalid = true;
break;
}
}
}
if (!invalid) {
result.push_back(
printing::PageRange{.from = page_nums[0], .to = page_nums[1]});
}
}
if (invalid) {
DLOG(WARNING) << "Invalid page range \"" << range_string << "\".\n";
}
}
printing::PageRange::Normalize(result);
return result;
}
SkBitmap TestRunner::PrintFrameToBitmap(blink::WebLocalFrame* frame) {
gfx::SizeF page_size = gfx::SizeF(GetPrintingPageSize(frame));
auto print_params = blink::WebPrintParams(page_size);
int default_margin = GetPrintingMargin();
print_params.default_page_description.margin_top = default_margin;
print_params.default_page_description.margin_right = default_margin;
print_params.default_page_description.margin_bottom = default_margin;
print_params.default_page_description.margin_left = default_margin;
gfx::RectF printable_area(page_size);
printable_area.Inset(GetSafePrintableInset());
print_params.printable_area_in_css_pixels = printable_area;
print_params.scale_factor = printing_scale_factor_;
print_params.print_scaling_option =
should_center_and_shrink_to_fit_paper_
? printing::mojom::PrintScalingOption::kCenterShrinkToFitPaper
: printing::mojom::PrintScalingOption::kSourceSize;
auto* frame_widget = frame->LocalRoot()->FrameWidget();
frame_widget->UpdateAllLifecyclePhases(blink::DocumentUpdateReason::kTest);
uint32_t page_count = frame->PrintBegin(print_params, blink::WebNode());
const printing::PageRanges& page_ranges = GetPrintingPageRanges(frame);
std::vector<uint32_t> pages(
printing::PageNumber::GetPages(page_ranges, page_count));
gfx::Size spool_size = frame->SpoolSizeInPixelsForTesting(pages);
bool is_opaque = false;
SkBitmap bitmap;
if (!bitmap.tryAllocN32Pixels(spool_size.width(), spool_size.height(),
is_opaque)) {
LOG(ERROR) << "Failed to create bitmap width=" << spool_size.width()
<< " height=" << spool_size.height();
return SkBitmap();
}
printing::MetafileSkia metafile(printing::mojom::SkiaDocumentType::kMSKP,
printing::PrintSettings::NewCookie());
cc::SkiaPaintCanvas canvas(bitmap);
canvas.SetPrintingMetafile(&metafile);
frame->PrintPagesForTesting(&canvas, spool_size, &pages);
frame->PrintEnd();
return bitmap;
}
#endif
SkBitmap TestRunner::DumpPixelsInRenderer(blink::WebLocalFrame* main_frame) {
DCHECK(!main_frame->Parent());
DCHECK(CanDumpPixelsFromRenderer());
if (web_test_runtime_flags_.dump_drag_image()) {
if (!drag_image_.isNull())
return drag_image_;
SkBitmap bitmap;
bitmap.allocN32Pixels(1, 1);
bitmap.eraseColor(0);
return bitmap;
}
#if BUILDFLAG(ENABLE_PRINTING)
blink::WebLocalFrame* target_frame = main_frame;
std::string frame_name = web_test_runtime_flags_.printing_frame();
if (!frame_name.empty()) {
blink::WebFrame* frame_to_print =
main_frame->FindFrameByName(blink::WebString::FromUTF8(frame_name));
if (frame_to_print && frame_to_print->IsWebLocalFrame())
target_frame = frame_to_print->ToWebLocalFrame();
}
return PrintFrameToBitmap(target_frame);
#else
NOTREACHED();
#endif
}
void TestRunner::ReplicateWebTestRuntimeFlagsChanges(
const base::Value::Dict& changed_values) {
if (!test_is_running_)
return;
web_test_runtime_flags_.tracked_dictionary().ApplyUntrackedChanges(
changed_values);
}
bool TestRunner::HasCustomTextDump(std::string* custom_text_dump) const {
if (ShouldDumpAsCustomText()) {
*custom_text_dump = CustomDumpText();
return true;
}
return false;
}
bool TestRunner::ShouldDumpFrameLoadCallbacks() const {
return test_is_running_ &&
web_test_runtime_flags_.dump_frame_load_callbacks();
}
void TestRunner::SetShouldDumpFrameLoadCallbacks(bool value,
WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_frame_load_callbacks(value);
OnWebTestRuntimeFlagsChanged(source);
}
bool TestRunner::ShouldDumpPingLoaderCallbacks() const {
return test_is_running_ &&
web_test_runtime_flags_.dump_ping_loader_callbacks();
}
bool TestRunner::ShouldDumpUserGestureInFrameLoadCallbacks() const {
return test_is_running_ &&
web_test_runtime_flags_.dump_user_gesture_in_frame_load_callbacks();
}
bool TestRunner::ShouldDumpTitleChanges() const {
return web_test_runtime_flags_.dump_title_changes();
}
bool TestRunner::ShouldDumpIconChanges() const {
return web_test_runtime_flags_.dump_icon_changes();
}
bool TestRunner::ShouldDumpBackForwardList() const {
return dump_back_forward_list_;
}
bool TestRunner::ShouldWaitUntilExternalURLLoad() const {
return web_test_runtime_flags_.wait_until_external_url_load();
}
const std::set<std::string>* TestRunner::HttpHeadersToClear() const {
return &http_headers_to_clear_;
}
bool TestRunner::ClearReferrer() const {
return clear_referrer_;
}
void TestRunner::AddLoadingFrame(blink::WebLocalFrame* frame) {
if (!test_is_running_)
return;
if (loading_frames_.empty()) {
if (web_test_runtime_flags_.have_loading_frame())
return;
web_test_runtime_flags_.set_have_loading_frame(true);
auto* frame_proxy =
static_cast<WebFrameTestProxy*>(RenderFrame::FromWebFrame(frame));
OnWebTestRuntimeFlagsChanged(*frame_proxy);
}
loading_frames_.push_back(frame);
frame_will_start_load_ = false;
}
void TestRunner::RemoveLoadingFrame(blink::WebLocalFrame* frame) {
if (!base::Contains(loading_frames_, frame))
return;
std::erase(loading_frames_, frame);
if (!loading_frames_.empty())
return;
auto* frame_proxy =
static_cast<WebFrameTestProxy*>(RenderFrame::FromWebFrame(frame));
web_test_runtime_flags_.set_have_loading_frame(false);
if (!test_is_running_)
return;
main_frame_loaded_ = true;
OnWebTestRuntimeFlagsChanged(*frame_proxy);
work_queue_.set_frozen(true);
work_queue_.OnStatesChanged(*frame_proxy);
work_queue_.set_loading(false);
if (!web_test_runtime_flags_.wait_until_done() || did_notify_done_)
work_queue_.RequestWork(*frame_proxy);
}
void TestRunner::OnFrameDeactivated(WebFrameTestProxy& frame) {
if (!test_is_running_)
return;
DCHECK(frame.IsMainFrame());
RemoveMainFrame(frame);
if (frame.GetWebFrame()->IsLoading()) {
RemoveLoadingFrame(frame.GetWebFrame());
}
}
void TestRunner::OnFrameReactivated(WebFrameTestProxy& frame) {
if (!test_is_running_)
return;
DCHECK(frame.IsMainFrame());
DCHECK(!frame.GetWebFrame()->GetDocument().IsPrerendering());
if (frame.GetWebFrame()->IsLoading()) {
AddLoadingFrame(frame.GetWebFrame());
}
frame_will_start_load_ = false;
AddMainFrame(frame);
if (IsFrameInMainWindow(frame.GetWebFrame())) {
work_queue_.RequestWork(frame);
}
}
void TestRunner::FinishTestIfReady(blink::WebLocalFrame& source) {
FinishTestIfReady(
*static_cast<WebFrameTestProxy*>(RenderFrame::FromWebFrame(&source)));
}
void TestRunner::FinishTestIfReady(WebFrameTestProxy& source) {
if (!test_is_running_) {
return;
}
if (!main_frame_loaded_ && !did_notify_done_) {
return;
}
if (frame_will_start_load_ || !loading_frames_.empty()) {
return;
}
if (work_queue_.has_items()) {
return;
}
if (web_test_runtime_flags_.wait_until_done() && !did_notify_done_) {
return;
}
FinishTest(source);
}
void TestRunner::TestFinishedFromSecondaryRenderer(WebFrameTestProxy& source) {
NotifyDone(source);
}
void TestRunner::AddMainFrame(WebFrameTestProxy& frame) {
main_frames_.insert(&frame);
}
void TestRunner::RemoveMainFrame(WebFrameTestProxy& frame) {
main_frames_.erase(&frame);
}
void TestRunner::PolicyDelegateDone(WebFrameTestProxy& source) {
DCHECK(web_test_runtime_flags_.wait_until_done());
FinishTest(source);
}
bool TestRunner::PolicyDelegateEnabled() const {
return web_test_runtime_flags_.policy_delegate_enabled();
}
bool TestRunner::PolicyDelegateIsPermissive() const {
return web_test_runtime_flags_.policy_delegate_is_permissive();
}
bool TestRunner::PolicyDelegateShouldNotifyDone() const {
return web_test_runtime_flags_.policy_delegate_should_notify_done();
}
void TestRunner::SetDragImage(const SkBitmap& drag_image) {
if (web_test_runtime_flags_.dump_drag_image()) {
if (drag_image_.isNull())
drag_image_ = drag_image;
}
}
bool TestRunner::ShouldDumpNavigationPolicy() const {
return web_test_runtime_flags_.dump_navigation_policy();
}
WebFrameTestProxy* TestRunner::FindInProcessMainWindowMainFrame() {
for (WebFrameTestProxy* main_frame : main_frames_) {
if (main_frame->GetWebFrame()->GetDocument().IsPrerendering()) {
continue;
}
if (IsFrameInMainWindow(main_frame->GetWebFrame()))
return main_frame;
}
return nullptr;
}
void TestRunner::WaitUntilDone(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_wait_until_done(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::NotifyDone(WebFrameTestProxy& source) {
if (!web_test_runtime_flags_.wait_until_done()) {
return;
}
if (did_notify_done_) {
return;
}
did_notify_done_ = true;
FinishTestIfReady(source);
}
void TestRunner::QueueBackNavigation(int how_far_back,
WebFrameTestProxy& source) {
work_queue_.AddWork(mojom::WorkItem::NewBackForward(
mojom::WorkItemBackForward::New(-how_far_back)),
source);
}
void TestRunner::QueueForwardNavigation(int how_far_forward,
WebFrameTestProxy& source) {
work_queue_.AddWork(mojom::WorkItem::NewBackForward(
mojom::WorkItemBackForward::New(how_far_forward)),
source);
}
void TestRunner::QueueReload(WebFrameTestProxy& source) {
work_queue_.AddWork(mojom::WorkItem::NewReload(mojom::WorkItemReload::New()),
source);
}
void TestRunner::QueueLoadingScript(const std::string& script,
WebFrameTestProxy& source) {
work_queue_.AddWork(mojom::WorkItem::NewLoadingScript(
mojom::WorkItemLoadingScript::New(script)),
source);
}
void TestRunner::QueueNonLoadingScript(const std::string& script,
WebFrameTestProxy& source) {
work_queue_.AddWork(mojom::WorkItem::NewNonLoadingScript(
mojom::WorkItemNonLoadingScript::New(script)),
source);
}
void TestRunner::QueueLoad(const GURL& current_url,
const std::string& relative_url,
const std::string& target,
WebFrameTestProxy& source) {
GURL full_url = current_url.Resolve(relative_url);
work_queue_.AddWork(mojom::WorkItem::NewLoad(
mojom::WorkItemLoad::New(full_url.spec(), target)),
source);
}
void TestRunner::ProcessWorkItem(mojom::WorkItemPtr work_item,
WebFrameTestProxy& source) {
work_queue_.ProcessWorkItem(std::move(work_item), source);
}
void TestRunner::ReplicateWorkQueueStates(const base::Value::Dict& values,
WebFrameTestProxy& source) {
if (!test_is_running_)
return;
work_queue_.ReplicateStates(values, source);
}
bool TestRunner::IsFrameInMainWindow(blink::WebLocalFrame* frame) {
blink::WebView* view = frame->View();
for (auto& window : main_windows_) {
if (window->GetWebView() == view)
return true;
}
return false;
}
void TestRunner::SetMainWindowAndTestConfiguration(
blink::WebLocalFrame* frame,
mojom::WebTestRunTestConfigurationPtr config) {
blink::WebView* view = frame->View();
if (!IsFrameInMainWindow(frame)) {
main_windows_.push_back(std::make_unique<MainWindowTracker>(view, this));
}
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
std::string web_settings_switch_value =
command_line->GetSwitchValueASCII(switches::kWebSettingsForTesting);
for (auto [key, value] :
TestRunnerUtils::ParseWebSettingsString(web_settings_switch_value)) {
view->GetSettings()->SetFromStrings(blink::WebString::FromASCII(key),
blink::WebString::FromASCII(value));
}
if (command_line->HasSwitch(switches::kTargetDeviceScaleForTesting)) {
auto target_scale_factor_for_testing = command_line->GetSwitchValueASCII(
switches::kTargetDeviceScaleForTesting);
double scale_factor;
if (base::StringToDouble(
TrimWhitespaceASCII(target_scale_factor_for_testing,
base::TRIM_ALL),
&scale_factor)) {
frame->FrameWidget()->SetDeviceScaleFactorForTesting(scale_factor);
}
}
test_config_ = std::move(*config);
SetTestIsRunning(true);
std::string spec = GURL(test_config_.test_url).spec();
size_t path_start = spec.rfind("web_tests/");
if (path_start != std::string::npos)
spec = spec.substr(path_start);
bool is_devtools_test =
spec.find("/devtools/") != std::string::npos ||
spec.find("/inspector-protocol/") != std::string::npos;
auto* source =
static_cast<WebFrameTestProxy*>(RenderFrame::FromWebFrame(frame));
if (is_devtools_test)
SetDumpConsoleMessages(false, *source);
if (!test_config_.protocol_mode)
SetShouldDumpAsLayout(true, *source);
bool wpt_printing_test = test_config_.wpt_print_mode;
if (spec.find("/loading/") != std::string::npos)
SetShouldDumpFrameLoadCallbacks(true, *source);
if (IsWebPlatformTest(spec)) {
SetIsWebPlatformTestsMode(*source);
if (spec.find("/print/") != std::string::npos ||
spec.find("-print.html") != std::string::npos) {
wpt_printing_test = true;
}
}
if (wpt_printing_test) {
SetPrinting(*source);
view->GetSettings()->SetShouldPrintBackgrounds(true);
SetPrintingSize(kWPTPrintWidth, kWPTPrintHeight, *source);
SetPrintingMargin(kWPTPrintMargins, *source);
}
view->GetSettings()->SetV8CacheOptions(
is_devtools_test ? blink::mojom::V8CacheOptions::kNone
: blink::mojom::V8CacheOptions::kDefault);
}
blink::WebString TestRunner::GetAbsoluteWebStringFromUTF8Path(
const std::string& utf8_path) {
DCHECK(test_is_running_);
base::FilePath path = base::FilePath::FromUTF8Unsafe(utf8_path);
if (!path.IsAbsolute()) {
GURL base_url =
net::FilePathToFileURL(test_config_.current_working_directory.Append(
FILE_PATH_LITERAL("foo")));
net::FileURLToFilePath(base_url.Resolve(utf8_path), &path);
}
return blink::FilePathToWebString(path);
}
const mojom::WebTestRunTestConfiguration& TestRunner::TestConfig() const {
DCHECK(test_is_running_);
return test_config_;
}
void TestRunner::OnTestPreferencesChanged(const TestPreferences& test_prefs,
WebFrameTestProxy& frame) {
blink::WebView* web_view = frame.GetWebFrame()->View();
blink::web_pref::WebPreferences web_prefs = web_view->GetWebPreferences();
ExportWebTestSpecificPreferences(test_prefs, &web_prefs);
web_view->SetWebPreferences(web_prefs);
frame.GetWebTestControlHostRemote()->OverridePreferences(web_prefs);
}
void TestRunner::SetCustomPolicyDelegate(gin::Arguments* args,
WebFrameTestProxy& source) {
bool value;
args->GetNext(&value);
web_test_runtime_flags_.set_policy_delegate_enabled(value);
if (!args->PeekNext().IsEmpty() && args->PeekNext()->IsBoolean()) {
args->GetNext(&value);
web_test_runtime_flags_.set_policy_delegate_is_permissive(value);
}
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::WaitForPolicyDelegate(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_policy_delegate_enabled(true);
web_test_runtime_flags_.set_policy_delegate_should_notify_done(true);
web_test_runtime_flags_.set_wait_until_done(true);
OnWebTestRuntimeFlagsChanged(source);
}
int TestRunner::InProcessWindowCount() {
return main_frames_.size();
}
void TestRunner::AddOriginAccessAllowListEntry(
const std::string& source_origin,
const std::string& destination_protocol,
const std::string& destination_host,
bool allow_destination_subdomains) {
blink::WebURL url((GURL(source_origin)));
if (!url.IsValid())
return;
blink::WebSecurityPolicy::AddOriginAccessAllowListEntry(
url, blink::WebString::FromUTF8(destination_protocol),
blink::WebString::FromUTF8(destination_host), 0,
allow_destination_subdomains
? network::mojom::CorsDomainMatchMode::kAllowSubdomains
: network::mojom::CorsDomainMatchMode::kDisallowSubdomains,
network::mojom::CorsPortMatchMode::kAllowAnyPort,
network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
}
void TestRunner::SetTextSubpixelPositioning(bool value) {
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
blink::WebFontRenderStyle::SetSubpixelPositioning(value);
#endif
}
void TestRunner::SetMockScreenOrientation(const std::string& orientation_str,
WebFrameTestProxy& frame) {
display::mojom::ScreenOrientation orientation;
if (orientation_str == "portrait-primary") {
orientation = display::mojom::ScreenOrientation::kPortraitPrimary;
} else if (orientation_str == "portrait-secondary") {
orientation = display::mojom::ScreenOrientation::kPortraitSecondary;
} else if (orientation_str == "landscape-primary") {
orientation = display::mojom::ScreenOrientation::kLandscapePrimary;
} else {
DCHECK_EQ("landscape-secondary", orientation_str);
orientation = display::mojom::ScreenOrientation::kLandscapeSecondary;
}
bool changed = fake_screen_orientation_impl_.UpdateDeviceOrientation(
frame.GetWebView(), orientation);
if (changed) {
frame.GetWebTestControlHostRemote()->SimulateScreenOrientationChanged();
}
}
void TestRunner::DisableMockScreenOrientation(blink::WebView* view) {
fake_screen_orientation_impl_.SetDisabled(view, true);
}
void TestRunner::DumpEditingCallbacks(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_editting_callbacks(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpAsMarkup(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_as_markup(true);
web_test_runtime_flags_.set_generate_pixel_results(false);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpAsText(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_as_text(true);
web_test_runtime_flags_.set_generate_pixel_results(false);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpAsTextWithPixelResults(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_as_text(true);
web_test_runtime_flags_.set_generate_pixel_results(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpAsLayout(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_as_layout(true);
web_test_runtime_flags_.set_generate_pixel_results(false);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpAsLayoutWithPixelResults(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_as_layout(true);
web_test_runtime_flags_.set_generate_pixel_results(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpChildFrames(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_child_frames(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpIconChanges(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_icon_changes(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::SetAudioData(const gin::ArrayBufferView& view) {
uint8_t* bytes = static_cast<uint8_t*>(view.bytes());
audio_data_.resize(view.num_bytes());
std::copy(bytes, UNSAFE_TODO(bytes + view.num_bytes()), audio_data_.begin());
dump_as_audio_ = true;
}
void TestRunner::DumpFrameLoadCallbacks(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_frame_load_callbacks(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpPingLoaderCallbacks(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_ping_loader_callbacks(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpUserGestureInFrameLoadCallbacks(
WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_user_gesture_in_frame_load_callbacks(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpTitleChanges(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_title_changes(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::SetStorageAllowed(bool allowed, WebFrameTestProxy& source) {
web_test_runtime_flags_.set_storage_allowed(allowed);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::SetAllowRunningOfInsecureContent(bool allowed,
WebFrameTestProxy& source) {
web_test_runtime_flags_.set_running_insecure_content_allowed(allowed);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpPermissionClientCallbacks(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_web_content_settings_client_callbacks(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpBackForwardList() {
dump_back_forward_list_ = true;
}
void TestRunner::DumpSelectionRect(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_selection_rect(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::SetPrinting(WebFrameTestProxy& source) {
SetPrintingForFrame("", source);
}
void TestRunner::SetPrintingForFrame(const std::string& frame_name,
WebFrameTestProxy& source) {
web_test_runtime_flags_.set_printing_frame(frame_name);
web_test_runtime_flags_.set_is_printing(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::SetPrintingSize(int width,
int height,
WebFrameTestProxy& source) {
web_test_runtime_flags_.set_printing_width(width);
web_test_runtime_flags_.set_printing_height(height);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::SetPrintingMargin(int size, WebFrameTestProxy& source) {
web_test_runtime_flags_.set_printing_margin(size);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::SetSafePrintableInset(int inset, WebFrameTestProxy& source) {
web_test_runtime_flags_.set_safe_printable_inset(inset);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::SetShouldStayOnPageAfterHandlingBeforeUnload(
bool value,
WebFrameTestProxy& source) {
web_test_runtime_flags_.set_stay_on_page_after_handling_before_unload(value);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::SetWillSendRequestClearHeader(const std::string& header) {
if (!header.empty())
http_headers_to_clear_.insert(header);
}
void TestRunner::SetWillSendRequestClearReferrer() {
clear_referrer_ = true;
}
void TestRunner::WaitUntilExternalURLLoad(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_wait_until_external_url_load(true);
web_test_runtime_flags_.set_wait_until_done(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpDragImage(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_drag_image(true);
DumpAsTextWithPixelResults(source);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::DumpNavigationPolicy(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_navigation_policy(true);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::SetDumpConsoleMessages(bool value, WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_console_messages(value);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::SetIsWebPlatformTestsMode(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_is_web_platform_tests_mode(true);
OnWebTestRuntimeFlagsChanged(source);
}
bool TestRunner::IsWebPlatformTestsMode() const {
return web_test_runtime_flags_.is_web_platform_tests_mode();
}
void TestRunner::SetDumpJavaScriptDialogs(bool value,
WebFrameTestProxy& source) {
web_test_runtime_flags_.set_dump_javascript_dialogs(value);
OnWebTestRuntimeFlagsChanged(source);
}
void TestRunner::SetEffectiveConnectionType(
blink::WebEffectiveConnectionType connection_type) {
effective_connection_type_ = connection_type;
}
bool TestRunner::ShouldDumpConsoleMessages() const {
return test_is_running_ && web_test_runtime_flags_.dump_console_messages();
}
void TestRunner::PrintMessage(const std::string& message,
WebFrameTestProxy& source) {
source.GetWebTestControlHostRemote()->PrintMessage(message);
}
blink::WebString TestRunner::RegisterIsolatedFileSystem(
const std::vector<base::FilePath>& file_paths,
WebFrameTestProxy& source) {
std::string filesystem_id;
source.GetWebTestControlHostRemote()->RegisterIsolatedFileSystem(
file_paths, &filesystem_id);
return blink::WebString::FromUTF8(filesystem_id);
}
void TestRunner::FocusWindow(RenderFrame* main_frame, bool focus) {
if (!main_frame->IsMainFrame())
return;
auto* frame_proxy = static_cast<WebFrameTestProxy*>(main_frame);
blink::WebFrameWidget* widget = frame_proxy->GetLocalRootWebFrameWidget();
if (!focus) {
if (widget->HasFocus()) {
auto* web_view = frame_proxy->GetWebFrame()->View();
web_view->SetIsActive(false);
widget->SetFocus(false);
}
return;
}
for (WebFrameTestProxy* other_main_frame : main_frames_) {
if (other_main_frame != main_frame) {
blink::WebFrameWidget* other_widget =
other_main_frame->GetLocalRootWebFrameWidget();
if (other_widget->HasFocus()) {
auto* other_web_view = other_main_frame->GetWebFrame()->View();
other_web_view->SetIsActive(false);
other_widget->SetFocus(false);
}
}
}
if (!widget->HasFocus()) {
widget->SetFocus(true);
}
}
void TestRunner::SetAnimationRequiresRaster(bool do_raster) {
animation_requires_raster_ = do_raster;
}
void TestRunner::OnWebTestRuntimeFlagsChanged(WebFrameTestProxy& source) {
if (!test_is_running_)
return;
if (web_test_runtime_flags_.tracked_dictionary().changed_values().empty())
return;
source.GetWebTestControlHostRemote()->WebTestRuntimeFlagsChanged(
web_test_runtime_flags_.tracked_dictionary().changed_values().Clone());
web_test_runtime_flags_.tracked_dictionary().ResetChangeTracking();
}
void TestRunner::FinishTest(WebFrameTestProxy& source) {
WebFrameTestProxy* main_frame = FindInProcessMainWindowMainFrame();
if (!main_frame) {
if (did_notify_done_) {
source.GetWebTestControlHostRemote()->TestFinishedInSecondaryRenderer();
}
return;
}
if (!test_is_running_) {
return;
}
test_is_running_ = false;
auto* web_frame = main_frame->GetWebFrame();
web_frame->FrameWidget()->PrepareForFinalLifecyclUpdateForTesting();
web_frame->FrameWidget()->UpdateAllLifecyclePhases(
blink::DocumentUpdateReason::kTest);
auto dump_result = mojom::WebTestRendererDumpResult::New();
bool browser_should_dump_back_forward_list = ShouldDumpBackForwardList();
bool browser_should_dump_pixels = false;
if (ShouldDumpAsAudio()) {
TRACE_EVENT0("shell", "TestRunner::CaptureLocalAudioDump");
dump_result->audio = GetAudioData();
} else {
TextResultType text_result_type = ShouldGenerateTextResults();
bool pixel_result = ShouldGeneratePixelResults();
std::string spec = GURL(test_config_.test_url).spec();
size_t path_start = spec.rfind("web_tests/");
if (path_start != std::string::npos)
spec = spec.substr(path_start);
std::string mime_type =
web_frame->GetDocumentLoader()->GetWebResponse().MimeType().Utf8();
if (mime_type == "text/plain" ||
spec.find("/dumpAsText/") != std::string::npos) {
text_result_type = TextResultType::kText;
pixel_result = false;
}
std::string custom_text_dump;
if (HasCustomTextDump(&custom_text_dump)) {
dump_result->layout = custom_text_dump + "\n";
} else if (!IsRecursiveLayoutDumpRequested()) {
TRACE_EVENT0("shell", "TestRunner::CaptureLocalLayoutDump");
dump_result->layout = DumpLayoutAsString(web_frame, text_result_type);
}
if (pixel_result) {
if (CanDumpPixelsFromRenderer()) {
TRACE_EVENT0("shell", "TestRunner::CaptureLocalPixelsDump");
SkBitmap actual = DumpPixelsInRenderer(web_frame);
DCHECK_GT(actual.info().width(), 0);
DCHECK_GT(actual.info().height(), 0);
auto bytes = UNSAFE_TODO(
base::span(static_cast<const uint8_t*>(actual.getPixels()),
actual.computeByteSize()));
dump_result->actual_pixel_hash = Md5AsHexForWebTestPixels(bytes);
if (dump_result->actual_pixel_hash != test_config_.expected_pixel_hash)
dump_result->pixels = std::move(actual);
} else {
browser_should_dump_pixels = true;
if (ShouldDumpSelectionRect()) {
TRACE_EVENT0("shell", "TestRunner::CaptureLocalSelectionRect");
dump_result->selection_rect =
web_frame->GetSelectionBoundsRectForTesting();
}
}
}
}
source.GetWebTestControlHostRemote()->InitiateCaptureDump(
std::move(dump_result), browser_should_dump_back_forward_list,
browser_should_dump_pixels);
}
mojom::WebTestBluetoothFakeAdapterSetter&
TestRunner::GetBluetoothFakeAdapterSetter() {
if (!bluetooth_fake_adapter_setter_) {
RenderThread::Get()->BindHostReceiver(
bluetooth_fake_adapter_setter_.BindNewPipeAndPassReceiver());
bluetooth_fake_adapter_setter_.set_disconnect_handler(base::BindOnce(
&TestRunner::HandleBluetoothFakeAdapterSetterDisconnected,
base::Unretained(this)));
}
return *bluetooth_fake_adapter_setter_;
}
void TestRunner::HandleBluetoothFakeAdapterSetterDisconnected() {
bluetooth_fake_adapter_setter_.reset();
}
void TestRunner::DisableAutomaticDragDrop(WebFrameTestProxy& source) {
web_test_runtime_flags_.set_auto_drag_drop_enabled(false);
OnWebTestRuntimeFlagsChanged(source);
}
bool TestRunner::AutomaticDragDropEnabled() {
return web_test_runtime_flags_.auto_drag_drop_enabled();
}
const WebTestRuntimeFlags& TestRunner::GetFlags() {
return web_test_runtime_flags_;
}
}