[Media Router] Add integration tests and e2e tests for media router and presentation...
[chromium-blink-merge.git] / components / view_manager / connection_manager.cc
blob1b48c8e759a2aa2bd60b9561e085928922cea7b4
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/view_manager/connection_manager.h"
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "components/view_manager/client_connection.h"
10 #include "components/view_manager/connection_manager_delegate.h"
11 #include "components/view_manager/display_manager.h"
12 #include "components/view_manager/focus_controller.h"
13 #include "components/view_manager/server_view.h"
14 #include "components/view_manager/view_coordinate_conversions.h"
15 #include "components/view_manager/view_manager_service_impl.h"
16 #include "mojo/application/public/interfaces/service_provider.mojom.h"
17 #include "mojo/converters/geometry/geometry_type_converters.h"
18 #include "mojo/converters/input_events/input_events_type_converters.h"
20 using mojo::ConnectionSpecificId;
22 namespace view_manager {
23 namespace {
25 // Creates a copy of |view|. The copied view has |delegate| as its delegate.
26 // This does not recurse.
27 ServerView* CloneView(const ServerView* view, ServerViewDelegate* delegate) {
28 ServerView* clone = new ServerView(delegate, ClonedViewId());
29 clone->SetBounds(view->bounds());
30 clone->SetSurfaceId(view->surface_id());
31 clone->SetOpacity(view->opacity());
32 return clone;
35 // Creates copies of all the visible children of |parent|. Newly cloned views
36 // are added to |cloned_parent| and have |delegate| as their delegate. The
37 // stacking order of the cloned views is preseved.
38 void CloneViewTree(const ServerView* parent,
39 ServerView* cloned_parent,
40 ServerViewDelegate* delegate) {
41 DCHECK(parent->visible());
42 for (const ServerView* to_clone : parent->GetChildren()) {
43 if (to_clone->visible()) {
44 ServerView* cloned = CloneView(to_clone, delegate);
45 cloned_parent->Add(cloned);
46 CloneViewTree(to_clone, cloned, delegate);
51 // Recurses through all the children of |view| moving any cloned views to
52 // |new_parent| stacked above |stack_above|. |stack_above| is updated as views
53 // are moved.
54 void ReparentClonedViews(ServerView* new_parent,
55 ServerView** stack_above,
56 ServerView* view) {
57 if (view->id() == ClonedViewId()) {
58 const gfx::Rect new_bounds(ConvertRectBetweenViews(
59 view, new_parent, gfx::Rect(view->bounds().size())));
60 new_parent->Add(view);
61 new_parent->Reorder(view, *stack_above, mojo::ORDER_DIRECTION_ABOVE);
62 view->SetBounds(new_bounds);
63 *stack_above = view;
64 return;
67 for (ServerView* child : view->GetChildren())
68 ReparentClonedViews(new_parent, stack_above, child);
71 // Deletes |view| and all its descendants.
72 void DeleteViewTree(ServerView* view) {
73 for (ServerView* child : view->GetChildren())
74 DeleteViewTree(child);
76 delete view;
79 // TODO(sky): nuke, proof of concept.
80 bool DecrementAnimatingViewsOpacity(ServerView* view) {
81 if (view->id() == ClonedViewId()) {
82 const float new_opacity = view->opacity() - .05f;
83 if (new_opacity <= 0)
84 DeleteViewTree(view);
85 else
86 view->SetOpacity(new_opacity);
87 return true;
89 bool ret_value = false;
90 for (ServerView* child : view->GetChildren()) {
91 if (DecrementAnimatingViewsOpacity(child))
92 ret_value = true;
94 return ret_value;
97 } // namespace
99 ConnectionManager::ScopedChange::ScopedChange(
100 ViewManagerServiceImpl* connection,
101 ConnectionManager* connection_manager,
102 bool is_delete_view)
103 : connection_manager_(connection_manager),
104 connection_id_(connection->id()),
105 is_delete_view_(is_delete_view) {
106 connection_manager_->PrepareForChange(this);
109 ConnectionManager::ScopedChange::~ScopedChange() {
110 connection_manager_->FinishChange();
113 ConnectionManager::ConnectionManager(
114 ConnectionManagerDelegate* delegate,
115 bool is_headless,
116 mojo::ApplicationImpl* app_impl,
117 const scoped_refptr<gles2::GpuState>& gpu_state)
118 : delegate_(delegate),
119 window_manager_client_connection_(nullptr),
120 next_connection_id_(1),
121 next_root_id_(0),
122 event_dispatcher_(this),
123 current_change_(nullptr),
124 in_destructor_(false),
125 animation_runner_(base::TimeTicks::Now()),
126 focus_controller_(new FocusController(this)) {
127 view_manager_root_.reset(new ViewManagerRootImpl(
128 RootViewId(next_root_id_++), this, is_headless, app_impl, gpu_state));
129 view_manager_root_->Init();
132 ConnectionManager::~ConnectionManager() {
133 in_destructor_ = true;
135 // Deleting views will attempt to advance focus. When we're being destroyed
136 // that is not necessary. Additionally |focus_controller_| needs to be
137 // destroyed before |root_|.
138 focus_controller_.reset();
140 view_manager_root_.reset();
141 STLDeleteValues(&connection_map_);
142 // All the connections should have been destroyed.
143 DCHECK(connection_map_.empty());
146 ServerView* ConnectionManager::CreateServerView(const ViewId& id) {
147 ServerView* view = new ServerView(this, id);
148 view->AddObserver(this);
149 return view;
152 ConnectionSpecificId ConnectionManager::GetAndAdvanceNextConnectionId() {
153 const ConnectionSpecificId id = next_connection_id_++;
154 DCHECK_LT(id, next_connection_id_);
155 return id;
158 void ConnectionManager::OnConnectionError(ClientConnection* connection) {
159 if (connection == window_manager_client_connection_) {
160 window_manager_client_connection_ = nullptr;
161 delegate_->OnLostConnectionToWindowManager();
162 // Assume we've been destroyed.
163 return;
166 scoped_ptr<ClientConnection> connection_owner(connection);
168 connection_map_.erase(connection->service()->id());
170 // TODO(sky): I may want to advance focus differently if focus is in
171 // |connection|.
173 // Notify remaining connections so that they can cleanup.
174 for (auto& pair : connection_map_) {
175 pair.second->service()->OnWillDestroyViewManagerServiceImpl(
176 connection->service());
180 void ConnectionManager::EmbedAtView(mojo::ConnectionSpecificId creator_id,
181 const ViewId& view_id,
182 mojo::URLRequestPtr request) {
183 mojo::ViewManagerServicePtr service_ptr;
184 ClientConnection* client_connection =
185 delegate_->CreateClientConnectionForEmbedAtView(
186 this, GetProxy(&service_ptr), creator_id, request.Pass(), view_id);
187 AddConnection(client_connection);
188 client_connection->service()->Init(client_connection->client(),
189 service_ptr.Pass());
190 OnConnectionMessagedClient(client_connection->service()->id());
193 void ConnectionManager::EmbedAtView(mojo::ConnectionSpecificId creator_id,
194 const ViewId& view_id,
195 mojo::ViewManagerClientPtr client) {
196 mojo::ViewManagerServicePtr service_ptr;
197 ClientConnection* client_connection =
198 delegate_->CreateClientConnectionForEmbedAtView(
199 this, GetProxy(&service_ptr), creator_id, view_id, client.Pass());
200 AddConnection(client_connection);
201 client_connection->service()->Init(client_connection->client(),
202 service_ptr.Pass());
203 OnConnectionMessagedClient(client_connection->service()->id());
206 void ConnectionManager::OnAccelerator(ServerView* root, mojo::EventPtr event) {
207 // TODO(fsamuel): Support multiple roots.
208 view_manager_root_->client()->OnAccelerator(event.Pass());
211 ViewManagerServiceImpl* ConnectionManager::GetConnection(
212 ConnectionSpecificId connection_id) {
213 ConnectionMap::iterator i = connection_map_.find(connection_id);
214 return i == connection_map_.end() ? nullptr : i->second->service();
217 ServerView* ConnectionManager::GetView(const ViewId& id) {
218 // TODO(fsamuel): Support multiple roots.
219 if (view_manager_root_->root_view()->id() == id)
220 return view_manager_root_->root_view();
221 ViewManagerServiceImpl* service = GetConnection(id.connection_id);
222 return service ? service->GetView(id) : nullptr;
225 void ConnectionManager::SetFocusedView(ServerView* view) {
226 ServerView* old_focused = GetFocusedView();
227 if (old_focused == view)
228 return;
229 focus_controller_->SetFocusedView(view);
230 OnFocusChanged(old_focused, view);
233 ServerView* ConnectionManager::GetFocusedView() {
234 return focus_controller_->GetFocusedView();
237 bool ConnectionManager::IsViewAttachedToRoot(const ServerView* view) const {
238 // TODO(fsamuel): Support multiple roots.
239 return view_manager_root_->IsViewAttachedToRoot(view);
242 void ConnectionManager::SchedulePaint(const ServerView* view,
243 const gfx::Rect& bounds) {
244 // TODO(fsamuel): Support multiple roots.
245 view_manager_root_->SchedulePaintIfInViewport(view, bounds);
248 void ConnectionManager::OnDisplayClosed() {
249 // TODO(fsamuel): Only report we lost the connection to the window manager
250 // if there are no more roots.
251 delegate_->OnLostConnectionToWindowManager();
254 void ConnectionManager::OnConnectionMessagedClient(ConnectionSpecificId id) {
255 if (current_change_)
256 current_change_->MarkConnectionAsMessaged(id);
259 bool ConnectionManager::DidConnectionMessageClient(
260 ConnectionSpecificId id) const {
261 return current_change_ && current_change_->DidMessageConnection(id);
264 mojo::ViewportMetricsPtr ConnectionManager::GetViewportMetricsForView(
265 const ServerView* view) {
266 // TODO(fsamuel): Support multiple roots. We should pull the metrics from
267 // the viewport where this |view| belong.
268 return view_manager_root_->GetViewportMetrics().Clone();
271 const ViewManagerServiceImpl* ConnectionManager::GetConnectionWithRoot(
272 const ViewId& id) const {
273 for (auto& pair : connection_map_) {
274 if (pair.second->service()->IsRoot(id))
275 return pair.second->service();
277 return nullptr;
280 ViewManagerServiceImpl* ConnectionManager::GetEmbedRoot(
281 ViewManagerServiceImpl* service) {
282 while (service) {
283 const ViewId* root_id = service->root();
284 if (!root_id || root_id->connection_id == service->id())
285 return nullptr;
287 ViewManagerServiceImpl* parent_service =
288 GetConnection(root_id->connection_id);
289 service = parent_service;
290 if (service && service->is_embed_root())
291 return service;
293 return nullptr;
296 void ConnectionManager::SetWindowManagerClientConnection(
297 scoped_ptr<ClientConnection> connection) {
298 CHECK(!window_manager_client_connection_);
299 window_manager_client_connection_ = connection.release();
300 AddConnection(window_manager_client_connection_);
301 window_manager_client_connection_->service()->Init(
302 window_manager_client_connection_->client(), nullptr);
305 mojo::ViewManagerClient*
306 ConnectionManager::GetWindowManagerViewManagerClient() {
307 CHECK(window_manager_client_connection_);
308 return window_manager_client_connection_->client();
311 bool ConnectionManager::CloneAndAnimate(const ViewId& view_id) {
312 ServerView* view = GetView(view_id);
313 if (!view || !view->IsDrawn() || (view->GetRoot() == view))
314 return false;
315 if (!animation_timer_.IsRunning()) {
316 animation_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(100),
317 this, &ConnectionManager::DoAnimation);
319 ServerView* clone = CloneView(view, this);
320 CloneViewTree(view, clone, this);
321 view->parent()->Add(clone);
322 view->parent()->Reorder(clone, view, mojo::ORDER_DIRECTION_ABOVE);
323 return true;
326 void ConnectionManager::DispatchInputEventToView(const ServerView* view,
327 mojo::EventPtr event) {
328 // It's possible for events to flow through here from the platform_window
329 // before any connections are established with the view_manager.
330 if (!has_window_manager_client_connection())
331 return;
333 // If the view is an embed root, forward to the embedded view, not the owner.
334 ViewManagerServiceImpl* connection = GetConnectionWithRoot(view->id());
335 if (!connection)
336 connection = GetConnection(view->id().connection_id);
337 CHECK(connection);
338 connection->client()->OnViewInputEvent(ViewIdToTransportId(view->id()),
339 event.Pass(),
340 base::Bind(&base::DoNothing));
343 void ConnectionManager::OnEvent(ViewManagerRootImpl* root,
344 mojo::EventPtr event) {
345 event_dispatcher_.OnEvent(root->root_view(), event.Pass());
348 void ConnectionManager::AddAccelerator(ViewManagerRootImpl* root,
349 mojo::KeyboardCode keyboard_code,
350 mojo::EventFlags flags) {
351 event_dispatcher_.AddAccelerator(keyboard_code, flags);
354 void ConnectionManager::RemoveAccelerator(ViewManagerRootImpl* root,
355 mojo::KeyboardCode keyboard_code,
356 mojo::EventFlags flags) {
357 event_dispatcher_.RemoveAccelerator(keyboard_code, flags);
360 void ConnectionManager::ProcessViewBoundsChanged(const ServerView* view,
361 const gfx::Rect& old_bounds,
362 const gfx::Rect& new_bounds) {
363 for (auto& pair : connection_map_) {
364 pair.second->service()->ProcessViewBoundsChanged(
365 view, old_bounds, new_bounds, IsChangeSource(pair.first));
369 void ConnectionManager::ProcessWillChangeViewHierarchy(
370 const ServerView* view,
371 const ServerView* new_parent,
372 const ServerView* old_parent) {
373 for (auto& pair : connection_map_) {
374 pair.second->service()->ProcessWillChangeViewHierarchy(
375 view, new_parent, old_parent, IsChangeSource(pair.first));
379 void ConnectionManager::ProcessViewHierarchyChanged(
380 const ServerView* view,
381 const ServerView* new_parent,
382 const ServerView* old_parent) {
383 for (auto& pair : connection_map_) {
384 pair.second->service()->ProcessViewHierarchyChanged(
385 view, new_parent, old_parent, IsChangeSource(pair.first));
389 void ConnectionManager::ProcessViewReorder(
390 const ServerView* view,
391 const ServerView* relative_view,
392 const mojo::OrderDirection direction) {
393 for (auto& pair : connection_map_) {
394 pair.second->service()->ProcessViewReorder(view, relative_view, direction,
395 IsChangeSource(pair.first));
399 void ConnectionManager::ProcessViewDeleted(const ViewId& view) {
400 for (auto& pair : connection_map_) {
401 pair.second->service()->ProcessViewDeleted(view,
402 IsChangeSource(pair.first));
406 void ConnectionManager::ProcessViewportMetricsChanged(
407 const mojo::ViewportMetrics& old_metrics,
408 const mojo::ViewportMetrics& new_metrics) {
409 for (auto& pair : connection_map_) {
410 pair.second->service()->ProcessViewportMetricsChanged(
411 old_metrics, new_metrics, IsChangeSource(pair.first));
415 void ConnectionManager::PrepareForChange(ScopedChange* change) {
416 // Should only ever have one change in flight.
417 CHECK(!current_change_);
418 current_change_ = change;
421 void ConnectionManager::FinishChange() {
422 // PrepareForChange/FinishChange should be balanced.
423 CHECK(current_change_);
424 current_change_ = NULL;
427 void ConnectionManager::DoAnimation() {
428 // TODO(fsamuel): Support multiple roots.
429 if (!DecrementAnimatingViewsOpacity(view_manager_root_->root_view()))
430 animation_timer_.Stop();
433 void ConnectionManager::AddConnection(ClientConnection* connection) {
434 DCHECK_EQ(0u, connection_map_.count(connection->service()->id()));
435 connection_map_[connection->service()->id()] = connection;
438 void ConnectionManager::PrepareToDestroyView(ServerView* view) {
439 if (!in_destructor_ && IsViewAttachedToRoot(view) &&
440 view->id() != ClonedViewId()) {
441 // We're about to destroy a view. Any cloned views need to be reparented
442 // else the animation would no longer be visible. By moving to a visible
443 // view, view->parent(), we ensure the animation is still visible.
444 ServerView* parent_above = view;
445 ReparentClonedViews(view->parent(), &parent_above, view);
448 animation_runner_.CancelAnimationForView(view);
451 void ConnectionManager::PrepareToChangeViewHierarchy(ServerView* view,
452 ServerView* new_parent,
453 ServerView* old_parent) {
454 if (view->id() == ClonedViewId() || in_destructor_)
455 return;
457 if (IsViewAttachedToRoot(view)) {
458 // We're about to reparent a view. Any cloned views need to be reparented
459 // else the animation may be effected in unusual ways. For example, the view
460 // could move to a new location such that the animation is entirely clipped.
461 // By moving to view->parent() we ensure the animation is still visible.
462 ServerView* parent_above = view;
463 ReparentClonedViews(view->parent(), &parent_above, view);
466 animation_runner_.CancelAnimationForView(view);
469 void ConnectionManager::PrepareToChangeViewVisibility(ServerView* view) {
470 if (in_destructor_)
471 return;
473 if (IsViewAttachedToRoot(view) && view->id() != ClonedViewId() &&
474 view->IsDrawn()) {
475 // We're about to hide |view|, this would implicitly make any cloned views
476 // hide too. Reparent so that animations are still visible.
477 ServerView* parent_above = view;
478 ReparentClonedViews(view->parent(), &parent_above, view);
481 const bool is_parent_drawn = view->parent() && view->parent()->IsDrawn();
482 if (!is_parent_drawn || !view->visible())
483 animation_runner_.CancelAnimationForView(view);
486 void ConnectionManager::OnScheduleViewPaint(const ServerView* view) {
487 if (!in_destructor_)
488 SchedulePaint(view, gfx::Rect(view->bounds().size()));
491 const ServerView* ConnectionManager::GetRootView(const ServerView* view) const {
492 while (view && view->parent())
493 view = view->parent();
494 if (view_manager_root_->root_view() == view)
495 return view;
496 return nullptr;
499 void ConnectionManager::OnViewDestroyed(ServerView* view) {
500 if (!in_destructor_)
501 ProcessViewDeleted(view->id());
504 void ConnectionManager::OnWillChangeViewHierarchy(ServerView* view,
505 ServerView* new_parent,
506 ServerView* old_parent) {
507 if (view->id() == ClonedViewId() || in_destructor_)
508 return;
510 ProcessWillChangeViewHierarchy(view, new_parent, old_parent);
513 void ConnectionManager::OnViewHierarchyChanged(ServerView* view,
514 ServerView* new_parent,
515 ServerView* old_parent) {
516 if (in_destructor_)
517 return;
519 ProcessViewHierarchyChanged(view, new_parent, old_parent);
521 // TODO(beng): optimize.
522 if (old_parent)
523 SchedulePaint(old_parent, gfx::Rect(old_parent->bounds().size()));
524 if (new_parent)
525 SchedulePaint(new_parent, gfx::Rect(new_parent->bounds().size()));
528 void ConnectionManager::OnViewBoundsChanged(ServerView* view,
529 const gfx::Rect& old_bounds,
530 const gfx::Rect& new_bounds) {
531 if (in_destructor_)
532 return;
534 ProcessViewBoundsChanged(view, old_bounds, new_bounds);
535 if (!view->parent())
536 return;
538 // TODO(sky): optimize this.
539 SchedulePaint(view->parent(), old_bounds);
540 SchedulePaint(view->parent(), new_bounds);
543 void ConnectionManager::OnViewReordered(ServerView* view,
544 ServerView* relative,
545 mojo::OrderDirection direction) {
546 if (!in_destructor_)
547 SchedulePaint(view, gfx::Rect(view->bounds().size()));
550 void ConnectionManager::OnWillChangeViewVisibility(ServerView* view) {
551 if (in_destructor_)
552 return;
554 // Need to repaint if the view was drawn (which means it's in the process of
555 // hiding) or the view is transitioning to drawn.
556 if (view->parent() && (view->IsDrawn() ||
557 (!view->visible() && view->parent()->IsDrawn()))) {
558 SchedulePaint(view->parent(), view->bounds());
561 for (auto& pair : connection_map_) {
562 pair.second->service()->ProcessWillChangeViewVisibility(
563 view, IsChangeSource(pair.first));
567 void ConnectionManager::OnViewSharedPropertyChanged(
568 ServerView* view,
569 const std::string& name,
570 const std::vector<uint8_t>* new_data) {
571 for (auto& pair : connection_map_) {
572 pair.second->service()->ProcessViewPropertyChanged(
573 view, name, new_data, IsChangeSource(pair.first));
577 void ConnectionManager::CloneAndAnimate(mojo::Id transport_view_id) {
578 CloneAndAnimate(ViewIdFromTransportId(transport_view_id));
581 void ConnectionManager::OnFocusChanged(ServerView* old_focused_view,
582 ServerView* new_focused_view) {
583 // There are up to four connections that need to be notified:
584 // . the connection containing |old_focused_view|.
585 // . the connection with |old_focused_view| as its root.
586 // . the connection containing |new_focused_view|.
587 // . the connection with |new_focused_view| as its root.
588 // Some of these connections may be the same. The following takes care to
589 // notify each only once.
590 ViewManagerServiceImpl* owning_connection_old = nullptr;
591 ViewManagerServiceImpl* embedded_connection_old = nullptr;
593 if (old_focused_view) {
594 owning_connection_old = GetConnection(old_focused_view->id().connection_id);
595 if (owning_connection_old) {
596 owning_connection_old->ProcessFocusChanged(old_focused_view,
597 new_focused_view);
599 embedded_connection_old = GetConnectionWithRoot(old_focused_view->id());
600 if (embedded_connection_old) {
601 DCHECK_NE(owning_connection_old, embedded_connection_old);
602 embedded_connection_old->ProcessFocusChanged(old_focused_view,
603 new_focused_view);
606 ViewManagerServiceImpl* owning_connection_new = nullptr;
607 ViewManagerServiceImpl* embedded_connection_new = nullptr;
608 if (new_focused_view) {
609 owning_connection_new = GetConnection(new_focused_view->id().connection_id);
610 if (owning_connection_new &&
611 owning_connection_new != owning_connection_old &&
612 owning_connection_new != embedded_connection_old) {
613 owning_connection_new->ProcessFocusChanged(old_focused_view,
614 new_focused_view);
616 embedded_connection_new = GetConnectionWithRoot(new_focused_view->id());
617 if (embedded_connection_new &&
618 embedded_connection_new != owning_connection_old &&
619 embedded_connection_new != embedded_connection_old) {
620 DCHECK_NE(owning_connection_new, embedded_connection_new);
621 embedded_connection_new->ProcessFocusChanged(old_focused_view,
622 new_focused_view);
626 if (has_window_manager_client_connection()) {
627 // Window manager should always be notified of focus change.
628 ViewManagerServiceImpl* wm_connection =
629 window_manager_client_connection_->service();
630 if (wm_connection != owning_connection_old &&
631 wm_connection != embedded_connection_old &&
632 wm_connection != owning_connection_new &&
633 wm_connection != embedded_connection_new) {
634 wm_connection->ProcessFocusChanged(old_focused_view, new_focused_view);
639 } // namespace view_manager