Chromium Code Reviews| 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 | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |