Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(535)

Side by Side Diff: ui/accessibility/ax_tree.cc

Issue 2737043003: Add support for attribute change callbacks in AXNodeData. (Closed)
Patch Set: Address feedback, lambda in local var Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/accessibility/ax_tree.h ('k') | ui/accessibility/ax_tree_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « ui/accessibility/ax_tree.h ('k') | ui/accessibility/ax_tree_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698