Commit 11a39b97 authored by Daniel Nicoara's avatar Daniel Nicoara Committed by Commit Bot

cast: webview: Add window manager to handle EXO windows

The Webview WebContents and the aura::Window it attaches to are not
created in the same place and there is a disconnect between how the EXO
window is created and how the Webview is created.

Webview creation event results in a request to create an EXO window.
Thus WebviewRpcInstance doesn't have a window to display in until the
client creates an EXO window with the appropriate ID. There needs
to be a way to listen for window events to discover the EXO window
hosting the Webview. WebviewWindowManager listens for new
aura::Windows to be created and registers as an observer on them to
find windows with the exo::kClientSurfaceIdKey property. The ID is then
used to find the Webview that will be attached to the window.

BUG=b/132811925
TEST=Compiled

Change-Id: I053e2b792b311f0c95e791ef5c70a9e18b24f5ba
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1803957
Commit-Queue: Daniel Nicoara <dnicoara@chromium.org>
Reviewed-by: default avatarAlex Sakhartchouk <alexst@chromium.org>
Cr-Commit-Position: refs/heads/master@{#696906}
parent 77778c68
......@@ -386,6 +386,8 @@ cast_source_set("browser") {
"webview/webview_grpc_service.h",
"webview/webview_layout_manager.cc",
"webview/webview_layout_manager.h",
"webview/webview_window_manager.cc",
"webview/webview_window_manager.h",
]
configs += [ "//third_party/grpc:grpc_config" ]
deps += [
......
......@@ -12,8 +12,6 @@
#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"
......@@ -21,17 +19,6 @@
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.
......@@ -40,11 +27,13 @@ typedef base::RepeatingCallback<void(bool)> GrpcCallback;
// no other outstanding read or write operations.
// Deletion bounces off the webview thread to synchronize with request
// processing.
class WebviewRpcInstance : public WebviewController::Client {
class WebviewRpcInstance : public WebviewController::Client,
public WebviewWindowManager::Observer {
public:
WebviewRpcInstance(webview::WebviewService::AsyncService* service,
grpc::ServerCompletionQueue* cq,
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
WebviewWindowManager* window_manager);
~WebviewRpcInstance() override;
private:
......@@ -60,9 +49,13 @@ class WebviewRpcInstance : public WebviewController::Client {
void ProcessRequestOnWebviewThread(
std::unique_ptr<webview::WebviewRequest> request);
// WebviewController::Client:
void EnqueueSend(std::unique_ptr<webview::WebviewResponse> response) override;
void OnError(const std::string& error_message) override;
// WebviewWindowManager::Observer:
void OnNewWebviewContainerWindow(aura::Window* window, int app_id) override;
GrpcCallback init_callback_;
GrpcCallback read_callback_;
GrpcCallback write_callback_;
......@@ -87,14 +80,24 @@ class WebviewRpcInstance : public WebviewController::Client {
grpc::WriteOptions write_options_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
WebviewWindowManager* window_manager_;
int app_id_ = 0;
int window_id_ = 0;
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) {
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
WebviewWindowManager* window_manager)
: service_(service),
cq_(cq),
io_(&ctx_),
task_runner_(task_runner),
window_manager_(window_manager) {
write_options_.clear_buffer_hint();
write_options_.clear_corked();
......@@ -108,6 +111,7 @@ WebviewRpcInstance::WebviewRpcInstance(
base::Unretained(this));
service_->RequestCreateWebview(&ctx_, &io_, cq_, cq_, &init_callback_);
window_manager_->AddObserver(this);
}
WebviewRpcInstance::~WebviewRpcInstance() {
......@@ -115,6 +119,8 @@ WebviewRpcInstance::~WebviewRpcInstance() {
if (webview_) {
webview_.release()->Destroy();
}
window_manager_->RemoveObserver(this);
}
void WebviewRpcInstance::FinishComplete(bool ok) {
......@@ -136,7 +142,7 @@ void WebviewRpcInstance::InitComplete(bool ok) {
// Create a new instance to handle new requests.
// Instances of this class delete themselves.
new WebviewRpcInstance(service_, cq_, task_runner_);
new WebviewRpcInstance(service_, cq_, task_runner_, window_manager_);
}
void WebviewRpcInstance::ReadComplete(bool ok) {
......@@ -173,18 +179,12 @@ bool WebviewRpcInstance::Initialize() {
}
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;
}
app_id_ = app_id;
window_id_ = window_id;
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_);
......@@ -230,6 +230,17 @@ void WebviewRpcInstance::OnError(const std::string& error_message) {
send_pending_ = true;
}
void WebviewRpcInstance::OnNewWebviewContainerWindow(aura::Window* window,
int app_id) {
if (app_id != app_id_)
return;
webview_->AttachTo(window, window_id_);
// The Webview is attached! No reason to keep on listening for window property
// updates.
window_manager_->RemoveObserver(this);
}
} // namespace
WebviewAsyncService::WebviewAsyncService(
......@@ -252,7 +263,8 @@ void WebviewAsyncService::ThreadMain() {
void* tag;
bool ok;
// This self-deletes.
new WebviewRpcInstance(service_.get(), cq_.get(), ui_task_runner_);
new WebviewRpcInstance(service_.get(), cq_.get(), ui_task_runner_,
&window_manager_);
// This thread is joined when this service is destroyed.
while (cq_->Next(&tag, &ok)) {
reinterpret_cast<GrpcCallback*>(tag)->Run(ok);
......
......@@ -11,6 +11,7 @@
#include "base/threading/platform_thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromecast/browser/webview/proto/webview.grpc.pb.h"
#include "chromecast/browser/webview/webview_window_manager.h"
#include "third_party/grpc/src/include/grpcpp/server.h"
namespace chromecast {
......@@ -38,6 +39,8 @@ class WebviewAsyncService : public base::PlatformThread::Delegate {
std::unique_ptr<grpc::ServerCompletionQueue> cq_;
std::unique_ptr<webview::WebviewService::AsyncService> service_;
WebviewWindowManager window_manager_;
DISALLOW_COPY_AND_ASSIGN(WebviewAsyncService);
};
......
// 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_window_manager.h"
#include "components/exo/shell_surface_util.h"
#include "components/exo/surface.h"
#include "ui/aura/env.h"
namespace chromecast {
WebviewWindowManager::WebviewWindowManager() {
aura::Env::GetInstance()->AddObserver(this);
}
WebviewWindowManager::~WebviewWindowManager() {
aura::Env::GetInstance()->RemoveObserver(this);
}
void WebviewWindowManager::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void WebviewWindowManager::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void WebviewWindowManager::OnWindowInitialized(aura::Window* window) {
observed_windows_.push_back(window);
window->AddObserver(this);
}
void WebviewWindowManager::OnWindowDestroying(aura::Window* window) {
window->RemoveObserver(this);
auto it =
std::find(observed_windows_.begin(), observed_windows_.end(), window);
DCHECK(it != observed_windows_.end());
observed_windows_.erase(it);
}
void WebviewWindowManager::OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) {
if (key != exo::kClientSurfaceIdKey)
return;
int app_id = window->GetProperty(exo::kClientSurfaceIdKey);
LOG(INFO) << "Found window for webview " << app_id;
for (auto& observer : observers_)
observer.OnNewWebviewContainerWindow(window, app_id);
}
} // 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_WINDOW_MANAGER_H_
#define CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_WINDOW_MANAGER_H_
#include "base/observer_list.h"
#include "ui/aura/env_observer.h"
#include "ui/aura/window_observer.h"
namespace chromecast {
// Keeps track of new aura::Windows and listen for window property events to
// find Exo windows with the |exo::kClientSurfaceIdKey| property set.
class WebviewWindowManager : public aura::EnvObserver,
public aura::WindowObserver {
public:
class Observer {
public:
virtual ~Observer() = default;
// Notifies the observer when a window's |exo::kClientSurfaceIdKey| property
// is updated.
virtual void OnNewWebviewContainerWindow(aura::Window* window,
int app_id) = 0;
};
WebviewWindowManager();
~WebviewWindowManager() override;
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
private:
void OnWindowInitialized(aura::Window* window) override;
void OnWindowDestroying(aura::Window* window) override;
void OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) override;
std::vector<aura::Window*> observed_windows_;
base::ObserverList<Observer>::Unchecked observers_;
DISALLOW_COPY_AND_ASSIGN(WebviewWindowManager);
};
} // namespace chromecast
#endif // CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_WINDOW_MANAGER_H_
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