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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/accessibility/ax_tree.cc
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc
index 2d2a535f7e985a8ec5c0814b2628a2a05818cd77..c726a4d02f5e4b0b75035a92bd4e647b6f8bd4f3 100644
--- a/ui/accessibility/ax_tree.cc
+++ b/ui/accessibility/ax_tree.cc
@@ -24,6 +24,63 @@ 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;
+}
+
+// Given two vectors of <K, V> key, value pairs representing an "old" vs "new"
+// state, or "before" vs "after", calls a callback function for each key that
+// changed value.
+template <typename K, typename V, typename F>
+void CallIfAttributeValuesChanged(const std::vector<std::pair<K, V>>& pairs1,
+ const std::vector<std::pair<K, V>>& pairs2,
+ const V& empty_value,
+ F callback) {
+ // Fast path - if they both have the same keys in the same order.
+ if (KeyValuePairsKeysMatch(pairs1, pairs2)) {
+ for (size_t i = 0; i < pairs1.size(); ++i) {
+ if (pairs1[i].second != pairs2[i].second)
+ callback(pairs1[i].first, pairs1[i].second, pairs2[i].second);
+ }
+ return;
+ }
+
+ // Slower path - they don't have the same keys in the same order, so
+ // check all keys against each other, using maps to prevent this from
+ // becoming O(n^2) as the size grows.
+ auto map1 = MapFromKeyValuePairs(pairs1);
+ auto map2 = MapFromKeyValuePairs(pairs2);
+ for (size_t i = 0; i < pairs1.size(); ++i) {
+ const auto& new_iter = map2.find(pairs1[i].first);
+ if (pairs1[i].second != empty_value && new_iter == map2.end())
+ callback(pairs1[i].first, pairs1[i].second, empty_value);
+ }
+
+ for (size_t i = 0; i < pairs2.size(); ++i) {
+ const auto& iter = map1.find(pairs2[i].first);
+ if (iter == map1.end())
+ callback(pairs2[i].first, empty_value, pairs2[i].second);
+ else if (iter->second != pairs2[i].second)
+ callback(pairs2[i].first, iter->second, pairs2[i].second);
+ }
+}
+
} // namespace
// Intermediate state to keep track of during a tree update.
@@ -228,9 +285,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 +347,70 @@ 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));
+ }
+ }
+ }
+
+ auto string_callback = [this, node](AXStringAttribute attr,
+ const std::string& old_string,
+ const std::string& new_string) {
+ delegate_->OnStringAttributeChanged(this, node, attr, old_string,
+ new_string);
+ };
+ CallIfAttributeValuesChanged(old_data.string_attributes,
+ new_data.string_attributes, std::string(),
+ string_callback);
+
+ auto bool_callback = [this, node](AXBoolAttribute attr, const bool& old_bool,
+ const bool& new_bool) {
+ delegate_->OnBoolAttributeChanged(this, node, attr, new_bool);
+ };
+ CallIfAttributeValuesChanged(old_data.bool_attributes,
+ new_data.bool_attributes, false, bool_callback);
+
+ auto float_callback = [this, node](AXFloatAttribute attr,
+ const float& old_float,
+ const float& new_float) {
+ delegate_->OnFloatAttributeChanged(this, node, attr, old_float, new_float);
+ };
+ CallIfAttributeValuesChanged(old_data.float_attributes,
+ new_data.float_attributes, 0.0f, float_callback);
+
+ auto int_callback = [this, node](AXIntAttribute attr, const int& old_int,
+ const int& new_int) {
+ delegate_->OnIntAttributeChanged(this, node, attr, old_int, new_int);
+ };
+ CallIfAttributeValuesChanged(old_data.int_attributes, new_data.int_attributes,
+ 0, int_callback);
+
+ auto intlist_callback = [this, node](
+ AXIntListAttribute attr,
+ const std::vector<int32_t>& old_intlist,
+ const std::vector<int32_t>& new_intlist) {
+ delegate_->OnIntListAttributeChanged(this, node, attr, old_intlist,
+ new_intlist);
+ };
+ CallIfAttributeValuesChanged(old_data.intlist_attributes,
+ new_data.intlist_attributes,
+ std::vector<int32_t>(), intlist_callback);
+}
+
void AXTree::DestroySubtree(AXNode* node,
AXTreeUpdateState* update_state) {
DCHECK(update_state);
« 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