Index: mojo/services/view_manager/view_manager_service_impl.cc |
diff --git a/mojo/services/view_manager/view_manager_service_impl.cc b/mojo/services/view_manager/view_manager_service_impl.cc |
index b98b99dbe53b97939086409b03b8bca683febced..793a4543d0377a8629dee853f01de02a6e227f64 100644 |
--- a/mojo/services/view_manager/view_manager_service_impl.cc |
+++ b/mojo/services/view_manager/view_manager_service_impl.cc |
@@ -86,6 +86,10 @@ const View* ViewManagerServiceImpl::GetView(const ViewId& id) const { |
return root_node_manager_->GetView(id); |
} |
+bool ViewManagerServiceImpl::HasRoot(const NodeId& id) const { |
+ return roots_.find(NodeIdToTransportId(id)) != roots_.end(); |
+} |
+ |
void ViewManagerServiceImpl::OnViewManagerServiceImplDestroyed( |
ConnectionSpecificId id) { |
if (creator_id_ == id) |
@@ -119,7 +123,7 @@ void ViewManagerServiceImpl::ProcessNodeHierarchyChanged( |
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 deleted. |
- RemoveFromKnown(node); |
+ RemoveFromKnown(node, NULL); |
client()->OnNodeDeleted(NodeIdToTransportId(node->id()), |
server_change_id); |
root_node_manager_->OnConnectionMessagedClient(id_); |
@@ -407,21 +411,24 @@ void ViewManagerServiceImpl::GetUnknownNodesFrom( |
GetUnknownNodesFrom(children[i], nodes); |
} |
-void ViewManagerServiceImpl::RemoveFromKnown(const Node* node) { |
- if (node->id().connection_id == id_) |
+void ViewManagerServiceImpl::RemoveFromKnown(const Node* node, |
+ std::vector<Node*>* local_nodes) { |
+ if (node->id().connection_id == id_) { |
+ if (local_nodes) |
+ local_nodes->push_back(GetNode(node->id())); |
return; |
+ } |
known_nodes_.erase(NodeIdToTransportId(node->id())); |
std::vector<const Node*> children = node->GetChildren(); |
for (size_t i = 0; i < children.size(); ++i) |
- RemoveFromKnown(children[i]); |
+ RemoveFromKnown(children[i], local_nodes); |
} |
-bool ViewManagerServiceImpl::AddRoot(Id transport_node_id) { |
- if (roots_.count(transport_node_id) > 0) |
- return false; |
+void ViewManagerServiceImpl::AddRoot(const NodeId& node_id) { |
+ const Id transport_node_id(NodeIdToTransportId(node_id)); |
+ CHECK(roots_.count(transport_node_id) == 0); |
std::vector<const Node*> to_send; |
- const NodeId node_id(NodeIdFromTransportId(transport_node_id)); |
CHECK_EQ(creator_id_, node_id.connection_id); |
roots_.insert(transport_node_id); |
Node* node = GetNode(node_id); |
@@ -435,7 +442,31 @@ bool ViewManagerServiceImpl::AddRoot(Id transport_node_id) { |
} |
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 { |
@@ -737,13 +768,30 @@ void ViewManagerServiceImpl::Embed(const String& url, |
const Callback<void(bool)>& callback) { |
bool success = CanEmbed(transport_node_id); |
if (success) { |
- // We may already have this connection, if so reuse it. |
- ViewManagerServiceImpl* existing_connection = |
+ // Only allow a node to be the root for one connection. |
+ const NodeId node_id(NodeIdFromTransportId(transport_node_id)); |
+ ViewManagerServiceImpl* connection_by_url = |
root_node_manager_->GetConnectionByCreator(id_, url.To<std::string>()); |
- if (existing_connection) |
- success = existing_connection->AddRoot(transport_node_id); |
- else |
- root_node_manager_->Embed(id_, url, transport_node_id); |
+ ViewManagerServiceImpl* connection_with_node_as_root = |
+ root_node_manager_->GetConnectionWithRoot(node_id); |
+ if ((connection_by_url != connection_with_node_as_root || |
+ (!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); |
} |