Commit b9d7693b authored by Xiyuan Xia's avatar Xiyuan Xia Committed by Commit Bot

RemoteViewHost embeds after added to a widget

The embedding aura::Window must be attached to a root window so that
window server could figure out the correct display and pass it to the
other side. Deferring the EmbedUsingToken call until RemoteViewHost
is added to a widget.

Bug: 812434
Change-Id: Ie65d12d8b883b1a74426c33c3f106bbb637c0f69
Reviewed-on: https://chromium-review.googlesource.com/998498Reviewed-by: default avatarScott Violet <sky@chromium.org>
Commit-Queue: Xiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548529}
parent 3d1aabcb
...@@ -24,9 +24,21 @@ void RemoteViewHost::EmbedUsingToken(const base::UnguessableToken& embed_token, ...@@ -24,9 +24,21 @@ void RemoteViewHost::EmbedUsingToken(const base::UnguessableToken& embed_token,
// Only works with mus. // Only works with mus.
DCHECK_EQ(aura::Env::Mode::MUS, aura::Env::GetInstanceDontCreate()->mode()); DCHECK_EQ(aura::Env::Mode::MUS, aura::Env::GetInstanceDontCreate()->mode());
embed_token_ = embed_token;
embed_flags_ = embed_flags;
embed_callback_ = std::move(callback);
if (GetWidget())
CreateEmbeddingRoot();
}
void RemoteViewHost::CreateEmbeddingRoot() {
// Should not be attached to anything. // Should not be attached to anything.
DCHECK(!native_view()); DCHECK(!native_view());
// There is a pending embed request.
DCHECK(!embed_token_.is_empty());
embedding_root_ = std::make_unique<aura::Window>(nullptr); embedding_root_ = std::make_unique<aura::Window>(nullptr);
embedding_root_->set_owned_by_parent(false); embedding_root_->set_owned_by_parent(false);
...@@ -36,33 +48,29 @@ void RemoteViewHost::EmbedUsingToken(const base::UnguessableToken& embed_token, ...@@ -36,33 +48,29 @@ void RemoteViewHost::EmbedUsingToken(const base::UnguessableToken& embed_token,
embedding_root_->SetType(aura::client::WINDOW_TYPE_CONTROL); embedding_root_->SetType(aura::client::WINDOW_TYPE_CONTROL);
embedding_root_->Init(ui::LAYER_NOT_DRAWN); embedding_root_->Init(ui::LAYER_NOT_DRAWN);
// Must happen before EmbedUsingToken call for window server to figure out
// the relevant display.
Attach(embedding_root_.get());
aura::WindowPortMus::Get(embedding_root_.get()) aura::WindowPortMus::Get(embedding_root_.get())
->EmbedUsingToken(embed_token, embed_flags, ->EmbedUsingToken(embed_token_, embed_flags_,
base::BindOnce(&RemoteViewHost::OnEmbedResult, base::BindOnce(&RemoteViewHost::OnEmbedResult,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr()));
embed_token, std::move(callback)));
} }
void RemoteViewHost::OnEmbedResult(const base::UnguessableToken& token, void RemoteViewHost::OnEmbedResult(bool success) {
EmbedCallback callback, LOG_IF(ERROR, !success) << "Failed to embed, token=" << embed_token_;
bool success) {
LOG_IF(ERROR, !success) << "Failed to embed, token=" << token;
// Attach to |embedding_root_| if embed succeeds and this view is added to a
// widget but has not yet attached to |embedding_root_|.
if (success && GetWidget() && !native_view())
Attach(embedding_root_.get());
if (!success && embedding_root_) if (!success && embedding_root_)
embedding_root_.reset(); embedding_root_.reset();
if (callback) if (embed_callback_)
std::move(callback).Run(success); std::move(embed_callback_).Run(success);
} }
void RemoteViewHost::AddedToWidget() { void RemoteViewHost::AddedToWidget() {
if (embedding_root_ && !native_view()) if (!native_view() && !embed_token_.is_empty())
Attach(embedding_root_.get()); CreateEmbeddingRoot();
} }
} // namespace views } // namespace views
...@@ -23,25 +23,32 @@ class RemoteViewHost : public views::NativeViewHost { ...@@ -23,25 +23,32 @@ class RemoteViewHost : public views::NativeViewHost {
RemoteViewHost(); RemoteViewHost();
~RemoteViewHost() override; ~RemoteViewHost() override;
// Creates an aura::window to embed the remote contents and attach to it when // Embeds the remote contents after this view is added to a widget.
// the embed succeeds. |embed_token| is the token obtained from the WindowTree // |embed_token| is the token obtained from the WindowTree embed API
// embed API (ScheduleEmbed/ForExistingClient). |embed_flags| are the // (ScheduleEmbed/ForExistingClient). |embed_flags| are the embedding flags
// embedding flags (see window_tree_constants.mojom). |callback| is an // (see window_tree_constants.mojom). |callback| is an optional callback
// optional callback invoked with the embed result. // invoked with the embed result.
// Note that |callback| should not be used to add the view to a widget because
// the actual embedding only happens after the view is added.
using EmbedCallback = base::OnceCallback<void(bool success)>; using EmbedCallback = base::OnceCallback<void(bool success)>;
void EmbedUsingToken(const base::UnguessableToken& embed_token, void EmbedUsingToken(const base::UnguessableToken& embed_token,
int embed_flags, int embed_flags,
EmbedCallback callback); EmbedCallback callback);
private: private:
// Creates the embedding aura::Window and attach to it.
void CreateEmbeddingRoot();
// Invoked after the embed operation. // Invoked after the embed operation.
void OnEmbedResult(const base::UnguessableToken& token, void OnEmbedResult(bool success);
EmbedCallback callback,
bool success);
// views::NativeViewHost: // views::NativeViewHost:
void AddedToWidget() override; void AddedToWidget() override;
base::UnguessableToken embed_token_;
int embed_flags_ = 0;
EmbedCallback embed_callback_;
std::unique_ptr<aura::Window> embedding_root_; std::unique_ptr<aura::Window> embedding_root_;
base::WeakPtrFactory<RemoteViewHost> weak_ptr_factory_{this}; base::WeakPtrFactory<RemoteViewHost> weak_ptr_factory_{this};
......
...@@ -87,13 +87,13 @@ TEST_F(RemoteViewHostTest, BadEmbed) { ...@@ -87,13 +87,13 @@ TEST_F(RemoteViewHostTest, BadEmbed) {
// Ownership will be passed to |widget| later. // Ownership will be passed to |widget| later.
RemoteViewHost* host = new RemoteViewHost(); RemoteViewHost* host = new RemoteViewHost();
std::unique_ptr<views::Widget> widget = CreateTestWidget(host);
EXPECT_FALSE(host->native_view());
// Embed fails with unknown token. // Embed fails with unknown token.
EXPECT_FALSE(Embed(host, unknown_token)); EXPECT_FALSE(Embed(host, unknown_token));
// |host| is not attached before and after adding to a widget. // |host| is not attached after adding to a widget.
EXPECT_FALSE(host->native_view());
std::unique_ptr<views::Widget> widget = CreateTestWidget(host);
EXPECT_FALSE(host->native_view()); EXPECT_FALSE(host->native_view());
} }
...@@ -117,43 +117,34 @@ TEST_F(RemoteViewHostTest, AddToWidgetBeforeEmbed) { ...@@ -117,43 +117,34 @@ TEST_F(RemoteViewHostTest, AddToWidgetBeforeEmbed) {
EXPECT_TRUE(host->native_view()); EXPECT_TRUE(host->native_view());
} }
// Tests when RemoveViewHost is added to a widget while embedding. // Tests when RemoveViewHost is added to a widget after embedding.
TEST_F(RemoteViewHostTest, AddToWidgetWhileEmbedding) { TEST_F(RemoteViewHostTest, AddToWidgetAfterEmbed) {
const base::UnguessableToken token = base::UnguessableToken::Create(); const base::UnguessableToken token = base::UnguessableToken::Create();
window_tree()->AddScheduledEmbedToken(token); window_tree()->AddScheduledEmbedToken(token);
// Ownership will be passed to |widget| later. // Ownership will be passed to |widget| later.
RemoteViewHost* host = new RemoteViewHost(); RemoteViewHost* host = new RemoteViewHost();
// |host| is not attached because embed operation is not performed. // Request embedding but it will be deferred until added to a widget.
EXPECT_FALSE(host->native_view());
base::RunLoop run_loop; base::RunLoop run_loop;
std::unique_ptr<views::Widget> widget; bool embed_result = false;
host->EmbedUsingToken( host->EmbedUsingToken(
token, 0u /* no flags */, token, 0u /* no flags */,
base::BindOnce(&RemoteViewHostTest::CreateTestWidgetWhileEmbeddingHelper, base::BindOnce(
base::Unretained(this), &run_loop, host, &widget)); [](base::RunLoop* run_loop, bool* result, bool success) {
run_loop.Run(); *result = success;
run_loop->Quit();
// |host| is attached to the embedding window. },
EXPECT_TRUE(host->native_view()); &run_loop, &embed_result));
}
// Tests when RemoveViewHost is added to a widget after embedding.
TEST_F(RemoteViewHostTest, AddToWidgetAfterEmbed) {
const base::UnguessableToken token = base::UnguessableToken::Create();
window_tree()->AddScheduledEmbedToken(token);
// Ownership will be passed to |widget| later.
RemoteViewHost* host = new RemoteViewHost();
// Embed succeeds.
EXPECT_TRUE(Embed(host, token));
// |host| is attached after adding to a widget. // |host| is not attached before adding to a widget.
EXPECT_FALSE(host->native_view()); EXPECT_FALSE(host->native_view());
// Add to a widget and wait for embed to finish.
std::unique_ptr<views::Widget> widget = CreateTestWidget(host); std::unique_ptr<views::Widget> widget = CreateTestWidget(host);
run_loop.Run();
// |host| is attached after added to a widget.
EXPECT_TRUE(host->native_view()); EXPECT_TRUE(host->native_view());
} }
......
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