blob: d62e9fc97ba96f78d4b6074760280eb1207ed8f8 [file] [log] [blame]
// Copyright 2016 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 "mash/webtest/webtest.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/timer/timer.h"
#include "mash/public/interfaces/launchable.mojom.h"
#include "services/navigation/public/interfaces/view.mojom.h"
#include "services/service_manager/public/c/main.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/interface_registry.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_context.h"
#include "services/service_manager/public/cpp/service_runner.h"
#include "services/tracing/public/cpp/provider.h"
#include "ui/aura/mus/window_port_mus.h"
#include "ui/aura/window.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/paint_throbber.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/textfield/textfield_controller.h"
#include "ui/views/mus/aura_init.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "url/gurl.h"
namespace views {
class AuraInit;
}
namespace mash {
namespace webtest {
namespace {
// Callback from Embed().
void EmbedCallback(bool result) {}
} // namespace
class UI : public views::WidgetDelegateView,
public navigation::mojom::ViewClient {
public:
UI(Webtest* webtest,
navigation::mojom::ViewPtr view,
navigation::mojom::ViewClientRequest request)
: webtest_(webtest),
view_(std::move(view)),
view_client_binding_(this, std::move(request)) {}
~UI() override {
webtest_->RemoveWindow(GetWidget());
}
void NavigateTo(const GURL& url) {
view_->NavigateTo(url);
}
private:
// Overridden from views::WidgetDelegate:
base::string16 GetWindowTitle() const override {
// TODO(beng): use resources.
if (current_title_.empty())
return base::ASCIIToUTF16("navigation::View client");
base::string16 format = base::ASCIIToUTF16("%s - navigation::View client");
base::ReplaceFirstSubstringAfterOffset(
&format, 0, base::ASCIIToUTF16("%s"), current_title_);
return format;
}
bool CanResize() const override { return true; }
bool CanMaximize() const override { return true; }
bool CanMinimize() const override { return true; }
// Overridden from views::View:
void Layout() override {
gfx::Rect local_bounds = GetLocalBounds();
if (content_area_) {
gfx::Point offset = local_bounds.origin();
ConvertPointToWidget(this, &offset);
int width = local_bounds.width();
int height = local_bounds.height();
content_area_->SetBounds(
gfx::Rect(offset.x(), offset.y(), width, height));
}
}
void ViewHierarchyChanged(
const views::View::ViewHierarchyChangedDetails& details) override {
if (details.is_add && GetWidget() && !content_area_) {
aura::Window* window = GetWidget()->GetNativeWindow();
content_area_ = new aura::Window(nullptr);
content_area_->Init(ui::LAYER_NOT_DRAWN);
window->AddChild(content_area_);
ui::mojom::WindowTreeClientPtr client;
view_->GetWindowTreeClient(MakeRequest(&client));
const uint32_t embed_flags = 0; // Nothing special.
aura::WindowPortMus::Get(content_area_)
->Embed(std::move(client), embed_flags, base::Bind(&EmbedCallback));
}
}
// navigation::mojom::ViewClient:
void OpenURL(navigation::mojom::OpenURLParamsPtr params) override {}
void LoadingStateChanged(bool is_loading) override {}
void NavigationStateChanged(const GURL& url,
const std::string& title,
bool can_go_back,
bool can_go_forward) override {
current_title_ = base::UTF8ToUTF16(title);
GetWidget()->UpdateWindowTitle();
}
void LoadProgressChanged(double progress) override {}
void UpdateHoverURL(const GURL& url) override {}
void ViewCreated(navigation::mojom::ViewPtr view,
navigation::mojom::ViewClientRequest request,
bool is_popup,
const gfx::Rect& initial_rect,
bool user_gesture) override {
views::Widget* window = views::Widget::CreateWindowWithContextAndBounds(
new UI(webtest_, std::move(view), std::move(request)), nullptr,
initial_rect);
window->Show();
webtest_->AddWindow(window);
}
void Close() override {
GetWidget()->Close();
}
void NavigationPending(navigation::mojom::NavigationEntryPtr entry) override {
}
void NavigationCommitted(
navigation::mojom::NavigationCommittedDetailsPtr details,
int current_index) override {}
void NavigationEntryChanged(navigation::mojom::NavigationEntryPtr entry,
int entry_index) override {}
void NavigationListPruned(bool from_front, int count) override {}
Webtest* webtest_;
aura::Window* content_area_ = nullptr;
navigation::mojom::ViewPtr view_;
mojo::Binding<navigation::mojom::ViewClient> view_client_binding_;
base::string16 current_title_;
DISALLOW_COPY_AND_ASSIGN(UI);
};
Webtest::Webtest() {
registry_.AddInterface<mojom::Launchable>(this);
}
Webtest::~Webtest() {}
void Webtest::AddWindow(views::Widget* window) {
windows_.push_back(window);
}
void Webtest::RemoveWindow(views::Widget* window) {
auto it = std::find(windows_.begin(), windows_.end(), window);
DCHECK(it != windows_.end());
windows_.erase(it);
if (windows_.empty())
base::MessageLoop::current()->QuitWhenIdle();
}
void Webtest::OnStart() {
tracing_.Initialize(context()->connector(), context()->identity().name());
aura_init_ = base::MakeUnique<views::AuraInit>(
context()->connector(), context()->identity(), "views_mus_resources.pak",
std::string(), nullptr, views::AuraInit::Mode::AURA_MUS);
}
void Webtest::OnBindInterface(const service_manager::ServiceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
registry_.BindInterface(source_info.identity, interface_name,
std::move(interface_pipe));
}
void Webtest::Launch(uint32_t what, mojom::LaunchMode how) {
bool reuse = how == mojom::LaunchMode::REUSE ||
how == mojom::LaunchMode::DEFAULT;
if (reuse && !windows_.empty()) {
windows_.back()->Activate();
return;
}
navigation::mojom::ViewFactoryPtr view_factory;
context()->connector()->BindInterface("navigation", &view_factory);
navigation::mojom::ViewPtr view;
navigation::mojom::ViewClientPtr view_client;
navigation::mojom::ViewClientRequest view_client_request(&view_client);
view_factory->CreateView(std::move(view_client), MakeRequest(&view));
UI* ui = new UI(this, std::move(view), std::move(view_client_request));
views::Widget* window = views::Widget::CreateWindowWithContextAndBounds(
ui, nullptr, gfx::Rect(50, 10, 600, 600));
ui->NavigateTo(GURL("http://www.theverge.com/"));
window->Show();
AddWindow(window);
}
void Webtest::Create(const service_manager::Identity& remote_identity,
mojom::LaunchableRequest request) {
bindings_.AddBinding(this, std::move(request));
}
} // namespace webtest
} // namespace mash