Home | History | Annotate | Download | only in lib
      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