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/public/cpp/view_manager/view.h" 6 7 #include "mojo/public/cpp/application/connect.h" 8 #include "mojo/public/cpp/application/service_provider_impl.h" 9 #include "mojo/public/interfaces/application/shell.mojom.h" 10 #include "mojo/services/public/cpp/view_manager/lib/bitmap_uploader.h" 11 #include "mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.h" 12 #include "mojo/services/public/cpp/view_manager/lib/view_private.h" 13 #include "mojo/services/public/cpp/view_manager/view_observer.h" 14 #include "mojo/services/public/interfaces/gpu/gpu.mojom.h" 15 #include "mojo/services/public/interfaces/surfaces/surfaces_service.mojom.h" 16 #include "ui/gfx/canvas.h" 17 18 namespace mojo { 19 20 namespace { 21 22 void NotifyViewTreeChangeAtReceiver( 23 View* receiver, 24 const ViewObserver::TreeChangeParams& params, 25 bool change_applied) { 26 ViewObserver::TreeChangeParams local_params = params; 27 local_params.receiver = receiver; 28 if (change_applied) { 29 FOR_EACH_OBSERVER(ViewObserver, 30 *ViewPrivate(receiver).observers(), 31 OnTreeChanged(local_params)); 32 } else { 33 FOR_EACH_OBSERVER(ViewObserver, 34 *ViewPrivate(receiver).observers(), 35 OnTreeChanging(local_params)); 36 } 37 } 38 39 void NotifyViewTreeChangeUp( 40 View* start_at, 41 const ViewObserver::TreeChangeParams& params, 42 bool change_applied) { 43 for (View* current = start_at; current; current = current->parent()) 44 NotifyViewTreeChangeAtReceiver(current, params, change_applied); 45 } 46 47 void NotifyViewTreeChangeDown( 48 View* start_at, 49 const ViewObserver::TreeChangeParams& params, 50 bool change_applied) { 51 NotifyViewTreeChangeAtReceiver(start_at, params, change_applied); 52 View::Children::const_iterator it = start_at->children().begin(); 53 for (; it != start_at->children().end(); ++it) 54 NotifyViewTreeChangeDown(*it, params, change_applied); 55 } 56 57 void NotifyViewTreeChange( 58 const ViewObserver::TreeChangeParams& params, 59 bool change_applied) { 60 NotifyViewTreeChangeDown(params.target, params, change_applied); 61 if (params.old_parent) 62 NotifyViewTreeChangeUp(params.old_parent, params, change_applied); 63 if (params.new_parent) 64 NotifyViewTreeChangeUp(params.new_parent, params, change_applied); 65 } 66 67 class ScopedTreeNotifier { 68 public: 69 ScopedTreeNotifier(View* target, View* old_parent, View* new_parent) { 70 params_.target = target; 71 params_.old_parent = old_parent; 72 params_.new_parent = new_parent; 73 NotifyViewTreeChange(params_, false); 74 } 75 ~ScopedTreeNotifier() { 76 NotifyViewTreeChange(params_, true); 77 } 78 79 private: 80 ViewObserver::TreeChangeParams params_; 81 82 DISALLOW_COPY_AND_ASSIGN(ScopedTreeNotifier); 83 }; 84 85 void RemoveChildImpl(View* child, View::Children* children) { 86 View::Children::iterator it = 87 std::find(children->begin(), children->end(), child); 88 if (it != children->end()) { 89 children->erase(it); 90 ViewPrivate(child).ClearParent(); 91 } 92 } 93 94 class ScopedOrderChangedNotifier { 95 public: 96 ScopedOrderChangedNotifier(View* view, 97 View* relative_view, 98 OrderDirection direction) 99 : view_(view), 100 relative_view_(relative_view), 101 direction_(direction) { 102 FOR_EACH_OBSERVER(ViewObserver, 103 *ViewPrivate(view_).observers(), 104 OnViewReordering(view_, relative_view_, direction_)); 105 } 106 ~ScopedOrderChangedNotifier() { 107 FOR_EACH_OBSERVER(ViewObserver, 108 *ViewPrivate(view_).observers(), 109 OnViewReordered(view_, relative_view_, direction_)); 110 } 111 112 private: 113 View* view_; 114 View* relative_view_; 115 OrderDirection direction_; 116 117 DISALLOW_COPY_AND_ASSIGN(ScopedOrderChangedNotifier); 118 }; 119 120 // Returns true if the order actually changed. 121 bool ReorderImpl(View::Children* children, 122 View* view, 123 View* relative, 124 OrderDirection direction) { 125 DCHECK(relative); 126 DCHECK_NE(view, relative); 127 DCHECK_EQ(view->parent(), relative->parent()); 128 129 const size_t child_i = 130 std::find(children->begin(), children->end(), view) - children->begin(); 131 const size_t target_i = 132 std::find(children->begin(), children->end(), relative) - 133 children->begin(); 134 if ((direction == ORDER_DIRECTION_ABOVE && child_i == target_i + 1) || 135 (direction == ORDER_DIRECTION_BELOW && child_i + 1 == target_i)) { 136 return false; 137 } 138 139 ScopedOrderChangedNotifier notifier(view, relative, direction); 140 141 const size_t dest_i = direction == ORDER_DIRECTION_ABOVE 142 ? (child_i < target_i ? target_i : target_i + 1) 143 : (child_i < target_i ? target_i - 1 : target_i); 144 children->erase(children->begin() + child_i); 145 children->insert(children->begin() + dest_i, view); 146 147 return true; 148 } 149 150 class ScopedSetBoundsNotifier { 151 public: 152 ScopedSetBoundsNotifier(View* view, 153 const gfx::Rect& old_bounds, 154 const gfx::Rect& new_bounds) 155 : view_(view), 156 old_bounds_(old_bounds), 157 new_bounds_(new_bounds) { 158 FOR_EACH_OBSERVER(ViewObserver, 159 *ViewPrivate(view_).observers(), 160 OnViewBoundsChanging(view_, old_bounds_, new_bounds_)); 161 } 162 ~ScopedSetBoundsNotifier() { 163 FOR_EACH_OBSERVER(ViewObserver, 164 *ViewPrivate(view_).observers(), 165 OnViewBoundsChanged(view_, old_bounds_, new_bounds_)); 166 } 167 168 private: 169 View* view_; 170 const gfx::Rect old_bounds_; 171 const gfx::Rect new_bounds_; 172 173 DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier); 174 }; 175 176 // Some operations are only permitted in the connection that created the view. 177 bool OwnsView(ViewManager* manager, View* view) { 178 return !manager || 179 static_cast<ViewManagerClientImpl*>(manager)->OwnsView(view->id()); 180 } 181 182 } // namespace 183 184 //////////////////////////////////////////////////////////////////////////////// 185 // View, public: 186 187 // static 188 View* View::Create(ViewManager* view_manager) { 189 View* view = new View(view_manager); 190 static_cast<ViewManagerClientImpl*>(view_manager)->AddView(view); 191 return view; 192 } 193 194 void View::Destroy() { 195 if (!OwnsView(manager_, this)) 196 return; 197 198 if (manager_) 199 static_cast<ViewManagerClientImpl*>(manager_)->DestroyView(id_); 200 while (!children_.empty()) { 201 View* child = children_.front(); 202 if (!OwnsView(manager_, child)) { 203 ViewPrivate(child).ClearParent(); 204 children_.erase(children_.begin()); 205 } else { 206 child->Destroy(); 207 DCHECK(std::find(children_.begin(), children_.end(), child) == 208 children_.end()); 209 } 210 } 211 LocalDestroy(); 212 } 213 214 void View::SetBounds(const gfx::Rect& bounds) { 215 if (!OwnsView(manager_, this)) 216 return; 217 218 if (manager_) 219 static_cast<ViewManagerClientImpl*>(manager_)->SetBounds(id_, bounds); 220 LocalSetBounds(bounds_, bounds); 221 } 222 223 void View::SetVisible(bool value) { 224 if (manager_) 225 static_cast<ViewManagerClientImpl*>(manager_)->SetVisible(id_, value); 226 } 227 228 void View::AddObserver(ViewObserver* observer) { 229 observers_.AddObserver(observer); 230 } 231 232 void View::RemoveObserver(ViewObserver* observer) { 233 observers_.RemoveObserver(observer); 234 } 235 236 void View::AddChild(View* child) { 237 // TODO(beng): not necessarily valid to all connections, but possibly to the 238 // embeddee in an embedder-embeddee relationship. 239 if (manager_) 240 CHECK_EQ(ViewPrivate(child).view_manager(), manager_); 241 LocalAddChild(child); 242 if (manager_) 243 static_cast<ViewManagerClientImpl*>(manager_)->AddChild(child->id(), id_); 244 } 245 246 void View::RemoveChild(View* child) { 247 // TODO(beng): not necessarily valid to all connections, but possibly to the 248 // embeddee in an embedder-embeddee relationship. 249 if (manager_) 250 CHECK_EQ(ViewPrivate(child).view_manager(), manager_); 251 LocalRemoveChild(child); 252 if (manager_) { 253 static_cast<ViewManagerClientImpl*>(manager_)->RemoveChild(child->id(), 254 id_); 255 } 256 } 257 258 void View::MoveToFront() { 259 Reorder(parent_->children_.back(), ORDER_DIRECTION_ABOVE); 260 } 261 262 void View::MoveToBack() { 263 Reorder(parent_->children_.front(), ORDER_DIRECTION_BELOW); 264 } 265 266 void View::Reorder(View* relative, OrderDirection direction) { 267 if (!LocalReorder(relative, direction)) 268 return; 269 if (manager_) { 270 static_cast<ViewManagerClientImpl*>(manager_)->Reorder(id_, 271 relative->id(), 272 direction); 273 } 274 } 275 276 bool View::Contains(View* child) const { 277 if (manager_) 278 CHECK_EQ(ViewPrivate(child).view_manager(), manager_); 279 for (View* p = child->parent(); p; p = p->parent()) { 280 if (p == this) 281 return true; 282 } 283 return false; 284 } 285 286 View* View::GetChildById(Id id) { 287 if (id == id_) 288 return this; 289 // TODO(beng): this could be improved depending on how we decide to own views. 290 Children::const_iterator it = children_.begin(); 291 for (; it != children_.end(); ++it) { 292 View* view = (*it)->GetChildById(id); 293 if (view) 294 return view; 295 } 296 return NULL; 297 } 298 299 void View::SetSurfaceId(SurfaceIdPtr id) { 300 if (manager_) { 301 static_cast<ViewManagerClientImpl*>(manager_)->SetSurfaceId(id_, id.Pass()); 302 } 303 } 304 305 void View::SetContents(const SkBitmap& contents) { 306 if (manager_) { 307 if (!bitmap_uploader_) 308 CreateBitmapUploader(); 309 bitmap_uploader_->SetSize(bounds_.size()); 310 bitmap_uploader_->SetBitmap(contents); 311 } 312 } 313 314 void View::SetColor(SkColor color) { 315 if (manager_) { 316 if (!bitmap_uploader_) 317 CreateBitmapUploader(); 318 bitmap_uploader_->SetSize(bounds_.size()); 319 bitmap_uploader_->SetColor(color); 320 } 321 } 322 323 void View::SetFocus() { 324 if (manager_) 325 static_cast<ViewManagerClientImpl*>(manager_)->SetFocus(id_); 326 } 327 328 void View::Embed(const String& url) { 329 static_cast<ViewManagerClientImpl*>(manager_)->Embed(url, id_); 330 } 331 332 scoped_ptr<ServiceProvider> 333 View::Embed(const String& url, 334 scoped_ptr<ServiceProviderImpl> exported_services) { 335 scoped_ptr<ServiceProvider> imported_services; 336 // BindToProxy() takes ownership of |exported_services|. 337 ServiceProviderImpl* registry = exported_services.release(); 338 ServiceProviderPtr sp; 339 if (registry) { 340 BindToProxy(registry, &sp); 341 imported_services.reset(registry->CreateRemoteServiceProvider()); 342 } 343 static_cast<ViewManagerClientImpl*>(manager_)->Embed(url, id_, sp.Pass()); 344 return imported_services.Pass(); 345 } 346 347 //////////////////////////////////////////////////////////////////////////////// 348 // View, protected: 349 350 View::View() 351 : manager_(NULL), 352 id_(static_cast<Id>(-1)), 353 parent_(NULL) {} 354 355 View::~View() { 356 FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDestroying(this)); 357 if (parent_) 358 parent_->LocalRemoveChild(this); 359 // TODO(beng): It'd be better to do this via a destruction observer in the 360 // ViewManagerClientImpl. 361 if (manager_) 362 static_cast<ViewManagerClientImpl*>(manager_)->RemoveView(id_); 363 FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDestroyed(this)); 364 } 365 366 //////////////////////////////////////////////////////////////////////////////// 367 // View, private: 368 369 View::View(ViewManager* manager) 370 : manager_(manager), 371 id_(static_cast<ViewManagerClientImpl*>(manager_)->CreateView()), 372 parent_(NULL) {} 373 374 void View::LocalDestroy() { 375 delete this; 376 } 377 378 void View::LocalAddChild(View* child) { 379 ScopedTreeNotifier notifier(child, child->parent(), this); 380 if (child->parent()) 381 RemoveChildImpl(child, &child->parent_->children_); 382 children_.push_back(child); 383 child->parent_ = this; 384 } 385 386 void View::LocalRemoveChild(View* child) { 387 DCHECK_EQ(this, child->parent()); 388 ScopedTreeNotifier notifier(child, this, NULL); 389 RemoveChildImpl(child, &children_); 390 } 391 392 bool View::LocalReorder(View* relative, OrderDirection direction) { 393 return ReorderImpl(&parent_->children_, this, relative, direction); 394 } 395 396 void View::LocalSetBounds(const gfx::Rect& old_bounds, 397 const gfx::Rect& new_bounds) { 398 DCHECK(old_bounds == bounds_); 399 ScopedSetBoundsNotifier notifier(this, old_bounds, new_bounds); 400 bounds_ = new_bounds; 401 } 402 403 void View::CreateBitmapUploader() { 404 ViewManagerClientImpl* vmci = static_cast<ViewManagerClientImpl*>(manager_); 405 SurfacesServicePtr surfaces_service; 406 InterfacePtr<ServiceProvider> surfaces_service_provider; 407 vmci->shell()->ConnectToApplication("mojo:mojo_surfaces_service", 408 Get(&surfaces_service_provider)); 409 ConnectToService(surfaces_service_provider.get(), &surfaces_service); 410 GpuPtr gpu_service; 411 InterfacePtr<ServiceProvider> gpu_service_provider; 412 vmci->shell()->ConnectToApplication("mojo:mojo_native_viewport_service", 413 Get(&gpu_service_provider)); 414 ConnectToService(gpu_service_provider.get(), &gpu_service); 415 bitmap_uploader_.reset(new BitmapUploader( 416 vmci, id_, surfaces_service.Pass(), gpu_service.Pass())); 417 } 418 419 } // namespace mojo 420