Commit 09f2244e authored by Albert Chaulk's avatar Albert Chaulk Committed by Commit Bot

Add a webview service for cast_shell

The client will use GRPC to talk to cast_shell to create and manage
webviews. One RPC corresponds to a given webview and input and
commands and send over this channel. Presentation is handled by
wayland/exo and associating a wayland surface with a webview

TEST=local test w/ desktop cast_shell & wayland_fullscreen_client
BUG=b/132811925

Change-Id: I8f0da747805973174c46f1d824758c6c2ee04674
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1678288
Commit-Queue: Albert Chaulk <achaulk@chromium.org>
Reviewed-by: default avatarYuwei Huang <yuweih@chromium.org>
Reviewed-by: default avatarJoe Downing <joedow@chromium.org>
Reviewed-by: default avatarDaniele Castagna <dcastagna@chromium.org>
Reviewed-by: default avatarDaniel Nicoara <dnicoara@chromium.org>
Cr-Commit-Position: refs/heads/master@{#678456}
parent d88ca476
...@@ -381,8 +381,16 @@ cast_source_set("browser") { ...@@ -381,8 +381,16 @@ cast_source_set("browser") {
"exo/wayland_server_controller.h", "exo/wayland_server_controller.h",
"exo/wm_helper_cast_shell.cc", "exo/wm_helper_cast_shell.cc",
"exo/wm_helper_cast_shell.h", "exo/wm_helper_cast_shell.h",
] "webview/webview_controller.cc",
"webview/webview_controller.h",
"webview/webview_grpc_service.cc",
"webview/webview_grpc_service.h",
"webview/webview_layout_manager.cc",
"webview/webview_layout_manager.h",
]
configs += [ "//third_party/grpc:grpc_config" ]
deps += [ deps += [
"//chromecast/browser/webview/proto",
"//components/exo", "//components/exo",
"//components/exo/wayland", "//components/exo/wayland",
"//services/viz/privileged/interfaces/compositing", "//services/viz/privileged/interfaces/compositing",
......
include_rules = [
"+components/exo",
"+third_party/grpc",
]
# 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.
import("//third_party/grpc/grpc_library.gni")
cc_grpc_library("proto") {
sources = [
"webview.proto",
]
}
// 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.
// This provides an API to create and control webviews via gRPC.
// Each webview is a separate bidirectional message stream, the client creates
// a new one by sending a WebviewCreate message first. Subsequently, the client
// navigates and injects input as desired and the server will respond with
// event messages whenever page state changes, whether or not in direct response
// to client actions, eg if the renderer crashes.
syntax = "proto3";
option optimize_for = LITE_RUNTIME;
package chromecast.webview;
message AccessibilityTreeInfo {
string ax_tree_id = 1;
}
// Create a new, empty webview
message WebviewCreateRequest {
// This identifies the surface that this webview will display into.
// It should be unique and the same as whatever was set into
// |aura_surface_set_client_surface_id| on the wayland surface.
// It is an error to attempt to create a webview if the surface
// does not yet exist.
int32 webview_id = 1;
// This is the cast window ID that will be assigned to the web contents
// window.
int32 window_id = 2;
}
message WebviewCreateResponse {
AccessibilityTreeInfo accessibility_info = 1;
}
// These are a translation of ui::Event and children.
message KeyInput {
int32 key_code = 1;
int32 dom_code = 2;
int32 dom_key = 3;
bool is_char = 4;
}
message TouchInput {
float x = 1;
float y = 2;
float root_x = 3;
float root_y = 4;
int32 pointer_type = 5;
int32 pointer_id = 6;
float radius_x = 7;
float radius_y = 8;
float force = 9;
float twist = 10;
float tilt_x = 11;
float tilt_y = 12;
float tangential_pressure = 13;
}
message MouseEvent {
float x = 1;
float y = 2;
float root_x = 3;
float root_y = 4;
int32 changed_button_flags = 5;
}
message InputEvent {
int32 event_type = 1;
int32 flags = 2;
int64 timestamp = 3;
KeyInput key = 4;
TouchInput touch = 5;
MouseEvent mouse = 6;
}
// Navigate this webview to the provided url.
message NavigateRequest {
string url = 1;
}
message AsyncPageEvent {
enum State {
IDLE = 0;
LOADING = 1;
LOADED = 2;
CLOSED = 3;
DESTROYED = 4;
ERROR = 5;
}
// This is always set to the current state.
State current_page_state = 1;
// These will be set if the event just happened.
int32 stopped_error_code = 2;
bool resource_load_failed = 3;
bool did_first_visually_non_empty_paint = 4;
}
message StopPageRequest {
int32 error_code = 1;
}
message WebviewRequest {
oneof type {
// This must be the first message.
WebviewCreateRequest create = 1;
// No response.
InputEvent input = 2;
// Expect page events to follow.
NavigateRequest navigate = 3;
// Expect page events to follow.
StopPageRequest stop_page = 4;
}
}
message WebviewResponse {
oneof type {
WebviewCreateResponse create_response = 1;
AsyncPageEvent page_event = 2;
}
}
service WebviewService {
rpc CreateWebview(stream WebviewRequest) returns (stream WebviewResponse);
}
// 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 "chromecast/browser/webview/webview_controller.h"
#include "chromecast/base/version.h"
#include "chromecast/browser/cast_web_contents_impl.h"
#include "chromecast/browser/webview/proto/webview.pb.h"
#include "chromecast/browser/webview/webview_layout_manager.h"
#include "content/public/browser/web_contents.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
#include "ui/events/event.h"
namespace chromecast {
WebviewController::WebviewController(content::BrowserContext* browser_context,
Client* client)
: client_(client) {
content::WebContents::CreateParams create_params(browser_context, nullptr);
contents_ = content::WebContents::Create(create_params);
CastWebContents::InitParams cast_contents_init;
cast_contents_init.is_root_window = true;
cast_contents_init.enabled_for_dev = CAST_IS_DEBUG_BUILD();
cast_contents_init.delegate = this;
cast_web_contents_ = std::make_unique<CastWebContentsImpl>(
contents_.get(), cast_contents_init);
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
auto ax_id = contents_->GetMainFrame()->GetAXTreeID().ToString();
response->mutable_create_response()
->mutable_accessibility_info()
->set_ax_tree_id(ax_id);
client->EnqueueSend(std::move(response));
}
WebviewController::~WebviewController() {}
void WebviewController::ProcessRequest(const webview::WebviewRequest& request) {
switch (request.type_case()) {
case webview::WebviewRequest::kInput:
ProcessInputEvent(request.input());
break;
case webview::WebviewRequest::kNavigate:
if (request.has_navigate()) {
LOG(INFO) << "Navigate webview to " << request.navigate().url();
stopped_ = false;
cast_web_contents_->LoadUrl(GURL(request.navigate().url()));
} else {
client_->OnError("navigate() not supplied");
}
break;
case webview::WebviewRequest::kStopPage:
if (request.has_stop_page()) {
cast_web_contents_->Stop(request.stop_page().error_code());
} else {
client_->OnError("stop_page() not supplied");
}
break;
default:
client_->OnError("Unknown request code");
break;
}
}
void WebviewController::ClosePage() {
cast_web_contents_->ClosePage();
}
void WebviewController::AttachTo(aura::Window* window, int window_id) {
auto* contents_window = contents_->GetNativeView();
window->SetLayoutManager(new WebviewLayoutManager(contents_window));
contents_window->set_id(window_id);
contents_window->SetBounds(gfx::Rect(window->bounds().size()));
contents_window->Show();
window->AddChild(contents_->GetNativeView());
}
void WebviewController::ProcessInputEvent(const webview::InputEvent& ev) {
ui::EventHandler* handler = contents_->GetNativeView()->delegate();
ui::EventType type = static_cast<ui::EventType>(ev.event_type());
switch (type) {
case ui::ET_TOUCH_RELEASED:
case ui::ET_TOUCH_PRESSED:
case ui::ET_TOUCH_MOVED:
case ui::ET_TOUCH_CANCELLED:
if (ev.has_touch()) {
auto& touch = ev.touch();
ui::TouchEvent evt(
type, gfx::PointF(touch.x(), touch.y()),
gfx::PointF(touch.root_x(), touch.root_y()),
base::TimeTicks() +
base::TimeDelta::FromMicroseconds(ev.timestamp()),
ui::PointerDetails(
static_cast<ui::EventPointerType>(touch.pointer_type()),
static_cast<ui::PointerId>(touch.pointer_id()),
touch.radius_x(), touch.radius_y(), touch.force(),
touch.twist(), touch.tilt_x(), touch.tilt_y(),
touch.tangential_pressure()),
ev.flags());
handler->OnTouchEvent(&evt);
} else {
client_->OnError("touch() not supplied for touch event");
}
break;
case ui::ET_MOUSE_PRESSED:
case ui::ET_MOUSE_DRAGGED:
case ui::ET_MOUSE_RELEASED:
case ui::ET_MOUSE_MOVED:
case ui::ET_MOUSE_ENTERED:
case ui::ET_MOUSE_EXITED:
case ui::ET_MOUSEWHEEL:
case ui::ET_MOUSE_CAPTURE_CHANGED:
if (ev.has_mouse()) {
auto& mouse = ev.mouse();
ui::MouseEvent evt(
type, gfx::PointF(mouse.x(), mouse.y()),
gfx::PointF(mouse.root_x(), mouse.root_y()),
base::TimeTicks() +
base::TimeDelta::FromMicroseconds(ev.timestamp()),
ev.flags(), mouse.changed_button_flags());
handler->OnMouseEvent(&evt);
} else {
client_->OnError("mouse() not supplied for mouse event");
}
break;
default:
break;
}
}
webview::AsyncPageEvent_State WebviewController::current_state() {
// The PB enum is defined identically.
return static_cast<webview::AsyncPageEvent_State>(
cast_web_contents_->page_state());
}
void WebviewController::OnPageStateChanged(CastWebContents* cast_web_contents) {
if (client_) {
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
auto* event = response->mutable_page_event();
event->set_current_page_state(current_state());
client_->EnqueueSend(std::move(response));
}
}
void WebviewController::OnPageStopped(CastWebContents* cast_web_contents,
int error_code) {
stopped_ = true;
if (client_) {
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
auto* event = response->mutable_page_event();
event->set_current_page_state(current_state());
event->set_stopped_error_code(error_code);
client_->EnqueueSend(std::move(response));
} else {
// Can't destroy in an observer callback, so post a task to do it.
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
}
}
void WebviewController::ResourceLoadFailed(CastWebContents* cast_web_contents) {
if (client_) {
std::unique_ptr<webview::WebviewResponse> response =
std::make_unique<webview::WebviewResponse>();
auto* event = response->mutable_page_event();
event->set_current_page_state(current_state());
event->set_resource_load_failed(true);
client_->EnqueueSend(std::move(response));
}
}
void WebviewController::Destroy() {
// This webview is now abandoned and should close.
client_ = nullptr;
if (stopped_) {
// If the page has been stopped this can be deleted immediately.
delete this;
} else {
// This will eventually call OnPageStopped.
cast_web_contents_->ClosePage();
}
}
} // namespace chromecast
// 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.
#ifndef CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_CONTROLLER_H_
#define CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_CONTROLLER_H_
#include <memory>
#include <string>
#include "chromecast/browser/cast_web_contents.h"
#include "chromecast/browser/webview/proto/webview.pb.h"
namespace aura {
class Window;
} // namespace aura
namespace chromecast {
class CastWebContents;
} // namespace chromecast
namespace content {
class BrowserContext;
class WebContents;
} // namespace content
namespace chromecast {
// This owns a WebContents and CastWebContents and processes proto commands
// to allow the web contents to be controlled and embedded.
class WebviewController : public CastWebContents::Delegate,
public CastWebContents::Observer {
public:
class Client {
public:
virtual ~Client() {}
virtual void EnqueueSend(
std::unique_ptr<webview::WebviewResponse> response) = 0;
virtual void OnError(const std::string& error_message) = 0;
};
WebviewController(content::BrowserContext* browser_context, Client* client);
~WebviewController() override;
// Cause the controller to be destroyed after giving the webpage a chance to
// run unload events. This unsets the client so no more messages will be
// sent.
void Destroy();
// Close the page. This will cause a stopped response to eventually be sent.
void ClosePage();
void ProcessRequest(const webview::WebviewRequest& request);
// Attach this web contents to an aura window as a child.
void AttachTo(aura::Window* window, int window_id);
private:
webview::AsyncPageEvent_State current_state();
void ProcessInputEvent(const webview::InputEvent& ev);
bool Check(bool condition, const char* error);
// CastWebContents::Delegate
void OnPageStateChanged(CastWebContents* cast_web_contents) override;
void OnPageStopped(CastWebContents* cast_web_contents,
int error_code) override;
// CastWebContents::Observer
void ResourceLoadFailed(CastWebContents* cast_web_contents) override;
Client* client_; // Not owned.
std::unique_ptr<content::WebContents> contents_;
std::unique_ptr<CastWebContents> cast_web_contents_;
bool stopped_ = false;
DISALLOW_COPY_AND_ASSIGN(WebviewController);
};
} // namespace chromecast
#endif // CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_CONTROLLER_H_
// 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 "chromecast/browser/webview/webview_grpc_service.h"
#include <deque>
#include <mutex>
#include "base/bind.h"
#include "base/callback.h"
#include "chromecast/browser/cast_browser_context.h"
#include "chromecast/browser/cast_browser_process.h"
#include "chromecast/browser/webview/webview_controller.h"
#include "components/exo/surface.h"
#include "components/exo/wm_helper.h"
#include "third_party/grpc/src/include/grpcpp/grpcpp.h"
#include "third_party/grpc/src/include/grpcpp/security/server_credentials.h"
#include "third_party/grpc/src/include/grpcpp/server_builder.h"
namespace chromecast {
namespace {
aura::Window* FindChildWindowWithID(aura::Window* window, int id) {
if (window->GetProperty(exo::kClientSurfaceIdKey) == id)
return window;
for (auto* w : window->children()) {
auto* ret = FindChildWindowWithID(w, id);
if (ret)
return ret;
}
return nullptr;
}
typedef base::RepeatingCallback<void(bool)> GrpcCallback;
// Threading model and life cycle.
// WebviewRpcInstance creates copies of itself and deletes itself as needed.
// Instances are deleted when the GRPC Finish request completes and there are
// no other outstanding read or write operations.
// Deletion bounces off the webview thread to synchronize with request
// processing.
class WebviewRpcInstance : public WebviewController::Client {
public:
WebviewRpcInstance(webview::WebviewService::AsyncService* service,
grpc::ServerCompletionQueue* cq,
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
~WebviewRpcInstance() override;
private:
void InitComplete(bool ok);
void ReadComplete(bool ok);
void WriteComplete(bool ok);
void FinishComplete(bool ok);
bool Initialize();
void StartRead();
void CreateWebview(int app_id, int window_id);
void ProcessRequestOnWebviewThread(
std::unique_ptr<webview::WebviewRequest> request);
void EnqueueSend(std::unique_ptr<webview::WebviewResponse> response) override;
void OnError(const std::string& error_message) override;
GrpcCallback init_callback_;
GrpcCallback read_callback_;
GrpcCallback write_callback_;
GrpcCallback destroy_callback_;
grpc::ServerContext ctx_;
webview::WebviewService::AsyncService* service_;
grpc::ServerCompletionQueue* cq_;
std::unique_ptr<webview::WebviewRequest> request_;
grpc::ServerAsyncReaderWriter<webview::WebviewResponse,
webview::WebviewRequest>
io_;
std::unique_ptr<WebviewController> webview_;
std::mutex send_lock_;
bool errored_ = false;
std::string error_message_;
bool send_pending_ = false;
bool destroying_ = false;
std::deque<std::unique_ptr<webview::WebviewResponse>> pending_messages_;
grpc::WriteOptions write_options_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(WebviewRpcInstance);
};
WebviewRpcInstance::WebviewRpcInstance(
webview::WebviewService::AsyncService* service,
grpc::ServerCompletionQueue* cq,
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: service_(service), cq_(cq), io_(&ctx_), task_runner_(task_runner) {
write_options_.clear_buffer_hint();
write_options_.clear_corked();
init_callback_ = base::BindRepeating(&WebviewRpcInstance::InitComplete,
base::Unretained(this));
read_callback_ = base::BindRepeating(&WebviewRpcInstance::ReadComplete,
base::Unretained(this));
write_callback_ = base::BindRepeating(&WebviewRpcInstance::WriteComplete,
base::Unretained(this));
destroy_callback_ = base::BindRepeating(&WebviewRpcInstance::FinishComplete,
base::Unretained(this));
service_->RequestCreateWebview(&ctx_, &io_, cq_, cq_, &init_callback_);
}
WebviewRpcInstance::~WebviewRpcInstance() {
DCHECK(destroying_);
if (webview_) {
webview_.release()->Destroy();
}
}
void WebviewRpcInstance::FinishComplete(bool ok) {
// Bounce off of the webview thread to allow it to complete any pending work.
destroying_ = true;
if (!send_pending_) {
task_runner_->DeleteSoon(FROM_HERE, this);
}
}
void WebviewRpcInstance::ProcessRequestOnWebviewThread(
std::unique_ptr<webview::WebviewRequest> request) {
webview_->ProcessRequest(*request.get());
}
void WebviewRpcInstance::InitComplete(bool ok) {
request_ = std::make_unique<webview::WebviewRequest>();
io_.Read(request_.get(), &read_callback_);
// Create a new instance to handle new requests.
// Instances of this class delete themselves.
new WebviewRpcInstance(service_, cq_, task_runner_);
}
void WebviewRpcInstance::ReadComplete(bool ok) {
if (!ok) {
io_.Finish(grpc::Status(), &destroy_callback_);
} else if (webview_) {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&WebviewRpcInstance::ProcessRequestOnWebviewThread,
base::Unretained(this),
base::Passed(std::move(request_))));
request_ = std::make_unique<webview::WebviewRequest>();
io_.Read(request_.get(), &read_callback_);
} else if (!Initialize()) {
io_.Finish(grpc::Status(grpc::FAILED_PRECONDITION, "Failed initialization"),
&destroy_callback_);
}
// In this case initialization is pending and the main webview thread will
// start the first read.
}
bool WebviewRpcInstance::Initialize() {
if (request_->type_case() != webview::WebviewRequest::kCreate)
return false;
// This needs to be done on a valid thread.
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&WebviewRpcInstance::CreateWebview, base::Unretained(this),
request_->create().webview_id(),
request_->create().window_id()));
return true;
}
void WebviewRpcInstance::CreateWebview(int app_id, int window_id) {
auto* root_window =
exo::WMHelper::GetInstance()->GetRootWindowForNewWindows();
auto* surface_window = FindChildWindowWithID(root_window, app_id);
if (!surface_window) {
OnError("Failed to find valid surface to display webview on");
return;
}
content::BrowserContext* browser_context =
shell::CastBrowserProcess::GetInstance()->browser_context();
webview_ = std::make_unique<WebviewController>(browser_context, this);
webview_->AttachTo(surface_window, window_id);
// Begin reading again.
io_.Read(request_.get(), &read_callback_);
}
void WebviewRpcInstance::WriteComplete(bool ok) {
std::unique_lock<std::mutex> l(send_lock_);
send_pending_ = false;
if (destroying_) {
// It is possible for the read & finish to complete while a write is
// outstanding, in that case just re-call it to delete this instance.
FinishComplete(true);
} else if (errored_) {
io_.Finish(grpc::Status(grpc::UNKNOWN, error_message_), &destroy_callback_);
} else if (!pending_messages_.empty()) {
send_pending_ = true;
io_.Write(*pending_messages_.front().get(), write_options_,
&write_callback_);
pending_messages_.pop_front();
}
}
void WebviewRpcInstance::EnqueueSend(
std::unique_ptr<webview::WebviewResponse> response) {
std::unique_lock<std::mutex> l(send_lock_);
if (errored_ || destroying_)
return;
if (!send_pending_ && pending_messages_.empty()) {
send_pending_ = true;
io_.Write(*response.get(), write_options_, &write_callback_);
} else {
pending_messages_.emplace_back(std::move(response));
}
}
void WebviewRpcInstance::OnError(const std::string& error_message) {
std::unique_lock<std::mutex> l(send_lock_);
errored_ = true;
error_message_ = error_message;
if (!send_pending_)
io_.Finish(grpc::Status(grpc::UNKNOWN, error_message_), &destroy_callback_);
send_pending_ = true;
}
} // namespace
WebviewAsyncService::WebviewAsyncService(
scoped_refptr<base::SingleThreadTaskRunner> webview_task_runner)
: webview_task_runner_(std::move(webview_task_runner)) {}
WebviewAsyncService::~WebviewAsyncService() {
if (server_) {
server_->Shutdown();
cq_->Shutdown();
base::PlatformThread::Join(rpc_thread_);
}
}
void WebviewAsyncService::StartWithSocket(const base::FilePath& socket_path) {
DCHECK(!server_.get());
grpc::ServerBuilder builder;
builder.AddListeningPort("unix:" + socket_path.value(),
grpc::InsecureServerCredentials());
builder.RegisterService(&service_);
cq_ = builder.AddCompletionQueue();
server_ = builder.BuildAndStart();
base::PlatformThread::Create(0, this, &rpc_thread_);
}
void WebviewAsyncService::ThreadMain() {
base::PlatformThread::SetName("CastWebviewGrpcMessagePump");
void* tag;
bool ok;
// This self-deletes.
new WebviewRpcInstance(&service_, cq_.get(), webview_task_runner_);
// This thread is joined when this service is destroyed.
while (cq_->Next(&tag, &ok)) {
reinterpret_cast<GrpcCallback*>(tag)->Run(ok);
}
}
} // namespace chromecast
// 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.
#ifndef CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_GRPC_SERVICE_H_
#define CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_GRPC_SERVICE_H_
#include <string>
#include "base/files/file_path.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromecast/browser/webview/proto/webview.grpc.pb.h"
#include "third_party/grpc/src/include/grpcpp/server.h"
namespace chromecast {
// This is a service that provides a GRPC interface to create and control
// webviews. See the proto file for commands.
class WebviewAsyncService : public base::PlatformThread::Delegate {
public:
explicit WebviewAsyncService(
scoped_refptr<base::SingleThreadTaskRunner> webview_task_runner);
~WebviewAsyncService() override;
// Start the server listening on an address, eg "localhost:12345".
void StartWithSocket(const base::FilePath& socket_path);
private:
void ThreadMain() override;
base::PlatformThreadHandle rpc_thread_;
scoped_refptr<base::SingleThreadTaskRunner> webview_task_runner_;
std::unique_ptr<grpc::ServerCompletionQueue> cq_;
webview::WebviewService::AsyncService service_;
std::unique_ptr<grpc::Server> server_;
DISALLOW_COPY_AND_ASSIGN(WebviewAsyncService);
};
} // namespace chromecast
#endif // CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_GRPC_SERVICE_H_
// 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 "chromecast/browser/webview/webview_layout_manager.h"
#include "ui/aura/window.h"
namespace chromecast {
WebviewLayoutManager::WebviewLayoutManager(aura::Window* web_contents_window)
: web_contents_window_(web_contents_window) {}
WebviewLayoutManager::~WebviewLayoutManager() {}
void WebviewLayoutManager::OnWindowResized() {
web_contents_window_->SetBounds(web_contents_window_->parent()->bounds());
}
void WebviewLayoutManager::OnWindowAddedToLayout(aura::Window* child) {}
void WebviewLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {}
void WebviewLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {}
void WebviewLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
bool visible) {}
void WebviewLayoutManager::SetChildBounds(aura::Window* child,
const gfx::Rect& requested_bounds) {
SetChildBoundsDirect(child, requested_bounds);
}
} // namespace chromecast
// 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.
#ifndef CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_LAYOUT_MANAGER_H_
#define CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_LAYOUT_MANAGER_H_
#include "base/macros.h"
#include "ui/aura/layout_manager.h"
namespace chromecast {
// Resizes the provided window to be the parent window's size.
class WebviewLayoutManager : public aura::LayoutManager {
public:
explicit WebviewLayoutManager(aura::Window* web_contents_window);
~WebviewLayoutManager() override;
void OnWindowResized() override;
void OnWindowAddedToLayout(aura::Window* child) override;
void OnWillRemoveWindowFromLayout(aura::Window* child) override;
void OnWindowRemovedFromLayout(aura::Window* child) override;
void OnChildWindowVisibilityChanged(aura::Window* child,
bool visible) override;
void SetChildBounds(aura::Window* child,
const gfx::Rect& requested_bounds) override;
private:
aura::Window* web_contents_window_;
DISALLOW_COPY_AND_ASSIGN(WebviewLayoutManager);
};
} // namespace chromecast
#endif // CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_LAYOUT_MANAGER_H_
...@@ -33,8 +33,11 @@ config("nanopb_config") { ...@@ -33,8 +33,11 @@ config("nanopb_config") {
# The gRPC library. Note that server side code will not be built. You probably # The gRPC library. Note that server side code will not be built. You probably
# want to use cc_grpc_library() from grpc_library.gni directly. # want to use cc_grpc_library() from grpc_library.gni directly.
static_library("grpcpp") { static_library("grpcpp") {
# This is currently only used by remoting. # This is currently only used by remoting and chromecast.
visibility = [ "//remoting/*" ] visibility = [
"//chromecast/*",
"//remoting/*",
]
sources = [ sources = [
"src/src/cpp/client/channel_cc.cc", "src/src/cpp/client/channel_cc.cc",
"src/src/cpp/client/client_context.cc", "src/src/cpp/client/client_context.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment