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

Unified Diff: chrome/renderer/extensions/automation_internal_custom_bindings.cc

Issue 1457683009: Complete live region support in ChromeVox Next. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed last feedback Created 5 years 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
Index: chrome/renderer/extensions/automation_internal_custom_bindings.cc
diff --git a/chrome/renderer/extensions/automation_internal_custom_bindings.cc b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
index e68edce85d3ff451f7ef206e19c291edfaf64043..c10c21145ba4dd5e91a41b44f9e6c665881364e9 100644
--- a/chrome/renderer/extensions/automation_internal_custom_bindings.cc
+++ b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
@@ -393,7 +393,10 @@ private:
AutomationInternalCustomBindings::AutomationInternalCustomBindings(
ScriptContext* context)
- : ObjectBackedNativeHandler(context), is_active_profile_(true) {
+ : ObjectBackedNativeHandler(context),
+ is_active_profile_(true),
+ tree_change_observer_overall_filter_(
+ api::automation::TREE_CHANGE_OBSERVER_FILTER_NOTREECHANGES) {
// It's safe to use base::Unretained(this) here because these bindings
// will only be called on a valid AutomationInternalCustomBindings instance
// and none of the functions have any side effects.
@@ -406,6 +409,8 @@ AutomationInternalCustomBindings::AutomationInternalCustomBindings(
ROUTE_FUNCTION(GetRoutingID);
ROUTE_FUNCTION(StartCachingAccessibilityTrees);
ROUTE_FUNCTION(DestroyAccessibilityTree);
+ ROUTE_FUNCTION(AddTreeChangeObserver);
+ ROUTE_FUNCTION(RemoveTreeChangeObserver);
ROUTE_FUNCTION(GetChildIDAtIndex);
#undef ROUTE_FUNCTION
@@ -732,6 +737,51 @@ void AutomationInternalCustomBindings::DestroyAccessibilityTree(
delete cache;
}
+void AutomationInternalCustomBindings::AddTreeChangeObserver(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ if (args.Length() != 2 || !args[0]->IsNumber() || !args[1]->IsString()) {
+ ThrowInvalidArgumentsException(this);
+ return;
+ }
+
+ TreeChangeObserver observer;
+ observer.id = args[0]->Int32Value();
+ std::string filter_str = *v8::String::Utf8Value(args[1]);
+ observer.filter = api::automation::ParseTreeChangeObserverFilter(filter_str);
+
+ tree_change_observers_.push_back(observer);
+ UpdateOverallTreeChangeObserverFilter();
+}
+
+void AutomationInternalCustomBindings::RemoveTreeChangeObserver(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ if (args.Length() != 1 || !args[0]->IsNumber()) {
+ ThrowInvalidArgumentsException(this);
+ return;
+ }
+
+ int observer_id = args[0]->Int32Value();
+
+ for (auto iter = tree_change_observers_.begin();
+ iter != tree_change_observers_.end(); ++iter) {
+ if (iter->id == observer_id) {
+ tree_change_observers_.erase(iter);
+ break;
+ }
+ }
+
+ UpdateOverallTreeChangeObserverFilter();
+}
+
+void AutomationInternalCustomBindings::UpdateOverallTreeChangeObserverFilter() {
+ tree_change_observer_overall_filter_ =
+ api::automation::TREE_CHANGE_OBSERVER_FILTER_NOTREECHANGES;
+ for (const auto& observer : tree_change_observers_) {
+ tree_change_observer_overall_filter_ =
+ std::max(observer.filter, tree_change_observer_overall_filter_);
+ }
+}
+
void AutomationInternalCustomBindings::RouteTreeIDFunction(
const std::string& name,
TreeIDFunction callback) {
@@ -816,15 +866,19 @@ void AutomationInternalCustomBindings::OnAccessibilityEvent(
// Update the internal state whether it's the active profile or not.
cache->location_offset = params.location_offset;
+ deleted_node_ids_.clear();
if (!cache->tree.Unserialize(params.update)) {
LOG(ERROR) << cache->tree.error();
return;
}
- // Don't send the event if it's not the active profile.
+ // Don't send any events if it's not the active profile.
if (!is_active_profile)
return;
+ SendNodesRemovedEvent(&cache->tree, deleted_node_ids_);
+ deleted_node_ids_.clear();
+
v8::Isolate* isolate = GetIsolate();
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context()->v8_context());
@@ -847,6 +901,7 @@ void AutomationInternalCustomBindings::OnNodeWillBeDeleted(ui::AXTree* tree,
SendTreeChangeEvent(
api::automation::TREE_CHANGE_TYPE_NODEREMOVED,
tree, node);
+ deleted_node_ids_.push_back(node->id());
}
void AutomationInternalCustomBindings::OnSubtreeWillBeDeleted(
@@ -909,6 +964,62 @@ void AutomationInternalCustomBindings::SendTreeChangeEvent(
if (!is_active_profile_)
return;
+ // Always notify the custom bindings when there's a node with a child tree
+ // ID that might need to be loaded.
+ if (node->data().HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID))
+ SendChildTreeIDEvent(tree, node);
+
+ switch (tree_change_observer_overall_filter_) {
+ case api::automation::TREE_CHANGE_OBSERVER_FILTER_NOTREECHANGES:
+ default:
+ return;
+ case api::automation::TREE_CHANGE_OBSERVER_FILTER_LIVEREGIONTREECHANGES:
+ if (!node->data().HasStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS) &&
+ node->data().role != ui::AX_ROLE_ALERT) {
+ return;
+ }
+ break;
+ case api::automation::TREE_CHANGE_OBSERVER_FILTER_ALLTREECHANGES:
+ break;
+ }
+
+ auto iter = axtree_to_tree_cache_map_.find(tree);
+ if (iter == axtree_to_tree_cache_map_.end())
+ return;
+
+ int tree_id = iter->second->tree_id;
+
+ v8::Isolate* isolate = GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Context::Scope context_scope(context()->v8_context());
+
+ for (const auto& observer : tree_change_observers_) {
+ switch (observer.filter) {
+ case api::automation::TREE_CHANGE_OBSERVER_FILTER_NOTREECHANGES:
+ default:
+ continue;
+ case api::automation::TREE_CHANGE_OBSERVER_FILTER_LIVEREGIONTREECHANGES:
+ if (!node->data().HasStringAttribute(
+ ui::AX_ATTR_CONTAINER_LIVE_STATUS) &&
+ node->data().role != ui::AX_ROLE_ALERT) {
+ continue;
+ }
+ break;
+ case api::automation::TREE_CHANGE_OBSERVER_FILTER_ALLTREECHANGES:
+ break;
+ }
+
+ v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 4U));
+ args->Set(0U, v8::Integer::New(GetIsolate(), observer.id));
+ args->Set(1U, v8::Integer::New(GetIsolate(), tree_id));
+ args->Set(2U, v8::Integer::New(GetIsolate(), node->id()));
+ args->Set(3U, CreateV8String(isolate, ToString(change_type)));
+ context()->DispatchEvent("automationInternal.onTreeChange", args);
+ }
+}
+
+void AutomationInternalCustomBindings::SendChildTreeIDEvent(ui::AXTree* tree,
+ ui::AXNode* node) {
auto iter = axtree_to_tree_cache_map_.find(tree);
if (iter == axtree_to_tree_cache_map_.end())
return;
@@ -918,11 +1029,31 @@ void AutomationInternalCustomBindings::SendTreeChangeEvent(
v8::Isolate* isolate = GetIsolate();
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context()->v8_context());
- v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 3U));
+ v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 2U));
args->Set(0U, v8::Integer::New(GetIsolate(), tree_id));
args->Set(1U, v8::Integer::New(GetIsolate(), node->id()));
- args->Set(2U, CreateV8String(isolate, ToString(change_type)));
- context()->DispatchEvent("automationInternal.onTreeChange", args);
+ context()->DispatchEvent("automationInternal.onChildTreeID", args);
+}
+
+void AutomationInternalCustomBindings::SendNodesRemovedEvent(
+ ui::AXTree* tree,
+ const std::vector<int>& ids) {
+ auto iter = axtree_to_tree_cache_map_.find(tree);
+ if (iter == axtree_to_tree_cache_map_.end())
+ return;
+
+ int tree_id = iter->second->tree_id;
+
+ v8::Isolate* isolate = GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Context::Scope context_scope(context()->v8_context());
+ v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 2U));
+ args->Set(0U, v8::Integer::New(GetIsolate(), tree_id));
+ v8::Local<v8::Array> nodes(v8::Array::New(GetIsolate(), ids.size()));
+ args->Set(1U, nodes);
+ for (size_t i = 0; i < ids.size(); ++i)
+ nodes->Set(i, v8::Integer::New(GetIsolate(), ids[i]));
+ context()->DispatchEvent("automationInternal.onNodesRemoved", args);
}
} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698