diff options
author | sky <sky@chromium.org> | 2015-06-03 16:00:36 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-03 23:01:03 +0000 |
commit | 8c4fcb30177421448d1558fe7fefdc7a3f95587f (patch) | |
tree | 697438bbd74bca6f15d0d36b2d8b012cfcf1dc9d | |
parent | 9121836d9a7161859eda701a08d667f39d149917 (diff) | |
download | chromium_src-8c4fcb30177421448d1558fe7fefdc7a3f95587f.zip chromium_src-8c4fcb30177421448d1558fe7fefdc7a3f95587f.tar.gz chromium_src-8c4fcb30177421448d1558fe7fefdc7a3f95587f.tar.bz2 |
Provides another Embed() that takes no serviceproviders
This embed also allows an EmbedRoot ancestor to call Embed() in the
view.
BUG=490221
TEST=covered by tests
R=ben@chromium.org
Review URL: https://codereview.chromium.org/1154303006
Cr-Commit-Position: refs/heads/master@{#332717}
13 files changed, 197 insertions, 41 deletions
diff --git a/components/view_manager/default_access_policy.cc b/components/view_manager/default_access_policy.cc index bafbced..b307c55 100644 --- a/components/view_manager/default_access_policy.cc +++ b/components/view_manager/default_access_policy.cc @@ -60,7 +60,9 @@ bool DefaultAccessPolicy::CanDescendIntoViewForViewTree( } bool DefaultAccessPolicy::CanEmbed(const ServerView* view) const { - return WasCreatedByThisConnection(view); + return WasCreatedByThisConnection(view) || + (view->allows_reembed() && + delegate_->IsViewKnownForAccessPolicy(view)); } bool DefaultAccessPolicy::CanChangeViewVisibility( diff --git a/components/view_manager/public/cpp/lib/view.cc b/components/view_manager/public/cpp/lib/view.cc index f4aa435..cc78b6c 100644 --- a/components/view_manager/public/cpp/lib/view.cc +++ b/components/view_manager/public/cpp/lib/view.cc @@ -385,6 +385,13 @@ void View::Embed(ViewManagerClientPtr client) { static_cast<ViewManagerClientImpl*>(manager_)->Embed(id_, client.Pass()); } +void View::EmbedAllowingReembed(mojo::URLRequestPtr request) { + if (PrepareForEmbed()) { + static_cast<ViewManagerClientImpl*>(manager_) + ->EmbedAllowingReembed(request.Pass(), id_); + } +} + //////////////////////////////////////////////////////////////////////////////// // View, protected: @@ -591,8 +598,11 @@ void View::NotifyViewVisibilityChangedUp(View* target) { } bool View::PrepareForEmbed() { - if (!OwnsView(manager_, this)) + // TODO(sky): this check isn't quite enough. See what service does. + if (!OwnsView(manager_, this) && + !static_cast<ViewManagerClientImpl*>(manager_)->is_embed_root()) { return false; + } while (!children_.empty()) RemoveChild(children_[0]); diff --git a/components/view_manager/public/cpp/lib/view_manager_client_impl.cc b/components/view_manager/public/cpp/lib/view_manager_client_impl.cc index 13396ae..4a44f4f 100644 --- a/components/view_manager/public/cpp/lib/view_manager_client_impl.cc +++ b/components/view_manager/public/cpp/lib/view_manager_client_impl.cc @@ -108,7 +108,8 @@ ViewManagerClientImpl::ViewManagerClientImpl( capture_view_(nullptr), focused_view_(nullptr), activated_view_(nullptr), - binding_(this, request.Pass()) { + binding_(this, request.Pass()), + is_embed_root_(false) { } ViewManagerClientImpl::~ViewManagerClientImpl() { @@ -221,6 +222,13 @@ void ViewManagerClientImpl::Embed(Id view_id, ViewManagerClientPtr client) { service_->Embed(view_id, client.Pass(), ActionCompletedCallback()); } +void ViewManagerClientImpl::EmbedAllowingReembed(mojo::URLRequestPtr request, + Id view_id) { + DCHECK(service_); + service_->EmbedAllowingReembed(request.Pass(), view_id, + ActionCompletedCallback()); +} + void ViewManagerClientImpl::AddView(View* view) { DCHECK(views_.find(view->id()) == views_.end()); views_[view->id()] = view; @@ -278,6 +286,8 @@ View* ViewManagerClientImpl::CreateView() { } void ViewManagerClientImpl::SetEmbedRoot() { + // TODO(sky): this isn't right. The server may ignore the call. + is_embed_root_ = true; service_->SetEmbedRoot(); } diff --git a/components/view_manager/public/cpp/lib/view_manager_client_impl.h b/components/view_manager/public/cpp/lib/view_manager_client_impl.h index f848028..b2e7f64 100644 --- a/components/view_manager/public/cpp/lib/view_manager_client_impl.h +++ b/components/view_manager/public/cpp/lib/view_manager_client_impl.h @@ -59,6 +59,7 @@ class ViewManagerClientImpl : public ViewManager, InterfaceRequest<ServiceProvider> services, ServiceProviderPtr exposed_services); void Embed(Id view_id, ViewManagerClientPtr client); + void EmbedAllowingReembed(mojo::URLRequestPtr request, Id view_id); void set_change_acked_callback(const Callback<void(void)>& callback) { change_acked_callback_ = callback; @@ -72,6 +73,8 @@ class ViewManagerClientImpl : public ViewManager, void SetViewManagerService(ViewManagerServicePtr service); + bool is_embed_root() const { return is_embed_root_; } + private: class RootObserver; @@ -154,6 +157,8 @@ class ViewManagerClientImpl : public ViewManager, scoped_ptr<RootObserver> root_observer_; + bool is_embed_root_; + MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerClientImpl); }; diff --git a/components/view_manager/public/cpp/view.h b/components/view_manager/public/cpp/view.h index 311d89d..bf519ee 100644 --- a/components/view_manager/public/cpp/view.h +++ b/components/view_manager/public/cpp/view.h @@ -134,6 +134,7 @@ class View { InterfaceRequest<ServiceProvider> services, ServiceProviderPtr exposed_services); void Embed(ViewManagerClientPtr client); + void EmbedAllowingReembed(mojo::URLRequestPtr request); protected: // This class is subclassed only by test classes that provide a public ctor. diff --git a/components/view_manager/public/interfaces/view_manager.mojom b/components/view_manager/public/interfaces/view_manager.mojom index 3730eda..a20533f 100644 --- a/components/view_manager/public/interfaces/view_manager.mojom +++ b/components/view_manager/public/interfaces/view_manager.mojom @@ -117,13 +117,16 @@ interface ViewManagerService { SetEmbedRoot(); // A connection may grant access to a view from another connection by way of - // the embed functions. There are two variants of this call: + // the embed functions. The following variants exist: // // . EmbedRequest: the ViewManager connects to the app at the supplied request // and asks it for a ViewManagerClient. - // . With the second variant a ViewManagerClient is directly supplied. + // . Embed: the client supplies the ViewManagerClient to use. + // . EmbedAllowingReembed: similar to EmbedRequest(), but no + // ServiceProviders are supplied. Additionally this version allows an + // EmbedRoot ancestor to call Embed() in this view at a later date. // - // In both cases the new ViewManagerClient is configured with a root of + // In all cases the new ViewManagerClient is configured with a root of // |view_id|. // // The caller must have created |view_id|. If not the request fails and the @@ -156,6 +159,7 @@ interface ViewManagerService { ServiceProvider&? services, ServiceProvider? exposed_services) => (bool success); Embed(uint32 view_id, ViewManagerClient client) => (bool success); + EmbedAllowingReembed(URLRequest request, uint32 view_id) => (bool success); SetFocus(uint32 view_id) => (bool success); }; diff --git a/components/view_manager/server_view.cc b/components/view_manager/server_view.cc index d916afa..0e89d99 100644 --- a/components/view_manager/server_view.cc +++ b/components/view_manager/server_view.cc @@ -18,6 +18,7 @@ ServerView::ServerView(ServerViewDelegate* delegate, const ViewId& id) parent_(nullptr), visible_(false), opacity_(1), + allows_reembed_(false), // Don't notify newly added observers during notification. This causes // problems for code that adds an observer as part of an observer // notification (such as ServerViewDrawTracker). diff --git a/components/view_manager/server_view.h b/components/view_manager/server_view.h index afe54c7..4f61f77 100644 --- a/components/view_manager/server_view.h +++ b/components/view_manager/server_view.h @@ -87,6 +87,10 @@ class ServerView { void SetSurfaceId(cc::SurfaceId surface_id); const cc::SurfaceId& surface_id() const { return surface_id_; } + // See mojom for for details. + void set_allows_reembed(bool value) { allows_reembed_ = value; } + bool allows_reembed() const { return allows_reembed_; } + #if !defined(NDEBUG) std::string GetDebugWindowHierarchy() const; void BuildDebugInfo(const std::string& depth, std::string* result) const; @@ -107,6 +111,7 @@ class ServerView { cc::SurfaceId surface_id_; float opacity_; gfx::Transform transform_; + bool allows_reembed_; std::map<std::string, std::vector<uint8_t>> properties_; diff --git a/components/view_manager/view_manager_client_apptest.cc b/components/view_manager/view_manager_client_apptest.cc index d870c8b..469f757 100644 --- a/components/view_manager/view_manager_client_apptest.cc +++ b/components/view_manager/view_manager_client_apptest.cc @@ -83,6 +83,18 @@ bool WaitForBoundsToChange(View* view) { return DoRunLoopWithTimeout(); } +// Increments the width of |view| and waits for a bounds change in |other_vm|s +// root. +bool IncrementWidthAndWaitForChange(View* view, ViewManager* other_vm) { + mojo::Rect bounds = view->bounds(); + bounds.width++; + view->SetBounds(bounds); + View* view_in_vm = other_vm->GetRoot(); + if (view_in_vm == view || view_in_vm->id() != view->id()) + return false; + return WaitForBoundsToChange(view_in_vm); +} + // Spins a run loop until the tree beginning at |root| has |tree_size| views // (including |root|). class TreeSizeMatchesObserver : public ViewObserver { @@ -196,6 +208,8 @@ class ViewManagerTest : public test::ApplicationTestBase, on_will_embed_return_value_ = value; } + ViewManager* most_recent_view_manager() { return most_recent_view_manager_; } + // Overridden from ApplicationDelegate: void Initialize(ApplicationImpl* app) override { view_manager_client_factory_.reset( @@ -212,14 +226,11 @@ class ViewManagerTest : public test::ApplicationTestBase, // Embeds another version of the test app @ view; returns nullptr on timeout. ViewManager* Embed(ViewManager* view_manager, View* view) { - DCHECK_EQ(view_manager, view->view_manager()); - most_recent_view_manager_ = nullptr; - view->Embed(application_impl()->url()); - if (!DoRunLoopWithTimeout()) - return nullptr; - ViewManager* vm = nullptr; - std::swap(vm, most_recent_view_manager_); - return vm; + return EmbedImpl(view_manager, view, EmbedType::NO_REEMBED); + } + + ViewManager* EmbedAllowingReembed(ViewManager* view_manager, View* view) { + return EmbedImpl(view_manager, view, EmbedType::ALLOW_REEMBED); } bool got_disconnect() const { return got_disconnect_; } @@ -246,6 +257,30 @@ class ViewManagerTest : public test::ApplicationTestBase, } private: + enum class EmbedType { + ALLOW_REEMBED, + NO_REEMBED, + }; + + ViewManager* EmbedImpl(ViewManager* view_manager, + View* view, + EmbedType type) { + DCHECK_EQ(view_manager, view->view_manager()); + most_recent_view_manager_ = nullptr; + if (type == EmbedType::ALLOW_REEMBED) { + mojo::URLRequestPtr request(mojo::URLRequest::New()); + request->url = mojo::String::From(application_impl()->url()); + view->EmbedAllowingReembed(request.Pass()); + } else { + view->Embed(application_impl()->url()); + } + if (!DoRunLoopWithTimeout()) + return nullptr; + ViewManager* vm = nullptr; + std::swap(vm, most_recent_view_manager_); + return vm; + } + // Overridden from testing::Test: void SetUp() override { ApplicationTestBase::SetUp(); @@ -786,12 +821,58 @@ TEST_F(ViewManagerTest, OnWillEmbedFails) { // possible there is still an OnEmbed() message in flight. Sets the bounds of // |view1| and wait for it to the change in |view_manager|, that way we know // |view_manager| has processed all messages for it. - mojo::Rect bounds = view1->bounds(); - bounds.width++; - view1->SetBounds(bounds); - WaitForBoundsToChange(view_manager->GetRoot()); + EXPECT_TRUE(IncrementWidthAndWaitForChange(view1, view_manager)); EXPECT_EQ(1u, on_will_embed_count()); } +// Verify an Embed() from an ancestor is not allowed. +TEST_F(ViewManagerTest, ReembedFails) { + window_manager()->SetEmbedRoot(); + + View* view1 = window_manager()->CreateView(); + window_manager()->GetRoot()->AddChild(view1); + + ViewManager* view_manager = Embed(window_manager(), view1); + ASSERT_TRUE(view_manager); + View* view2 = view_manager->CreateView(); + view_manager->GetRoot()->AddChild(view2); + Embed(view_manager, view2); + + // Try to embed in view2 from the window_manager. This should fail as the + // Embed() didn't grab reembed. + View* view2_in_wm = window_manager()->GetViewById(view2->id()); + view2_in_wm->Embed(application_impl()->url()); + + // The Embed() call above returns immediately. To ensure the server has + // processed it nudge the bounds and wait for it to be processed. + EXPECT_TRUE(IncrementWidthAndWaitForChange(view1, view_manager)); + + EXPECT_EQ(nullptr, most_recent_view_manager()); +} + +// Verify an Embed() from an ancestor is allowed if the ancestor is an embed +// root and Embed was done by way of EmbedAllowingReembed(). +TEST_F(ViewManagerTest, ReembedSucceeds) { + window_manager()->SetEmbedRoot(); + + View* view1 = window_manager()->CreateView(); + window_manager()->GetRoot()->AddChild(view1); + + ViewManager* view_manager = Embed(window_manager(), view1); + View* view2 = view_manager->CreateView(); + view_manager->GetRoot()->AddChild(view2); + EmbedAllowingReembed(view_manager, view2); + + View* view2_in_wm = window_manager()->GetViewById(view2->id()); + ViewManager* view_manager2 = Embed(window_manager(), view2_in_wm); + ASSERT_TRUE(view_manager2); + + // The Embed() call above returns immediately. To ensure the server has + // processed it nudge the bounds and wait for it to be processed. + EXPECT_TRUE(IncrementWidthAndWaitForChange(view1, view_manager)); + + EXPECT_EQ(nullptr, most_recent_view_manager()); +} + } // namespace mojo diff --git a/components/view_manager/view_manager_service_impl.cc b/components/view_manager/view_manager_service_impl.cc index 1ec8255..96c34f6 100644 --- a/components/view_manager/view_manager_service_impl.cc +++ b/components/view_manager/view_manager_service_impl.cc @@ -165,17 +165,30 @@ void ViewManagerServiceImpl::SetEmbedRoot() { is_embed_root_ = true; } -void ViewManagerServiceImpl::EmbedRequest( - mojo::URLRequestPtr request, - const ViewId& view_id, - InterfaceRequest<ServiceProvider> services, - ServiceProviderPtr exposed_services, - const mojo::Callback<void(bool)>& callback) { +void ViewManagerServiceImpl::Embed(mojo::URLRequestPtr request, + const ViewId& view_id, + EmbedType type, + InterfaceRequest<ServiceProvider> services, + ServiceProviderPtr exposed_services, + const mojo::Callback<void(bool)>& callback) { if (!CanEmbed(view_id)) { callback.Run(false); return; } - ViewManagerServiceImpl* embed_root = connection_manager_->GetEmbedRoot(this); + + ViewManagerServiceImpl* embed_root = nullptr; + + // Only the creator is allowed to reset reembed. + ServerView* view = GetView(view_id); + DCHECK(view); // CanEmbed() returns true only if |view_id| is valid. + if (view->id().connection_id == id_) { + view->set_allows_reembed(type == EmbedType::ALLOW_REEMBED); + + // Only consult the embed root if the creator is doing the embed. If someone + // other than the creator is doing the embed they were granted embed access. + embed_root = connection_manager_->GetEmbedRoot(this); + } + if (!embed_root) { PrepareForEmbed(view_id); connection_manager_->EmbedAtView(id_, request.Pass(), view_id, @@ -726,8 +739,17 @@ void ViewManagerServiceImpl::EmbedRequest( InterfaceRequest<ServiceProvider> services, ServiceProviderPtr exposed_services, const Callback<void(bool)>& callback) { - EmbedRequest(request.Pass(), ViewIdFromTransportId(transport_view_id), - services.Pass(), exposed_services.Pass(), callback); + Embed(request.Pass(), ViewIdFromTransportId(transport_view_id), + EmbedType::NO_REEMBED, services.Pass(), exposed_services.Pass(), + callback); +} + +void ViewManagerServiceImpl::EmbedAllowingReembed( + mojo::URLRequestPtr request, + mojo::Id transport_view_id, + const mojo::Callback<void(bool)>& callback) { + Embed(request.Pass(), ViewIdFromTransportId(transport_view_id), + EmbedType::ALLOW_REEMBED, nullptr, nullptr, callback); } void ViewManagerServiceImpl::Embed(mojo::Id transport_view_id, diff --git a/components/view_manager/view_manager_service_impl.h b/components/view_manager/view_manager_service_impl.h index 06c18bb..643c868 100644 --- a/components/view_manager/view_manager_service_impl.h +++ b/components/view_manager/view_manager_service_impl.h @@ -35,7 +35,10 @@ class ServerView; class ViewManagerServiceImpl : public mojo::ViewManagerService, public AccessPolicyDelegate { public: - using ViewIdSet = base::hash_set<mojo::Id>; + enum class EmbedType { + ALLOW_REEMBED, + NO_REEMBED, + }; ViewManagerServiceImpl(ConnectionManager* connection_manager, mojo::ConnectionSpecificId creator_id, @@ -83,11 +86,12 @@ class ViewManagerServiceImpl : public mojo::ViewManagerService, bool AddView(const ViewId& parent_id, const ViewId& child_id); std::vector<const ServerView*> GetViewTree(const ViewId& view_id) const; bool SetViewVisibility(const ViewId& view_id, bool visible); - void EmbedRequest(mojo::URLRequestPtr request, - const ViewId& view_id, - mojo::InterfaceRequest<mojo::ServiceProvider> services, - mojo::ServiceProviderPtr exposed_services, - const mojo::Callback<void(bool)>& callback); + void Embed(mojo::URLRequestPtr request, + const ViewId& view_id, + EmbedType type, + mojo::InterfaceRequest<mojo::ServiceProvider> services, + mojo::ServiceProviderPtr exposed_services, + const mojo::Callback<void(bool)>& callback); bool Embed(const ViewId& view_id, mojo::ViewManagerClientPtr client); // The following methods are invoked after the corresponding change has been @@ -123,7 +127,9 @@ class ViewManagerServiceImpl : public mojo::ViewManagerService, const ServerView* new_focused_view); private: - typedef std::map<mojo::ConnectionSpecificId, ServerView*> ViewMap; + using ViewIdSet = base::hash_set<mojo::Id>; + using ViewMap = std::map<mojo::ConnectionSpecificId, ServerView*>; + struct PendingEmbed; bool IsViewKnown(const ServerView* view) const; @@ -230,6 +236,10 @@ class ViewManagerServiceImpl : public mojo::ViewManagerService, void Embed(mojo::Id transport_view_id, mojo::ViewManagerClientPtr client, const mojo::Callback<void(bool)>& callback) override; + void EmbedAllowingReembed( + mojo::URLRequestPtr request, + mojo::Id transport_view_id, + const mojo::Callback<void(bool)>& callback) override; void SetFocus(uint32_t view_id, const SetFocusCallback& callback) override; // AccessPolicyDelegate: diff --git a/components/view_manager/view_manager_service_unittest.cc b/components/view_manager/view_manager_service_unittest.cc index 59caa2f..970b47e 100644 --- a/components/view_manager/view_manager_service_unittest.cc +++ b/components/view_manager/view_manager_service_unittest.cc @@ -297,8 +297,9 @@ void SetUpAnimate1(ViewManagerServiceTest* test, ViewId* embed_view_id) { EXPECT_TRUE(test->wm_connection()->AddView(*(test->wm_connection()->root()), *embed_view_id)); mojo::URLRequestPtr request(mojo::URLRequest::New()); - test->wm_connection()->EmbedRequest(request.Pass(), *embed_view_id, nullptr, - nullptr, mojo::Callback<void(bool)>()); + test->wm_connection()->Embed(request.Pass(), *embed_view_id, + ViewManagerServiceImpl::EmbedType::NO_REEMBED, + nullptr, nullptr, mojo::Callback<void(bool)>()); ViewManagerServiceImpl* connection1 = test->connection_manager()->GetConnectionWithRoot(*embed_view_id); ASSERT_TRUE(connection1 != nullptr); @@ -435,8 +436,9 @@ TEST_F(ViewManagerServiceTest, CloneAndAnimateLargerDepth) { EXPECT_TRUE( wm_connection()->AddView(*(wm_connection()->root()), embed_view_id)); mojo::URLRequestPtr request(mojo::URLRequest::New()); - wm_connection()->EmbedRequest(request.Pass(), embed_view_id, nullptr, nullptr, - mojo::Callback<void(bool)>()); + wm_connection()->Embed(request.Pass(), embed_view_id, + ViewManagerServiceImpl::EmbedType::NO_REEMBED, nullptr, + nullptr, mojo::Callback<void(bool)>()); ViewManagerServiceImpl* connection1 = connection_manager()->GetConnectionWithRoot(embed_view_id); ASSERT_TRUE(connection1 != nullptr); @@ -484,8 +486,9 @@ TEST_F(ViewManagerServiceTest, FocusOnPointer) { wm_connection()->AddView(*(wm_connection()->root()), embed_view_id)); connection_manager()->root()->SetBounds(gfx::Rect(0, 0, 100, 100)); mojo::URLRequestPtr request(mojo::URLRequest::New()); - wm_connection()->EmbedRequest(request.Pass(), embed_view_id, nullptr, nullptr, - mojo::Callback<void(bool)>()); + wm_connection()->Embed(request.Pass(), embed_view_id, + ViewManagerServiceImpl::EmbedType::NO_REEMBED, nullptr, + nullptr, mojo::Callback<void(bool)>()); ViewManagerServiceImpl* connection1 = connection_manager()->GetConnectionWithRoot(embed_view_id); ASSERT_TRUE(connection1 != nullptr); diff --git a/components/view_manager/window_manager_access_policy.cc b/components/view_manager/window_manager_access_policy.cc index 8581e5a..c84c20a 100644 --- a/components/view_manager/window_manager_access_policy.cc +++ b/components/view_manager/window_manager_access_policy.cc @@ -52,7 +52,9 @@ bool WindowManagerAccessPolicy::CanDescendIntoViewForViewTree( } bool WindowManagerAccessPolicy::CanEmbed(const ServerView* view) const { - return view->id().connection_id == connection_id_; + return view->id().connection_id == connection_id_ || + (view->allows_reembed() && + delegate_->IsViewKnownForAccessPolicy(view)); } bool WindowManagerAccessPolicy::CanChangeViewVisibility( |