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.
4
5#include "mojo/services/view_manager/view_manager_service_impl.h"
6
7#include "base/bind.h"
8#include "mojo/services/public/cpp/geometry/geometry_type_converters.h"
9#include "mojo/services/public/cpp/input_events/input_events_type_converters.h"
10#include "mojo/services/public/cpp/surfaces/surfaces_type_converters.h"
11#include "mojo/services/view_manager/connection_manager.h"
12#include "mojo/services/view_manager/default_access_policy.h"
13#include "mojo/services/view_manager/server_view.h"
14#include "mojo/services/view_manager/window_manager_access_policy.h"
15
16namespace mojo {
17namespace service {
18
19ViewManagerServiceImpl::ViewManagerServiceImpl(
20    ConnectionManager* connection_manager,
21    ConnectionSpecificId creator_id,
22    const std::string& creator_url,
23    const std::string& url,
24    const ViewId& root_id,
25    InterfaceRequest<ServiceProvider> service_provider)
26    : connection_manager_(connection_manager),
27      id_(connection_manager_->GetAndAdvanceNextConnectionId()),
28      url_(url),
29      creator_id_(creator_id),
30      creator_url_(creator_url),
31      delete_on_connection_error_(false),
32      service_provider_(service_provider.Pass()) {
33  CHECK(GetView(root_id));
34  roots_.insert(ViewIdToTransportId(root_id));
35  if (root_id == RootViewId())
36    access_policy_.reset(new WindowManagerAccessPolicy(id_, this));
37  else
38    access_policy_.reset(new DefaultAccessPolicy(id_, this));
39}
40
41ViewManagerServiceImpl::~ViewManagerServiceImpl() {
42  // Delete any views we created.
43  if (!view_map_.empty()) {
44    ConnectionManager::ScopedChange change(this, connection_manager_, true);
45    while (!view_map_.empty())
46      delete view_map_.begin()->second;
47  }
48
49  connection_manager_->RemoveConnection(this);
50}
51
52const ServerView* ViewManagerServiceImpl::GetView(const ViewId& id) const {
53  if (id_ == id.connection_id) {
54    ViewMap::const_iterator i = view_map_.find(id.view_id);
55    return i == view_map_.end() ? NULL : i->second;
56  }
57  return connection_manager_->GetView(id);
58}
59
60bool ViewManagerServiceImpl::HasRoot(const ViewId& id) const {
61  return roots_.find(ViewIdToTransportId(id)) != roots_.end();
62}
63
64void ViewManagerServiceImpl::OnViewManagerServiceImplDestroyed(
65    ConnectionSpecificId id) {
66  if (creator_id_ == id)
67    creator_id_ = kInvalidConnectionId;
68}
69
70void ViewManagerServiceImpl::ProcessViewBoundsChanged(
71    const ServerView* view,
72    const gfx::Rect& old_bounds,
73    const gfx::Rect& new_bounds,
74    bool originated_change) {
75  if (originated_change || !IsViewKnown(view))
76    return;
77  client()->OnViewBoundsChanged(ViewIdToTransportId(view->id()),
78                                Rect::From(old_bounds),
79                                Rect::From(new_bounds));
80}
81
82void ViewManagerServiceImpl::ProcessWillChangeViewHierarchy(
83    const ServerView* view,
84    const ServerView* new_parent,
85    const ServerView* old_parent,
86    bool originated_change) {
87  if (originated_change)
88    return;
89
90  const bool old_drawn = view->IsDrawn(connection_manager_->root());
91  const bool new_drawn = view->visible() && new_parent &&
92      new_parent->IsDrawn(connection_manager_->root());
93  if (old_drawn == new_drawn)
94    return;
95
96  NotifyDrawnStateChanged(view, new_drawn);
97}
98
99void ViewManagerServiceImpl::ProcessViewHierarchyChanged(
100    const ServerView* view,
101    const ServerView* new_parent,
102    const ServerView* old_parent,
103    bool originated_change) {
104  if (originated_change && !IsViewKnown(view) && new_parent &&
105      IsViewKnown(new_parent)) {
106    std::vector<const ServerView*> unused;
107    GetUnknownViewsFrom(view, &unused);
108  }
109  if (originated_change || connection_manager_->is_processing_delete_view() ||
110      connection_manager_->DidConnectionMessageClient(id_)) {
111    return;
112  }
113
114  if (!access_policy_->ShouldNotifyOnHierarchyChange(
115          view, &new_parent, &old_parent)) {
116    return;
117  }
118  // Inform the client of any new views and update the set of views we know
119  // about.
120  std::vector<const ServerView*> to_send;
121  if (!IsViewKnown(view))
122    GetUnknownViewsFrom(view, &to_send);
123  const ViewId new_parent_id(new_parent ? new_parent->id() : ViewId());
124  const ViewId old_parent_id(old_parent ? old_parent->id() : ViewId());
125  client()->OnViewHierarchyChanged(ViewIdToTransportId(view->id()),
126                                   ViewIdToTransportId(new_parent_id),
127                                   ViewIdToTransportId(old_parent_id),
128                                   ViewsToViewDatas(to_send));
129  connection_manager_->OnConnectionMessagedClient(id_);
130}
131
132void ViewManagerServiceImpl::ProcessViewReorder(const ServerView* view,
133                                                const ServerView* relative_view,
134                                                OrderDirection direction,
135                                                bool originated_change) {
136  if (originated_change || !IsViewKnown(view) || !IsViewKnown(relative_view))
137    return;
138
139  client()->OnViewReordered(ViewIdToTransportId(view->id()),
140                            ViewIdToTransportId(relative_view->id()),
141                            direction);
142}
143
144void ViewManagerServiceImpl::ProcessViewDeleted(const ViewId& view,
145                                                bool originated_change) {
146  view_map_.erase(view.view_id);
147
148  const bool in_known = known_views_.erase(ViewIdToTransportId(view)) > 0;
149  roots_.erase(ViewIdToTransportId(view));
150
151  if (originated_change)
152    return;
153
154  if (in_known) {
155    client()->OnViewDeleted(ViewIdToTransportId(view));
156    connection_manager_->OnConnectionMessagedClient(id_);
157  }
158}
159
160void ViewManagerServiceImpl::ProcessWillChangeViewVisibility(
161    const ServerView* view,
162    bool originated_change) {
163  if (originated_change)
164    return;
165
166  if (IsViewKnown(view)) {
167    client()->OnViewVisibilityChanged(ViewIdToTransportId(view->id()),
168                                      !view->visible());
169    return;
170  }
171
172  bool view_target_drawn_state;
173  if (view->visible()) {
174    // View is being hidden, won't be drawn.
175    view_target_drawn_state = false;
176  } else {
177    // View is being shown. View will be drawn if its parent is drawn.
178    view_target_drawn_state =
179        view->parent() && view->parent()->IsDrawn(connection_manager_->root());
180  }
181
182  NotifyDrawnStateChanged(view, view_target_drawn_state);
183}
184
185void ViewManagerServiceImpl::OnConnectionError() {
186  if (delete_on_connection_error_)
187    delete this;
188}
189
190bool ViewManagerServiceImpl::IsViewKnown(const ServerView* view) const {
191  return known_views_.count(ViewIdToTransportId(view->id())) > 0;
192}
193
194bool ViewManagerServiceImpl::CanReorderView(const ServerView* view,
195                                            const ServerView* relative_view,
196                                            OrderDirection direction) const {
197  if (!view || !relative_view)
198    return false;
199
200  if (!view->parent() || view->parent() != relative_view->parent())
201    return false;
202
203  if (!access_policy_->CanReorderView(view, relative_view, direction))
204    return false;
205
206  std::vector<const ServerView*> children = view->parent()->GetChildren();
207  const size_t child_i =
208      std::find(children.begin(), children.end(), view) - children.begin();
209  const size_t target_i =
210      std::find(children.begin(), children.end(), relative_view) -
211      children.begin();
212  if ((direction == ORDER_DIRECTION_ABOVE && child_i == target_i + 1) ||
213      (direction == ORDER_DIRECTION_BELOW && child_i + 1 == target_i)) {
214    return false;
215  }
216
217  return true;
218}
219
220bool ViewManagerServiceImpl::DeleteViewImpl(ViewManagerServiceImpl* source,
221                                            ServerView* view) {
222  DCHECK(view);
223  DCHECK_EQ(view->id().connection_id, id_);
224  ConnectionManager::ScopedChange change(source, connection_manager_, true);
225  delete view;
226  return true;
227}
228
229void ViewManagerServiceImpl::GetUnknownViewsFrom(
230    const ServerView* view,
231    std::vector<const ServerView*>* views) {
232  if (IsViewKnown(view) || !access_policy_->CanGetViewTree(view))
233    return;
234  views->push_back(view);
235  known_views_.insert(ViewIdToTransportId(view->id()));
236  if (!access_policy_->CanDescendIntoViewForViewTree(view))
237    return;
238  std::vector<const ServerView*> children(view->GetChildren());
239  for (size_t i = 0 ; i < children.size(); ++i)
240    GetUnknownViewsFrom(children[i], views);
241}
242
243void ViewManagerServiceImpl::RemoveFromKnown(
244    const ServerView* view,
245    std::vector<ServerView*>* local_views) {
246  if (view->id().connection_id == id_) {
247    if (local_views)
248      local_views->push_back(GetView(view->id()));
249    return;
250  }
251  known_views_.erase(ViewIdToTransportId(view->id()));
252  std::vector<const ServerView*> children = view->GetChildren();
253  for (size_t i = 0; i < children.size(); ++i)
254    RemoveFromKnown(children[i], local_views);
255}
256
257void ViewManagerServiceImpl::RemoveRoot(const ViewId& view_id) {
258  const Id transport_view_id(ViewIdToTransportId(view_id));
259  CHECK(roots_.count(transport_view_id) > 0);
260
261  roots_.erase(transport_view_id);
262
263  // No need to do anything if we created the view.
264  if (view_id.connection_id == id_)
265    return;
266
267  client()->OnViewDeleted(transport_view_id);
268  connection_manager_->OnConnectionMessagedClient(id_);
269
270  // This connection no longer knows about the view. Unparent any views that
271  // were parented to views in the root.
272  std::vector<ServerView*> local_views;
273  RemoveFromKnown(GetView(view_id), &local_views);
274  for (size_t i = 0; i < local_views.size(); ++i)
275    local_views[i]->parent()->Remove(local_views[i]);
276}
277
278void ViewManagerServiceImpl::RemoveChildrenAsPartOfEmbed(
279    const ViewId& view_id) {
280  ServerView* view = GetView(view_id);
281  CHECK(view);
282  CHECK(view->id().connection_id == view_id.connection_id);
283  std::vector<ServerView*> children = view->GetChildren();
284  for (size_t i = 0; i < children.size(); ++i)
285    view->Remove(children[i]);
286}
287
288Array<ViewDataPtr> ViewManagerServiceImpl::ViewsToViewDatas(
289    const std::vector<const ServerView*>& views) {
290  Array<ViewDataPtr> array(views.size());
291  for (size_t i = 0; i < views.size(); ++i)
292    array[i] = ViewToViewData(views[i]).Pass();
293  return array.Pass();
294}
295
296ViewDataPtr ViewManagerServiceImpl::ViewToViewData(const ServerView* view) {
297  DCHECK(IsViewKnown(view));
298  const ServerView* parent = view->parent();
299  // If the parent isn't known, it means the parent is not visible to us (not
300  // in roots), and should not be sent over.
301  if (parent && !IsViewKnown(parent))
302    parent = NULL;
303  ViewDataPtr view_data(ViewData::New());
304  view_data->parent_id = ViewIdToTransportId(parent ? parent->id() : ViewId());
305  view_data->view_id = ViewIdToTransportId(view->id());
306  view_data->bounds = Rect::From(view->bounds());
307  view_data->visible = view->visible();
308  view_data->drawn = view->IsDrawn(connection_manager_->root());
309  return view_data.Pass();
310}
311
312void ViewManagerServiceImpl::GetViewTreeImpl(
313    const ServerView* view,
314    std::vector<const ServerView*>* views) const {
315  DCHECK(view);
316
317  if (!access_policy_->CanGetViewTree(view))
318    return;
319
320  views->push_back(view);
321
322  if (!access_policy_->CanDescendIntoViewForViewTree(view))
323    return;
324
325  std::vector<const ServerView*> children(view->GetChildren());
326  for (size_t i = 0 ; i < children.size(); ++i)
327    GetViewTreeImpl(children[i], views);
328}
329
330void ViewManagerServiceImpl::NotifyDrawnStateChanged(const ServerView* view,
331                                                     bool new_drawn_value) {
332  // Even though we don't know about view, it may be an ancestor of one of our
333  // roots, in which case the change may effect our roots drawn state.
334  for (ViewIdSet::iterator i = roots_.begin(); i != roots_.end(); ++i) {
335    const ServerView* root = GetView(ViewIdFromTransportId(*i));
336    DCHECK(root);
337    if (view->Contains(root) &&
338        (new_drawn_value != root->IsDrawn(connection_manager_->root()))) {
339      client()->OnViewDrawnStateChanged(ViewIdToTransportId(root->id()),
340                                        new_drawn_value);
341    }
342  }
343}
344
345void ViewManagerServiceImpl::CreateView(
346    Id transport_view_id,
347    const Callback<void(ErrorCode)>& callback) {
348  const ViewId view_id(ViewIdFromTransportId(transport_view_id));
349  ErrorCode error_code = ERROR_CODE_NONE;
350  if (view_id.connection_id != id_) {
351    error_code = ERROR_CODE_ILLEGAL_ARGUMENT;
352  } else if (view_map_.find(view_id.view_id) != view_map_.end()) {
353    error_code = ERROR_CODE_VALUE_IN_USE;
354  } else {
355    view_map_[view_id.view_id] = new ServerView(connection_manager_, view_id);
356    known_views_.insert(transport_view_id);
357  }
358  callback.Run(error_code);
359}
360
361void ViewManagerServiceImpl::DeleteView(
362    Id transport_view_id,
363    const Callback<void(bool)>& callback) {
364  ServerView* view = GetView(ViewIdFromTransportId(transport_view_id));
365  bool success = false;
366  if (view && access_policy_->CanDeleteView(view)) {
367    ViewManagerServiceImpl* connection =
368        connection_manager_->GetConnection(view->id().connection_id);
369    success = connection && connection->DeleteViewImpl(this, view);
370  }
371  callback.Run(success);
372}
373
374void ViewManagerServiceImpl::AddView(
375    Id parent_id,
376    Id child_id,
377    const Callback<void(bool)>& callback) {
378  bool success = false;
379  ServerView* parent = GetView(ViewIdFromTransportId(parent_id));
380  ServerView* child = GetView(ViewIdFromTransportId(child_id));
381  if (parent && child && child->parent() != parent &&
382      !child->Contains(parent) && access_policy_->CanAddView(parent, child)) {
383    success = true;
384    ConnectionManager::ScopedChange change(this, connection_manager_, false);
385    parent->Add(child);
386  }
387  callback.Run(success);
388}
389
390void ViewManagerServiceImpl::RemoveViewFromParent(
391    Id view_id,
392    const Callback<void(bool)>& callback) {
393  bool success = false;
394  ServerView* view = GetView(ViewIdFromTransportId(view_id));
395  if (view && view->parent() && access_policy_->CanRemoveViewFromParent(view)) {
396    success = true;
397    ConnectionManager::ScopedChange change(this, connection_manager_, false);
398    view->parent()->Remove(view);
399  }
400  callback.Run(success);
401}
402
403void ViewManagerServiceImpl::ReorderView(Id view_id,
404                                         Id relative_view_id,
405                                         OrderDirection direction,
406                                         const Callback<void(bool)>& callback) {
407  bool success = false;
408  ServerView* view = GetView(ViewIdFromTransportId(view_id));
409  ServerView* relative_view = GetView(ViewIdFromTransportId(relative_view_id));
410  if (CanReorderView(view, relative_view, direction)) {
411    success = true;
412    ConnectionManager::ScopedChange change(this, connection_manager_, false);
413    view->parent()->Reorder(view, relative_view, direction);
414    connection_manager_->ProcessViewReorder(view, relative_view, direction);
415  }
416  callback.Run(success);
417}
418
419void ViewManagerServiceImpl::GetViewTree(
420    Id view_id,
421    const Callback<void(Array<ViewDataPtr>)>& callback) {
422  ServerView* view = GetView(ViewIdFromTransportId(view_id));
423  std::vector<const ServerView*> views;
424  if (view) {
425    GetViewTreeImpl(view, &views);
426    // TODO(sky): this should map in views that weren't none.
427  }
428  callback.Run(ViewsToViewDatas(views));
429}
430
431void ViewManagerServiceImpl::SetViewSurfaceId(
432    Id view_id,
433    SurfaceIdPtr surface_id,
434    const Callback<void(bool)>& callback) {
435  // TODO(sky): add coverage of not being able to set for random node.
436  ServerView* view = GetView(ViewIdFromTransportId(view_id));
437  if (!view || !access_policy_->CanSetViewSurfaceId(view)) {
438    callback.Run(false);
439    return;
440  }
441  view->SetSurfaceId(surface_id.To<cc::SurfaceId>());
442  callback.Run(true);
443}
444
445void ViewManagerServiceImpl::SetViewBounds(
446    Id view_id,
447    RectPtr bounds,
448    const Callback<void(bool)>& callback) {
449  ServerView* view = GetView(ViewIdFromTransportId(view_id));
450  const bool success = view && access_policy_->CanSetViewBounds(view);
451  if (success) {
452    ConnectionManager::ScopedChange change(this, connection_manager_, false);
453    view->SetBounds(bounds.To<gfx::Rect>());
454  }
455  callback.Run(success);
456}
457
458void ViewManagerServiceImpl::SetViewVisibility(
459    Id transport_view_id,
460    bool visible,
461    const Callback<void(bool)>& callback) {
462  ServerView* view = GetView(ViewIdFromTransportId(transport_view_id));
463  if (!view || view->visible() == visible ||
464      !access_policy_->CanChangeViewVisibility(view)) {
465    callback.Run(false);
466    return;
467  }
468  {
469    ConnectionManager::ScopedChange change(this, connection_manager_, false);
470    view->SetVisible(visible);
471  }
472  callback.Run(true);
473}
474
475void ViewManagerServiceImpl::Embed(
476    const String& url,
477    Id transport_view_id,
478    ServiceProviderPtr service_provider,
479    const Callback<void(bool)>& callback) {
480  InterfaceRequest<ServiceProvider> spir;
481  spir.Bind(service_provider.PassMessagePipe());
482
483  if (ViewIdFromTransportId(transport_view_id) == InvalidViewId()) {
484    connection_manager_->EmbedRoot(url, spir.Pass());
485    callback.Run(true);
486    return;
487  }
488  const ServerView* view = GetView(ViewIdFromTransportId(transport_view_id));
489  if (!view || !access_policy_->CanEmbed(view)) {
490    callback.Run(false);
491    return;
492  }
493
494  // Only allow a node to be the root for one connection.
495  const ViewId view_id(ViewIdFromTransportId(transport_view_id));
496  ViewManagerServiceImpl* existing_owner =
497      connection_manager_->GetConnectionWithRoot(view_id);
498
499  ConnectionManager::ScopedChange change(this, connection_manager_, true);
500  RemoveChildrenAsPartOfEmbed(view_id);
501  if (existing_owner) {
502    // Never message the originating connection.
503    connection_manager_->OnConnectionMessagedClient(id_);
504    existing_owner->RemoveRoot(view_id);
505  }
506  connection_manager_->Embed(id_, url, transport_view_id, spir.Pass());
507  callback.Run(true);
508}
509
510void ViewManagerServiceImpl::DispatchOnViewInputEvent(Id transport_view_id,
511                                                      EventPtr event) {
512  // We only allow the WM to dispatch events. At some point this function will
513  // move to a separate interface and the check can go away.
514  if (id_ != kWindowManagerConnection)
515    return;
516
517  const ViewId view_id(ViewIdFromTransportId(transport_view_id));
518
519  // If another app is embedded at this view, we forward the input event to the
520  // embedded app, rather than the app that created the view.
521  ViewManagerServiceImpl* connection =
522      connection_manager_->GetConnectionWithRoot(view_id);
523  if (!connection)
524    connection = connection_manager_->GetConnection(view_id.connection_id);
525  if (connection) {
526    connection->client()->OnViewInputEvent(
527        transport_view_id,
528        event.Pass(),
529        base::Bind(&base::DoNothing));
530  }
531}
532
533void ViewManagerServiceImpl::OnConnectionEstablished() {
534  connection_manager_->AddConnection(this);
535
536  std::vector<const ServerView*> to_send;
537  for (ViewIdSet::const_iterator i = roots_.begin(); i != roots_.end(); ++i)
538    GetUnknownViewsFrom(GetView(ViewIdFromTransportId(*i)), &to_send);
539
540  client()->OnEmbed(id_,
541                    creator_url_,
542                    ViewToViewData(to_send.front()),
543                    service_provider_.Pass());
544}
545
546const base::hash_set<Id>&
547ViewManagerServiceImpl::GetRootsForAccessPolicy() const {
548  return roots_;
549}
550
551bool ViewManagerServiceImpl::IsViewKnownForAccessPolicy(
552    const ServerView* view) const {
553  return IsViewKnown(view);
554}
555
556bool ViewManagerServiceImpl::IsViewRootOfAnotherConnectionForAccessPolicy(
557    const ServerView* view) const {
558  ViewManagerServiceImpl* connection =
559      connection_manager_->GetConnectionWithRoot(view->id());
560  return connection && connection != this;
561}
562
563}  // namespace service
564}  // namespace mojo
565