Home | History | Annotate | Download | only in accessibility
      1 // Copyright 2013 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 #ifndef UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_
      6 #define UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_
      7 
      8 #include <set>
      9 
     10 #include "base/containers/hash_tables.h"
     11 #include "base/logging.h"
     12 #include "base/stl_util.h"
     13 #include "ui/accessibility/ax_tree_source.h"
     14 #include "ui/accessibility/ax_tree_update.h"
     15 
     16 namespace ui {
     17 
     18 struct ClientTreeNode;
     19 
     20 // AXTreeSerializer is a helper class that serializes incremental
     21 // updates to an AXTreeSource as a AXTreeUpdate struct.
     22 // These structs can be unserialized by a client object such as an
     23 // AXTree. An AXTreeSerializer keeps track of the tree of node ids that its
     24 // client is aware of so that it will never generate an AXTreeUpdate that
     25 // results in an invalid tree.
     26 //
     27 // Every node in the source tree must have an id that's a unique positive
     28 // integer, the same node must not appear twice.
     29 //
     30 // Usage:
     31 //
     32 // You must call SerializeChanges() every time a node in the tree changes,
     33 // and send the generated AXTreeUpdate to the client.
     34 //
     35 // If a node is added, call SerializeChanges on its parent.
     36 // If a node is removed, call SerializeChanges on its parent.
     37 // If a whole new subtree is added, just call SerializeChanges on its root.
     38 // If the root of the tree changes, call SerializeChanges on the new root.
     39 //
     40 // AXTreeSerializer will avoid re-serializing nodes that do not change.
     41 // For example, if node 1 has children 2, 3, 4, 5 and then child 2 is
     42 // removed and a new child 6 is added, the AXTreeSerializer will only
     43 // update nodes 1 and 6 (and any children of node 6 recursively). It will
     44 // assume that nodes 3, 4, and 5 are not modified unless you explicitly
     45 // call SerializeChanges() on them.
     46 //
     47 // As long as the source tree has unique ids for every node and no loops,
     48 // and as long as every update is applied to the client tree, AXTreeSerializer
     49 // will continue to work. If the source tree makes a change but fails to
     50 // call SerializeChanges properly, the trees may get out of sync - but
     51 // because AXTreeSerializer always keeps track of what updates it's sent,
     52 // it will never send an invalid update and the client tree will not break,
     53 // it just may not contain all of the changes.
     54 template<class AXSourceNode>
     55 class AXTreeSerializer {
     56  public:
     57   explicit AXTreeSerializer(AXTreeSource<AXSourceNode>* tree);
     58   ~AXTreeSerializer();
     59 
     60   // Throw out the internal state that keeps track of the nodes the client
     61   // knows about. This has the effect that the next update will send the
     62   // entire tree over because it assumes the client knows nothing.
     63   void Reset();
     64 
     65   // Serialize all changes to |node| and append them to |out_update|.
     66   void SerializeChanges(const AXSourceNode* node,
     67                         AXTreeUpdate* out_update);
     68 
     69   // Only for unit testing. Normally this class relies on getting a call
     70   // to SerializeChanges() every time the source tree changes. For unit
     71   // testing, it's convenient to create a static AXTree for the initial
     72   // state and then call ChangeTreeSourceForTesting and then SerializeChanges
     73   // to simulate the changes you'd get if a tree changed from the initial
     74   // state to the second tree's state.
     75   void ChangeTreeSourceForTesting(AXTreeSource<AXSourceNode>* new_tree);
     76 
     77  private:
     78   // Return the least common ancestor of a node in the source tree
     79   // and a node in the client tree, or NULL if there is no such node.
     80   // The least common ancestor is the closest ancestor to |node| (which
     81   // may be |node| itself) that's in both the source tree and client tree,
     82   // and for which both the source and client tree agree on their ancestor
     83   // chain up to the root.
     84   //
     85   // Example 1:
     86   //
     87   //    Client Tree    Source tree |
     88   //        1              1       |
     89   //       / \            / \      |
     90   //      2   3          2   4     |
     91   //
     92   // LCA(source node 2, client node 2) is node 2.
     93   // LCA(source node 3, client node 4) is node 1.
     94   //
     95   // Example 2:
     96   //
     97   //    Client Tree    Source tree |
     98   //        1              1       |
     99   //       / \            / \      |
    100   //      2   3          2   3     |
    101   //     / \            /   /      |
    102   //    4   7          8   4       |
    103   //   / \                / \      |
    104   //  5   6              5   6     |
    105   //
    106   // LCA(source node 8, client node 7) is node 2.
    107   // LCA(source node 5, client node 5) is node 1.
    108   // It's not node 5, because the two trees disagree on the parent of
    109   // node 4, so the LCA is the first ancestor both trees agree on.
    110   const AXSourceNode* LeastCommonAncestor(const AXSourceNode* node,
    111                                           ClientTreeNode* client_node);
    112 
    113   // Return the least common ancestor of |node| that's in the client tree.
    114   // This just walks up the ancestors of |node| until it finds a node that's
    115   // also in the client tree, and then calls LeastCommonAncestor on the
    116   // source node and client node.
    117   const AXSourceNode* LeastCommonAncestor(const AXSourceNode* node);
    118 
    119   // Walk the subtree rooted at |node| and return true if any nodes that
    120   // would be updated are being reparented. If so, update |lca| to point
    121   // to the least common ancestor of the previous LCA and the previous
    122   // parent of the node being reparented.
    123   bool AnyDescendantWasReparented(const AXSourceNode* node,
    124                                   const AXSourceNode** lca);
    125 
    126   ClientTreeNode* ClientTreeNodeById(int32 id);
    127 
    128   // Delete the given client tree node and recursively delete all of its
    129   // descendants.
    130   void DeleteClientSubtree(ClientTreeNode* client_node);
    131 
    132   // Helper function, called recursively with each new node to serialize.
    133   void SerializeChangedNodes(const AXSourceNode* node,
    134                              AXTreeUpdate* out_update);
    135 
    136   // The tree source.
    137   AXTreeSource<AXSourceNode>* tree_;
    138 
    139   // Our representation of the client tree.
    140   ClientTreeNode* client_root_;
    141 
    142   // A map from IDs to nodes in the client tree.
    143   base::hash_map<int32, ClientTreeNode*> client_id_map_;
    144 };
    145 
    146 // In order to keep track of what nodes the client knows about, we keep a
    147 // representation of the client tree - just IDs and parent/child
    148 // relationships.
    149 struct AX_EXPORT ClientTreeNode {
    150   ClientTreeNode();
    151   virtual ~ClientTreeNode();
    152   int32 id;
    153   ClientTreeNode* parent;
    154   std::vector<ClientTreeNode*> children;
    155 };
    156 
    157 template<class AXSourceNode>
    158 AXTreeSerializer<AXSourceNode>::AXTreeSerializer(
    159     AXTreeSource<AXSourceNode>* tree)
    160     : tree_(tree),
    161       client_root_(NULL) {
    162 }
    163 
    164 template<class AXSourceNode>
    165 AXTreeSerializer<AXSourceNode>::~AXTreeSerializer() {
    166   Reset();
    167 }
    168 
    169 template<class AXSourceNode>
    170 void AXTreeSerializer<AXSourceNode>::Reset() {
    171   if (client_root_) {
    172     DeleteClientSubtree(client_root_);
    173     client_root_ = NULL;
    174   }
    175 }
    176 
    177 template<class AXSourceNode>
    178 void AXTreeSerializer<AXSourceNode>::ChangeTreeSourceForTesting(
    179     AXTreeSource<AXSourceNode>* new_tree) {
    180   tree_ = new_tree;
    181 }
    182 
    183 template<class AXSourceNode>
    184 const AXSourceNode* AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
    185     const AXSourceNode* node, ClientTreeNode* client_node) {
    186   if (node == NULL || client_node == NULL)
    187     return NULL;
    188 
    189   std::vector<const AXSourceNode*> ancestors;
    190   while (node) {
    191     ancestors.push_back(node);
    192     node = tree_->GetParent(node);
    193   }
    194 
    195   std::vector<ClientTreeNode*> client_ancestors;
    196   while (client_node) {
    197     client_ancestors.push_back(client_node);
    198     client_node = client_node->parent;
    199   }
    200 
    201   // Start at the root. Keep going until the source ancestor chain and
    202   // client ancestor chain disagree. The last node before they disagree
    203   // is the LCA.
    204   const AXSourceNode* lca = NULL;
    205   int source_index = static_cast<int>(ancestors.size() - 1);
    206   int client_index = static_cast<int>(client_ancestors.size() - 1);
    207   while (source_index >= 0 && client_index >= 0) {
    208     if (tree_->GetId(ancestors[source_index]) !=
    209             client_ancestors[client_index]->id) {
    210       return lca;
    211     }
    212     lca = ancestors[source_index];
    213     source_index--;
    214     client_index--;
    215   }
    216   return lca;
    217 }
    218 
    219 template<class AXSourceNode>
    220 const AXSourceNode* AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
    221     const AXSourceNode* node) {
    222   // Walk up the tree until the source node's id also exists in the
    223   // client tree, then call LeastCommonAncestor on those two nodes.
    224   ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
    225   while (node && !client_node) {
    226     node = tree_->GetParent(node);
    227     if (node)
    228       client_node = ClientTreeNodeById(tree_->GetId(node));
    229   }
    230   return LeastCommonAncestor(node, client_node);
    231 }
    232 
    233 template<class AXSourceNode>
    234 bool AXTreeSerializer<AXSourceNode>::AnyDescendantWasReparented(
    235     const AXSourceNode* node, const AXSourceNode** lca) {
    236   bool result = false;
    237   int id = tree_->GetId(node);
    238   int child_count = tree_->GetChildCount(node);
    239   for (int i = 0; i < child_count; ++i) {
    240     const AXSourceNode* child = tree_->GetChildAtIndex(node, i);
    241     int child_id = tree_->GetId(child);
    242     ClientTreeNode* client_child = ClientTreeNodeById(child_id);
    243     if (client_child) {
    244       if (!client_child->parent) {
    245         // If the client child has no parent, it must have been the
    246         // previous root node, so there is no LCA and we can exit early.
    247         *lca = NULL;
    248         return true;
    249       } else if (client_child->parent->id != id) {
    250         // If the client child's parent is not this node, update the LCA
    251         // and return true (reparenting was found).
    252         *lca = LeastCommonAncestor(*lca, client_child);
    253         result = true;
    254       } else {
    255         // This child is already in the client tree, we won't
    256         // recursively serialize it so we don't need to check this
    257         // subtree recursively for reparenting.
    258         continue;
    259       }
    260     }
    261 
    262     // This is a new child or reparented child, check it recursively.
    263     if (AnyDescendantWasReparented(child, lca))
    264       result = true;
    265   }
    266   return result;
    267 }
    268 
    269 template<class AXSourceNode>
    270 ClientTreeNode* AXTreeSerializer<AXSourceNode>::ClientTreeNodeById(int32 id) {
    271   base::hash_map<int32, ClientTreeNode*>::iterator iter =
    272       client_id_map_.find(id);
    273   if (iter != client_id_map_.end())
    274     return iter->second;
    275   else
    276     return NULL;
    277 }
    278 
    279 template<class AXSourceNode>
    280 void AXTreeSerializer<AXSourceNode>::SerializeChanges(
    281     const AXSourceNode* node,
    282     AXTreeUpdate* out_update) {
    283   // If the node isn't in the client tree, we need to serialize starting
    284   // with the LCA.
    285   const AXSourceNode* lca = LeastCommonAncestor(node);
    286 
    287   if (client_root_) {
    288     // If the LCA is anything other than the node itself, tell the
    289     // client to first delete the subtree rooted at the LCA.
    290     bool need_delete = (lca != node);
    291     if (lca) {
    292       // Check for any reparenting within this subtree - if there is
    293       // any, we need to delete and reserialize the whole subtree
    294       // that contains the old and new parents of the reparented node.
    295       if (AnyDescendantWasReparented(lca, &lca))
    296         need_delete = true;
    297     }
    298 
    299     if (lca == NULL) {
    300       // If there's no LCA, just tell the client to destroy the whole
    301       // tree and then we'll serialize everything from the new root.
    302       out_update->node_id_to_clear = client_root_->id;
    303       DeleteClientSubtree(client_root_);
    304       client_id_map_.erase(client_root_->id);
    305       client_root_ = NULL;
    306     } else if (need_delete) {
    307       // Otherwise, if we need to reserialize a subtree, first we need
    308       // to delete those nodes in our client tree so that
    309       // SerializeChangedNodes() will be sure to send them again.
    310       out_update->node_id_to_clear = tree_->GetId(lca);
    311       ClientTreeNode* client_lca = ClientTreeNodeById(tree_->GetId(lca));
    312       CHECK(client_lca);
    313       for (size_t i = 0; i < client_lca->children.size(); ++i) {
    314         client_id_map_.erase(client_lca->children[i]->id);
    315         DeleteClientSubtree(client_lca->children[i]);
    316       }
    317       client_lca->children.clear();
    318     }
    319   }
    320 
    321   // Serialize from the LCA, or from the root if there isn't one.
    322   if (!lca)
    323     lca = tree_->GetRoot();
    324   SerializeChangedNodes(lca, out_update);
    325 }
    326 
    327 template<class AXSourceNode>
    328 void AXTreeSerializer<AXSourceNode>::DeleteClientSubtree(
    329     ClientTreeNode* client_node) {
    330   for (size_t i = 0; i < client_node->children.size(); ++i) {
    331     client_id_map_.erase(client_node->children[i]->id);
    332     DeleteClientSubtree(client_node->children[i]);
    333   }
    334   client_node->children.clear();
    335 }
    336 
    337 template<class AXSourceNode>
    338 void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes(
    339     const AXSourceNode* node,
    340     AXTreeUpdate* out_update) {
    341   // This method has three responsibilities:
    342   // 1. Serialize |node| into an AXNodeData, and append it to
    343   //    the AXTreeUpdate to be sent to the client.
    344   // 2. Determine if |node| has any new children that the client doesn't
    345   //    know about yet, and call SerializeChangedNodes recursively on those.
    346   // 3. Update our internal data structure that keeps track of what nodes
    347   //    the client knows about.
    348 
    349   // First, find the ClientTreeNode for this id in our data structure where
    350   // we keep track of what accessibility objects the client already knows
    351   // about. If we don't find it, then this must be the new root of the
    352   // accessibility tree.
    353   int id = tree_->GetId(node);
    354   ClientTreeNode* client_node = ClientTreeNodeById(id);
    355   if (!client_node) {
    356     if (client_root_) {
    357       client_id_map_.erase(client_root_->id);
    358       DeleteClientSubtree(client_root_);
    359     }
    360     client_root_ = new ClientTreeNode();
    361     client_node = client_root_;
    362     client_node->id = id;
    363     client_node->parent = NULL;
    364     client_id_map_[client_node->id] = client_node;
    365   }
    366 
    367   // Iterate over the ids of the children of |node|.
    368   // Create a set of the child ids so we can quickly look
    369   // up which children are new and which ones were there before.
    370   base::hash_set<int32> new_child_ids;
    371   int child_count = tree_->GetChildCount(node);
    372   for (int i = 0; i < child_count; ++i) {
    373     AXSourceNode* child = tree_->GetChildAtIndex(node, i);
    374     int new_child_id = tree_->GetId(child);
    375     new_child_ids.insert(new_child_id);
    376 
    377     // This is a sanity check - there shouldn't be any reparenting
    378     // because we've already handled it above.
    379     ClientTreeNode* client_child = client_id_map_[new_child_id];
    380     CHECK(!client_child || client_child->parent == client_node);
    381   }
    382 
    383   // Go through the old children and delete subtrees for child
    384   // ids that are no longer present, and create a map from
    385   // id to ClientTreeNode for the rest. It's important to delete
    386   // first in a separate pass so that nodes that are reparented
    387   // don't end up children of two different parents in the middle
    388   // of an update, which can lead to a double-free.
    389   base::hash_map<int32, ClientTreeNode*> client_child_id_map;
    390   std::vector<ClientTreeNode*> old_children;
    391   old_children.swap(client_node->children);
    392   for (size_t i = 0; i < old_children.size(); ++i) {
    393     ClientTreeNode* old_child = old_children[i];
    394     int old_child_id = old_child->id;
    395     if (new_child_ids.find(old_child_id) == new_child_ids.end()) {
    396       client_id_map_.erase(old_child_id);
    397       DeleteClientSubtree(old_child);
    398     } else {
    399       client_child_id_map[old_child_id] = old_child;
    400     }
    401   }
    402 
    403   // Serialize this node. This fills in all of the fields in
    404   // AXNodeData except child_ids, which we handle below.
    405   out_update->nodes.push_back(AXNodeData());
    406   AXNodeData* serialized_node = &out_update->nodes.back();
    407   tree_->SerializeNode(node, serialized_node);
    408   if (serialized_node->id == client_root_->id)
    409     serialized_node->role = AX_ROLE_ROOT_WEB_AREA;
    410   serialized_node->child_ids.clear();
    411 
    412   // Iterate over the children, make note of the ones that are new
    413   // and need to be serialized, and update the ClientTreeNode
    414   // data structure to reflect the new tree.
    415   std::vector<AXSourceNode*> children_to_serialize;
    416   client_node->children.reserve(child_count);
    417   for (int i = 0; i < child_count; ++i) {
    418     AXSourceNode* child = tree_->GetChildAtIndex(node, i);
    419     int child_id = tree_->GetId(child);
    420 
    421     // No need to do anything more with children that aren't new;
    422     // the client will reuse its existing object.
    423     if (new_child_ids.find(child_id) == new_child_ids.end())
    424       continue;
    425 
    426     new_child_ids.erase(child_id);
    427     serialized_node->child_ids.push_back(child_id);
    428     if (client_child_id_map.find(child_id) != client_child_id_map.end()) {
    429       ClientTreeNode* reused_child = client_child_id_map[child_id];
    430       client_node->children.push_back(reused_child);
    431     } else {
    432       ClientTreeNode* new_child = new ClientTreeNode();
    433       new_child->id = child_id;
    434       new_child->parent = client_node;
    435       client_node->children.push_back(new_child);
    436       client_id_map_[child_id] = new_child;
    437       children_to_serialize.push_back(child);
    438     }
    439   }
    440 
    441   // Serialize all of the new children, recursively.
    442   for (size_t i = 0; i < children_to_serialize.size(); ++i)
    443     SerializeChangedNodes(children_to_serialize[i], out_update);
    444 }
    445 
    446 }  // namespace ui
    447 
    448 #endif  // UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_
    449