blob: 807ebbaff827c4203588ef2091d0b055e84c537a [file] [log] [blame]
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "build/build_config.h"
#include "cc/test/test_ukm_recorder_factory.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_settings.h"
#include "cc/trees/render_frame_metadata_observer.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/network/public/mojom/content_security_policy.mojom-blink-forward.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/common/frame/frame_policy.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/tree_scope_type.mojom-blink.h"
#include "third_party/blink/public/mojom/input/touch_event.mojom-blink.h"
#include "third_party/blink/public/mojom/page/widget.mojom-blink.h"
#include "third_party/blink/public/platform/interface_registry.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/public/web/web_console_message.h"
#include "third_party/blink/public/web/web_frame_widget.h"
#include "third_party/blink/public/web/web_navigation_params.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/public/web/web_view_client.h"
#include "third_party/blink/renderer/core/frame/csp/conversion_util.h"
#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/frame/web_remote_frame_impl.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/core/testing/fake_web_plugin.h"
#include "third_party/blink/renderer/core/testing/mock_policy_container_host.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/network/http_parsers.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "ui/base/ime/mojom/text_input_state.mojom-blink.h"
namespace blink {
namespace frame_test_helpers {
namespace {
// The frame test helpers coordinate frame loads in a carefully choreographed
// dance. Since the parser is threaded, simply spinning the run loop once is not
// enough to ensure completion of a load. Instead, the following pattern is
// used to ensure that tests see the final state:
// 1. Starts a load.
// 2. Enter the run loop.
// 3. Posted task triggers the load, and starts pumping pending resource
// requests using runServeAsyncRequestsTask().
// 4. TestWebFrameClient watches for DidStartLoading/DidStopLoading calls,
// keeping track of how many loads it thinks are in flight.
// 5. While RunServeAsyncRequestsTask() observes TestWebFrameClient to still
// have loads in progress, it posts itself back to the run loop.
// 6. When RunServeAsyncRequestsTask() notices there are no more loads in
// progress, it exits the run loop.
// 7. At this point, all parsing, resource loads, and layout should be finished.
void RunServeAsyncRequestsTask(scoped_refptr<base::TaskRunner> task_runner) {
// TODO(kinuko,toyoshim): Create a mock factory and use it instead of
// getting the platform's one. (crbug.com/751425)
WebURLLoaderMockFactory::GetSingletonInstance()->ServeAsynchronousRequests();
if (TestWebFrameClient::IsLoading()) {
task_runner->PostTask(FROM_HERE,
WTF::Bind(&RunServeAsyncRequestsTask, task_runner));
} else {
test::ExitRunLoop();
}
}
// Helper to create a default test client if the supplied client pointer is
// null. The |owned_client| is used to store the client if it must be created.
// In both cases the client to be used is returned.
template <typename T>
T* CreateDefaultClientIfNeeded(T* client, std::unique_ptr<T>& owned_client) {
if (client)
return client;
owned_client = std::make_unique<T>();
return owned_client.get();
}
viz::FrameSinkId AllocateFrameSinkId() {
// A static increasing count of frame sinks created so they are all unique.
static uint32_t s_frame_sink_count = 0;
return viz::FrameSinkId(++s_frame_sink_count, 1);
}
// Installs a create hook and uninstalls it when this object is
// destroyed.
class ScopedCreateWebFrameWidget {
public:
explicit ScopedCreateWebFrameWidget(CreateWebFrameWidgetCallback* hook) {
InstallCreateWebFrameWidgetHook(hook);
}
~ScopedCreateWebFrameWidget() { InstallCreateWebFrameWidgetHook(nullptr); }
};
} // namespace
cc::LayerTreeSettings GetSynchronousSingleThreadLayerTreeSettings() {
cc::LayerTreeSettings settings;
// Use synchronous compositing so that the MessageLoop becomes idle and the
// test makes progress.
settings.single_thread_proxy_scheduler = false;
settings.use_layer_lists = true;
#if defined(OS_MAC)
settings.enable_elastic_overscroll = true;
#endif
return settings;
}
void LoadFrameDontWait(WebLocalFrame* frame, const WebURL& url) {
auto* impl = To<WebLocalFrameImpl>(frame);
if (url.ProtocolIs("javascript")) {
impl->GetFrame()->LoadJavaScriptURL(url);
} else {
auto params = std::make_unique<WebNavigationParams>();
params->url = url;
params->navigation_timings.navigation_start = base::TimeTicks::Now();
params->navigation_timings.fetch_start = base::TimeTicks::Now();
params->is_browser_initiated = true;
MockPolicyContainerHost mock_policy_container_host;
params->policy_container = std::make_unique<WebPolicyContainer>(
WebPolicyContainerPolicies(),
mock_policy_container_host.BindNewEndpointAndPassDedicatedRemote());
params->sandbox_flags =
static_cast<TestWebFrameClient*>(frame->Client())->sandbox_flags();
FillNavigationParamsResponse(params.get());
impl->CommitNavigation(std::move(params), nullptr /* extra_data */);
}
}
void LoadFrame(WebLocalFrame* frame, const std::string& url) {
LoadFrameDontWait(frame, url_test_helpers::ToKURL(url));
PumpPendingRequestsForFrameToLoad(frame);
}
void LoadHTMLString(WebLocalFrame* frame,
const std::string& html,
const WebURL& base_url,
const base::TickClock* clock) {
auto* impl = To<WebLocalFrameImpl>(frame);
std::unique_ptr<WebNavigationParams> navigation_params =
WebNavigationParams::CreateWithHTMLStringForTesting(html, base_url);
navigation_params->tick_clock = clock;
navigation_params->sandbox_flags = network::mojom::WebSandboxFlags::kNone;
impl->CommitNavigation(std::move(navigation_params),
nullptr /* extra_data */);
PumpPendingRequestsForFrameToLoad(frame);
}
void LoadHistoryItem(WebLocalFrame* frame,
const WebHistoryItem& item,
mojom::FetchCacheMode cache_mode) {
auto* impl = To<WebLocalFrameImpl>(frame);
HistoryItem* history_item = item;
auto params = std::make_unique<WebNavigationParams>();
params->url = history_item->Url();
params->frame_load_type = WebFrameLoadType::kBackForward;
params->history_item = item;
params->navigation_timings.navigation_start = base::TimeTicks::Now();
params->navigation_timings.fetch_start = base::TimeTicks::Now();
params->sandbox_flags =
static_cast<TestWebFrameClient*>(frame->Client())->sandbox_flags();
FillNavigationParamsResponse(params.get());
impl->CommitNavigation(std::move(params), nullptr /* extra_data */);
PumpPendingRequestsForFrameToLoad(frame);
}
void ReloadFrame(WebLocalFrame* frame) {
frame->StartReload(WebFrameLoadType::kReload);
PumpPendingRequestsForFrameToLoad(frame);
}
void ReloadFrameBypassingCache(WebLocalFrame* frame) {
frame->StartReload(WebFrameLoadType::kReloadBypassingCache);
PumpPendingRequestsForFrameToLoad(frame);
}
void PumpPendingRequestsForFrameToLoad(WebLocalFrame* frame) {
scoped_refptr<base::TaskRunner> task_runner =
frame->GetTaskRunner(blink::TaskType::kInternalTest);
task_runner->PostTask(FROM_HERE,
WTF::Bind(&RunServeAsyncRequestsTask, task_runner));
test::EnterRunLoop();
}
void FillNavigationParamsResponse(WebNavigationParams* params) {
KURL kurl(params->url);
// Empty documents and srcdoc will be handled by DocumentLoader.
if (DocumentLoader::WillLoadUrlAsEmpty(kurl) || kurl.IsAboutSrcdocURL())
return;
WebURLLoaderMockFactory::GetSingletonInstance()->FillNavigationParamsResponse(
params);
// Parse Content Security Policy response headers into the policy container,
// simulating what the browser does.
for (auto& csp : ParseContentSecurityPolicies(
params->response.HttpHeaderField("Content-Security-Policy"),
network::mojom::blink::ContentSecurityPolicyType::kEnforce,
network::mojom::blink::ContentSecurityPolicySource::kHTTP,
params->response.ResponseUrl())) {
params->policy_container->policies.content_security_policies.emplace_back(
ConvertToPublic(std::move(csp)));
}
}
WebMouseEvent CreateMouseEvent(WebInputEvent::Type type,
WebMouseEvent::Button button,
const IntPoint& point,
int modifiers) {
WebMouseEvent result(type, modifiers,
WebInputEvent::GetStaticTimeStampForTests());
result.pointer_type = WebPointerProperties::PointerType::kMouse;
result.SetPositionInWidget(point.X(), point.Y());
result.SetPositionInScreen(point.X(), point.Y());
result.button = button;
result.click_count = 1;
return result;
}
WebLocalFrameImpl* CreateLocalChild(
WebLocalFrame& parent,
mojom::blink::TreeScopeType scope,
TestWebFrameClient* client,
WebPolicyContainerBindParams policy_container_bind_params) {
MockPolicyContainerHost mock_policy_container_host;
mock_policy_container_host.BindWithNewEndpoint(
std::move(policy_container_bind_params.receiver));
std::unique_ptr<TestWebFrameClient> owned_client;
client = CreateDefaultClientIfNeeded(client, owned_client);
auto* frame = To<WebLocalFrameImpl>(
parent.CreateLocalChild(scope, client, nullptr, LocalFrameToken()));
client->Bind(frame, std::move(owned_client));
return frame;
}
WebLocalFrameImpl* CreateLocalChild(
WebLocalFrame& parent,
mojom::blink::TreeScopeType scope,
std::unique_ptr<TestWebFrameClient> self_owned,
WebPolicyContainerBindParams policy_container_bind_params) {
MockPolicyContainerHost mock_policy_container_host;
mock_policy_container_host.BindWithNewEndpoint(
std::move(policy_container_bind_params.receiver));
DCHECK(self_owned);
TestWebFrameClient* client = self_owned.get();
auto* frame = To<WebLocalFrameImpl>(
parent.CreateLocalChild(scope, client, nullptr, LocalFrameToken()));
client->Bind(frame, std::move(self_owned));
return frame;
}
WebRemoteFrameImpl* CreateRemote(TestWebRemoteFrameClient* client) {
std::unique_ptr<TestWebRemoteFrameClient> owned_client;
client = CreateDefaultClientIfNeeded(client, owned_client);
auto* frame = MakeGarbageCollected<WebRemoteFrameImpl>(
mojom::blink::TreeScopeType::kDocument, client,
InterfaceRegistry::GetEmptyInterfaceRegistry(),
client->GetRemoteAssociatedInterfaces(), RemoteFrameToken());
client->Bind(frame, std::move(owned_client));
return frame;
}
WebRemoteFrameImpl* CreateRemoteChild(
WebRemoteFrame& parent,
const WebString& name,
scoped_refptr<SecurityOrigin> security_origin,
TestWebRemoteFrameClient* client) {
std::unique_ptr<TestWebRemoteFrameClient> owned_client;
client = CreateDefaultClientIfNeeded(client, owned_client);
auto* frame = To<WebRemoteFrameImpl>(parent.CreateRemoteChild(
mojom::blink::TreeScopeType::kDocument, name, FramePolicy(), client,
InterfaceRegistry::GetEmptyInterfaceRegistry(),
client->GetRemoteAssociatedInterfaces(), RemoteFrameToken(),
/*devtools_frame_token=*/base::UnguessableToken(), nullptr));
client->Bind(frame, std::move(owned_client));
if (!security_origin)
security_origin = SecurityOrigin::CreateUniqueOpaque();
frame->GetFrame()->SetReplicatedOrigin(std::move(security_origin), false);
return frame;
}
WebViewHelper::WebViewHelper(
CreateTestWebFrameWidgetCallback create_web_frame_callback)
: web_view_(nullptr),
agent_group_scheduler_(
blink::ThreadScheduler::Current()->CreateAgentGroupScheduler()),
platform_(Platform::Current()) {
DocumentLoader::DisableCodeCacheForTesting();
CreateTestWebFrameWidgetCallback create_callback =
std::move(create_web_frame_callback);
if (!create_callback) {
create_callback =
base::BindRepeating(&WebViewHelper::CreateTestWebFrameWidget<>);
}
// Due to return type differences we need to bind the RepeatingCallback
// in a wrapper.
create_widget_callback_wrapper_ = base::BindRepeating(
[](const CreateTestWebFrameWidgetCallback& create_test_web_widget,
base::PassKey<WebLocalFrame> pass_key,
CrossVariantMojoAssociatedRemote<
mojom::blink::FrameWidgetHostInterfaceBase> frame_widget_host,
CrossVariantMojoAssociatedReceiver<
mojom::blink::FrameWidgetInterfaceBase> frame_widget,
CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
widget_host,
CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
widget,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const viz::FrameSinkId& frame_sink_id, bool hidden,
bool never_composited, bool is_for_child_local_root,
bool is_for_nested_main_frame) -> WebFrameWidget* {
return create_test_web_widget.Run(
std::move(pass_key), std::move(frame_widget_host),
std::move(frame_widget), std::move(widget_host), std::move(widget),
std::move(task_runner), frame_sink_id, hidden, never_composited,
is_for_child_local_root, is_for_nested_main_frame);
},
std::move(create_callback));
}
WebViewHelper::~WebViewHelper() {
// Close the WebViewImpl before the WebViewClient is destroyed.
Reset();
}
WebViewImpl* WebViewHelper::InitializeWithOpener(
WebFrame* opener,
TestWebFrameClient* web_frame_client,
TestWebViewClient* web_view_client,
void (*update_settings_func)(WebSettings*)) {
Reset();
InitializeWebView(web_view_client, opener ? opener->View() : nullptr);
if (update_settings_func)
update_settings_func(web_view_->GetSettings());
std::unique_ptr<TestWebFrameClient> owned_web_frame_client;
web_frame_client =
CreateDefaultClientIfNeeded(web_frame_client, owned_web_frame_client);
WebLocalFrame* frame = WebLocalFrame::CreateMainFrame(
web_view_, web_frame_client, nullptr, LocalFrameToken(),
// Passing a null policy_container will create an empty, default policy
// container.
/*policy_container=*/nullptr, opener);
web_frame_client->Bind(frame, std::move(owned_web_frame_client));
TestWebFrameWidget* frame_widget =
CreateFrameWidgetAndInitializeCompositing(frame);
// We inform the WebView when it has a local main frame attached once the
// WebFrame is fully set up and the WebFrameWidget is initialized (which is
// the case by this point).
web_view_->DidAttachLocalMainFrame();
// Set an initial size for subframes.
if (frame->Parent())
frame_widget->Resize(gfx::Size());
return web_view_;
}
WebViewImpl* WebViewHelper::Initialize(
TestWebFrameClient* web_frame_client,
TestWebViewClient* web_view_client,
void (*update_settings_func)(WebSettings*)) {
return InitializeWithOpener(nullptr, web_frame_client, web_view_client,
update_settings_func);
}
WebViewImpl* WebViewHelper::InitializeWithSettings(
void (*update_settings_func)(WebSettings*)) {
return InitializeWithOpener(nullptr, nullptr, nullptr, update_settings_func);
}
WebViewImpl* WebViewHelper::InitializeAndLoad(
const std::string& url,
TestWebFrameClient* web_frame_client,
TestWebViewClient* web_view_client,
void (*update_settings_func)(WebSettings*)) {
DocumentLoader::DisableCodeCacheForTesting();
Initialize(web_frame_client, web_view_client, update_settings_func);
LoadFrame(GetWebView()->MainFrameImpl(), url);
return GetWebView();
}
WebViewImpl* WebViewHelper::InitializeRemote(
TestWebRemoteFrameClient* client,
scoped_refptr<SecurityOrigin> security_origin,
TestWebViewClient* web_view_client) {
return InitializeRemoteWithOpener(nullptr, client, security_origin,
web_view_client);
}
WebViewImpl* WebViewHelper::InitializeRemoteWithOpener(
WebFrame* opener,
TestWebRemoteFrameClient* web_remote_frame_client,
scoped_refptr<SecurityOrigin> security_origin,
TestWebViewClient* web_view_client) {
Reset();
InitializeWebView(web_view_client, nullptr);
std::unique_ptr<TestWebRemoteFrameClient> owned_web_remote_frame_client;
web_remote_frame_client = CreateDefaultClientIfNeeded(
web_remote_frame_client, owned_web_remote_frame_client);
WebRemoteFrameImpl* frame = WebRemoteFrameImpl::CreateMainFrame(
web_view_, web_remote_frame_client,
InterfaceRegistry::GetEmptyInterfaceRegistry(),
web_remote_frame_client->GetRemoteAssociatedInterfaces(),
RemoteFrameToken(), /*devtools_frame_token=*/base::UnguessableToken(),
opener);
web_remote_frame_client->Bind(frame,
std::move(owned_web_remote_frame_client));
if (!security_origin)
security_origin = SecurityOrigin::CreateUniqueOpaque();
frame->GetFrame()->SetReplicatedOrigin(std::move(security_origin), false);
return web_view_;
}
void WebViewHelper::CheckFrameIsAssociatedWithWebView(WebFrame* frame) {
// Find the main frame and assert that it is the same.
while (frame->Parent()) {
frame = frame->Parent();
}
CHECK_EQ(web_view_->MainFrame(), frame);
}
WebLocalFrameImpl* WebViewHelper::CreateLocalChild(
WebRemoteFrame& parent,
const WebString& name,
const WebFrameOwnerProperties& properties,
WebFrame* previous_sibling,
TestWebFrameClient* client) {
CheckFrameIsAssociatedWithWebView(&parent);
std::unique_ptr<TestWebFrameClient> owned_client;
client = CreateDefaultClientIfNeeded(client, owned_client);
MockPolicyContainerHost mock_policy_container_host;
auto* frame = To<WebLocalFrameImpl>(parent.CreateLocalChild(
mojom::blink::TreeScopeType::kDocument, name, FramePolicy(), client,
nullptr, previous_sibling, properties, LocalFrameToken(), nullptr,
std::make_unique<WebPolicyContainer>(
WebPolicyContainerPolicies(),
mock_policy_container_host.BindNewEndpointAndPassDedicatedRemote())));
client->Bind(frame, std::move(owned_client));
TestWebFrameWidget* frame_widget =
CreateFrameWidgetAndInitializeCompositing(frame);
// Set an initial size for subframes.
frame_widget->Resize(gfx::Size());
return frame;
}
WebLocalFrameImpl* WebViewHelper::CreateProvisional(
WebFrame& old_frame,
TestWebFrameClient* client) {
CheckFrameIsAssociatedWithWebView(&old_frame);
std::unique_ptr<TestWebFrameClient> owned_client;
client = CreateDefaultClientIfNeeded(client, owned_client);
auto* frame = To<WebLocalFrameImpl>(WebLocalFrame::CreateProvisional(
client, nullptr, LocalFrameToken(), &old_frame, FramePolicy(),
WebFrame::ToCoreFrame(old_frame)->Tree().GetName()));
client->Bind(frame, std::move(owned_client));
// Create a widget, if necessary.
if (!frame->Parent() || frame->Parent()->IsWebRemoteFrame()) {
TestWebFrameWidget* frame_widget =
CreateFrameWidgetAndInitializeCompositing(frame);
// Set an initial size for subframes.
if (frame->Parent())
frame_widget->Resize(gfx::Size());
}
return frame;
}
TestWebFrameWidget* WebViewHelper::CreateFrameWidget(WebLocalFrame* frame) {
ScopedCreateWebFrameWidget create_hook(&create_widget_callback_wrapper_);
mojo::AssociatedRemote<mojom::blink::FrameWidget> frame_widget_remote;
mojo::PendingAssociatedReceiver<mojom::blink::FrameWidget>
frame_widget_receiver =
frame_widget_remote.BindNewEndpointAndPassDedicatedReceiver();
mojo::AssociatedRemote<mojom::blink::FrameWidgetHost> frame_widget_host;
mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetHost>
frame_widget_host_receiver =
frame_widget_host.BindNewEndpointAndPassDedicatedReceiver();
mojo::AssociatedRemote<mojom::blink::Widget> widget_remote;
mojo::PendingAssociatedReceiver<mojom::blink::Widget> widget_receiver =
widget_remote.BindNewEndpointAndPassDedicatedReceiver();
mojo::AssociatedRemote<mojom::blink::WidgetHost> widget_host;
mojo::PendingAssociatedReceiver<mojom::blink::WidgetHost>
widget_host_receiver =
widget_host.BindNewEndpointAndPassDedicatedReceiver();
auto* frame_widget =
static_cast<TestWebFrameWidget*>(frame->InitializeFrameWidget(
frame_widget_host.Unbind(), std::move(frame_widget_receiver),
widget_host.Unbind(), std::move(widget_receiver),
AllocateFrameSinkId()));
frame_widget->BindWidgetChannels(std::move(widget_remote),
std::move(widget_host_receiver),
std::move(frame_widget_host_receiver));
return frame_widget;
}
TestWebFrameWidget* WebViewHelper::CreateFrameWidgetAndInitializeCompositing(
WebLocalFrame* frame) {
TestWebFrameWidget* frame_widget = CreateFrameWidget(frame);
// The WebWidget requires the compositor to be set before it is used.
cc::LayerTreeSettings layer_tree_settings =
GetSynchronousSingleThreadLayerTreeSettings();
display::ScreenInfos initial_screen_infos(
frame_widget->GetInitialScreenInfo());
frame_widget->InitializeCompositing(frame_widget->GetAgentGroupScheduler(),
initial_screen_infos,
&layer_tree_settings);
frame_widget->SetCompositorVisible(true);
return frame_widget;
}
void WebViewHelper::LoadAhem() {
LocalFrame* local_frame =
To<LocalFrame>(WebFrame::ToCoreFrame(*LocalMainFrame()));
DCHECK(local_frame);
RenderingTest::LoadAhem(*local_frame);
}
void WebViewHelper::Reset() {
DCHECK_EQ(platform_, Platform::Current())
<< "Platform::Current() should be the same for the life of a test, "
"including shutdown.";
if (test_web_view_client_)
test_web_view_client_->DestroyChildViews();
if (web_view_) {
DCHECK(!TestWebFrameClient::IsLoading());
web_view_->Close();
web_view_ = nullptr;
}
test_web_view_client_ = nullptr;
}
cc::LayerTreeHost* WebViewHelper::GetLayerTreeHost() const {
return GetMainFrameWidget()->LayerTreeHostForTesting();
}
WebLocalFrameImpl* WebViewHelper::LocalMainFrame() const {
return To<WebLocalFrameImpl>(web_view_->MainFrame());
}
WebRemoteFrameImpl* WebViewHelper::RemoteMainFrame() const {
return To<WebRemoteFrameImpl>(web_view_->MainFrame());
}
TestWebFrameWidget* WebViewHelper::GetMainFrameWidget() const {
return static_cast<TestWebFrameWidget*>(LocalMainFrame()->FrameWidgetImpl());
}
void WebViewHelper::Resize(const gfx::Size& size) {
GetWebView()->MainFrameWidget()->Resize(size);
}
void WebViewHelper::InitializeWebView(TestWebViewClient* web_view_client,
class WebView* opener) {
test_web_view_client_ =
CreateDefaultClientIfNeeded(web_view_client, owned_test_web_view_client_);
web_view_ = To<WebViewImpl>(
WebView::Create(test_web_view_client_,
/*is_hidden=*/false,
/*is_prerendering=*/false,
/*is_inside_portal=*/false,
/*compositing_enabled=*/true,
/*widgets_never_composited=*/false,
/*opener=*/opener, mojo::NullAssociatedReceiver(),
*agent_group_scheduler_,
/*session_storage_namespace_id=*/base::EmptyString(),
/*page_base_background_color=*/absl::nullopt));
// This property must be set at initialization time, it is not supported to be
// changed afterward, and does nothing.
web_view_->GetSettings()->SetViewportEnabled(viewport_enabled_);
web_view_->GetSettings()->SetJavaScriptEnabled(true);
web_view_->GetSettings()->SetPluginsEnabled(true);
// Enable (mocked) network loads of image URLs, as this simplifies
// the completion of resource loads upon test shutdown & helps avoid
// dormant loads trigger Resource leaks for image loads.
//
// Consequently, all external image resources must be mocked.
web_view_->GetSettings()->SetLoadsImagesAutomatically(true);
// If a test turned off this settings, opened WebViews should propagate that.
if (opener) {
web_view_->GetSettings()->SetAllowUniversalAccessFromFileURLs(
To<WebViewImpl>(opener)
->GetPage()
->GetSettings()
.GetAllowUniversalAccessFromFileURLs());
}
web_view_->SetDefaultPageScaleLimits(1, 4);
}
int TestWebFrameClient::loads_in_progress_ = 0;
TestWebFrameClient::TestWebFrameClient()
: associated_interface_provider_(new AssociatedInterfaceProvider(nullptr)),
effective_connection_type_(WebEffectiveConnectionType::kTypeUnknown) {}
TestWebFrameClient::~TestWebFrameClient() = default;
void TestWebFrameClient::Bind(WebLocalFrame* frame,
std::unique_ptr<TestWebFrameClient> self_owned) {
DCHECK(!frame_);
DCHECK(!self_owned || self_owned.get() == this);
frame_ = To<WebLocalFrameImpl>(frame);
self_owned_ = std::move(self_owned);
}
void TestWebFrameClient::FrameDetached() {
frame_->Close();
self_owned_.reset();
}
WebLocalFrame* TestWebFrameClient::CreateChildFrame(
mojom::blink::TreeScopeType scope,
const WebString& name,
const WebString& fallback_name,
const FramePolicy& frame_policy,
const WebFrameOwnerProperties&,
FrameOwnerElementType,
WebPolicyContainerBindParams policy_container_bind_params) {
MockPolicyContainerHost mock_policy_container_host;
mock_policy_container_host.BindWithNewEndpoint(
std::move(policy_container_bind_params.receiver));
auto client = std::make_unique<TestWebFrameClient>();
auto* frame = To<WebLocalFrameImpl>(frame_->CreateLocalChild(
scope, client.get(), nullptr, LocalFrameToken()));
client->sandbox_flags_ = frame_policy.sandbox_flags;
TestWebFrameClient* client_ptr = client.get();
client_ptr->Bind(frame, std::move(client));
return frame;
}
void TestWebFrameClient::InitializeAsChildFrame(WebLocalFrame* parent) {}
void TestWebFrameClient::DidStartLoading() {
++loads_in_progress_;
}
void TestWebFrameClient::DidStopLoading() {
DCHECK_GT(loads_in_progress_, 0);
--loads_in_progress_;
}
bool TestWebFrameClient::SwapIn(WebFrame* previous_frame) {
bool result = previous_frame->Swap(frame_);
if (!frame_->Parent())
frame_->View()->DidAttachLocalMainFrame();
return result;
}
void TestWebFrameClient::BeginNavigation(
std::unique_ptr<WebNavigationInfo> info) {
navigation_callback_.Cancel();
if (DocumentLoader::WillLoadUrlAsEmpty(info->url_request.Url()) &&
!frame_->HasCommittedFirstRealLoad()) {
CommitNavigation(std::move(info));
return;
}
if (!frame_->WillStartNavigation(*info))
return;
navigation_callback_.Reset(
base::BindOnce(&TestWebFrameClient::CommitNavigation,
weak_factory_.GetWeakPtr(), std::move(info)));
frame_->GetTaskRunner(blink::TaskType::kInternalLoading)
->PostTask(FROM_HERE, navigation_callback_.callback());
}
void TestWebFrameClient::CommitNavigation(
std::unique_ptr<WebNavigationInfo> info) {
if (!frame_)
return;
auto params = WebNavigationParams::CreateFromInfo(*info);
MockPolicyContainerHost mock_policy_container_host;
params->policy_container = std::make_unique<WebPolicyContainer>(
WebPolicyContainerPolicies(),
mock_policy_container_host.BindNewEndpointAndPassDedicatedRemote());
if (info->archive_status != WebNavigationInfo::ArchiveStatus::Present)
FillNavigationParamsResponse(params.get());
frame_->CommitNavigation(std::move(params), nullptr /* extra_data */);
}
WebEffectiveConnectionType TestWebFrameClient::GetEffectiveConnectionType() {
return effective_connection_type_;
}
void TestWebFrameClient::SetEffectiveConnectionTypeForTesting(
WebEffectiveConnectionType effective_connection_type) {
effective_connection_type_ = effective_connection_type;
}
void TestWebFrameClient::DidAddMessageToConsole(
const WebConsoleMessage& message,
const WebString& source_name,
unsigned source_line,
const WebString& stack_trace) {
console_messages_.push_back(message.text);
}
WebPlugin* TestWebFrameClient::CreatePlugin(const WebPluginParams& params) {
return new FakeWebPlugin(params);
}
AssociatedInterfaceProvider*
TestWebFrameClient::GetRemoteNavigationAssociatedInterfaces() {
return associated_interface_provider_.get();
}
void TestWebFrameClient::DidMeaningfulLayout(
WebMeaningfulLayout meaningful_layout) {
switch (meaningful_layout) {
case WebMeaningfulLayout::kVisuallyNonEmpty:
visually_non_empty_layout_count_++;
break;
case WebMeaningfulLayout::kFinishedParsing:
finished_parsing_layout_count_++;
break;
case WebMeaningfulLayout::kFinishedLoading:
finished_loading_layout_count_++;
break;
}
}
TestWebRemoteFrameClient::TestWebRemoteFrameClient()
: associated_interface_provider_(new AssociatedInterfaceProvider(nullptr)) {
}
void TestWebRemoteFrameClient::Bind(
WebRemoteFrame* frame,
std::unique_ptr<TestWebRemoteFrameClient> self_owned) {
DCHECK(!frame_);
DCHECK(!self_owned || self_owned.get() == this);
frame_ = frame;
self_owned_ = std::move(self_owned);
}
void TestWebRemoteFrameClient::FrameDetached(DetachType type) {
frame_->Close();
self_owned_.reset();
}
TestWidgetInputHandlerHost* TestWebFrameWidget::GetInputHandlerHost() {
if (!widget_input_handler_host_)
widget_input_handler_host_ = std::make_unique<TestWidgetInputHandlerHost>();
return widget_input_handler_host_.get();
}
display::ScreenInfo TestWebFrameWidget::GetInitialScreenInfo() {
return display::ScreenInfo();
}
cc::FakeLayerTreeFrameSink* TestWebFrameWidget::LastCreatedFrameSink() {
DCHECK(LayerTreeHostForTesting()->IsSingleThreaded());
return last_created_frame_sink_;
}
std::unique_ptr<TestWebFrameWidgetHost> TestWebFrameWidget::CreateWidgetHost() {
return std::make_unique<TestWebFrameWidgetHost>();
}
void TestWebFrameWidget::BindWidgetChannels(
mojo::AssociatedRemote<mojom::blink::Widget> widget_remote,
mojo::PendingAssociatedReceiver<mojom::blink::WidgetHost> receiver,
mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetHost>
frame_receiver) {
widget_host_ = CreateWidgetHost();
widget_host_->BindWidgetHost(std::move(receiver), std::move(frame_receiver));
mojo::Remote<mojom::blink::WidgetInputHandler> input_handler;
widget_remote->GetWidgetInputHandler(
input_handler.BindNewPipeAndPassReceiver(),
GetInputHandlerHost()->BindNewRemote());
}
bool TestWebFrameWidget::HaveScrollEventHandlers() const {
return LayerTreeHostForTesting()->have_scroll_event_handlers();
}
std::unique_ptr<cc::LayerTreeFrameSink>
TestWebFrameWidget::AllocateNewLayerTreeFrameSink() {
std::unique_ptr<cc::FakeLayerTreeFrameSink> sink =
cc::FakeLayerTreeFrameSink::Create3d();
last_created_frame_sink_ = sink.get();
return sink;
}
void TestWebFrameWidget::WillQueueSyntheticEvent(
const WebCoalescedInputEvent& event) {
injected_scroll_events_.push_back(
std::make_unique<WebCoalescedInputEvent>(event));
}
void TestWebFrameWidgetHost::SetCursor(const ui::Cursor& cursor) {
cursor_set_count_++;
}
void TestWebFrameWidgetHost::UpdateTooltipUnderCursor(
const String& tooltip_text,
base::i18n::TextDirection text_direction_hint) {}
void TestWebFrameWidgetHost::UpdateTooltipFromKeyboard(
const String& tooltip_text,
base::i18n::TextDirection text_direction_hint,
const gfx::Rect& bounds) {}
void TestWebFrameWidgetHost::ClearKeyboardTriggeredTooltip() {}
void TestWebFrameWidgetHost::TextInputStateChanged(
ui::mojom::blink::TextInputStatePtr state) {
if (state->show_ime_if_needed)
++virtual_keyboard_request_count_;
}
void TestWebFrameWidgetHost::SelectionBoundsChanged(
const gfx::Rect& anchor_rect,
base::i18n::TextDirection anchor_dir,
const gfx::Rect& focus_rect,
base::i18n::TextDirection focus_dir,
const gfx::Rect& bounding_box,
bool is_anchor_first) {}
void TestWebFrameWidgetHost::CreateFrameSink(
mojo::PendingReceiver<viz::mojom::blink::CompositorFrameSink>
compositor_frame_sink_receiver,
mojo::PendingRemote<viz::mojom::blink::CompositorFrameSinkClient>
compositor_frame_sink_client) {}
void TestWebFrameWidgetHost::RegisterRenderFrameMetadataObserver(
mojo::PendingReceiver<cc::mojom::blink::RenderFrameMetadataObserverClient>
render_frame_metadata_observer_client_receiver,
mojo::PendingRemote<cc::mojom::blink::RenderFrameMetadataObserver>
render_frame_metadata_observer) {}
void TestWebFrameWidgetHost::AnimateDoubleTapZoomInMainFrame(
const gfx::Point& tap_point,
const gfx::Rect& rect_to_zoom) {}
void TestWebFrameWidgetHost::ZoomToFindInPageRectInMainFrame(
const gfx::Rect& rect_to_zoom) {}
void TestWebFrameWidgetHost::SetHasTouchEventConsumers(
mojom::blink::TouchEventConsumersPtr consumers) {}
void TestWebFrameWidgetHost::IntrinsicSizingInfoChanged(
mojom::blink::IntrinsicSizingInfoPtr sizing_info) {}
void TestWebFrameWidgetHost::AutoscrollStart(const gfx::PointF& position) {}
void TestWebFrameWidgetHost::AutoscrollFling(const gfx::Vector2dF& position) {}
void TestWebFrameWidgetHost::AutoscrollEnd() {}
void TestWebFrameWidgetHost::StartDragging(
const blink::WebDragData& drag_data,
blink::DragOperationsMask operations_allowed,
const SkBitmap& bitmap,
const gfx::Vector2d& bitmap_offset_in_dip,
mojom::blink::DragEventSourceInfoPtr event_info) {}
void TestWebFrameWidgetHost::BindWidgetHost(
mojo::PendingAssociatedReceiver<mojom::blink::WidgetHost> receiver,
mojo::PendingAssociatedReceiver<mojom::blink::FrameWidgetHost>
frame_receiver) {
receiver_.Bind(std::move(receiver));
frame_receiver_.Bind(std::move(frame_receiver));
}
void TestWebViewClient::DestroyChildViews() {
child_web_views_.clear();
}
WebView* TestWebViewClient::CreateView(WebLocalFrame* opener,
const WebURLRequest&,
const WebWindowFeatures&,
const WebString& name,
WebNavigationPolicy,
network::mojom::blink::WebSandboxFlags,
const SessionStorageNamespaceId&,
bool& consumed_user_gesture,
const absl::optional<WebImpression>&) {
auto webview_helper = std::make_unique<WebViewHelper>();
WebView* result = webview_helper->InitializeWithOpener(opener);
child_web_views_.push_back(std::move(webview_helper));
return result;
}
mojo::PendingRemote<mojom::blink::WidgetInputHandlerHost>
TestWidgetInputHandlerHost::BindNewRemote() {
receiver_.reset();
return receiver_.BindNewPipeAndPassRemote();
}
void TestWidgetInputHandlerHost::SetTouchActionFromMain(
cc::TouchAction touch_action) {}
void TestWidgetInputHandlerHost::DidOverscroll(
mojom::blink::DidOverscrollParamsPtr params) {}
void TestWidgetInputHandlerHost::DidStartScrollingViewport() {}
void TestWidgetInputHandlerHost::ImeCancelComposition() {}
void TestWidgetInputHandlerHost::ImeCompositionRangeChanged(
const gfx::Range& range,
const WTF::Vector<gfx::Rect>& bounds) {}
void TestWidgetInputHandlerHost::SetMouseCapture(bool capture) {}
void TestWidgetInputHandlerHost::RequestMouseLock(
bool from_user_gesture,
bool unadjusted_movement,
RequestMouseLockCallback callback) {}
} // namespace frame_test_helpers
} // namespace blink