Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / mus / connection_manager.cc
blobb82ed5f42f95cb80463877ae20113787b915b712
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 "cc/quads/surface_draw_quad.h"
12 #include "components/mus/client_connection.h"
13 #include "components/mus/connection_manager_delegate.h"
14 #include "components/mus/server_view.h"
15 #include "components/mus/view_coordinate_conversions.h"
16 #include "components/mus/view_tree_host_connection.h"
17 #include "components/mus/view_tree_impl.h"
18 #include "mojo/application/public/cpp/application_connection.h"
19 #include "mojo/converters/geometry/geometry_type_converters.h"
20 #include "mojo/converters/input_events/input_events_type_converters.h"
21 #include "mojo/converters/surfaces/surfaces_type_converters.h"
22 #include "ui/gfx/geometry/size_conversions.h"
24 namespace mus {
26 ConnectionManager::ScopedChange::ScopedChange(
27 ViewTreeImpl* connection,
28 ConnectionManager* connection_manager,
29 bool is_delete_view)
30 : connection_manager_(connection_manager),
31 connection_id_(connection->id()),
32 is_delete_view_(is_delete_view) {
33 connection_manager_->PrepareForChange(this);
36 ConnectionManager::ScopedChange::~ScopedChange() {
37 connection_manager_->FinishChange();
40 ConnectionManager::ConnectionManager(
41 ConnectionManagerDelegate* delegate,
42 const scoped_refptr<SurfacesState>& surfaces_state)
43 : delegate_(delegate),
44 surfaces_state_(surfaces_state),
45 next_connection_id_(1),
46 next_host_id_(0),
47 current_change_(nullptr),
48 in_destructor_(false) {}
50 ConnectionManager::~ConnectionManager() {
51 in_destructor_ = true;
53 // Copy the HostConnectionMap because it will be mutated as the connections
54 // are closed.
55 HostConnectionMap host_connection_map(host_connection_map_);
56 for (auto& pair : host_connection_map)
57 pair.second->CloseConnection();
59 STLDeleteValues(&connection_map_);
60 // All the connections should have been destroyed.
61 DCHECK(host_connection_map_.empty());
62 DCHECK(connection_map_.empty());
65 void ConnectionManager::AddHost(ViewTreeHostConnection* host_connection) {
66 DCHECK_EQ(0u, host_connection_map_.count(host_connection->view_tree_host()));
67 host_connection_map_[host_connection->view_tree_host()] = host_connection;
70 ServerView* ConnectionManager::CreateServerView(const ViewId& id) {
71 ServerView* view = new ServerView(this, id);
72 view->AddObserver(this);
73 return view;
76 ConnectionSpecificId ConnectionManager::GetAndAdvanceNextConnectionId() {
77 const ConnectionSpecificId id = next_connection_id_++;
78 DCHECK_LT(id, next_connection_id_);
79 return id;
82 uint16_t ConnectionManager::GetAndAdvanceNextHostId() {
83 const uint16_t id = next_host_id_++;
84 DCHECK_LT(id, next_host_id_);
85 return id;
88 void ConnectionManager::OnConnectionError(ClientConnection* connection) {
89 // This will be null if the root has been destroyed.
90 const ViewId* view_id = connection->service()->root();
91 ServerView* view =
92 view_id ? GetView(*connection->service()->root()) : nullptr;
93 // If the ViewTree root is a viewport root, then we'll wait until
94 // the root connection goes away to cleanup.
95 if (view && (GetRootView(view) == view))
96 return;
98 scoped_ptr<ClientConnection> connection_owner(connection);
100 connection_map_.erase(connection->service()->id());
102 // Notify remaining connections so that they can cleanup.
103 for (auto& pair : connection_map_) {
104 pair.second->service()->OnWillDestroyViewTreeImpl(connection->service());
108 void ConnectionManager::OnHostConnectionClosed(
109 ViewTreeHostConnection* connection) {
110 auto it = host_connection_map_.find(connection->view_tree_host());
111 DCHECK(it != host_connection_map_.end());
113 // Get the ClientConnection by ViewTreeImpl ID.
114 ConnectionMap::iterator service_connection_it =
115 connection_map_.find(it->first->GetViewTree()->id());
116 DCHECK(service_connection_it != connection_map_.end());
118 // Tear down the associated ViewTree connection.
119 // TODO(fsamuel): I don't think this is quite right, we should tear down all
120 // connections within the root's viewport. We should probably employ an
121 // observer pattern to do this. Each ViewTreeImpl should track its
122 // parent's lifetime.
123 host_connection_map_.erase(it);
124 OnConnectionError(service_connection_it->second);
126 // If we have no more roots left, let the app know so it can terminate.
127 if (!host_connection_map_.size())
128 delegate_->OnNoMoreRootConnections();
131 void ConnectionManager::EmbedAtView(ConnectionSpecificId creator_id,
132 const ViewId& view_id,
133 uint32_t policy_bitmask,
134 mojo::URLRequestPtr request) {
135 mojo::ViewTreePtr service_ptr;
136 ClientConnection* client_connection =
137 delegate_->CreateClientConnectionForEmbedAtView(
138 this, GetProxy(&service_ptr), creator_id, request.Pass(), view_id,
139 policy_bitmask);
140 AddConnection(client_connection);
141 client_connection->service()->Init(client_connection->client(),
142 service_ptr.Pass());
143 OnConnectionMessagedClient(client_connection->service()->id());
146 ViewTreeImpl* ConnectionManager::EmbedAtView(ConnectionSpecificId creator_id,
147 const ViewId& view_id,
148 uint32_t policy_bitmask,
149 mojo::ViewTreeClientPtr client) {
150 mojo::ViewTreePtr service_ptr;
151 ClientConnection* client_connection =
152 delegate_->CreateClientConnectionForEmbedAtView(
153 this, GetProxy(&service_ptr), creator_id, view_id, policy_bitmask,
154 client.Pass());
155 AddConnection(client_connection);
156 client_connection->service()->Init(client_connection->client(),
157 service_ptr.Pass());
158 OnConnectionMessagedClient(client_connection->service()->id());
160 return client_connection->service();
163 ViewTreeImpl* ConnectionManager::GetConnection(
164 ConnectionSpecificId connection_id) {
165 ConnectionMap::iterator i = connection_map_.find(connection_id);
166 return i == connection_map_.end() ? nullptr : i->second->service();
169 ServerView* ConnectionManager::GetView(const ViewId& id) {
170 for (auto& pair : host_connection_map_) {
171 if (pair.first->root_view()->id() == id)
172 return pair.first->root_view();
174 ViewTreeImpl* service = GetConnection(id.connection_id);
175 return service ? service->GetView(id) : nullptr;
178 bool ConnectionManager::IsViewAttachedToRoot(const ServerView* view) const {
179 for (auto& pair : host_connection_map_) {
180 if (pair.first->IsViewAttachedToRoot(view))
181 return true;
183 return false;
186 void ConnectionManager::SchedulePaint(const ServerView* view,
187 const gfx::Rect& bounds) {
188 for (auto& pair : host_connection_map_) {
189 if (pair.first->SchedulePaintIfInViewport(view, bounds))
190 return;
194 void ConnectionManager::OnConnectionMessagedClient(ConnectionSpecificId id) {
195 if (current_change_)
196 current_change_->MarkConnectionAsMessaged(id);
199 bool ConnectionManager::DidConnectionMessageClient(
200 ConnectionSpecificId id) const {
201 return current_change_ && current_change_->DidMessageConnection(id);
204 mojo::ViewportMetricsPtr ConnectionManager::GetViewportMetricsForView(
205 const ServerView* view) {
206 ViewTreeHostImpl* host = GetViewTreeHostByView(view);
207 if (host)
208 return host->GetViewportMetrics().Clone();
210 if (!host_connection_map_.empty())
211 return host_connection_map_.begin()->first->GetViewportMetrics().Clone();
213 mojo::ViewportMetricsPtr metrics = mojo::ViewportMetrics::New();
214 metrics->size_in_pixels = mojo::Size::New();
215 return metrics.Pass();
218 const ViewTreeImpl* ConnectionManager::GetConnectionWithRoot(
219 const ViewId& id) const {
220 for (auto& pair : connection_map_) {
221 if (pair.second->service()->IsRoot(id))
222 return pair.second->service();
224 return nullptr;
227 ViewTreeHostImpl* ConnectionManager::GetViewTreeHostByView(
228 const ServerView* view) {
229 return const_cast<ViewTreeHostImpl*>(
230 static_cast<const ConnectionManager*>(this)->GetViewTreeHostByView(view));
233 const ViewTreeHostImpl* ConnectionManager::GetViewTreeHostByView(
234 const ServerView* view) const {
235 while (view && view->parent())
236 view = view->parent();
237 for (auto& pair : host_connection_map_) {
238 if (view == pair.first->root_view())
239 return pair.first;
241 return nullptr;
244 ViewTreeImpl* ConnectionManager::GetEmbedRoot(ViewTreeImpl* service) {
245 while (service) {
246 const ViewId* root_id = service->root();
247 if (!root_id || root_id->connection_id == service->id())
248 return nullptr;
250 ViewTreeImpl* parent_service = GetConnection(root_id->connection_id);
251 service = parent_service;
252 if (service && service->is_embed_root())
253 return service;
255 return nullptr;
258 void ConnectionManager::ProcessViewBoundsChanged(const ServerView* view,
259 const gfx::Rect& old_bounds,
260 const gfx::Rect& new_bounds) {
261 for (auto& pair : connection_map_) {
262 pair.second->service()->ProcessViewBoundsChanged(
263 view, old_bounds, new_bounds, IsChangeSource(pair.first));
267 void ConnectionManager::ProcessWillChangeViewHierarchy(
268 const ServerView* view,
269 const ServerView* new_parent,
270 const ServerView* old_parent) {
271 for (auto& pair : connection_map_) {
272 pair.second->service()->ProcessWillChangeViewHierarchy(
273 view, new_parent, old_parent, IsChangeSource(pair.first));
277 void ConnectionManager::ProcessViewHierarchyChanged(
278 const ServerView* view,
279 const ServerView* new_parent,
280 const ServerView* old_parent) {
281 for (auto& pair : connection_map_) {
282 pair.second->service()->ProcessViewHierarchyChanged(
283 view, new_parent, old_parent, IsChangeSource(pair.first));
287 void ConnectionManager::ProcessViewReorder(
288 const ServerView* view,
289 const ServerView* relative_view,
290 const mojo::OrderDirection direction) {
291 for (auto& pair : connection_map_) {
292 pair.second->service()->ProcessViewReorder(view, relative_view, direction,
293 IsChangeSource(pair.first));
297 void ConnectionManager::ProcessViewDeleted(const ViewId& view) {
298 for (auto& pair : connection_map_) {
299 pair.second->service()->ProcessViewDeleted(view,
300 IsChangeSource(pair.first));
304 void ConnectionManager::ProcessViewportMetricsChanged(
305 const mojo::ViewportMetrics& old_metrics,
306 const mojo::ViewportMetrics& new_metrics) {
307 for (auto& pair : connection_map_) {
308 pair.second->service()->ProcessViewportMetricsChanged(
309 old_metrics, new_metrics, IsChangeSource(pair.first));
313 void ConnectionManager::PrepareForChange(ScopedChange* change) {
314 // Should only ever have one change in flight.
315 CHECK(!current_change_);
316 current_change_ = change;
319 void ConnectionManager::FinishChange() {
320 // PrepareForChange/FinishChange should be balanced.
321 CHECK(current_change_);
322 current_change_ = NULL;
325 void ConnectionManager::AddConnection(ClientConnection* connection) {
326 DCHECK_EQ(0u, connection_map_.count(connection->service()->id()));
327 connection_map_[connection->service()->id()] = connection;
330 scoped_ptr<cc::CompositorFrame>
331 ConnectionManager::UpdateViewTreeFromCompositorFrame(
332 const mojo::CompositorFramePtr& input) {
333 return ConvertToCompositorFrame(input, this);
336 SurfacesState* ConnectionManager::GetSurfacesState() {
337 return surfaces_state_.get();
340 void ConnectionManager::OnScheduleViewPaint(const ServerView* view) {
341 if (!in_destructor_)
342 SchedulePaint(view, gfx::Rect(view->bounds().size()));
345 const ServerView* ConnectionManager::GetRootView(const ServerView* view) const {
346 const ViewTreeHostImpl* host = GetViewTreeHostByView(view);
347 return host ? host->root_view() : nullptr;
350 void ConnectionManager::OnViewDestroyed(ServerView* view) {
351 if (!in_destructor_)
352 ProcessViewDeleted(view->id());
355 void ConnectionManager::OnWillChangeViewHierarchy(ServerView* view,
356 ServerView* new_parent,
357 ServerView* old_parent) {
358 if (in_destructor_)
359 return;
361 ProcessWillChangeViewHierarchy(view, new_parent, old_parent);
364 void ConnectionManager::OnViewHierarchyChanged(ServerView* view,
365 ServerView* new_parent,
366 ServerView* old_parent) {
367 if (in_destructor_)
368 return;
370 ProcessViewHierarchyChanged(view, new_parent, old_parent);
372 // TODO(beng): optimize.
373 if (old_parent)
374 SchedulePaint(old_parent, gfx::Rect(old_parent->bounds().size()));
375 if (new_parent)
376 SchedulePaint(new_parent, gfx::Rect(new_parent->bounds().size()));
379 void ConnectionManager::OnViewBoundsChanged(ServerView* view,
380 const gfx::Rect& old_bounds,
381 const gfx::Rect& new_bounds) {
382 if (in_destructor_)
383 return;
385 ProcessViewBoundsChanged(view, old_bounds, new_bounds);
386 if (!view->parent())
387 return;
389 // TODO(sky): optimize this.
390 SchedulePaint(view->parent(), old_bounds);
391 SchedulePaint(view->parent(), new_bounds);
394 void ConnectionManager::OnViewReordered(ServerView* view,
395 ServerView* relative,
396 mojo::OrderDirection direction) {
397 if (!in_destructor_)
398 SchedulePaint(view, gfx::Rect(view->bounds().size()));
401 void ConnectionManager::OnWillChangeViewVisibility(ServerView* view) {
402 if (in_destructor_)
403 return;
405 // Need to repaint if the view was drawn (which means it's in the process of
406 // hiding) or the view is transitioning to drawn.
407 if (view->parent() &&
408 (view->IsDrawn() || (!view->visible() && view->parent()->IsDrawn()))) {
409 SchedulePaint(view->parent(), view->bounds());
412 for (auto& pair : connection_map_) {
413 pair.second->service()->ProcessWillChangeViewVisibility(
414 view, IsChangeSource(pair.first));
418 void ConnectionManager::OnViewSharedPropertyChanged(
419 ServerView* view,
420 const std::string& name,
421 const std::vector<uint8_t>* new_data) {
422 for (auto& pair : connection_map_) {
423 pair.second->service()->ProcessViewPropertyChanged(
424 view, name, new_data, IsChangeSource(pair.first));
428 void ConnectionManager::OnViewTextInputStateChanged(
429 ServerView* view,
430 const ui::TextInputState& state) {
431 ViewTreeHostImpl* host = GetViewTreeHostByView(view);
432 host->UpdateTextInputState(view, state);
435 bool ConnectionManager::ConvertSurfaceDrawQuad(
436 const mojo::QuadPtr& input,
437 const mojo::CompositorFrameMetadataPtr& metadata,
438 cc::SharedQuadState* sqs,
439 cc::RenderPass* render_pass) {
440 unsigned int id = static_cast<unsigned int>(
441 input->surface_quad_state->surface.To<cc::SurfaceId>().id);
442 // TODO(fsamuel): Security checks:
443 // 1. We need to make sure the embedder can only position views it's allowed
444 // to access.
445 // 2. We need to make sure that the embedder cannot place views in areas
446 // outside of its own bounds.
447 ServerView* view = GetView(ViewIdFromTransportId(id));
448 // If a CompositorFrame message arrives late, say during a navigation, then
449 // it may contain view IDs that no longer exist.
450 if (!view || view->surface_id().is_null())
451 return false;
453 // TODO(fsamuel): This shouldn't be in the ConnectionManager. Let's find a
454 // better home for it. http://crbug.com/533029.
455 cc::SurfaceDrawQuad* surface_quad =
456 render_pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>();
457 surface_quad->SetAll(
458 sqs,
459 input->rect.To<gfx::Rect>(),
460 input->opaque_rect.To<gfx::Rect>(),
461 input->visible_rect.To<gfx::Rect>(),
462 input->needs_blending,
463 view->surface_id());
464 return true;
467 } // namespace mus