blob: a2af3c85a43496f3eb171ffbe93b9013b542b8de [file] [log] [blame]
// Copyright 2019 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 "ash/shell/content/embedded_browser.h"
#include "ash/shell.h"
#include "ash/ws/window_service_owner.h"
#include "base/bind_helpers.h"
#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/unguessable_token.h"
#include "content/public/browser/web_contents.h"
#include "services/ws/remote_view_host/server_remote_view_host.h"
#include "ui/base/ui_base_features.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/mus/remote_view/remote_view_provider.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "url/gurl.h"
namespace ash {
namespace shell {
namespace {
// Simulate a widget created on Window Service side to host a native window.
// For classic, it is done by NativeViewHost. For single process mash,
// it uses ServerRemoteViewHost. To implement for mash, the code should be
// moved to ash process somehow and invoked over mojo.
class HostWidget : public views::WidgetDelegateView {
public:
// Creates HostWidget to host remote content represented by |token| for mash.
static void CreateFromToken(const base::UnguessableToken& token) {
// HostWidget deletes itself when underlying widget closes.
new HostWidget(nullptr, token);
}
// Creates HostWidget that hosts |native_window| directly for classic.
static void CreateFromNativeWindow(gfx::NativeWindow native_window) {
// HostWidget deletes itself when underlying widget closes.
new HostWidget(native_window, base::nullopt);
}
private:
HostWidget(gfx::NativeWindow native_window,
base::Optional<base::UnguessableToken> token) {
// Note this does not work under multi process mash.
DCHECK(!features::IsMultiProcessMash());
SetLayoutManager(std::make_unique<views::FillLayout>());
auto* widget = new views::Widget;
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.context = Shell::GetPrimaryRootWindow();
params.bounds = gfx::Rect(20, 0, 800, 600);
params.delegate = this;
widget->Init(params);
widget->Show();
if (native_window) {
title_ = base::ASCIIToUTF16("Classic: Embed by NativeViewHost");
auto* host = new views::NativeViewHost();
AddChildView(host);
host->Attach(native_window);
} else {
title_ = base::ASCIIToUTF16("SPM: Embed by ServerRemoteViewHost");
auto* host = new ws::ServerRemoteViewHost(
ash::Shell::Get()->window_service_owner()->window_service());
AddChildView(host);
host->EmbedUsingToken(token.value(), 0, base::DoNothing());
}
Layout();
}
// views::WidgetDelegateView:
base::string16 GetWindowTitle() const override { return title_; }
base::string16 title_;
DISALLOW_COPY_AND_ASSIGN(HostWidget);
};
} // namespace
EmbeddedBrowser::EmbeddedBrowser(content::BrowserContext* context,
const GURL& url) {
contents_ =
content::WebContents::Create(content::WebContents::CreateParams(context));
contents_->GetController().LoadURLWithParams(
content::NavigationController::LoadURLParams(url));
contents_->GetNativeView()->Show();
if (!features::IsUsingWindowService()) {
HostWidget::CreateFromNativeWindow(contents_->GetNativeView());
return;
}
remote_view_provider_ =
std::make_unique<views::RemoteViewProvider>(contents_->GetNativeView());
remote_view_provider_->GetEmbedToken(
base::BindOnce([](const base::UnguessableToken& token) {
HostWidget::CreateFromToken(token);
}));
}
EmbeddedBrowser::~EmbeddedBrowser() = default;
// static
void EmbeddedBrowser::Create(content::BrowserContext* context,
const GURL& url) {
// EmbeddedBrowser deletes itself when the hosting widget is closed.
new EmbeddedBrowser(context, url);
}
void EmbeddedBrowser::OnUnembed() {
delete this;
}
} // namespace shell
} // namespace ash