Commit ff84e05a authored by sky@chromium.org's avatar sky@chromium.org

Makes it so a node can only the root of one connection at a time

This resulted in needing to make structural changes. For example, if
connection 2 has a root of A, and A has the children B and C then if A
is assigned to another connection (by way of the owner calling Embed
again), then connection 2 is told A has been deleted and B and C are
removed as children of A.

Because this does structural changes the server change id is advanced.

BUG=389339
TEST=covered by unit tests
R=ben@chromium.org

Review URL: https://codereview.chromium.org/397803003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@283663 0039d316-1c4b-4281-b951-d872f2087c98
parent 36b7914e
...@@ -478,6 +478,7 @@ class EmbedTransaction : public ViewManagerTransaction { ...@@ -478,6 +478,7 @@ class EmbedTransaction : public ViewManagerTransaction {
private: private:
// Overridden from ViewManagerTransaction: // Overridden from ViewManagerTransaction:
virtual void DoCommit() OVERRIDE { virtual void DoCommit() OVERRIDE {
GetAndAdvanceNextServerChangeId();
service()->Embed(url_, node_id_, ActionCompletedCallback()); service()->Embed(url_, node_id_, ActionCompletedCallback());
} }
virtual void DoActionCompleted(bool success) OVERRIDE { virtual void DoActionCompleted(bool success) OVERRIDE {
......
...@@ -127,12 +127,20 @@ interface ViewManagerService { ...@@ -127,12 +127,20 @@ interface ViewManagerService {
SetFocus(uint32 node_id) => (bool success); SetFocus(uint32 node_id) => (bool success);
// Embeds the app for |url| in the specified node. More specifically this // Embeds the app for |url| in the specified node. More specifically this
// creates a new connection to the specified url, expecting to get an // creates a new connection to the specified url, expecting to get a
// ViewManagerClient and configures it with the root node |node|. Fails // ViewManagerClient and configures it with the root node |node|. Fails
// if |node| was not created by this connection. // if |node| was not created by this connection.
//
// If a particular client invokes Embed() multiple times with the same url, // If a particular client invokes Embed() multiple times with the same url,
// the connection is reused. When this happens the ViewManagerClient is // the connection is reused. When this happens the ViewManagerClient is
// notified of the additional roots by way of OnRootAdded(). // notified of the additional roots by way of OnRootAdded().
//
// A node may only be a root of one connection at a time. Subsequent calls to
// Embed() for the same node result in the node being removed from the
// current connection. The current connection is told this by way of
// OnNodeDeleted().
//
// This advances the server change id.
Embed(string url, uint32 node_id) => (bool success); Embed(string url, uint32 node_id) => (bool success);
// TODO(sky): move these to a separate interface when FIFO works. // TODO(sky): move these to a separate interface when FIFO works.
......
...@@ -33,6 +33,10 @@ RootNodeManager::ScopedChange::~ScopedChange() { ...@@ -33,6 +33,10 @@ RootNodeManager::ScopedChange::~ScopedChange() {
root_->FinishChange(); root_->FinishChange();
} }
void RootNodeManager::ScopedChange::SendServerChangeIdAdvanced() {
root_->SendServerChangeIdAdvanced();
}
RootNodeManager::Context::Context() { RootNodeManager::Context::Context() {
// Pass in false as native viewport creates the PlatformEventSource. // Pass in false as native viewport creates the PlatformEventSource.
aura::Env::CreateInstance(false); aura::Env::CreateInstance(false);
...@@ -141,6 +145,16 @@ ViewManagerServiceImpl* RootNodeManager::GetConnectionByCreator( ...@@ -141,6 +145,16 @@ ViewManagerServiceImpl* RootNodeManager::GetConnectionByCreator(
return NULL; return NULL;
} }
ViewManagerServiceImpl* RootNodeManager::GetConnectionWithRoot(
const NodeId& id) {
for (ConnectionMap::const_iterator i = connection_map_.begin();
i != connection_map_.end(); ++i) {
if (i->second->HasRoot(id))
return i->second;
}
return NULL;
}
void RootNodeManager::DispatchViewInputEventToWindowManager( void RootNodeManager::DispatchViewInputEventToWindowManager(
const View* view, const View* view,
const ui::Event* event) { const ui::Event* event) {
...@@ -236,6 +250,15 @@ void RootNodeManager::FinishChange() { ...@@ -236,6 +250,15 @@ void RootNodeManager::FinishChange() {
current_change_ = NULL; current_change_ = NULL;
} }
void RootNodeManager::SendServerChangeIdAdvanced() {
CHECK(current_change_);
for (ConnectionMap::iterator i = connection_map_.begin();
i != connection_map_.end(); ++i) {
if (!DidConnectionMessageClient(i->first))
i->second->client()->OnServerChangeIdAdvanced(next_server_change_id_ + 1);
}
}
ViewManagerServiceImpl* RootNodeManager::EmbedImpl( ViewManagerServiceImpl* RootNodeManager::EmbedImpl(
const ConnectionSpecificId creator_id, const ConnectionSpecificId creator_id,
const String& url, const String& url,
...@@ -261,6 +284,7 @@ ViewManagerServiceImpl* RootNodeManager::EmbedImpl( ...@@ -261,6 +284,7 @@ ViewManagerServiceImpl* RootNodeManager::EmbedImpl(
root_id); root_id);
BindToPipe(connection, pipe.handle0.Pass()); BindToPipe(connection, pipe.handle0.Pass());
connections_created_by_connect_.insert(connection); connections_created_by_connect_.insert(connection);
OnConnectionMessagedClient(connection->id());
return connection; return connection;
} }
......
...@@ -69,6 +69,10 @@ class MOJO_VIEW_MANAGER_EXPORT RootNodeManager ...@@ -69,6 +69,10 @@ class MOJO_VIEW_MANAGER_EXPORT RootNodeManager
return message_ids_.count(connection_id) > 0; return message_ids_.count(connection_id) > 0;
} }
// Sends OnServerChangeIdAdvanced() to all connections that have not yet
// been messaged.
void SendServerChangeIdAdvanced();
private: private:
RootNodeManager* root_; RootNodeManager* root_;
const ConnectionSpecificId connection_id_; const ConnectionSpecificId connection_id_;
...@@ -133,6 +137,9 @@ class MOJO_VIEW_MANAGER_EXPORT RootNodeManager ...@@ -133,6 +137,9 @@ class MOJO_VIEW_MANAGER_EXPORT RootNodeManager
ConnectionSpecificId creator_id, ConnectionSpecificId creator_id,
const std::string& url) const; const std::string& url) const;
// Returns the ViewManagerServiceImpl that has |id| as a root.
ViewManagerServiceImpl* GetConnectionWithRoot(const NodeId& id);
void DispatchViewInputEventToWindowManager(const View* view, void DispatchViewInputEventToWindowManager(const View* view,
const ui::Event* event); const ui::Event* event);
...@@ -178,6 +185,9 @@ class MOJO_VIEW_MANAGER_EXPORT RootNodeManager ...@@ -178,6 +185,9 @@ class MOJO_VIEW_MANAGER_EXPORT RootNodeManager
// Balances a call to PrepareForChange(). // Balances a call to PrepareForChange().
void FinishChange(); void FinishChange();
// See description in ScopedChange.
void SendServerChangeIdAdvanced();
// Returns true if the specified connection originated the current change. // Returns true if the specified connection originated the current change.
bool IsChangeSource(ConnectionSpecificId connection_id) const { bool IsChangeSource(ConnectionSpecificId connection_id) const {
return current_change_ && current_change_->connection_id() == connection_id; return current_change_ && current_change_->connection_id() == connection_id;
......
...@@ -86,6 +86,10 @@ const View* ViewManagerServiceImpl::GetView(const ViewId& id) const { ...@@ -86,6 +86,10 @@ const View* ViewManagerServiceImpl::GetView(const ViewId& id) const {
return root_node_manager_->GetView(id); return root_node_manager_->GetView(id);
} }
bool ViewManagerServiceImpl::HasRoot(const NodeId& id) const {
return roots_.find(NodeIdToTransportId(id)) != roots_.end();
}
void ViewManagerServiceImpl::OnViewManagerServiceImplDestroyed( void ViewManagerServiceImpl::OnViewManagerServiceImplDestroyed(
ConnectionSpecificId id) { ConnectionSpecificId id) {
if (creator_id_ == id) if (creator_id_ == id)
...@@ -119,7 +123,7 @@ void ViewManagerServiceImpl::ProcessNodeHierarchyChanged( ...@@ -119,7 +123,7 @@ void ViewManagerServiceImpl::ProcessNodeHierarchyChanged(
if (node->id().connection_id != id_ && !IsNodeDescendantOfRoots(node)) { if (node->id().connection_id != id_ && !IsNodeDescendantOfRoots(node)) {
// Node was a descendant of roots and is no longer, treat it as though the // Node was a descendant of roots and is no longer, treat it as though the
// node was deleted. // node was deleted.
RemoveFromKnown(node); RemoveFromKnown(node, NULL);
client()->OnNodeDeleted(NodeIdToTransportId(node->id()), client()->OnNodeDeleted(NodeIdToTransportId(node->id()),
server_change_id); server_change_id);
root_node_manager_->OnConnectionMessagedClient(id_); root_node_manager_->OnConnectionMessagedClient(id_);
...@@ -407,21 +411,24 @@ void ViewManagerServiceImpl::GetUnknownNodesFrom( ...@@ -407,21 +411,24 @@ void ViewManagerServiceImpl::GetUnknownNodesFrom(
GetUnknownNodesFrom(children[i], nodes); GetUnknownNodesFrom(children[i], nodes);
} }
void ViewManagerServiceImpl::RemoveFromKnown(const Node* node) { void ViewManagerServiceImpl::RemoveFromKnown(const Node* node,
if (node->id().connection_id == id_) std::vector<Node*>* local_nodes) {
if (node->id().connection_id == id_) {
if (local_nodes)
local_nodes->push_back(GetNode(node->id()));
return; return;
}
known_nodes_.erase(NodeIdToTransportId(node->id())); known_nodes_.erase(NodeIdToTransportId(node->id()));
std::vector<const Node*> children = node->GetChildren(); std::vector<const Node*> children = node->GetChildren();
for (size_t i = 0; i < children.size(); ++i) for (size_t i = 0; i < children.size(); ++i)
RemoveFromKnown(children[i]); RemoveFromKnown(children[i], local_nodes);
} }
bool ViewManagerServiceImpl::AddRoot(Id transport_node_id) { void ViewManagerServiceImpl::AddRoot(const NodeId& node_id) {
if (roots_.count(transport_node_id) > 0) const Id transport_node_id(NodeIdToTransportId(node_id));
return false; CHECK(roots_.count(transport_node_id) == 0);
std::vector<const Node*> to_send; std::vector<const Node*> to_send;
const NodeId node_id(NodeIdFromTransportId(transport_node_id));
CHECK_EQ(creator_id_, node_id.connection_id); CHECK_EQ(creator_id_, node_id.connection_id);
roots_.insert(transport_node_id); roots_.insert(transport_node_id);
Node* node = GetNode(node_id); Node* node = GetNode(node_id);
...@@ -435,7 +442,31 @@ bool ViewManagerServiceImpl::AddRoot(Id transport_node_id) { ...@@ -435,7 +442,31 @@ bool ViewManagerServiceImpl::AddRoot(Id transport_node_id) {
} }
client()->OnRootAdded(NodesToNodeDatas(to_send)); client()->OnRootAdded(NodesToNodeDatas(to_send));
return true; root_node_manager_->OnConnectionMessagedClient(id_);
}
void ViewManagerServiceImpl::RemoveRoot(const NodeId& node_id) {
const Id transport_node_id(NodeIdToTransportId(node_id));
CHECK(roots_.count(transport_node_id) > 0);
roots_.erase(transport_node_id);
if (roots_.empty())
roots_.insert(NodeIdToTransportId(InvalidNodeId()));
// No need to do anything if we created the node.
if (node_id.connection_id == id_)
return;
client()->OnNodeDeleted(transport_node_id,
root_node_manager_->next_server_change_id());
root_node_manager_->OnConnectionMessagedClient(id_);
// This connection no longer knows about the node. Unparent any nodes that
// were parented to nodes in the root.
std::vector<Node*> local_nodes;
RemoveFromKnown(GetNode(node_id), &local_nodes);
for (size_t i = 0; i < local_nodes.size(); ++i)
local_nodes[i]->GetParent()->Remove(local_nodes[i]);
} }
bool ViewManagerServiceImpl::IsNodeDescendantOfRoots(const Node* node) const { bool ViewManagerServiceImpl::IsNodeDescendantOfRoots(const Node* node) const {
...@@ -737,13 +768,30 @@ void ViewManagerServiceImpl::Embed(const String& url, ...@@ -737,13 +768,30 @@ void ViewManagerServiceImpl::Embed(const String& url,
const Callback<void(bool)>& callback) { const Callback<void(bool)>& callback) {
bool success = CanEmbed(transport_node_id); bool success = CanEmbed(transport_node_id);
if (success) { if (success) {
// We may already have this connection, if so reuse it. // Only allow a node to be the root for one connection.
ViewManagerServiceImpl* existing_connection = const NodeId node_id(NodeIdFromTransportId(transport_node_id));
ViewManagerServiceImpl* connection_by_url =
root_node_manager_->GetConnectionByCreator(id_, url.To<std::string>()); root_node_manager_->GetConnectionByCreator(id_, url.To<std::string>());
if (existing_connection) ViewManagerServiceImpl* connection_with_node_as_root =
success = existing_connection->AddRoot(transport_node_id); root_node_manager_->GetConnectionWithRoot(node_id);
else if ((connection_by_url != connection_with_node_as_root ||
root_node_manager_->Embed(id_, url, transport_node_id); (!connection_by_url && !connection_with_node_as_root)) &&
(!connection_by_url || !connection_by_url->HasRoot(node_id))) {
RootNodeManager::ScopedChange change(
this, root_node_manager_,
RootNodeManager::CHANGE_TYPE_ADVANCE_SERVER_CHANGE_ID, true);
// Never message the originating connection.
root_node_manager_->OnConnectionMessagedClient(id_);
if (connection_with_node_as_root)
connection_with_node_as_root->RemoveRoot(node_id);
if (connection_by_url)
connection_by_url->AddRoot(node_id);
else
root_node_manager_->Embed(id_, url, transport_node_id);
change.SendServerChangeIdAdvanced();
} else {
success = false;
}
} }
callback.Run(success); callback.Run(success);
} }
......
...@@ -68,6 +68,9 @@ class MOJO_VIEW_MANAGER_EXPORT ViewManagerServiceImpl ...@@ -68,6 +68,9 @@ class MOJO_VIEW_MANAGER_EXPORT ViewManagerServiceImpl
} }
const View* GetView(const ViewId& id) const; const View* GetView(const ViewId& id) const;
// Returns true if this has |id| as a root.
bool HasRoot(const NodeId& id) const;
// Invoked when a connection is destroyed. // Invoked when a connection is destroyed.
void OnViewManagerServiceImplDestroyed(ConnectionSpecificId id); void OnViewManagerServiceImplDestroyed(ConnectionSpecificId id);
...@@ -141,13 +144,16 @@ class MOJO_VIEW_MANAGER_EXPORT ViewManagerServiceImpl ...@@ -141,13 +144,16 @@ class MOJO_VIEW_MANAGER_EXPORT ViewManagerServiceImpl
void GetUnknownNodesFrom(const Node* node, std::vector<const Node*>* nodes); void GetUnknownNodesFrom(const Node* node, std::vector<const Node*>* nodes);
// Removes |node| and all its descendants from |known_nodes_|. This does not // Removes |node| and all its descendants from |known_nodes_|. This does not
// recurse through nodes that were created by this connection. // recurse through nodes that were created by this connection. All nodes owned
void RemoveFromKnown(const Node* node); // by this connection are added to |local_nodes|.
void RemoveFromKnown(const Node* node, std::vector<Node*>* local_nodes);
// Adds |node_id| to the set of roots this connection knows about. The caller
// should have verified |node_id| is not among the roots of this connection.
void AddRoot(const NodeId& node_id);
// Adds |transport_node_id| to the set of roots this connection knows about. // Removes |node_id| from the set of roots this connection knows about.
// Returns true if |transport_node_id| was not already a root for this void RemoveRoot(const NodeId& node_id);
// connection.
bool AddRoot(Id transport_node_id);
// Returns true if |node| is a non-null and a descendant of |roots_| (or // Returns true if |node| is a non-null and a descendant of |roots_| (or
// |roots_| is empty). // |roots_| is empty).
......
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