Chromium Code Reviews| Index: ui/accessibility/ax_tree.cc |
| diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc |
| index 2d2a535f7e985a8ec5c0814b2628a2a05818cd77..e67ca5975feae1c9482702605fa6f7a74a604896 100644 |
| --- a/ui/accessibility/ax_tree.cc |
| +++ b/ui/accessibility/ax_tree.cc |
| @@ -24,6 +24,26 @@ std::string TreeToStringHelper(AXNode* node, int indent) { |
| return result; |
| } |
| +template <typename K, typename V> |
| +bool KeyValuePairsKeysMatch(std::vector<std::pair<K, V>> pairs1, |
| + std::vector<std::pair<K, V>> pairs2) { |
| + if (pairs1.size() != pairs2.size()) |
| + return false; |
| + for (size_t i = 0; i < pairs1.size(); ++i) { |
| + if (pairs1[i].first != pairs2[i].first) |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +template <typename K, typename V> |
| +std::map<K, V> MapFromKeyValuePairs(std::vector<std::pair<K, V>> pairs) { |
| + std::map<K, V> result; |
| + for (size_t i = 0; i < pairs.size(); ++i) |
| + result[pairs[i].first] = pairs[i].second; |
| + return result; |
| +} |
| + |
| } // namespace |
| // Intermediate state to keep track of during a tree update. |
| @@ -228,9 +248,8 @@ bool AXTree::UpdateNode(const AXNodeData& src, |
| AXNode* node = GetFromId(src.id); |
| if (node) { |
| update_state->pending_nodes.erase(node); |
| - if (delegate_ && |
| - update_state->new_nodes.find(node) == update_state->new_nodes.end()) |
| - delegate_->OnNodeDataWillChange(this, node->data(), src); |
| + if (update_state->new_nodes.find(node) == update_state->new_nodes.end()) |
| + CallNodeChangeCallbacks(node, src); |
| node->SetData(src); |
| } else { |
| if (!is_new_root) { |
| @@ -291,6 +310,193 @@ bool AXTree::UpdateNode(const AXNodeData& src, |
| return success; |
| } |
| +void AXTree::CallNodeChangeCallbacks(AXNode* node, const AXNodeData& new_data) { |
| + if (!delegate_) |
| + return; |
| + |
| + const AXNodeData& old_data = node->data(); |
| + delegate_->OnNodeDataWillChange(this, old_data, new_data); |
| + |
| + if (old_data.role != new_data.role) |
| + delegate_->OnRoleChanged(this, node, old_data.role, new_data.role); |
| + |
| + if (old_data.state != new_data.state) { |
| + for (int i = AX_STATE_NONE + 1; i <= AX_STATE_LAST; ++i) { |
| + AXState state = static_cast<AXState>(i); |
| + if (old_data.HasStateFlag(state) != new_data.HasStateFlag(state)) { |
| + delegate_->OnStateChanged(this, node, state, |
| + new_data.HasStateFlag(state)); |
| + } |
| + } |
| + } |
| + |
| + const auto& old_strings = old_data.string_attributes; |
| + const auto& new_strings = new_data.string_attributes; |
| + if (KeyValuePairsKeysMatch(old_strings, new_strings)) { |
| + for (size_t i = 0; i < old_strings.size(); ++i) { |
| + if (old_strings[i].second != new_strings[i].second) { |
| + 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%
|
| + old_strings[i].second, |
| + new_strings[i].second); |
| + } |
| + } |
| + } else { |
| + auto old_string_map = MapFromKeyValuePairs(old_strings); |
| + auto new_string_map = MapFromKeyValuePairs(new_strings); |
| + for (size_t i = 0; i < old_strings.size(); ++i) { |
| + const auto& new_iter = new_string_map.find(old_strings[i].first); |
| + if (new_iter == new_string_map.end()) { |
| + delegate_->OnStringAttributeChanged(this, node, old_strings[i].first, |
| + old_strings[i].second, ""); |
| + } |
| + } |
| + for (size_t i = 0; i < new_strings.size(); ++i) { |
| + const auto& old_iter = old_string_map.find(new_strings[i].first); |
| + if (old_iter == old_string_map.end()) { |
| + delegate_->OnStringAttributeChanged(this, node, new_strings[i].first, |
| + "", new_strings[i].second); |
| + } else if (old_iter->second != new_strings[i].second) { |
| + delegate_->OnStringAttributeChanged(this, node, new_strings[i].first, |
| + old_iter->second, |
| + new_strings[i].second); |
| + } |
| + } |
| + } |
| + |
| + const auto& old_bools = old_data.bool_attributes; |
| + const auto& new_bools = new_data.bool_attributes; |
| + if (KeyValuePairsKeysMatch(old_bools, new_bools)) { |
| + for (size_t i = 0; i < old_bools.size(); ++i) { |
| + if (old_bools[i].second != new_bools[i].second) { |
| + delegate_->OnBoolAttributeChanged(this, node, old_bools[i].first, |
| + new_bools[i].second); |
| + } |
| + } |
| + } else { |
| + auto old_bool_map = MapFromKeyValuePairs(old_bools); |
| + auto new_bool_map = MapFromKeyValuePairs(new_bools); |
| + for (size_t i = 0; i < old_bools.size(); ++i) { |
| + const auto& new_iter = new_bool_map.find(old_bools[i].first); |
| + if (old_bools[i].second && new_iter == new_bool_map.end()) { |
| + delegate_->OnBoolAttributeChanged(this, node, old_bools[i].first, |
| + false); |
| + } |
| + } |
| + for (size_t i = 0; i < new_bools.size(); ++i) { |
| + const auto& old_iter = old_bool_map.find(new_bools[i].first); |
| + if (old_iter == old_bool_map.end()) { |
| + if (new_bools[i].second) { |
| + delegate_->OnBoolAttributeChanged(this, node, new_bools[i].first, |
| + new_bools[i].second); |
| + } |
| + } else if (old_iter->second != new_bools[i].second) { |
| + delegate_->OnBoolAttributeChanged(this, node, new_bools[i].first, |
| + new_bools[i].second); |
| + } |
| + } |
| + } |
| + |
| + const auto& old_floats = old_data.float_attributes; |
| + const auto& new_floats = new_data.float_attributes; |
| + if (KeyValuePairsKeysMatch(old_floats, new_floats)) { |
| + for (size_t i = 0; i < old_floats.size(); ++i) { |
| + if (old_floats[i].second != new_floats[i].second) { |
| + delegate_->OnFloatAttributeChanged(this, node, old_floats[i].first, |
| + old_floats[i].second, |
| + new_floats[i].second); |
| + } |
| + } |
| + } else { |
| + auto old_float_map = MapFromKeyValuePairs(old_floats); |
| + auto new_float_map = MapFromKeyValuePairs(new_floats); |
| + for (size_t i = 0; i < old_floats.size(); ++i) { |
| + const auto& new_iter = new_float_map.find(old_floats[i].first); |
| + if (new_iter == new_float_map.end()) { |
| + delegate_->OnFloatAttributeChanged(this, node, old_floats[i].first, |
| + old_floats[i].second, 0.0); |
| + } |
| + } |
| + for (size_t i = 0; i < new_floats.size(); ++i) { |
| + const auto& old_iter = old_float_map.find(new_floats[i].first); |
| + if (old_iter == old_float_map.end()) { |
| + delegate_->OnFloatAttributeChanged(this, node, new_floats[i].first, 0.0, |
| + new_floats[i].second); |
| + } else if (old_iter->second != new_floats[i].second) { |
| + delegate_->OnFloatAttributeChanged(this, node, new_floats[i].first, |
| + old_iter->second, |
| + new_floats[i].second); |
| + } |
| + } |
| + } |
| + |
| + const auto& old_ints = old_data.int_attributes; |
| + const auto& new_ints = new_data.int_attributes; |
| + if (KeyValuePairsKeysMatch(old_ints, new_ints)) { |
| + for (size_t i = 0; i < old_ints.size(); ++i) { |
| + if (old_ints[i].second != new_ints[i].second) { |
| + delegate_->OnIntAttributeChanged(this, node, old_ints[i].first, |
| + old_ints[i].second, |
| + new_ints[i].second); |
| + } |
| + } |
| + } else { |
| + auto old_int_map = MapFromKeyValuePairs(old_ints); |
| + auto new_int_map = MapFromKeyValuePairs(new_ints); |
| + for (size_t i = 0; i < old_ints.size(); ++i) { |
| + const auto& new_iter = new_int_map.find(old_ints[i].first); |
| + if (new_iter == new_int_map.end()) { |
| + delegate_->OnIntAttributeChanged(this, node, old_ints[i].first, |
| + old_ints[i].second, 0); |
| + } |
| + } |
| + for (size_t i = 0; i < new_ints.size(); ++i) { |
| + const auto& old_iter = old_int_map.find(new_ints[i].first); |
| + if (old_iter == old_int_map.end()) { |
| + delegate_->OnIntAttributeChanged(this, node, new_ints[i].first, 0, |
| + new_ints[i].second); |
| + } else if (old_iter->second != new_ints[i].second) { |
| + delegate_->OnIntAttributeChanged(this, node, new_ints[i].first, |
| + old_iter->second, new_ints[i].second); |
| + } |
| + } |
| + } |
| + |
| + const auto& old_intlists = old_data.intlist_attributes; |
| + const auto& new_intlists = new_data.intlist_attributes; |
| + if (KeyValuePairsKeysMatch(old_intlists, new_intlists)) { |
| + for (size_t i = 0; i < old_intlists.size(); ++i) { |
| + if (old_intlists[i].second != new_intlists[i].second) { |
| + delegate_->OnIntListAttributeChanged(this, node, old_intlists[i].first, |
| + old_intlists[i].second, |
| + new_intlists[i].second); |
| + } |
| + } |
| + } else { |
| + auto old_intlist_map = MapFromKeyValuePairs(old_intlists); |
| + auto new_intlist_map = MapFromKeyValuePairs(new_intlists); |
| + for (size_t i = 0; i < old_intlists.size(); ++i) { |
| + const auto& new_iter = new_intlist_map.find(old_intlists[i].first); |
| + if (new_iter == new_intlist_map.end()) { |
| + delegate_->OnIntListAttributeChanged(this, node, old_intlists[i].first, |
| + old_intlists[i].second, |
| + std::vector<int32_t>()); |
| + } |
| + } |
| + for (size_t i = 0; i < new_intlists.size(); ++i) { |
| + const auto& old_iter = old_intlist_map.find(new_intlists[i].first); |
| + if (old_iter == old_intlist_map.end()) { |
| + delegate_->OnIntListAttributeChanged(this, node, new_intlists[i].first, |
| + std::vector<int32_t>(), |
| + new_intlists[i].second); |
| + } else if (old_iter->second != new_intlists[i].second) { |
| + delegate_->OnIntListAttributeChanged(this, node, new_intlists[i].first, |
| + old_iter->second, |
| + new_intlists[i].second); |
| + } |
| + } |
| + } |
| +} |
| + |
| void AXTree::DestroySubtree(AXNode* node, |
| AXTreeUpdateState* update_state) { |
| DCHECK(update_state); |