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

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

Issue 2737043003: Add support for attribute change callbacks in AXNodeData. (Closed)
Patch Set: 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
27 } // namespace 47 } // namespace
28 48
29 // Intermediate state to keep track of during a tree update. 49 // Intermediate state to keep track of during a tree update.
30 struct AXTreeUpdateState { 50 struct AXTreeUpdateState {
31 AXTreeUpdateState() : new_root(nullptr) {} 51 AXTreeUpdateState() : new_root(nullptr) {}
32 // Returns whether this update changes |node|. 52 // Returns whether this update changes |node|.
33 bool HasChangedNode(const AXNode* node) { 53 bool HasChangedNode(const AXNode* node) {
34 return changed_node_ids.find(node->id()) != changed_node_ids.end(); 54 return changed_node_ids.find(node->id()) != changed_node_ids.end();
35 } 55 }
36 56
(...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 241 // This method updates one node in the tree based on serialized data
222 // received in an AXTreeUpdate. See AXTreeUpdate for pre and post 242 // received in an AXTreeUpdate. See AXTreeUpdate for pre and post
223 // conditions. 243 // conditions.
224 244
225 // Look up the node by id. If it's not found, then either the root 245 // 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 246 // of the tree is being swapped, or we're out of sync with the source
227 // and this is a serious error. 247 // and this is a serious error.
228 AXNode* node = GetFromId(src.id); 248 AXNode* node = GetFromId(src.id);
229 if (node) { 249 if (node) {
230 update_state->pending_nodes.erase(node); 250 update_state->pending_nodes.erase(node);
231 if (delegate_ && 251 if (update_state->new_nodes.find(node) == update_state->new_nodes.end())
232 update_state->new_nodes.find(node) == update_state->new_nodes.end()) 252 CallNodeChangeCallbacks(node, src);
233 delegate_->OnNodeDataWillChange(this, node->data(), src);
234 node->SetData(src); 253 node->SetData(src);
235 } else { 254 } else {
236 if (!is_new_root) { 255 if (!is_new_root) {
237 error_ = base::StringPrintf( 256 error_ = base::StringPrintf(
238 "%d is not in the tree and not the new root", src.id); 257 "%d is not in the tree and not the new root", src.id);
239 return false; 258 return false;
240 } 259 }
241 260
242 update_state->new_root = CreateNode(NULL, src.id, 0, update_state); 261 update_state->new_root = CreateNode(NULL, src.id, 0, update_state);
243 node = update_state->new_root; 262 node = update_state->new_root;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 // DestroySubtree. 303 // DestroySubtree.
285 AXNode* old_root = root_; 304 AXNode* old_root = root_;
286 root_ = node; 305 root_ = node;
287 if (old_root && old_root != node) 306 if (old_root && old_root != node)
288 DestroySubtree(old_root, update_state); 307 DestroySubtree(old_root, update_state);
289 } 308 }
290 309
291 return success; 310 return success;
292 } 311 }
293 312
313 void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) {
314 if (!delegate_)
315 return;
316
317 const AXNodeData& old_data = node->data();
318 delegate_->OnNodeDataWillChange(this, old_data, new_data);
319
320 if (old_data.role != new_data.role)
321 delegate_->OnRoleChanged(this, node, old_data.role, new_data.role);
322
323 if (old_data.state != new_data.state) {
324 for (int i = AX_STATE_NONE + 1; i <= AX_STATE_LAST; ++i) {
325 AXState state = static_cast<AXState>(i);
326 if (old_data.HasStateFlag(state) != new_data.HasStateFlag(state)) {
327 delegate_->OnStateChanged(this, node, state,
328 new_data.HasStateFlag(state));
329 }
330 }
331 }
332
333 const auto& old_strings = old_data.string_attributes;
334 const auto& new_strings = new_data.string_attributes;
335 if (KeyValuePairsKeysMatch(old_strings, new_strings)) {
336 for (size_t i = 0; i < old_strings.size(); ++i) {
337 if (old_strings[i].second != new_strings[i].second) {
338 delegate_->OnStringAttributeChanged(this, node, old_strings[i].first,
aboxhall 2017/03/09 00:46:06 Can we fix this duplication somehow? Something som
dmazzoni 2017/03/10 23:40:25 Figured it out! What do you think? It's about 90%
339 old_strings[i].second,
340 new_strings[i].second);
341 }
342 }
343 } else {
344 auto old_string_map = MapFromKeyValuePairs(old_strings);
345 auto new_string_map = MapFromKeyValuePairs(new_strings);
346 for (size_t i = 0; i < old_strings.size(); ++i) {
347 const auto& new_iter = new_string_map.find(old_strings[i].first);
348 if (new_iter == new_string_map.end()) {
349 delegate_->OnStringAttributeChanged(this, node, old_strings[i].first,
350 old_strings[i].second, "");
351 }
352 }
353 for (size_t i = 0; i < new_strings.size(); ++i) {
354 const auto& old_iter = old_string_map.find(new_strings[i].first);
355 if (old_iter == old_string_map.end()) {
356 delegate_->OnStringAttributeChanged(this, node, new_strings[i].first,
357 "", new_strings[i].second);
358 } else if (old_iter->second != new_strings[i].second) {
359 delegate_->OnStringAttributeChanged(this, node, new_strings[i].first,
360 old_iter->second,
361 new_strings[i].second);
362 }
363 }
364 }
365
366 const auto& old_bools = old_data.bool_attributes;
367 const auto& new_bools = new_data.bool_attributes;
368 if (KeyValuePairsKeysMatch(old_bools, new_bools)) {
369 for (size_t i = 0; i < old_bools.size(); ++i) {
370 if (old_bools[i].second != new_bools[i].second) {
371 delegate_->OnBoolAttributeChanged(this, node, old_bools[i].first,
372 new_bools[i].second);
373 }
374 }
375 } else {
376 auto old_bool_map = MapFromKeyValuePairs(old_bools);
377 auto new_bool_map = MapFromKeyValuePairs(new_bools);
378 for (size_t i = 0; i < old_bools.size(); ++i) {
379 const auto& new_iter = new_bool_map.find(old_bools[i].first);
380 if (old_bools[i].second && new_iter == new_bool_map.end()) {
381 delegate_->OnBoolAttributeChanged(this, node, old_bools[i].first,
382 false);
383 }
384 }
385 for (size_t i = 0; i < new_bools.size(); ++i) {
386 const auto& old_iter = old_bool_map.find(new_bools[i].first);
387 if (old_iter == old_bool_map.end()) {
388 if (new_bools[i].second) {
389 delegate_->OnBoolAttributeChanged(this, node, new_bools[i].first,
390 new_bools[i].second);
391 }
392 } else if (old_iter->second != new_bools[i].second) {
393 delegate_->OnBoolAttributeChanged(this, node, new_bools[i].first,
394 new_bools[i].second);
395 }
396 }
397 }
398
399 const auto& old_floats = old_data.float_attributes;
400 const auto& new_floats = new_data.float_attributes;
401 if (KeyValuePairsKeysMatch(old_floats, new_floats)) {
402 for (size_t i = 0; i < old_floats.size(); ++i) {
403 if (old_floats[i].second != new_floats[i].second) {
404 delegate_->OnFloatAttributeChanged(this, node, old_floats[i].first,
405 old_floats[i].second,
406 new_floats[i].second);
407 }
408 }
409 } else {
410 auto old_float_map = MapFromKeyValuePairs(old_floats);
411 auto new_float_map = MapFromKeyValuePairs(new_floats);
412 for (size_t i = 0; i < old_floats.size(); ++i) {
413 const auto& new_iter = new_float_map.find(old_floats[i].first);
414 if (new_iter == new_float_map.end()) {
415 delegate_->OnFloatAttributeChanged(this, node, old_floats[i].first,
416 old_floats[i].second, 0.0);
417 }
418 }
419 for (size_t i = 0; i < new_floats.size(); ++i) {
420 const auto& old_iter = old_float_map.find(new_floats[i].first);
421 if (old_iter == old_float_map.end()) {
422 delegate_->OnFloatAttributeChanged(this, node, new_floats[i].first, 0.0,
423 new_floats[i].second);
424 } else if (old_iter->second != new_floats[i].second) {
425 delegate_->OnFloatAttributeChanged(this, node, new_floats[i].first,
426 old_iter->second,
427 new_floats[i].second);
428 }
429 }
430 }
431
432 const auto& old_ints = old_data.int_attributes;
433 const auto& new_ints = new_data.int_attributes;
434 if (KeyValuePairsKeysMatch(old_ints, new_ints)) {
435 for (size_t i = 0; i < old_ints.size(); ++i) {
436 if (old_ints[i].second != new_ints[i].second) {
437 delegate_->OnIntAttributeChanged(this, node, old_ints[i].first,
438 old_ints[i].second,
439 new_ints[i].second);
440 }
441 }
442 } else {
443 auto old_int_map = MapFromKeyValuePairs(old_ints);
444 auto new_int_map = MapFromKeyValuePairs(new_ints);
445 for (size_t i = 0; i < old_ints.size(); ++i) {
446 const auto& new_iter = new_int_map.find(old_ints[i].first);
447 if (new_iter == new_int_map.end()) {
448 delegate_->OnIntAttributeChanged(this, node, old_ints[i].first,
449 old_ints[i].second, 0);
450 }
451 }
452 for (size_t i = 0; i < new_ints.size(); ++i) {
453 const auto& old_iter = old_int_map.find(new_ints[i].first);
454 if (old_iter == old_int_map.end()) {
455 delegate_->OnIntAttributeChanged(this, node, new_ints[i].first, 0,
456 new_ints[i].second);
457 } else if (old_iter->second != new_ints[i].second) {
458 delegate_->OnIntAttributeChanged(this, node, new_ints[i].first,
459 old_iter->second, new_ints[i].second);
460 }
461 }
462 }
463
464 const auto& old_intlists = old_data.intlist_attributes;
465 const auto& new_intlists = new_data.intlist_attributes;
466 if (KeyValuePairsKeysMatch(old_intlists, new_intlists)) {
467 for (size_t i = 0; i < old_intlists.size(); ++i) {
468 if (old_intlists[i].second != new_intlists[i].second) {
469 delegate_->OnIntListAttributeChanged(this, node, old_intlists[i].first,
470 old_intlists[i].second,
471 new_intlists[i].second);
472 }
473 }
474 } else {
475 auto old_intlist_map = MapFromKeyValuePairs(old_intlists);
476 auto new_intlist_map = MapFromKeyValuePairs(new_intlists);
477 for (size_t i = 0; i < old_intlists.size(); ++i) {
478 const auto& new_iter = new_intlist_map.find(old_intlists[i].first);
479 if (new_iter == new_intlist_map.end()) {
480 delegate_->OnIntListAttributeChanged(this, node, old_intlists[i].first,
481 old_intlists[i].second,
482 std::vector<int32_t>());
483 }
484 }
485 for (size_t i = 0; i < new_intlists.size(); ++i) {
486 const auto& old_iter = old_intlist_map.find(new_intlists[i].first);
487 if (old_iter == old_intlist_map.end()) {
488 delegate_->OnIntListAttributeChanged(this, node, new_intlists[i].first,
489 std::vector<int32_t>(),
490 new_intlists[i].second);
491 } else if (old_iter->second != new_intlists[i].second) {
492 delegate_->OnIntListAttributeChanged(this, node, new_intlists[i].first,
493 old_iter->second,
494 new_intlists[i].second);
495 }
496 }
497 }
498 }
499
294 void AXTree::DestroySubtree(AXNode* node, 500 void AXTree::DestroySubtree(AXNode* node,
295 AXTreeUpdateState* update_state) { 501 AXTreeUpdateState* update_state) {
296 DCHECK(update_state); 502 DCHECK(update_state);
297 if (delegate_) { 503 if (delegate_) {
298 if (!update_state->HasChangedNode(node)) 504 if (!update_state->HasChangedNode(node))
299 delegate_->OnSubtreeWillBeDeleted(this, node); 505 delegate_->OnSubtreeWillBeDeleted(this, node);
300 else 506 else
301 delegate_->OnSubtreeWillBeReparented(this, node); 507 delegate_->OnSubtreeWillBeReparented(this, node);
302 } 508 }
303 DestroyNodeAndSubtree(node, update_state); 509 DestroyNodeAndSubtree(node, update_state);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 update_state->pending_nodes.insert(child); 581 update_state->pending_nodes.insert(child);
376 update_state->new_nodes.insert(child); 582 update_state->new_nodes.insert(child);
377 } 583 }
378 new_children->push_back(child); 584 new_children->push_back(child);
379 } 585 }
380 586
381 return success; 587 return success;
382 } 588 }
383 589
384 } // namespace ui 590 } // 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