override drawImage
[chromium-blink-merge.git] / components / view_manager / connection_manager.cc
blob5a9657c2b85e5c8b653cee4939a10e585818cea9
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/converters/geometry/geometry_type_converters.h"
17 #include "mojo/converters/input_events/input_events_type_converters.h"
18 #include "third_party/mojo/src/mojo/public/interfaces/application/service_provider.mojom.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(ConnectionManagerDelegate* delegate,
114 scoped_ptr<DisplayManager> display_manager,
115 mojo::WindowManagerInternal* wm_internal)
116 : delegate_(delegate),
117 window_manager_client_connection_(nullptr),
118 next_connection_id_(1),
119 display_manager_(display_manager.Pass()),
120 root_(CreateServerView(RootViewId())),
121 wm_internal_(wm_internal),
122 current_change_(nullptr),
123 in_destructor_(false),
124 animation_runner_(base::TimeTicks::Now()),
125 event_dispatcher_(this),
126 event_dispatcher_binding_(&event_dispatcher_),
127 focus_controller_(new FocusController(this, root_.get())) {
128 root_->SetBounds(gfx::Rect(800, 600));
129 root_->SetVisible(true);
131 mojo::NativeViewportEventDispatcherPtr event_dispatcher_ptr;
132 event_dispatcher_binding_.Bind(GetProxy(&event_dispatcher_ptr));
133 display_manager_->Init(this, event_dispatcher_ptr.Pass());
136 ConnectionManager::~ConnectionManager() {
137 in_destructor_ = true;
139 // Deleting views will attempt to advance focus. When we're being destroyed
140 // that is not necessary. Additionally |focus_controller_| needs to be
141 // destroyed before |root_|.
142 focus_controller_.reset();
144 STLDeleteValues(&connection_map_);
145 // All the connections should have been destroyed.
146 DCHECK(connection_map_.empty());
147 root_.reset();
150 ServerView* ConnectionManager::CreateServerView(const ViewId& id) {
151 ServerView* view = new ServerView(this, id);
152 view->AddObserver(this);
153 return view;
156 ConnectionSpecificId ConnectionManager::GetAndAdvanceNextConnectionId() {
157 const ConnectionSpecificId id = next_connection_id_++;
158 DCHECK_LT(id, next_connection_id_);
159 return id;
162 void ConnectionManager::OnConnectionError(ClientConnection* connection) {
163 if (connection == window_manager_client_connection_) {
164 window_manager_client_connection_ = nullptr;
165 delegate_->OnLostConnectionToWindowManager();
166 // Assume we've been destroyed.
167 return;
170 scoped_ptr<ClientConnection> connection_owner(connection);
172 connection_map_.erase(connection->service()->id());
174 // TODO(sky): I may want to advance focus differently if focus is in
175 // |connection|.
177 // Notify remaining connections so that they can cleanup.
178 for (auto& pair : connection_map_) {
179 pair.second->service()->OnWillDestroyViewManagerServiceImpl(
180 connection->service());
184 void ConnectionManager::EmbedAtView(
185 ConnectionSpecificId creator_id,
186 const std::string& url,
187 const ViewId& view_id,
188 mojo::InterfaceRequest<mojo::ServiceProvider> services,
189 mojo::ServiceProviderPtr exposed_services) {
190 std::string creator_url;
191 ConnectionMap::const_iterator it = connection_map_.find(creator_id);
192 if (it != connection_map_.end())
193 creator_url = it->second->service()->url();
195 mojo::ViewManagerServicePtr service_ptr;
196 ClientConnection* client_connection =
197 delegate_->CreateClientConnectionForEmbedAtView(
198 this, GetProxy(&service_ptr), creator_id, creator_url, url, view_id);
199 AddConnection(client_connection);
200 client_connection->service()->Init(client_connection->client(),
201 service_ptr.Pass(), services.Pass(),
202 exposed_services.Pass());
203 OnConnectionMessagedClient(client_connection->service()->id());
206 void ConnectionManager::EmbedAtView(mojo::ConnectionSpecificId creator_id,
207 const ViewId& view_id,
208 mojo::ViewManagerClientPtr client) {
209 std::string creator_url;
210 ConnectionMap::const_iterator it = connection_map_.find(creator_id);
211 if (it != connection_map_.end())
212 creator_url = it->second->service()->url();
214 mojo::ViewManagerServicePtr service_ptr;
215 ClientConnection* client_connection =
216 delegate_->CreateClientConnectionForEmbedAtView(
217 this, GetProxy(&service_ptr), creator_id, creator_url, view_id,
218 client.Pass());
219 AddConnection(client_connection);
220 client_connection->service()->Init(client_connection->client(),
221 service_ptr.Pass(), nullptr, nullptr);
222 OnConnectionMessagedClient(client_connection->service()->id());
225 ViewManagerServiceImpl* ConnectionManager::GetConnection(
226 ConnectionSpecificId connection_id) {
227 ConnectionMap::iterator i = connection_map_.find(connection_id);
228 return i == connection_map_.end() ? nullptr : i->second->service();
231 ServerView* ConnectionManager::GetView(const ViewId& id) {
232 if (id == root_->id())
233 return root_.get();
234 ViewManagerServiceImpl* service = GetConnection(id.connection_id);
235 return service ? service->GetView(id) : nullptr;
238 void ConnectionManager::SetFocusedView(ServerView* view) {
239 ServerView* old_focused = GetFocusedView();
240 if (old_focused == view)
241 return;
242 focus_controller_->SetFocusedView(view);
243 OnFocusChanged(old_focused, view);
246 ServerView* ConnectionManager::GetFocusedView() {
247 return focus_controller_->GetFocusedView();
250 void ConnectionManager::OnConnectionMessagedClient(ConnectionSpecificId id) {
251 if (current_change_)
252 current_change_->MarkConnectionAsMessaged(id);
255 bool ConnectionManager::DidConnectionMessageClient(
256 ConnectionSpecificId id) const {
257 return current_change_ && current_change_->DidMessageConnection(id);
260 const ViewManagerServiceImpl* ConnectionManager::GetConnectionWithRoot(
261 const ViewId& id) const {
262 for (auto& pair : connection_map_) {
263 if (pair.second->service()->IsRoot(id))
264 return pair.second->service();
266 return nullptr;
269 void ConnectionManager::SetWindowManagerClientConnection(
270 scoped_ptr<ClientConnection> connection) {
271 CHECK(!window_manager_client_connection_);
272 window_manager_client_connection_ = connection.release();
273 AddConnection(window_manager_client_connection_);
274 window_manager_client_connection_->service()->Init(
275 window_manager_client_connection_->client(), nullptr, nullptr, nullptr);
278 mojo::ViewManagerClient*
279 ConnectionManager::GetWindowManagerViewManagerClient() {
280 CHECK(window_manager_client_connection_);
281 return window_manager_client_connection_->client();
284 bool ConnectionManager::CloneAndAnimate(const ViewId& view_id) {
285 ServerView* view = GetView(view_id);
286 if (!view || !view->IsDrawn(root_.get()) || view == root_.get())
287 return false;
288 if (!animation_timer_.IsRunning()) {
289 animation_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(100),
290 this, &ConnectionManager::DoAnimation);
292 ServerView* clone = CloneView(view, this);
293 CloneViewTree(view, clone, this);
294 view->parent()->Add(clone);
295 view->parent()->Reorder(clone, view, mojo::ORDER_DIRECTION_ABOVE);
296 return true;
299 void ConnectionManager::ProcessEvent(mojo::EventPtr event) {
300 event_dispatcher_.OnEvent(event.Pass(), EventDispatcher::OnEventCallback());
303 void ConnectionManager::DispatchInputEventToView(const ServerView* view,
304 mojo::EventPtr event) {
305 // If the view is an embed root, forward to the embedded view, not the owner.
306 ViewManagerServiceImpl* connection = GetConnectionWithRoot(view->id());
307 if (!connection)
308 connection = GetConnection(view->id().connection_id);
309 CHECK(connection);
310 connection->client()->OnViewInputEvent(ViewIdToTransportId(view->id()),
311 event.Pass(),
312 base::Bind(&base::DoNothing));
315 void ConnectionManager::ProcessViewBoundsChanged(const ServerView* view,
316 const gfx::Rect& old_bounds,
317 const gfx::Rect& new_bounds) {
318 for (auto& pair : connection_map_) {
319 pair.second->service()->ProcessViewBoundsChanged(
320 view, old_bounds, new_bounds, IsChangeSource(pair.first));
324 void ConnectionManager::ProcessViewportMetricsChanged(
325 const mojo::ViewportMetrics& old_metrics,
326 const mojo::ViewportMetrics& new_metrics) {
327 for (auto& pair : connection_map_) {
328 pair.second->service()->ProcessViewportMetricsChanged(
329 old_metrics, new_metrics, IsChangeSource(pair.first));
333 void ConnectionManager::ProcessWillChangeViewHierarchy(
334 const ServerView* view,
335 const ServerView* new_parent,
336 const ServerView* old_parent) {
337 for (auto& pair : connection_map_) {
338 pair.second->service()->ProcessWillChangeViewHierarchy(
339 view, new_parent, old_parent, IsChangeSource(pair.first));
343 void ConnectionManager::ProcessViewHierarchyChanged(
344 const ServerView* view,
345 const ServerView* new_parent,
346 const ServerView* old_parent) {
347 for (auto& pair : connection_map_) {
348 pair.second->service()->ProcessViewHierarchyChanged(
349 view, new_parent, old_parent, IsChangeSource(pair.first));
353 void ConnectionManager::ProcessViewReorder(
354 const ServerView* view,
355 const ServerView* relative_view,
356 const mojo::OrderDirection direction) {
357 for (auto& pair : connection_map_) {
358 pair.second->service()->ProcessViewReorder(view, relative_view, direction,
359 IsChangeSource(pair.first));
363 void ConnectionManager::ProcessViewDeleted(const ViewId& view) {
364 for (auto& pair : connection_map_) {
365 pair.second->service()->ProcessViewDeleted(view,
366 IsChangeSource(pair.first));
370 void ConnectionManager::PrepareForChange(ScopedChange* change) {
371 // Should only ever have one change in flight.
372 CHECK(!current_change_);
373 current_change_ = change;
376 void ConnectionManager::FinishChange() {
377 // PrepareForChange/FinishChange should be balanced.
378 CHECK(current_change_);
379 current_change_ = NULL;
382 void ConnectionManager::DoAnimation() {
383 if (!DecrementAnimatingViewsOpacity(root()))
384 animation_timer_.Stop();
387 void ConnectionManager::AddConnection(ClientConnection* connection) {
388 DCHECK_EQ(0u, connection_map_.count(connection->service()->id()));
389 connection_map_[connection->service()->id()] = connection;
392 void ConnectionManager::PrepareToDestroyView(ServerView* view) {
393 if (!in_destructor_ && root_->Contains(view) && view != root_.get() &&
394 view->id() != ClonedViewId()) {
395 // We're about to destroy a view. Any cloned views need to be reparented
396 // else the animation would no longer be visible. By moving to a visible
397 // view, view->parent(), we ensure the animation is still visible.
398 ServerView* parent_above = view;
399 ReparentClonedViews(view->parent(), &parent_above, view);
402 animation_runner_.CancelAnimationForView(view);
405 void ConnectionManager::PrepareToChangeViewHierarchy(ServerView* view,
406 ServerView* new_parent,
407 ServerView* old_parent) {
408 if (view->id() == ClonedViewId() || in_destructor_)
409 return;
411 if (root_->Contains(view) && view != root_.get()) {
412 // We're about to reparent a view. Any cloned views need to be reparented
413 // else the animation may be effected in unusual ways. For example, the view
414 // could move to a new location such that the animation is entirely clipped.
415 // By moving to view->parent() we ensure the animation is still visible.
416 ServerView* parent_above = view;
417 ReparentClonedViews(view->parent(), &parent_above, view);
420 animation_runner_.CancelAnimationForView(view);
423 void ConnectionManager::PrepareToChangeViewVisibility(ServerView* view) {
424 if (in_destructor_)
425 return;
427 if (view != root_.get() && view->id() != ClonedViewId() &&
428 root_->Contains(view) && view->IsDrawn(root_.get())) {
429 // We're about to hide |view|, this would implicitly make any cloned views
430 // hide too. Reparent so that animations are still visible.
431 ServerView* parent_above = view;
432 ReparentClonedViews(view->parent(), &parent_above, view);
435 const bool is_parent_drawn =
436 view->parent() && view->parent()->IsDrawn(root_.get());
437 if (!is_parent_drawn || !view->visible())
438 animation_runner_.CancelAnimationForView(view);
441 void ConnectionManager::OnScheduleViewPaint(const ServerView* view) {
442 if (!in_destructor_)
443 display_manager_->SchedulePaint(view, gfx::Rect(view->bounds().size()));
446 void ConnectionManager::OnViewDestroyed(ServerView* view) {
447 if (!in_destructor_)
448 ProcessViewDeleted(view->id());
451 void ConnectionManager::OnWillChangeViewHierarchy(ServerView* view,
452 ServerView* new_parent,
453 ServerView* old_parent) {
454 if (view->id() == ClonedViewId() || in_destructor_)
455 return;
457 ProcessWillChangeViewHierarchy(view, new_parent, old_parent);
460 void ConnectionManager::OnViewHierarchyChanged(ServerView* view,
461 ServerView* new_parent,
462 ServerView* old_parent) {
463 if (in_destructor_)
464 return;
466 ProcessViewHierarchyChanged(view, new_parent, old_parent);
468 // TODO(beng): optimize.
469 if (old_parent) {
470 display_manager_->SchedulePaint(old_parent,
471 gfx::Rect(old_parent->bounds().size()));
473 if (new_parent) {
474 display_manager_->SchedulePaint(new_parent,
475 gfx::Rect(new_parent->bounds().size()));
479 void ConnectionManager::OnViewBoundsChanged(ServerView* view,
480 const gfx::Rect& old_bounds,
481 const gfx::Rect& new_bounds) {
482 if (in_destructor_)
483 return;
485 ProcessViewBoundsChanged(view, old_bounds, new_bounds);
486 if (!view->parent())
487 return;
489 // TODO(sky): optimize this.
490 display_manager_->SchedulePaint(view->parent(), old_bounds);
491 display_manager_->SchedulePaint(view->parent(), new_bounds);
494 void ConnectionManager::OnViewReordered(ServerView* view,
495 ServerView* relative,
496 mojo::OrderDirection direction) {
497 if (!in_destructor_)
498 display_manager_->SchedulePaint(view, gfx::Rect(view->bounds().size()));
501 void ConnectionManager::OnWillChangeViewVisibility(ServerView* view) {
502 if (in_destructor_)
503 return;
505 // Need to repaint if the view was drawn (which means it's in the process of
506 // hiding) or the view is transitioning to drawn.
507 if (view->IsDrawn(root_.get()) || (!view->visible() && view->parent() &&
508 view->parent()->IsDrawn(root_.get()))) {
509 display_manager_->SchedulePaint(view->parent(), view->bounds());
512 for (auto& pair : connection_map_) {
513 pair.second->service()->ProcessWillChangeViewVisibility(
514 view, IsChangeSource(pair.first));
518 void ConnectionManager::OnViewSharedPropertyChanged(
519 ServerView* view,
520 const std::string& name,
521 const std::vector<uint8_t>* new_data) {
522 for (auto& pair : connection_map_) {
523 pair.second->service()->ProcessViewPropertyChanged(
524 view, name, new_data, IsChangeSource(pair.first));
528 void ConnectionManager::SetViewportSize(mojo::SizePtr size) {
529 display_manager_->SetViewportSize(size.To<gfx::Size>());
532 void ConnectionManager::DispatchInputEventToViewDEPRECATED(
533 mojo::Id transport_view_id,
534 mojo::EventPtr event) {
535 const ViewId view_id(ViewIdFromTransportId(transport_view_id));
537 ViewManagerServiceImpl* connection = GetConnectionWithRoot(view_id);
538 if (!connection)
539 connection = GetConnection(view_id.connection_id);
540 if (connection) {
541 connection->client()->OnViewInputEvent(
542 transport_view_id, event.Pass(), base::Bind(&base::DoNothing));
546 void ConnectionManager::CloneAndAnimate(mojo::Id transport_view_id) {
547 CloneAndAnimate(ViewIdFromTransportId(transport_view_id));
550 void ConnectionManager::AddAccelerator(mojo::KeyboardCode keyboard_code,
551 mojo::EventFlags flags) {
552 event_dispatcher_.AddAccelerator(keyboard_code, flags);
555 void ConnectionManager::RemoveAccelerator(mojo::KeyboardCode keyboard_code,
556 mojo::EventFlags flags) {
557 event_dispatcher_.RemoveAccelerator(keyboard_code, flags);
560 void ConnectionManager::OnFocusChanged(ServerView* old_focused_view,
561 ServerView* new_focused_view) {
562 // There are up to four connections that need to be notified:
563 // . the connection containing |old_focused_view|.
564 // . the connection with |old_focused_view| as its root.
565 // . the connection containing |new_focused_view|.
566 // . the connection with |new_focused_view| as its root.
567 // Some of these connections may be the same. The following takes care to
568 // notify each only once.
569 ViewManagerServiceImpl* owning_connection_old = nullptr;
570 ViewManagerServiceImpl* embedded_connection_old = nullptr;
572 if (old_focused_view) {
573 owning_connection_old = GetConnection(old_focused_view->id().connection_id);
574 if (owning_connection_old) {
575 owning_connection_old->ProcessFocusChanged(old_focused_view,
576 new_focused_view);
578 embedded_connection_old = GetConnectionWithRoot(old_focused_view->id());
579 if (embedded_connection_old) {
580 DCHECK_NE(owning_connection_old, embedded_connection_old);
581 embedded_connection_old->ProcessFocusChanged(old_focused_view,
582 new_focused_view);
585 ViewManagerServiceImpl* owning_connection_new = nullptr;
586 ViewManagerServiceImpl* embedded_connection_new = nullptr;
587 if (new_focused_view) {
588 owning_connection_new = GetConnection(new_focused_view->id().connection_id);
589 if (owning_connection_new &&
590 owning_connection_new != owning_connection_old &&
591 owning_connection_new != embedded_connection_old) {
592 owning_connection_new->ProcessFocusChanged(old_focused_view,
593 new_focused_view);
595 embedded_connection_new = GetConnectionWithRoot(new_focused_view->id());
596 if (embedded_connection_new &&
597 embedded_connection_new != owning_connection_old &&
598 embedded_connection_new != embedded_connection_old) {
599 DCHECK_NE(owning_connection_new, embedded_connection_new);
600 embedded_connection_new->ProcessFocusChanged(old_focused_view,
601 new_focused_view);
605 if (has_window_manager_client_connection()) {
606 // Window manager should always be notified of focus change.
607 ViewManagerServiceImpl* wm_connection =
608 window_manager_client_connection_->service();
609 if (wm_connection != owning_connection_old &&
610 wm_connection != embedded_connection_old &&
611 wm_connection != owning_connection_new &&
612 wm_connection != embedded_connection_new) {
613 wm_connection->ProcessFocusChanged(old_focused_view, new_focused_view);
618 } // namespace view_manager