1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "mojo/services/view_manager/root_node_manager.h"
6
7#include "base/logging.h"
8#include "mojo/public/interfaces/service_provider/service_provider.mojom.h"
9#include "mojo/services/public/cpp/input_events/input_events_type_converters.h"
10#include "mojo/services/view_manager/view.h"
11#include "mojo/services/view_manager/view_manager_service_impl.h"
12#include "ui/aura/env.h"
13
14namespace mojo {
15namespace view_manager {
16namespace service {
17
18RootNodeManager::ScopedChange::ScopedChange(
19    ViewManagerServiceImpl* connection,
20    RootNodeManager* root,
21    RootNodeManager::ChangeType change_type,
22    bool is_delete_node)
23    : root_(root),
24      connection_id_(connection->id()),
25      change_type_(change_type),
26      is_delete_node_(is_delete_node) {
27  root_->PrepareForChange(this);
28}
29
30RootNodeManager::ScopedChange::~ScopedChange() {
31  root_->FinishChange();
32}
33
34RootNodeManager::Context::Context() {
35  // Pass in false as native viewport creates the PlatformEventSource.
36  aura::Env::CreateInstance(false);
37}
38
39RootNodeManager::Context::~Context() {
40  aura::Env::DeleteInstance();
41}
42
43RootNodeManager::RootNodeManager(ServiceProvider* service_provider,
44                                 RootViewManagerDelegate* view_manager_delegate)
45    : service_provider_(service_provider),
46      next_connection_id_(1),
47      next_server_change_id_(1),
48      root_view_manager_(service_provider, this, view_manager_delegate),
49      root_(this, RootNodeId()),
50      current_change_(NULL) {
51}
52
53RootNodeManager::~RootNodeManager() {
54  while (!connections_created_by_connect_.empty())
55    delete *(connections_created_by_connect_.begin());
56  // All the connections should have been destroyed.
57  DCHECK(connection_map_.empty());
58}
59
60ConnectionSpecificId RootNodeManager::GetAndAdvanceNextConnectionId() {
61  const ConnectionSpecificId id = next_connection_id_++;
62  DCHECK_LT(id, next_connection_id_);
63  return id;
64}
65
66void RootNodeManager::AddConnection(ViewManagerServiceImpl* connection) {
67  DCHECK_EQ(0u, connection_map_.count(connection->id()));
68  connection_map_[connection->id()] = connection;
69}
70
71void RootNodeManager::RemoveConnection(ViewManagerServiceImpl* connection) {
72  connection_map_.erase(connection->id());
73  connections_created_by_connect_.erase(connection);
74
75  // Notify remaining connections so that they can cleanup.
76  for (ConnectionMap::const_iterator i = connection_map_.begin();
77       i != connection_map_.end(); ++i) {
78    i->second->OnViewManagerServiceImplDestroyed(connection->id());
79  }
80}
81
82void RootNodeManager::EmbedRoot(const std::string& url) {
83  CHECK(connection_map_.empty());
84  Array<Id> roots(0);
85  EmbedImpl(kRootConnection, String::From(url), roots);
86}
87
88void RootNodeManager::Embed(ConnectionSpecificId creator_id,
89                            const String& url,
90                            const Array<Id>& node_ids) {
91  CHECK_GT(node_ids.size(), 0u);
92  EmbedImpl(creator_id, url, node_ids)->set_delete_on_connection_error();
93}
94
95ViewManagerServiceImpl* RootNodeManager::GetConnection(
96    ConnectionSpecificId connection_id) {
97  ConnectionMap::iterator i = connection_map_.find(connection_id);
98  return i == connection_map_.end() ? NULL : i->second;
99}
100
101Node* RootNodeManager::GetNode(const NodeId& id) {
102  if (id == root_.id())
103    return &root_;
104  ConnectionMap::iterator i = connection_map_.find(id.connection_id);
105  return i == connection_map_.end() ? NULL : i->second->GetNode(id);
106}
107
108View* RootNodeManager::GetView(const ViewId& id) {
109  ConnectionMap::iterator i = connection_map_.find(id.connection_id);
110  return i == connection_map_.end() ? NULL : i->second->GetView(id);
111}
112
113void RootNodeManager::OnConnectionMessagedClient(ConnectionSpecificId id) {
114  if (current_change_)
115    current_change_->MarkConnectionAsMessaged(id);
116}
117
118bool RootNodeManager::DidConnectionMessageClient(
119    ConnectionSpecificId id) const {
120  return current_change_ && current_change_->DidMessageConnection(id);
121}
122
123ViewManagerServiceImpl* RootNodeManager::GetConnectionByCreator(
124    ConnectionSpecificId creator_id,
125    const std::string& url) const {
126  for (ConnectionMap::const_iterator i = connection_map_.begin();
127       i != connection_map_.end(); ++i) {
128    if (i->second->creator_id() == creator_id && i->second->url() == url)
129      return i->second;
130  }
131  return NULL;
132}
133
134void RootNodeManager::DispatchViewInputEventToWindowManager(
135    const View* view,
136    const ui::Event* event) {
137  // Input events are forwarded to the WindowManager. The WindowManager
138  // eventually calls back to us with DispatchOnViewInputEvent().
139  ViewManagerServiceImpl* connection = GetConnection(kWindowManagerConnection);
140  if (!connection)
141    return;
142  connection->client()->DispatchOnViewInputEvent(
143      ViewIdToTransportId(view->id()),
144      TypeConverter<EventPtr, ui::Event>::ConvertFrom(*event));
145}
146
147void RootNodeManager::ProcessNodeBoundsChanged(const Node* node,
148                                               const gfx::Rect& old_bounds,
149                                               const gfx::Rect& new_bounds) {
150  for (ConnectionMap::iterator i = connection_map_.begin();
151       i != connection_map_.end(); ++i) {
152    i->second->ProcessNodeBoundsChanged(node, old_bounds, new_bounds,
153                                        IsChangeSource(i->first));
154  }
155}
156
157void RootNodeManager::ProcessNodeHierarchyChanged(const Node* node,
158                                                  const Node* new_parent,
159                                                  const Node* old_parent) {
160  for (ConnectionMap::iterator i = connection_map_.begin();
161       i != connection_map_.end(); ++i) {
162    i->second->ProcessNodeHierarchyChanged(
163        node, new_parent, old_parent, next_server_change_id_,
164        IsChangeSource(i->first));
165  }
166}
167
168void RootNodeManager::ProcessNodeReorder(const Node* node,
169                                         const Node* relative_node,
170                                         const OrderDirection direction) {
171  for (ConnectionMap::iterator i = connection_map_.begin();
172       i != connection_map_.end(); ++i) {
173    i->second->ProcessNodeReorder(
174        node, relative_node, direction, next_server_change_id_,
175        IsChangeSource(i->first));
176  }
177}
178
179void RootNodeManager::ProcessNodeViewReplaced(const Node* node,
180                                              const View* new_view,
181                                              const View* old_view) {
182  for (ConnectionMap::iterator i = connection_map_.begin();
183       i != connection_map_.end(); ++i) {
184    i->second->ProcessNodeViewReplaced(node, new_view, old_view,
185                                       IsChangeSource(i->first));
186  }
187}
188
189void RootNodeManager::ProcessNodeDeleted(const NodeId& node) {
190  for (ConnectionMap::iterator i = connection_map_.begin();
191       i != connection_map_.end(); ++i) {
192    i->second->ProcessNodeDeleted(node, next_server_change_id_,
193                                 IsChangeSource(i->first));
194  }
195}
196
197void RootNodeManager::ProcessViewDeleted(const ViewId& view) {
198  for (ConnectionMap::iterator i = connection_map_.begin();
199       i != connection_map_.end(); ++i) {
200    i->second->ProcessViewDeleted(view, IsChangeSource(i->first));
201  }
202}
203
204void RootNodeManager::PrepareForChange(ScopedChange* change) {
205  // Should only ever have one change in flight.
206  CHECK(!current_change_);
207  current_change_ = change;
208}
209
210void RootNodeManager::FinishChange() {
211  // PrepareForChange/FinishChange should be balanced.
212  CHECK(current_change_);
213  if (current_change_->change_type() == CHANGE_TYPE_ADVANCE_SERVER_CHANGE_ID)
214    next_server_change_id_++;
215  current_change_ = NULL;
216}
217
218ViewManagerServiceImpl* RootNodeManager::EmbedImpl(
219    const ConnectionSpecificId creator_id,
220    const String& url,
221    const Array<Id>& node_ids) {
222  MessagePipe pipe;
223  service_provider_->ConnectToService(
224      url,
225      ViewManagerServiceImpl::Client::Name_,
226      pipe.handle1.Pass(),
227      String());
228
229  std::string creator_url;
230  ConnectionMap::const_iterator it = connection_map_.find(creator_id);
231  if (it != connection_map_.end())
232    creator_url = it->second->url();
233
234  ViewManagerServiceImpl* connection =
235      new ViewManagerServiceImpl(this,
236                                creator_id,
237                                creator_url,
238                                url.To<std::string>());
239  connection->SetRoots(node_ids);
240  BindToPipe(connection, pipe.handle0.Pass());
241  connections_created_by_connect_.insert(connection);
242  return connection;
243}
244
245void RootNodeManager::OnNodeHierarchyChanged(const Node* node,
246                                             const Node* new_parent,
247                                             const Node* old_parent) {
248  if (!root_view_manager_.in_setup())
249    ProcessNodeHierarchyChanged(node, new_parent, old_parent);
250}
251
252void RootNodeManager::OnNodeViewReplaced(const Node* node,
253                                         const View* new_view,
254                                         const View* old_view) {
255  ProcessNodeViewReplaced(node, new_view, old_view);
256}
257
258void RootNodeManager::OnViewInputEvent(const View* view,
259                                       const ui::Event* event) {
260  DispatchViewInputEventToWindowManager(view, event);
261}
262
263}  // namespace service
264}  // namespace view_manager
265}  // namespace mojo
266