blob: 8992496bbc2789309aa2883afe1d67c9f21a474b [file] [log] [blame]
// Copyright 2015 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 "components/web_view/web_view_impl.h"
#include "base/command_line.h"
#include "components/devtools_service/public/cpp/switches.h"
#include "components/mus/public/cpp/scoped_view_ptr.h"
#include "components/mus/public/cpp/view.h"
#include "components/mus/public/cpp/view_tree_connection.h"
#include "components/web_view/client_initiated_frame_connection.h"
#include "components/web_view/frame.h"
#include "components/web_view/frame_connection.h"
#include "components/web_view/frame_devtools_agent.h"
#include "components/web_view/frame_tree.h"
#include "components/web_view/navigation_entry.h"
#include "components/web_view/pending_web_view_load.h"
#include "components/web_view/url_request_cloneable.h"
#include "mojo/application/public/cpp/application_impl.h"
#include "mojo/converters/geometry/geometry_type_converters.h"
#include "url/gurl.h"
namespace web_view {
namespace {
bool EnableRemoteDebugging() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
devtools_service::kRemoteDebuggingPort);
}
} // namespace
using web_view::mojom::ButtonState;
////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, public:
WebViewImpl::WebViewImpl(mojo::ApplicationImpl* app,
mojom::WebViewClientPtr client,
mojo::InterfaceRequest<mojom::WebView> request)
: app_(app),
client_(client.Pass()),
binding_(this, request.Pass()),
root_(nullptr),
content_(nullptr),
navigation_controller_(this) {
if (EnableRemoteDebugging())
devtools_agent_.reset(new FrameDevToolsAgent(app_, this));
OnDidNavigate();
}
WebViewImpl::~WebViewImpl() {
if (content_)
content_->RemoveObserver(this);
if (root_) {
root_->RemoveObserver(this);
mus::ScopedViewPtr::DeleteViewOrViewManager(root_);
}
}
void WebViewImpl::OnLoad(const GURL& pending_url) {
// Frames are uniqued based on the id of the associated View. By creating a
// new View each time through we ensure the renderers get a clean id, rather
// than one they may know about and try to incorrectly use.
if (content_) {
content_->Destroy();
DCHECK(!content_);
}
client_->TopLevelNavigationStarted(pending_url.spec());
content_ = root_->connection()->CreateView();
content_->SetBounds(*mojo::Rect::From(
gfx::Rect(0, 0, root_->bounds().width, root_->bounds().height)));
root_->AddChild(content_);
content_->SetVisible(true);
content_->AddObserver(this);
scoped_ptr<PendingWebViewLoad> pending_load(pending_load_.Pass());
scoped_ptr<FrameConnection> frame_connection(
pending_load->frame_connection());
mojo::ViewTreeClientPtr view_tree_client =
frame_connection->GetViewTreeClient();
Frame::ClientPropertyMap client_properties;
if (devtools_agent_) {
devtools_service::DevToolsAgentPtr forward_agent;
frame_connection->application_connection()->ConnectToService(
&forward_agent);
devtools_agent_->AttachFrame(forward_agent.Pass(), &client_properties);
}
mojom::FrameClient* frame_client = frame_connection->frame_client();
const uint32_t content_handler_id = frame_connection->GetContentHandlerID();
frame_tree_.reset(new FrameTree(content_handler_id, content_,
view_tree_client.Pass(), this, frame_client,
frame_connection.Pass(), client_properties));
}
////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, WebView implementation:
void WebViewImpl::LoadRequest(mojo::URLRequestPtr request) {
navigation_controller_.LoadURL(request.Pass());
}
void WebViewImpl::GetViewTreeClient(
mojo::InterfaceRequest<mojo::ViewTreeClient> view_tree_client) {
mus::ViewTreeConnection::Create(this, view_tree_client.Pass());
}
void WebViewImpl::GoBack() {
if (!navigation_controller_.CanGoBack())
return;
navigation_controller_.GoBack();
}
void WebViewImpl::GoForward() {
if (!navigation_controller_.CanGoForward())
return;
navigation_controller_.GoForward();
}
////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, mus::ViewTreeDelegate implementation:
void WebViewImpl::OnEmbed(mus::View* root) {
// We must have been granted embed root priviledges, otherwise we can't
// Embed() in any descendants.
DCHECK(root->connection()->IsEmbedRoot());
root->AddObserver(this);
root_ = root;
if (pending_load_ && pending_load_->is_content_handler_id_valid())
OnLoad(pending_load_->pending_url());
}
void WebViewImpl::OnConnectionLost(mus::ViewTreeConnection* connection) {
root_ = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, mus::ViewObserver implementation:
void WebViewImpl::OnViewBoundsChanged(mus::View* view,
const mojo::Rect& old_bounds,
const mojo::Rect& new_bounds) {
if (view != content_) {
mojo::Rect rect;
rect.width = new_bounds.width;
rect.height = new_bounds.height;
if (content_)
content_->SetBounds(rect);
}
}
void WebViewImpl::OnViewDestroyed(mus::View* view) {
// |FrameTree| cannot outlive the content view.
if (view == content_) {
frame_tree_.reset();
content_ = nullptr;
}
}
////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, FrameTreeDelegate implementation:
scoped_ptr<FrameUserData> WebViewImpl::CreateUserDataForNewFrame(
mojom::FrameClientPtr frame_client) {
return make_scoped_ptr(
new ClientInitiatedFrameConnection(frame_client.Pass()));
}
bool WebViewImpl::CanPostMessageEventToFrame(const Frame* source,
const Frame* target,
mojom::HTMLMessageEvent* event) {
return true;
}
void WebViewImpl::LoadingStateChanged(bool loading, double progress) {
client_->LoadingStateChanged(loading, progress);
}
void WebViewImpl::TitleChanged(const mojo::String& title) {
client_->TitleChanged(title);
}
void WebViewImpl::NavigateTopLevel(Frame* source, mojo::URLRequestPtr request) {
client_->TopLevelNavigateRequest(request.Pass());
}
void WebViewImpl::CanNavigateFrame(Frame* target,
mojo::URLRequestPtr request,
const CanNavigateFrameCallback& callback) {
FrameConnection::CreateConnectionForCanNavigateFrame(
app_, target, request.Pass(), callback);
}
void WebViewImpl::DidStartNavigation(Frame* frame) {}
void WebViewImpl::DidCommitProvisionalLoad(Frame* frame) {
navigation_controller_.FrameDidCommitProvisionalLoad(frame);
}
////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, FrameDevToolsAgentDelegate implementation:
void WebViewImpl::HandlePageNavigateRequest(const GURL& url) {
mojo::URLRequestPtr request(mojo::URLRequest::New());
request->url = url.spec();
client_->TopLevelNavigateRequest(request.Pass());
}
////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, NavigationControllerDelegate implementation:
void WebViewImpl::OnNavigate(mojo::URLRequestPtr request) {
pending_load_.reset(new PendingWebViewLoad(this));
pending_load_->Init(request.Pass());
}
void WebViewImpl::OnDidNavigate() {
client_->BackForwardChanged(navigation_controller_.CanGoBack()
? ButtonState::BUTTON_STATE_ENABLED
: ButtonState::BUTTON_STATE_DISABLED,
navigation_controller_.CanGoForward()
? ButtonState::BUTTON_STATE_ENABLED
: ButtonState::BUTTON_STATE_DISABLED);
}
} // namespace web_view