Roll ANGLE cc54ab3..c5b2ba5
[chromium-blink-merge.git] / components / mus / connection_manager.cc
blob8186ac28211f1ff76abb9e1b0168986d33bea98b
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.
5 #include "components/mus/connection_manager.h"
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "cc/output/compositor_frame.h"
10 #include "cc/quads/shared_quad_state.h"
11 #include "components/mus/client_connection.h"
12 #include "components/mus/connection_manager_delegate.h"
13 #include "components/mus/server_view.h"
14 #include "components/mus/view_coordinate_conversions.h"
15 #include "components/mus/view_tree_host_connection.h"
16 #include "components/mus/view_tree_impl.h"
17 #include "mojo/application/public/cpp/application_connection.h"
18 #include "mojo/converters/geometry/geometry_type_converters.h"
19 #include "mojo/converters/input_events/input_events_type_converters.h"
20 #include "mojo/converters/surfaces/surfaces_type_converters.h"
21 #include "ui/gfx/geometry/size_conversions.h"
23 namespace mus {
25 ConnectionManager::ScopedChange::ScopedChange(
26 ViewTreeImpl* connection,
27 ConnectionManager* connection_manager,
28 bool is_delete_view)
29 : connection_manager_(connection_manager),
30 connection_id_(connection->id()),
31 is_delete_view_(is_delete_view) {
32 connection_manager_->PrepareForChange(this);
35 ConnectionManager::ScopedChange::~ScopedChange() {
36 connection_manager_->FinishChange();
39 ConnectionManager::ConnectionManager(
40 ConnectionManagerDelegate* delegate,
41 const scoped_refptr<SurfacesState>& surfaces_state)
42 : delegate_(delegate),
43 surfaces_state_(surfaces_state),
44 next_connection_id_(1),
45 next_host_id_(0),
46 current_change_(nullptr),
47 in_destructor_(false) {}
49 ConnectionManager::~ConnectionManager() {
50 in_destructor_ = true;
52 // Copy the HostConnectionMap because it will be mutated as the connections
53 // are closed.
54 HostConnectionMap host_connection_map(host_connection_map_);
55 for (auto& pair : host_connection_map)
56 pair.second->CloseConnection();
58 STLDeleteValues(&connection_map_);
59 // All the connections should have been destroyed.
60 DCHECK(host_connection_map_.empty());
61 DCHECK(connection_map_.empty());
64 void ConnectionManager::AddHost(ViewTreeHostConnection* host_connection) {
65 DCHECK_EQ(0u, host_connection_map_.count(host_connection->view_tree_host()));
66 host_connection_map_[host_connection->view_tree_host()] = host_connection;
69 ServerView* ConnectionManager::CreateServerView(const ViewId& id) {
70 ServerView* view = new ServerView(this, id);
71 view->AddObserver(this);
72 return view;
75 ConnectionSpecificId ConnectionManager::GetAndAdvanceNextConnectionId() {
76 const ConnectionSpecificId id = next_connection_id_++;
77 DCHECK_LT(id, next_connection_id_);
78 return id;
81 uint16_t ConnectionManager::GetAndAdvanceNextHostId() {
82 const uint16_t id = next_host_id_++;
83 DCHECK_LT(id, next_host_id_);
84 return id;
87 void ConnectionManager::OnConnectionError(ClientConnection* connection) {
88 // This will be null if the root has been destroyed.
89 const ViewId* view_id = connection->service()->root();
90 ServerView* view =
91 view_id ? GetView(*connection->service()->root()) : nullptr;
92 // If the ViewTree root is a viewport root, then we'll wait until
93 // the root connection goes away to cleanup.
94 if (view && (GetRootView(view) == view))
95 return;
97 scoped_ptr<ClientConnection> connection_owner(connection);
99 connection_map_.erase(connection->service()->id());
101 // Notify remaining connections so that they can cleanup.
102 for (auto& pair : connection_map_) {
103 pair.second->service()->OnWillDestroyViewTreeImpl(connection->service());
107 void ConnectionManager::OnHostConnectionClosed(
108 ViewTreeHostConnection* connection) {
109 auto it = host_connection_map_.find(connection->view_tree_host());
110 DCHECK(it != host_connection_map_.end());
112 // Get the ClientConnection by ViewTreeImpl ID.
113 ConnectionMap::iterator service_connection_it =
114 connection_map_.find(it->first->GetViewTree()->id());
115 DCHECK(service_connection_it != connection_map_.end());
117 // Tear down the associated ViewTree connection.
118 // TODO(fsamuel): I don't think this is quite right, we should tear down all
119 // connections within the root's viewport. We should probably employ an
120 // observer pattern to do this. Each ViewTreeImpl should track its
121 // parent's lifetime.
122 host_connection_map_.erase(it);
123 OnConnectionError(service_connection_it->second);
125 // If we have no more roots left, let the app know so it can terminate.
126 if (!host_connection_map_.size())
127 delegate_->OnNoMoreRootConnections();
130 void ConnectionManager::EmbedAtView(ConnectionSpecificId creator_id,
131 const ViewId& view_id,
132 uint32_t policy_bitmask,
133 mojo::URLRequestPtr request) {
134 mojo::ViewTreePtr service_ptr;
135 ClientConnection* client_connection =
136 delegate_->CreateClientConnectionForEmbedAtView(
137 this, GetProxy(&service_ptr), creator_id, request.Pass(), view_id,
138 policy_bitmask);
139 AddConnection(client_connection);
140 client_connection->service()->Init(client_connection->client(),
141 service_ptr.Pass());
142 OnConnectionMessagedClient(client_connection->service()->id());
145 ViewTreeImpl* ConnectionManager::EmbedAtView(ConnectionSpecificId creator_id,
146 const ViewId& view_id,
147 uint32_t policy_bitmask,
148 mojo::ViewTreeClientPtr client) {
149 mojo::ViewTreePtr service_ptr;
150 ClientConnection* client_connection =
151 delegate_->CreateClientConnectionForEmbedAtView(
152 this, GetProxy(&service_ptr), creator_id, view_id, policy_bitmask,
153 client.Pass());
154 AddConnection(client_connection);
155 client_connection->service()->Init(client_connection->client(),
156 service_ptr.Pass());
157 OnConnectionMessagedClient(client_connection->service()->id());
159 return client_connection->service();
162 ViewTreeImpl* ConnectionManager::GetConnection(
163 ConnectionSpecificId connection_id) {
164 ConnectionMap::iterator i = connection_map_.find(connection_id);
165 return i == connection_map_.end() ? nullptr : i->second->service();
168 ServerView* ConnectionManager::GetView(const ViewId& id) {
169 for (auto& pair : host_connection_map_) {
170 if (pair.first->root_view()->id() == id)
171 return pair.first->root_view();
173 ViewTreeImpl* service = GetConnection(id.connection_id);
174 return service ? service->GetView(id) : nullptr;
177 bool ConnectionManager::IsViewAttachedToRoot(const ServerView* view) const {
178 for (auto& pair : host_connection_map_) {
179 if (pair.first->IsViewAttachedToRoot(view))
180 return true;
182 return false;
185 void ConnectionManager::SchedulePaint(const ServerView* view,
186 const gfx::Rect& bounds) {
187 for (auto& pair : host_connection_map_) {
188 if (pair.first->SchedulePaintIfInViewport(view, bounds))
189 return;
193 void ConnectionManager::OnConnectionMessagedClient(ConnectionSpecificId id) {
194 if (current_change_)
195 current_change_->MarkConnectionAsMessaged(id);
198 bool ConnectionManager::DidConnectionMessageClient(
199 ConnectionSpecificId id) const {
200 return current_change_ && current_change_->DidMessageConnection(id);
203 mojo::ViewportMetricsPtr ConnectionManager::GetViewportMetricsForView(
204 const ServerView* view) {
205 ViewTreeHostImpl* host = GetViewTreeHostByView(view);
206 if (host)
207 return host->GetViewportMetrics().Clone();
209 if (!host_connection_map_.empty())
210 return host_connection_map_.begin()->first->GetViewportMetrics().Clone();
212 mojo::ViewportMetricsPtr metrics = mojo::ViewportMetrics::New();
213 metrics->size_in_pixels = mojo::Size::New();
214 return metrics.Pass();
217 const ViewTreeImpl* ConnectionManager::GetConnectionWithRoot(
218 const ViewId& id) const {
219 for (auto& pair : connection_map_) {
220 if (pair.second->service()->IsRoot(id))
221 return pair.second->service();
223 return nullptr;
226 ViewTreeHostImpl* ConnectionManager::GetViewTreeHostByView(
227 const ServerView* view) {
228 return const_cast<ViewTreeHostImpl*>(
229 static_cast<const ConnectionManager*>(this)->GetViewTreeHostByView(view));
232 const ViewTreeHostImpl* ConnectionManager::GetViewTreeHostByView(
233 const ServerView* view) const {
234 while (view && view->parent())
235 view = view->parent();
236 for (auto& pair : host_connection_map_) {
237 if (view == pair.first->root_view())
238 return pair.first;
240 return nullptr;
243 ViewTreeImpl* ConnectionManager::GetEmbedRoot(ViewTreeImpl* service) {
244 while (service) {
245 const ViewId* root_id = service->root();
246 if (!root_id || root_id->connection_id == service->id())
247 return nullptr;
249 ViewTreeImpl* parent_service = GetConnection(root_id->connection_id);
250 service = parent_service;
251 if (service && service->is_embed_root())
252 return service;
254 return nullptr;
257 void ConnectionManager::ProcessViewBoundsChanged(const ServerView* view,
258 const gfx::Rect& old_bounds,
259 const gfx::Rect& new_bounds) {
260 for (auto& pair : connection_map_) {
261 pair.second->service()->ProcessViewBoundsChanged(
262 view, old_bounds, new_bounds, IsChangeSource(pair.first));
266 void ConnectionManager::ProcessWillChangeViewHierarchy(
267 const ServerView* view,
268 const ServerView* new_parent,
269 const ServerView* old_parent) {
270 for (auto& pair : connection_map_) {
271 pair.second->service()->ProcessWillChangeViewHierarchy(
272 view, new_parent, old_parent, IsChangeSource(pair.first));
276 void ConnectionManager::ProcessViewHierarchyChanged(
277 const ServerView* view,
278 const ServerView* new_parent,
279 const ServerView* old_parent) {
280 for (auto& pair : connection_map_) {
281 pair.second->service()->ProcessViewHierarchyChanged(
282 view, new_parent, old_parent, IsChangeSource(pair.first));
286 void ConnectionManager::ProcessViewReorder(
287 const ServerView* view,
288 const ServerView* relative_view,
289 const mojo::OrderDirection direction) {
290 for (auto& pair : connection_map_) {
291 pair.second->service()->ProcessViewReorder(view, relative_view, direction,
292 IsChangeSource(pair.first));
296 void ConnectionManager::ProcessViewDeleted(const ViewId& view) {
297 for (auto& pair : connection_map_) {
298 pair.second->service()->ProcessViewDeleted(view,
299 IsChangeSource(pair.first));
303 void ConnectionManager::ProcessViewportMetricsChanged(
304 const mojo::ViewportMetrics& old_metrics,
305 const mojo::ViewportMetrics& new_metrics) {
306 for (auto& pair : connection_map_) {
307 pair.second->service()->ProcessViewportMetricsChanged(
308 old_metrics, new_metrics, IsChangeSource(pair.first));
312 void ConnectionManager::PrepareForChange(ScopedChange* change) {
313 // Should only ever have one change in flight.
314 CHECK(!current_change_);
315 current_change_ = change;
318 void ConnectionManager::FinishChange() {
319 // PrepareForChange/FinishChange should be balanced.
320 CHECK(current_change_);
321 current_change_ = NULL;
324 void ConnectionManager::AddConnection(ClientConnection* connection) {
325 DCHECK_EQ(0u, connection_map_.count(connection->service()->id()));
326 connection_map_[connection->service()->id()] = connection;
329 scoped_ptr<cc::CompositorFrame>
330 ConnectionManager::UpdateViewTreeFromCompositorFrame(
331 const mojo::CompositorFramePtr& input) {
332 return ConvertToCompositorFrame(input, this);
335 SurfacesState* ConnectionManager::GetSurfacesState() {
336 return surfaces_state_.get();
339 void ConnectionManager::OnScheduleViewPaint(const ServerView* view) {
340 if (!in_destructor_)
341 SchedulePaint(view, gfx::Rect(view->bounds().size()));
344 const ServerView* ConnectionManager::GetRootView(const ServerView* view) const {
345 const ViewTreeHostImpl* host = GetViewTreeHostByView(view);
346 return host ? host->root_view() : nullptr;
349 void ConnectionManager::OnViewDestroyed(ServerView* view) {
350 if (!in_destructor_)
351 ProcessViewDeleted(view->id());
354 void ConnectionManager::OnWillChangeViewHierarchy(ServerView* view,
355 ServerView* new_parent,
356 ServerView* old_parent) {
357 if (in_destructor_)
358 return;
360 ProcessWillChangeViewHierarchy(view, new_parent, old_parent);
363 void ConnectionManager::OnViewHierarchyChanged(ServerView* view,
364 ServerView* new_parent,
365 ServerView* old_parent) {
366 if (in_destructor_)
367 return;
369 ProcessViewHierarchyChanged(view, new_parent, old_parent);
371 // TODO(beng): optimize.
372 if (old_parent)
373 SchedulePaint(old_parent, gfx::Rect(old_parent->bounds().size()));
374 if (new_parent)
375 SchedulePaint(new_parent, gfx::Rect(new_parent->bounds().size()));
378 void ConnectionManager::OnViewBoundsChanged(ServerView* view,
379 const gfx::Rect& old_bounds,
380 const gfx::Rect& new_bounds) {
381 if (in_destructor_)
382 return;
384 ProcessViewBoundsChanged(view, old_bounds, new_bounds);
385 if (!view->parent())
386 return;
388 // TODO(sky): optimize this.
389 SchedulePaint(view->parent(), old_bounds);
390 SchedulePaint(view->parent(), new_bounds);
393 void ConnectionManager::OnViewReordered(ServerView* view,
394 ServerView* relative,
395 mojo::OrderDirection direction) {
396 if (!in_destructor_)
397 SchedulePaint(view, gfx::Rect(view->bounds().size()));
400 void ConnectionManager::OnWillChangeViewVisibility(ServerView* view) {
401 if (in_destructor_)
402 return;
404 // Need to repaint if the view was drawn (which means it's in the process of
405 // hiding) or the view is transitioning to drawn.
406 if (view->parent() &&
407 (view->IsDrawn() || (!view->visible() && view->parent()->IsDrawn()))) {
408 SchedulePaint(view->parent(), view->bounds());
411 for (auto& pair : connection_map_) {
412 pair.second->service()->ProcessWillChangeViewVisibility(
413 view, IsChangeSource(pair.first));
417 void ConnectionManager::OnViewSharedPropertyChanged(
418 ServerView* view,
419 const std::string& name,
420 const std::vector<uint8_t>* new_data) {
421 for (auto& pair : connection_map_) {
422 pair.second->service()->ProcessViewPropertyChanged(
423 view, name, new_data, IsChangeSource(pair.first));
427 void ConnectionManager::OnViewTextInputStateChanged(
428 ServerView* view,
429 const ui::TextInputState& state) {
430 ViewTreeHostImpl* host = GetViewTreeHostByView(view);
431 host->UpdateTextInputState(view, state);
434 bool ConnectionManager::ConvertSurfaceDrawQuad(
435 const mojo::QuadPtr& input,
436 const mojo::CompositorFrameMetadataPtr& metadata,
437 cc::SharedQuadState* sqs,
438 cc::RenderPass* render_pass) {
439 unsigned int id = static_cast<unsigned int>(
440 input->surface_quad_state->surface.To<cc::SurfaceId>().id);
441 // TODO(fsamuel): Security checks:
442 // 1. We need to make sure the embedder can only position views it's allowed
443 // to access.
444 // 2. We need to make sure that the embedder cannot place views in areas
445 // outside of its own bounds.
446 ServerView* view = GetView(ViewIdFromTransportId(id));
447 // If a CompositorFrame message arrives late, say during a navigation, then
448 // it may contain view IDs that no longer exist.
449 if (!view)
450 return false;
451 gfx::Rect bounds(input->visible_rect.To<gfx::Rect>());
452 gfx::Point p;
453 sqs->quad_to_target_transform.TransformPoint(&p);
454 bounds.set_origin(p);
455 // TODO(fsamuel): This seems like a crude way to set the size that probably
456 // doesn't work correctly in the general case. We need to get transforms
457 // working correctly in the general case.
458 bounds.set_size(gfx::ToRoundedSize(
459 gfx::ScaleSize(bounds.size(), metadata->device_scale_factor)));
460 view->SetBounds(bounds);
461 return true;
464 } // namespace mus