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 using mojo::ConnectionSpecificId
;
25 namespace view_manager
{
27 ConnectionManager::ScopedChange::ScopedChange(
28 ViewTreeImpl
* connection
,
29 ConnectionManager
* connection_manager
,
31 : connection_manager_(connection_manager
),
32 connection_id_(connection
->id()),
33 is_delete_view_(is_delete_view
) {
34 connection_manager_
->PrepareForChange(this);
37 ConnectionManager::ScopedChange::~ScopedChange() {
38 connection_manager_
->FinishChange();
41 ConnectionManager::ConnectionManager(
42 ConnectionManagerDelegate
* delegate
,
43 const scoped_refptr
<surfaces::SurfacesState
>& surfaces_state
)
44 : delegate_(delegate
),
45 surfaces_state_(surfaces_state
),
46 next_connection_id_(1),
48 current_change_(nullptr),
49 in_destructor_(false) {}
51 ConnectionManager::~ConnectionManager() {
52 in_destructor_
= true;
54 // Copy the HostConnectionMap because it will be mutated as the connections
56 HostConnectionMap
host_connection_map(host_connection_map_
);
57 for (auto& pair
: host_connection_map
)
58 pair
.second
->CloseConnection();
60 STLDeleteValues(&connection_map_
);
61 // All the connections should have been destroyed.
62 DCHECK(host_connection_map_
.empty());
63 DCHECK(connection_map_
.empty());
66 void ConnectionManager::AddHost(ViewTreeHostConnection
* host_connection
) {
67 DCHECK_EQ(0u, host_connection_map_
.count(host_connection
->view_tree_host()));
68 host_connection_map_
[host_connection
->view_tree_host()] = host_connection
;
71 ServerView
* ConnectionManager::CreateServerView(const ViewId
& id
) {
72 ServerView
* view
= new ServerView(this, id
);
73 view
->AddObserver(this);
77 ConnectionSpecificId
ConnectionManager::GetAndAdvanceNextConnectionId() {
78 const ConnectionSpecificId id
= next_connection_id_
++;
79 DCHECK_LT(id
, next_connection_id_
);
83 uint16_t ConnectionManager::GetAndAdvanceNextHostId() {
84 const uint16_t id
= next_host_id_
++;
85 DCHECK_LT(id
, next_host_id_
);
89 void ConnectionManager::OnConnectionError(ClientConnection
* connection
) {
90 // This will be null if the root has been destroyed.
91 const ViewId
* view_id
= connection
->service()->root();
93 view_id
? GetView(*connection
->service()->root()) : nullptr;
94 // If the ViewTree root is a viewport root, then we'll wait until
95 // the root connection goes away to cleanup.
96 if (view
&& (GetRootView(view
) == view
))
99 scoped_ptr
<ClientConnection
> connection_owner(connection
);
101 connection_map_
.erase(connection
->service()->id());
103 // Notify remaining connections so that they can cleanup.
104 for (auto& pair
: connection_map_
) {
105 pair
.second
->service()->OnWillDestroyViewTreeImpl(connection
->service());
109 void ConnectionManager::OnHostConnectionClosed(
110 ViewTreeHostConnection
* connection
) {
111 auto it
= host_connection_map_
.find(connection
->view_tree_host());
112 DCHECK(it
!= host_connection_map_
.end());
114 // Get the ClientConnection by ViewTreeImpl ID.
115 ConnectionMap::iterator service_connection_it
=
116 connection_map_
.find(it
->first
->GetViewTree()->id());
117 DCHECK(service_connection_it
!= connection_map_
.end());
119 // Tear down the associated ViewTree connection.
120 // TODO(fsamuel): I don't think this is quite right, we should tear down all
121 // connections within the root's viewport. We should probably employ an
122 // observer pattern to do this. Each ViewTreeImpl should track its
123 // parent's lifetime.
124 host_connection_map_
.erase(it
);
125 OnConnectionError(service_connection_it
->second
);
127 // If we have no more roots left, let the app know so it can terminate.
128 if (!host_connection_map_
.size())
129 delegate_
->OnNoMoreRootConnections();
132 void ConnectionManager::EmbedAtView(mojo::ConnectionSpecificId creator_id
,
133 const ViewId
& view_id
,
134 uint32_t policy_bitmask
,
135 mojo::URLRequestPtr request
) {
136 mojo::ViewTreePtr service_ptr
;
137 ClientConnection
* client_connection
=
138 delegate_
->CreateClientConnectionForEmbedAtView(
139 this, GetProxy(&service_ptr
), creator_id
, request
.Pass(), view_id
,
141 AddConnection(client_connection
);
142 client_connection
->service()->Init(client_connection
->client(),
144 OnConnectionMessagedClient(client_connection
->service()->id());
147 ViewTreeImpl
* ConnectionManager::EmbedAtView(
148 mojo::ConnectionSpecificId creator_id
,
149 const ViewId
& view_id
,
150 uint32_t policy_bitmask
,
151 mojo::ViewTreeClientPtr client
) {
152 mojo::ViewTreePtr service_ptr
;
153 ClientConnection
* client_connection
=
154 delegate_
->CreateClientConnectionForEmbedAtView(
155 this, GetProxy(&service_ptr
), creator_id
, view_id
, policy_bitmask
,
157 AddConnection(client_connection
);
158 client_connection
->service()->Init(client_connection
->client(),
160 OnConnectionMessagedClient(client_connection
->service()->id());
162 return client_connection
->service();
165 ViewTreeImpl
* ConnectionManager::GetConnection(
166 ConnectionSpecificId connection_id
) {
167 ConnectionMap::iterator i
= connection_map_
.find(connection_id
);
168 return i
== connection_map_
.end() ? nullptr : i
->second
->service();
171 ServerView
* ConnectionManager::GetView(const ViewId
& id
) {
172 for (auto& pair
: host_connection_map_
) {
173 if (pair
.first
->root_view()->id() == id
)
174 return pair
.first
->root_view();
176 ViewTreeImpl
* service
= GetConnection(id
.connection_id
);
177 return service
? service
->GetView(id
) : nullptr;
180 bool ConnectionManager::IsViewAttachedToRoot(const ServerView
* view
) const {
181 for (auto& pair
: host_connection_map_
) {
182 if (pair
.first
->IsViewAttachedToRoot(view
))
188 void ConnectionManager::SchedulePaint(const ServerView
* view
,
189 const gfx::Rect
& bounds
) {
190 for (auto& pair
: host_connection_map_
) {
191 if (pair
.first
->SchedulePaintIfInViewport(view
, bounds
))
196 void ConnectionManager::OnConnectionMessagedClient(ConnectionSpecificId id
) {
198 current_change_
->MarkConnectionAsMessaged(id
);
201 bool ConnectionManager::DidConnectionMessageClient(
202 ConnectionSpecificId id
) const {
203 return current_change_
&& current_change_
->DidMessageConnection(id
);
206 mojo::ViewportMetricsPtr
ConnectionManager::GetViewportMetricsForView(
207 const ServerView
* view
) {
208 ViewTreeHostImpl
* host
= GetViewTreeHostByView(view
);
210 return host
->GetViewportMetrics().Clone();
212 if (!host_connection_map_
.empty())
213 return host_connection_map_
.begin()->first
->GetViewportMetrics().Clone();
215 mojo::ViewportMetricsPtr metrics
= mojo::ViewportMetrics::New();
216 metrics
->size_in_pixels
= mojo::Size::New();
217 return metrics
.Pass();
220 const ViewTreeImpl
* ConnectionManager::GetConnectionWithRoot(
221 const ViewId
& id
) const {
222 for (auto& pair
: connection_map_
) {
223 if (pair
.second
->service()->IsRoot(id
))
224 return pair
.second
->service();
229 ViewTreeHostImpl
* ConnectionManager::GetViewTreeHostByView(
230 const ServerView
* view
) {
231 return const_cast<ViewTreeHostImpl
*>(
232 static_cast<const ConnectionManager
*>(this)->GetViewTreeHostByView(view
));
235 const ViewTreeHostImpl
* ConnectionManager::GetViewTreeHostByView(
236 const ServerView
* view
) const {
237 while (view
&& view
->parent())
238 view
= view
->parent();
239 for (auto& pair
: host_connection_map_
) {
240 if (view
== pair
.first
->root_view())
246 ViewTreeImpl
* ConnectionManager::GetEmbedRoot(ViewTreeImpl
* service
) {
248 const ViewId
* root_id
= service
->root();
249 if (!root_id
|| root_id
->connection_id
== service
->id())
252 ViewTreeImpl
* parent_service
= GetConnection(root_id
->connection_id
);
253 service
= parent_service
;
254 if (service
&& service
->is_embed_root())
260 void ConnectionManager::ProcessViewBoundsChanged(const ServerView
* view
,
261 const gfx::Rect
& old_bounds
,
262 const gfx::Rect
& new_bounds
) {
263 for (auto& pair
: connection_map_
) {
264 pair
.second
->service()->ProcessViewBoundsChanged(
265 view
, old_bounds
, new_bounds
, IsChangeSource(pair
.first
));
269 void ConnectionManager::ProcessWillChangeViewHierarchy(
270 const ServerView
* view
,
271 const ServerView
* new_parent
,
272 const ServerView
* old_parent
) {
273 for (auto& pair
: connection_map_
) {
274 pair
.second
->service()->ProcessWillChangeViewHierarchy(
275 view
, new_parent
, old_parent
, IsChangeSource(pair
.first
));
279 void ConnectionManager::ProcessViewHierarchyChanged(
280 const ServerView
* view
,
281 const ServerView
* new_parent
,
282 const ServerView
* old_parent
) {
283 for (auto& pair
: connection_map_
) {
284 pair
.second
->service()->ProcessViewHierarchyChanged(
285 view
, new_parent
, old_parent
, IsChangeSource(pair
.first
));
289 void ConnectionManager::ProcessViewReorder(
290 const ServerView
* view
,
291 const ServerView
* relative_view
,
292 const mojo::OrderDirection direction
) {
293 for (auto& pair
: connection_map_
) {
294 pair
.second
->service()->ProcessViewReorder(view
, relative_view
, direction
,
295 IsChangeSource(pair
.first
));
299 void ConnectionManager::ProcessViewDeleted(const ViewId
& view
) {
300 for (auto& pair
: connection_map_
) {
301 pair
.second
->service()->ProcessViewDeleted(view
,
302 IsChangeSource(pair
.first
));
306 void ConnectionManager::ProcessViewportMetricsChanged(
307 const mojo::ViewportMetrics
& old_metrics
,
308 const mojo::ViewportMetrics
& new_metrics
) {
309 for (auto& pair
: connection_map_
) {
310 pair
.second
->service()->ProcessViewportMetricsChanged(
311 old_metrics
, new_metrics
, IsChangeSource(pair
.first
));
315 void ConnectionManager::PrepareForChange(ScopedChange
* change
) {
316 // Should only ever have one change in flight.
317 CHECK(!current_change_
);
318 current_change_
= change
;
321 void ConnectionManager::FinishChange() {
322 // PrepareForChange/FinishChange should be balanced.
323 CHECK(current_change_
);
324 current_change_
= NULL
;
327 void ConnectionManager::AddConnection(ClientConnection
* connection
) {
328 DCHECK_EQ(0u, connection_map_
.count(connection
->service()->id()));
329 connection_map_
[connection
->service()->id()] = connection
;
332 scoped_ptr
<cc::CompositorFrame
>
333 ConnectionManager::UpdateViewTreeFromCompositorFrame(
334 const mojo::CompositorFramePtr
& input
) {
335 return ConvertToCompositorFrame(input
, this);
338 surfaces::SurfacesState
* ConnectionManager::GetSurfacesState() {
339 return surfaces_state_
.get();
342 void ConnectionManager::OnScheduleViewPaint(const ServerView
* view
) {
344 SchedulePaint(view
, gfx::Rect(view
->bounds().size()));
347 const ServerView
* ConnectionManager::GetRootView(const ServerView
* view
) const {
348 const ViewTreeHostImpl
* host
= GetViewTreeHostByView(view
);
349 return host
? host
->root_view() : nullptr;
352 void ConnectionManager::OnViewDestroyed(ServerView
* view
) {
354 ProcessViewDeleted(view
->id());
357 void ConnectionManager::OnWillChangeViewHierarchy(ServerView
* view
,
358 ServerView
* new_parent
,
359 ServerView
* old_parent
) {
363 ProcessWillChangeViewHierarchy(view
, new_parent
, old_parent
);
366 void ConnectionManager::OnViewHierarchyChanged(ServerView
* view
,
367 ServerView
* new_parent
,
368 ServerView
* old_parent
) {
372 ProcessViewHierarchyChanged(view
, new_parent
, old_parent
);
374 // TODO(beng): optimize.
376 SchedulePaint(old_parent
, gfx::Rect(old_parent
->bounds().size()));
378 SchedulePaint(new_parent
, gfx::Rect(new_parent
->bounds().size()));
381 void ConnectionManager::OnViewBoundsChanged(ServerView
* view
,
382 const gfx::Rect
& old_bounds
,
383 const gfx::Rect
& new_bounds
) {
387 ProcessViewBoundsChanged(view
, old_bounds
, new_bounds
);
391 // TODO(sky): optimize this.
392 SchedulePaint(view
->parent(), old_bounds
);
393 SchedulePaint(view
->parent(), new_bounds
);
396 void ConnectionManager::OnViewReordered(ServerView
* view
,
397 ServerView
* relative
,
398 mojo::OrderDirection direction
) {
400 SchedulePaint(view
, gfx::Rect(view
->bounds().size()));
403 void ConnectionManager::OnWillChangeViewVisibility(ServerView
* view
) {
407 // Need to repaint if the view was drawn (which means it's in the process of
408 // hiding) or the view is transitioning to drawn.
409 if (view
->parent() &&
410 (view
->IsDrawn() || (!view
->visible() && view
->parent()->IsDrawn()))) {
411 SchedulePaint(view
->parent(), view
->bounds());
414 for (auto& pair
: connection_map_
) {
415 pair
.second
->service()->ProcessWillChangeViewVisibility(
416 view
, IsChangeSource(pair
.first
));
420 void ConnectionManager::OnViewSharedPropertyChanged(
422 const std::string
& name
,
423 const std::vector
<uint8_t>* new_data
) {
424 for (auto& pair
: connection_map_
) {
425 pair
.second
->service()->ProcessViewPropertyChanged(
426 view
, name
, new_data
, IsChangeSource(pair
.first
));
430 void ConnectionManager::OnViewTextInputStateChanged(
432 const ui::TextInputState
& state
) {
433 ViewTreeHostImpl
* host
= GetViewTreeHostByView(view
);
434 host
->UpdateTextInputState(view
, state
);
437 bool ConnectionManager::ConvertSurfaceDrawQuad(
438 const mojo::QuadPtr
& input
,
439 const mojo::CompositorFrameMetadataPtr
& metadata
,
440 cc::SharedQuadState
* sqs
,
441 cc::RenderPass
* render_pass
) {
442 unsigned int id
= static_cast<unsigned int>(
443 input
->surface_quad_state
->surface
.To
<cc::SurfaceId
>().id
);
444 // TODO(fsamuel): Security checks:
445 // 1. We need to make sure the embedder can only position views it's allowed
447 // 2. We need to make sure that the embedder cannot place views in areas
448 // outside of its own bounds.
449 ServerView
* view
= GetView(ViewIdFromTransportId(id
));
450 // If a CompositorFrame message arrives late, say during a navigation, then
451 // it may contain view IDs that no longer exist.
454 gfx::Rect
bounds(input
->visible_rect
.To
<gfx::Rect
>());
456 sqs
->quad_to_target_transform
.TransformPoint(&p
);
457 bounds
.set_origin(p
);
458 // TODO(fsamuel): This seems like a crude way to set the size that probably
459 // doesn't work correctly in the general case. We need to get transforms
460 // working correctly in the general case.
461 bounds
.set_size(gfx::ToRoundedSize(
462 gfx::ScaleSize(bounds
.size(), metadata
->device_scale_factor
)));
463 view
->SetBounds(bounds
);
467 } // namespace view_manager