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