blob: f792a5e76cd3a40a039136499677881f396d85a8 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/content_service_delegate_impl.h"
#include "base/macros.h"
#include "base/optional.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "services/content/navigable_contents_delegate.h"
#include "services/content/service.h"
#include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
#include "third_party/skia/include/core/SkColor.h"
namespace content {
namespace {
// Bridge between Content Service navigable contents delegation API and a
// WebContentsImpl.
class NavigableContentsDelegateImpl : public content::NavigableContentsDelegate,
public WebContentsDelegate,
public WebContentsObserver {
public:
explicit NavigableContentsDelegateImpl(
BrowserContext* browser_context,
const mojom::NavigableContentsParams& params,
mojom::NavigableContentsClient* client)
: client_(client),
enable_view_auto_resize_(params.enable_view_auto_resize),
auto_resize_min_size_(
params.auto_resize_min_size.value_or(gfx::Size(1, 1))),
auto_resize_max_size_(
params.auto_resize_max_size.value_or(gfx::Size(INT_MAX, INT_MAX))),
background_color_(params.override_background_color
? base::make_optional(params.background_color)
: base::nullopt) {
WebContents::CreateParams create_params(browser_context);
web_contents_ = WebContents::Create(create_params);
WebContentsObserver::Observe(web_contents_.get());
web_contents_->SetDelegate(this);
blink::mojom::RendererPreferences* renderer_prefs =
web_contents_->GetMutableRendererPrefs();
renderer_prefs->can_accept_load_drops = false;
renderer_prefs->browser_handles_all_top_level_requests =
params.suppress_navigations;
web_contents_->GetRenderViewHost()->SyncRendererPrefs();
}
~NavigableContentsDelegateImpl() override {
WebContentsObserver::Observe(nullptr);
}
bool TakeFocus(WebContents* source, bool reverse) override {
client_->ClearViewFocus();
return true;
}
private:
void NotifyAXTreeChange() {
auto* rfh = web_contents_->GetMainFrame();
if (rfh)
client_->UpdateContentAXTree(rfh->GetAXTreeID());
else
client_->UpdateContentAXTree(ui::AXTreeIDUnknown());
}
// content::NavigableContentsDelegate:
gfx::NativeView GetNativeView() override {
return web_contents_->GetNativeView();
}
void Navigate(const GURL& url,
content::mojom::NavigateParamsPtr params) override {
NavigationController::LoadURLParams load_url_params(url);
load_url_params.transition_type = ui::PAGE_TRANSITION_AUTO_TOPLEVEL;
load_url_params.should_clear_history_list =
params->should_clear_session_history;
web_contents_->GetController().LoadURLWithParams(load_url_params);
}
void GoBack(
content::mojom::NavigableContents::GoBackCallback callback) override {
content::NavigationController& controller = web_contents_->GetController();
if (controller.CanGoBack()) {
std::move(callback).Run(/*success=*/true);
controller.GoBack();
} else {
std::move(callback).Run(/*success=*/false);
}
}
void Focus() override { web_contents_->Focus(); }
void FocusThroughTabTraversal(bool reverse) override {
web_contents_->FocusThroughTabTraversal(reverse);
}
// WebContentsDelegate:
bool ShouldCreateWebContents(
content::WebContents* web_contents,
content::RenderFrameHost* opener,
content::SiteInstance* source_site_instance,
int32_t route_id,
int32_t main_frame_route_id,
int32_t main_frame_widget_route_id,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
const std::string& frame_name,
const GURL& target_url,
const std::string& partition_id,
content::SessionStorageNamespace* session_storage_namespace) override {
// This method is invoked when attempting to open links in a new tab, e.g.:
// <a href="https://www.google.com/" target="_blank">Link</a>
client_->DidSuppressNavigation(target_url,
WindowOpenDisposition::NEW_FOREGROUND_TAB,
/*from_user_gesture=*/true);
return false;
}
WebContents* OpenURLFromTab(WebContents* source,
const OpenURLParams& params) override {
client_->DidSuppressNavigation(params.url, params.disposition,
params.user_gesture);
return nullptr;
}
void ResizeDueToAutoResize(WebContents* web_contents,
const gfx::Size& new_size) override {
DCHECK_EQ(web_contents, web_contents_.get());
client_->DidAutoResizeView(new_size);
}
// WebContentsObserver:
void RenderViewReady() override {
if (background_color_) {
web_contents_->GetRenderViewHost()
->GetWidget()
->GetView()
->SetBackgroundColor(background_color_.value());
}
}
void RenderViewCreated(RenderViewHost* render_view_host) override {
if (background_color_) {
render_view_host->GetWidget()->GetView()->SetBackgroundColor(
background_color_.value());
}
}
void RenderViewHostChanged(RenderViewHost* old_host,
RenderViewHost* new_host) override {
if (enable_view_auto_resize_ && web_contents_->GetRenderWidgetHostView()) {
web_contents_->GetRenderWidgetHostView()->EnableAutoResize(
auto_resize_min_size_, auto_resize_max_size_);
}
if (background_color_) {
new_host->GetWidget()->GetView()->SetBackgroundColor(
background_color_.value());
}
NotifyAXTreeChange();
}
void DidFinishNavigation(NavigationHandle* navigation_handle) override {
client_->DidFinishNavigation(
navigation_handle->GetURL(), navigation_handle->IsInMainFrame(),
navigation_handle->IsErrorPage(),
navigation_handle->GetResponseHeaders()
? base::MakeRefCounted<net::HttpResponseHeaders>(
navigation_handle->GetResponseHeaders()->raw_headers())
: nullptr);
}
void DidStopLoading() override { client_->DidStopLoading(); }
std::unique_ptr<WebContents> web_contents_;
mojom::NavigableContentsClient* const client_;
const bool enable_view_auto_resize_;
const gfx::Size auto_resize_min_size_;
const gfx::Size auto_resize_max_size_;
const base::Optional<SkColor> background_color_;
DISALLOW_COPY_AND_ASSIGN(NavigableContentsDelegateImpl);
};
} // namespace
ContentServiceDelegateImpl::ContentServiceDelegateImpl(
BrowserContext* browser_context)
: browser_context_(browser_context) {}
ContentServiceDelegateImpl::~ContentServiceDelegateImpl() {
// This delegate is destroyed immediately before |browser_context_| is
// destroyed. We force-kill any Content Service instances which depend on
// |this|, since they will no longer be functional anyway.
std::set<content::Service*> instances;
std::swap(instances, service_instances_);
for (content::Service* service : instances) {
// Eventually destroys |service|. Ensures that no more calls into |this|
// will occur.
service->ForceQuit();
}
}
void ContentServiceDelegateImpl::AddService(content::Service* service) {
service_instances_.insert(service);
}
void ContentServiceDelegateImpl::WillDestroyServiceInstance(
content::Service* service) {
service_instances_.erase(service);
}
std::unique_ptr<content::NavigableContentsDelegate>
ContentServiceDelegateImpl::CreateNavigableContentsDelegate(
const mojom::NavigableContentsParams& params,
mojom::NavigableContentsClient* client) {
return std::make_unique<NavigableContentsDelegateImpl>(browser_context_,
params, client);
}
} // namespace content