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