| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/accessibility/ax_tree.h" | 5 #include "ui/accessibility/ax_tree.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <set> | 9 #include <set> |
| 10 | 10 |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
| 13 #include "ui/accessibility/ax_node.h" | 13 #include "ui/accessibility/ax_node.h" |
| 14 | 14 |
| 15 namespace ui { | 15 namespace ui { |
| 16 | 16 |
| 17 namespace { | 17 namespace { |
| 18 | 18 |
| 19 std::string TreeToStringHelper(AXNode* node, int indent) { | 19 std::string TreeToStringHelper(AXNode* node, int indent) { |
| 20 std::string result = std::string(2 * indent, ' '); | 20 std::string result = std::string(2 * indent, ' '); |
| 21 result += node->data().ToString() + "\n"; | 21 result += node->data().ToString() + "\n"; |
| 22 for (int i = 0; i < node->child_count(); ++i) | 22 for (int i = 0; i < node->child_count(); ++i) |
| 23 result += TreeToStringHelper(node->ChildAtIndex(i), indent + 1); | 23 result += TreeToStringHelper(node->ChildAtIndex(i), indent + 1); |
| 24 return result; | 24 return result; |
| 25 } | 25 } |
| 26 | 26 |
| 27 template <typename K, typename V> |
| 28 bool KeyValuePairsKeysMatch(std::vector<std::pair<K, V>> pairs1, |
| 29 std::vector<std::pair<K, V>> pairs2) { |
| 30 if (pairs1.size() != pairs2.size()) |
| 31 return false; |
| 32 for (size_t i = 0; i < pairs1.size(); ++i) { |
| 33 if (pairs1[i].first != pairs2[i].first) |
| 34 return false; |
| 35 } |
| 36 return true; |
| 37 } |
| 38 |
| 39 template <typename K, typename V> |
| 40 std::map<K, V> MapFromKeyValuePairs(std::vector<std::pair<K, V>> pairs) { |
| 41 std::map<K, V> result; |
| 42 for (size_t i = 0; i < pairs.size(); ++i) |
| 43 result[pairs[i].first] = pairs[i].second; |
| 44 return result; |
| 45 } |
| 46 |
| 47 // Given two vectors of <K, V> key, value pairs representing an "old" vs "new" |
| 48 // state, or "before" vs "after", calls a callback function for each key that |
| 49 // changed value. |
| 50 template <typename K, typename V, typename F> |
| 51 void CallIfAttributeValuesChanged(const std::vector<std::pair<K, V>>& pairs1, |
| 52 const std::vector<std::pair<K, V>>& pairs2, |
| 53 const V& empty_value, |
| 54 F callback) { |
| 55 // Fast path - if they both have the same keys in the same order. |
| 56 if (KeyValuePairsKeysMatch(pairs1, pairs2)) { |
| 57 for (size_t i = 0; i < pairs1.size(); ++i) { |
| 58 if (pairs1[i].second != pairs2[i].second) |
| 59 callback(pairs1[i].first, pairs1[i].second, pairs2[i].second); |
| 60 } |
| 61 return; |
| 62 } |
| 63 |
| 64 // Slower path - they don't have the same keys in the same order, so |
| 65 // check all keys against each other, using maps to prevent this from |
| 66 // becoming O(n^2) as the size grows. |
| 67 auto map1 = MapFromKeyValuePairs(pairs1); |
| 68 auto map2 = MapFromKeyValuePairs(pairs2); |
| 69 for (size_t i = 0; i < pairs1.size(); ++i) { |
| 70 const auto& new_iter = map2.find(pairs1[i].first); |
| 71 if (pairs1[i].second != empty_value && new_iter == map2.end()) |
| 72 callback(pairs1[i].first, pairs1[i].second, empty_value); |
| 73 } |
| 74 |
| 75 for (size_t i = 0; i < pairs2.size(); ++i) { |
| 76 const auto& iter = map1.find(pairs2[i].first); |
| 77 if (iter == map1.end()) |
| 78 callback(pairs2[i].first, empty_value, pairs2[i].second); |
| 79 else if (iter->second != pairs2[i].second) |
| 80 callback(pairs2[i].first, iter->second, pairs2[i].second); |
| 81 } |
| 82 } |
| 83 |
| 27 } // namespace | 84 } // namespace |
| 28 | 85 |
| 29 // Intermediate state to keep track of during a tree update. | 86 // Intermediate state to keep track of during a tree update. |
| 30 struct AXTreeUpdateState { | 87 struct AXTreeUpdateState { |
| 31 AXTreeUpdateState() : new_root(nullptr) {} | 88 AXTreeUpdateState() : new_root(nullptr) {} |
| 32 // Returns whether this update changes |node|. | 89 // Returns whether this update changes |node|. |
| 33 bool HasChangedNode(const AXNode* node) { | 90 bool HasChangedNode(const AXNode* node) { |
| 34 return changed_node_ids.find(node->id()) != changed_node_ids.end(); | 91 return changed_node_ids.find(node->id()) != changed_node_ids.end(); |
| 35 } | 92 } |
| 36 | 93 |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 // This method updates one node in the tree based on serialized data | 278 // This method updates one node in the tree based on serialized data |
| 222 // received in an AXTreeUpdate. See AXTreeUpdate for pre and post | 279 // received in an AXTreeUpdate. See AXTreeUpdate for pre and post |
| 223 // conditions. | 280 // conditions. |
| 224 | 281 |
| 225 // Look up the node by id. If it's not found, then either the root | 282 // Look up the node by id. If it's not found, then either the root |
| 226 // of the tree is being swapped, or we're out of sync with the source | 283 // of the tree is being swapped, or we're out of sync with the source |
| 227 // and this is a serious error. | 284 // and this is a serious error. |
| 228 AXNode* node = GetFromId(src.id); | 285 AXNode* node = GetFromId(src.id); |
| 229 if (node) { | 286 if (node) { |
| 230 update_state->pending_nodes.erase(node); | 287 update_state->pending_nodes.erase(node); |
| 231 if (delegate_ && | 288 if (update_state->new_nodes.find(node) == update_state->new_nodes.end()) |
| 232 update_state->new_nodes.find(node) == update_state->new_nodes.end()) | 289 CallNodeChangeCallbacks(node, src); |
| 233 delegate_->OnNodeDataWillChange(this, node->data(), src); | |
| 234 node->SetData(src); | 290 node->SetData(src); |
| 235 } else { | 291 } else { |
| 236 if (!is_new_root) { | 292 if (!is_new_root) { |
| 237 error_ = base::StringPrintf( | 293 error_ = base::StringPrintf( |
| 238 "%d is not in the tree and not the new root", src.id); | 294 "%d is not in the tree and not the new root", src.id); |
| 239 return false; | 295 return false; |
| 240 } | 296 } |
| 241 | 297 |
| 242 update_state->new_root = CreateNode(NULL, src.id, 0, update_state); | 298 update_state->new_root = CreateNode(NULL, src.id, 0, update_state); |
| 243 node = update_state->new_root; | 299 node = update_state->new_root; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 // DestroySubtree. | 340 // DestroySubtree. |
| 285 AXNode* old_root = root_; | 341 AXNode* old_root = root_; |
| 286 root_ = node; | 342 root_ = node; |
| 287 if (old_root && old_root != node) | 343 if (old_root && old_root != node) |
| 288 DestroySubtree(old_root, update_state); | 344 DestroySubtree(old_root, update_state); |
| 289 } | 345 } |
| 290 | 346 |
| 291 return success; | 347 return success; |
| 292 } | 348 } |
| 293 | 349 |
| 350 void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) { |
| 351 if (!delegate_) |
| 352 return; |
| 353 |
| 354 const AXNodeData& old_data = node->data(); |
| 355 delegate_->OnNodeDataWillChange(this, old_data, new_data); |
| 356 |
| 357 if (old_data.role != new_data.role) |
| 358 delegate_->OnRoleChanged(this, node, old_data.role, new_data.role); |
| 359 |
| 360 if (old_data.state != new_data.state) { |
| 361 for (int i = AX_STATE_NONE + 1; i <= AX_STATE_LAST; ++i) { |
| 362 AXState state = static_cast<AXState>(i); |
| 363 if (old_data.HasStateFlag(state) != new_data.HasStateFlag(state)) { |
| 364 delegate_->OnStateChanged(this, node, state, |
| 365 new_data.HasStateFlag(state)); |
| 366 } |
| 367 } |
| 368 } |
| 369 |
| 370 auto string_callback = [this, node](AXStringAttribute attr, |
| 371 const std::string& old_string, |
| 372 const std::string& new_string) { |
| 373 delegate_->OnStringAttributeChanged(this, node, attr, old_string, |
| 374 new_string); |
| 375 }; |
| 376 CallIfAttributeValuesChanged(old_data.string_attributes, |
| 377 new_data.string_attributes, std::string(), |
| 378 string_callback); |
| 379 |
| 380 auto bool_callback = [this, node](AXBoolAttribute attr, const bool& old_bool, |
| 381 const bool& new_bool) { |
| 382 delegate_->OnBoolAttributeChanged(this, node, attr, new_bool); |
| 383 }; |
| 384 CallIfAttributeValuesChanged(old_data.bool_attributes, |
| 385 new_data.bool_attributes, false, bool_callback); |
| 386 |
| 387 auto float_callback = [this, node](AXFloatAttribute attr, |
| 388 const float& old_float, |
| 389 const float& new_float) { |
| 390 delegate_->OnFloatAttributeChanged(this, node, attr, old_float, new_float); |
| 391 }; |
| 392 CallIfAttributeValuesChanged(old_data.float_attributes, |
| 393 new_data.float_attributes, 0.0f, float_callback); |
| 394 |
| 395 auto int_callback = [this, node](AXIntAttribute attr, const int& old_int, |
| 396 const int& new_int) { |
| 397 delegate_->OnIntAttributeChanged(this, node, attr, old_int, new_int); |
| 398 }; |
| 399 CallIfAttributeValuesChanged(old_data.int_attributes, new_data.int_attributes, |
| 400 0, int_callback); |
| 401 |
| 402 auto intlist_callback = [this, node]( |
| 403 AXIntListAttribute attr, |
| 404 const std::vector<int32_t>& old_intlist, |
| 405 const std::vector<int32_t>& new_intlist) { |
| 406 delegate_->OnIntListAttributeChanged(this, node, attr, old_intlist, |
| 407 new_intlist); |
| 408 }; |
| 409 CallIfAttributeValuesChanged(old_data.intlist_attributes, |
| 410 new_data.intlist_attributes, |
| 411 std::vector<int32_t>(), intlist_callback); |
| 412 } |
| 413 |
| 294 void AXTree::DestroySubtree(AXNode* node, | 414 void AXTree::DestroySubtree(AXNode* node, |
| 295 AXTreeUpdateState* update_state) { | 415 AXTreeUpdateState* update_state) { |
| 296 DCHECK(update_state); | 416 DCHECK(update_state); |
| 297 if (delegate_) { | 417 if (delegate_) { |
| 298 if (!update_state->HasChangedNode(node)) | 418 if (!update_state->HasChangedNode(node)) |
| 299 delegate_->OnSubtreeWillBeDeleted(this, node); | 419 delegate_->OnSubtreeWillBeDeleted(this, node); |
| 300 else | 420 else |
| 301 delegate_->OnSubtreeWillBeReparented(this, node); | 421 delegate_->OnSubtreeWillBeReparented(this, node); |
| 302 } | 422 } |
| 303 DestroyNodeAndSubtree(node, update_state); | 423 DestroyNodeAndSubtree(node, update_state); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 update_state->pending_nodes.insert(child); | 495 update_state->pending_nodes.insert(child); |
| 376 update_state->new_nodes.insert(child); | 496 update_state->new_nodes.insert(child); |
| 377 } | 497 } |
| 378 new_children->push_back(child); | 498 new_children->push_back(child); |
| 379 } | 499 } |
| 380 | 500 |
| 381 return success; | 501 return success; |
| 382 } | 502 } |
| 383 | 503 |
| 384 } // namespace ui | 504 } // namespace ui |
| OLD | NEW |