Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "chrome/renderer/extensions/automation_internal_custom_bindings.h" | 5 #include "chrome/renderer/extensions/automation_internal_custom_bindings.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/thread_task_runner_handle.h" | 9 #include "base/thread_task_runner_handle.h" |
| 10 #include "base/values.h" | 10 #include "base/values.h" |
| (...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 386 | 386 |
| 387 AutomationInternalCustomBindings* owner_; | 387 AutomationInternalCustomBindings* owner_; |
| 388 bool removed_; | 388 bool removed_; |
| 389 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 389 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| 390 | 390 |
| 391 DISALLOW_COPY_AND_ASSIGN(AutomationMessageFilter); | 391 DISALLOW_COPY_AND_ASSIGN(AutomationMessageFilter); |
| 392 }; | 392 }; |
| 393 | 393 |
| 394 AutomationInternalCustomBindings::AutomationInternalCustomBindings( | 394 AutomationInternalCustomBindings::AutomationInternalCustomBindings( |
| 395 ScriptContext* context) | 395 ScriptContext* context) |
| 396 : ObjectBackedNativeHandler(context), is_active_profile_(true) { | 396 : ObjectBackedNativeHandler(context), |
| 397 is_active_profile_(true), | |
| 398 tree_change_observer_overall_filter_( | |
| 399 api::automation::TREE_CHANGE_OBSERVER_FILTER_NOTREECHANGES) { | |
| 397 // It's safe to use base::Unretained(this) here because these bindings | 400 // It's safe to use base::Unretained(this) here because these bindings |
| 398 // will only be called on a valid AutomationInternalCustomBindings instance | 401 // will only be called on a valid AutomationInternalCustomBindings instance |
| 399 // and none of the functions have any side effects. | 402 // and none of the functions have any side effects. |
| 400 #define ROUTE_FUNCTION(FN) \ | 403 #define ROUTE_FUNCTION(FN) \ |
| 401 RouteFunction(#FN, \ | 404 RouteFunction(#FN, \ |
| 402 base::Bind(&AutomationInternalCustomBindings::FN, \ | 405 base::Bind(&AutomationInternalCustomBindings::FN, \ |
| 403 base::Unretained(this))) | 406 base::Unretained(this))) |
| 404 ROUTE_FUNCTION(IsInteractPermitted); | 407 ROUTE_FUNCTION(IsInteractPermitted); |
| 405 ROUTE_FUNCTION(GetSchemaAdditions); | 408 ROUTE_FUNCTION(GetSchemaAdditions); |
| 406 ROUTE_FUNCTION(GetRoutingID); | 409 ROUTE_FUNCTION(GetRoutingID); |
| 407 ROUTE_FUNCTION(StartCachingAccessibilityTrees); | 410 ROUTE_FUNCTION(StartCachingAccessibilityTrees); |
| 408 ROUTE_FUNCTION(DestroyAccessibilityTree); | 411 ROUTE_FUNCTION(DestroyAccessibilityTree); |
| 412 ROUTE_FUNCTION(AddTreeChangeObserver); | |
| 413 ROUTE_FUNCTION(RemoveTreeChangeObserver); | |
| 409 ROUTE_FUNCTION(GetChildIDAtIndex); | 414 ROUTE_FUNCTION(GetChildIDAtIndex); |
| 410 #undef ROUTE_FUNCTION | 415 #undef ROUTE_FUNCTION |
| 411 | 416 |
| 412 // Bindings that take a Tree ID and return a property of the tree. | 417 // Bindings that take a Tree ID and return a property of the tree. |
| 413 | 418 |
| 414 RouteTreeIDFunction( | 419 RouteTreeIDFunction( |
| 415 "GetRootID", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result, | 420 "GetRootID", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result, |
| 416 TreeCache* cache) { | 421 TreeCache* cache) { |
| 417 result.Set(v8::Integer::New(isolate, cache->tree.root()->id())); | 422 result.Set(v8::Integer::New(isolate, cache->tree.root()->id())); |
| 418 }); | 423 }); |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 725 auto iter = tree_id_to_tree_cache_map_.find(tree_id); | 730 auto iter = tree_id_to_tree_cache_map_.find(tree_id); |
| 726 if (iter == tree_id_to_tree_cache_map_.end()) | 731 if (iter == tree_id_to_tree_cache_map_.end()) |
| 727 return; | 732 return; |
| 728 | 733 |
| 729 TreeCache* cache = iter->second; | 734 TreeCache* cache = iter->second; |
| 730 tree_id_to_tree_cache_map_.erase(tree_id); | 735 tree_id_to_tree_cache_map_.erase(tree_id); |
| 731 axtree_to_tree_cache_map_.erase(&cache->tree); | 736 axtree_to_tree_cache_map_.erase(&cache->tree); |
| 732 delete cache; | 737 delete cache; |
| 733 } | 738 } |
| 734 | 739 |
| 740 void AutomationInternalCustomBindings::AddTreeChangeObserver( | |
| 741 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 742 if (args.Length() != 2 || !args[0]->IsNumber() || !args[1]->IsString()) { | |
| 743 ThrowInvalidArgumentsException(this); | |
| 744 return; | |
| 745 } | |
| 746 | |
| 747 TreeChangeObserver observer; | |
| 748 observer.id = args[0]->Int32Value(); | |
| 749 std::string filter_str = *v8::String::Utf8Value(args[1]); | |
| 750 observer.filter = api::automation::ParseTreeChangeObserverFilter(filter_str); | |
| 751 | |
| 752 tree_change_observers_.push_back(observer); | |
| 753 UpdateOverallTreeChangeObserverFilter(); | |
| 754 } | |
| 755 | |
| 756 void AutomationInternalCustomBindings::RemoveTreeChangeObserver( | |
| 757 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 758 if (args.Length() != 1 || !args[0]->IsNumber()) { | |
| 759 ThrowInvalidArgumentsException(this); | |
| 760 return; | |
| 761 } | |
| 762 | |
| 763 int observer_id = args[0]->Int32Value(); | |
| 764 | |
| 765 for (auto iter = tree_change_observers_.begin(); | |
| 766 iter != tree_change_observers_.end(); ++iter) { | |
| 767 if (iter->id == observer_id) { | |
| 768 tree_change_observers_.erase(iter); | |
| 769 break; | |
| 770 } | |
| 771 } | |
| 772 | |
| 773 UpdateOverallTreeChangeObserverFilter(); | |
| 774 } | |
| 775 | |
| 776 void AutomationInternalCustomBindings::UpdateOverallTreeChangeObserverFilter() { | |
| 777 tree_change_observer_overall_filter_ = | |
| 778 api::automation::TREE_CHANGE_OBSERVER_FILTER_NOTREECHANGES; | |
| 779 for (const auto& iter : tree_change_observers_) { | |
|
Peter Lundblad
2015/12/01 12:49:58
Mildly confusing to call something that is not an
dmazzoni
2015/12/01 19:19:01
Done.
| |
| 780 tree_change_observer_overall_filter_ = | |
| 781 std::max(iter.filter, tree_change_observer_overall_filter_); | |
| 782 } | |
| 783 } | |
| 784 | |
| 735 void AutomationInternalCustomBindings::RouteTreeIDFunction( | 785 void AutomationInternalCustomBindings::RouteTreeIDFunction( |
| 736 const std::string& name, | 786 const std::string& name, |
| 737 TreeIDFunction callback) { | 787 TreeIDFunction callback) { |
| 738 scoped_refptr<TreeIDWrapper> wrapper = new TreeIDWrapper(this, callback); | 788 scoped_refptr<TreeIDWrapper> wrapper = new TreeIDWrapper(this, callback); |
| 739 RouteFunction(name, base::Bind(&TreeIDWrapper::Run, wrapper)); | 789 RouteFunction(name, base::Bind(&TreeIDWrapper::Run, wrapper)); |
| 740 } | 790 } |
| 741 | 791 |
| 742 void AutomationInternalCustomBindings::RouteNodeIDFunction( | 792 void AutomationInternalCustomBindings::RouteNodeIDFunction( |
| 743 const std::string& name, | 793 const std::string& name, |
| 744 NodeIDFunction callback) { | 794 NodeIDFunction callback) { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 809 cache->tree_id = params.tree_id; | 859 cache->tree_id = params.tree_id; |
| 810 cache->tree.SetDelegate(this); | 860 cache->tree.SetDelegate(this); |
| 811 tree_id_to_tree_cache_map_.insert(std::make_pair(tree_id, cache)); | 861 tree_id_to_tree_cache_map_.insert(std::make_pair(tree_id, cache)); |
| 812 axtree_to_tree_cache_map_.insert(std::make_pair(&cache->tree, cache)); | 862 axtree_to_tree_cache_map_.insert(std::make_pair(&cache->tree, cache)); |
| 813 } else { | 863 } else { |
| 814 cache = iter->second; | 864 cache = iter->second; |
| 815 } | 865 } |
| 816 | 866 |
| 817 // Update the internal state whether it's the active profile or not. | 867 // Update the internal state whether it's the active profile or not. |
| 818 cache->location_offset = params.location_offset; | 868 cache->location_offset = params.location_offset; |
| 869 deleted_node_ids_.clear(); | |
| 819 if (!cache->tree.Unserialize(params.update)) { | 870 if (!cache->tree.Unserialize(params.update)) { |
| 820 LOG(ERROR) << cache->tree.error(); | 871 LOG(ERROR) << cache->tree.error(); |
| 821 return; | 872 return; |
| 822 } | 873 } |
| 823 | 874 |
| 824 // Don't send the event if it's not the active profile. | 875 // Don't send any events if it's not the active profile. |
| 825 if (!is_active_profile) | 876 if (!is_active_profile) |
| 826 return; | 877 return; |
| 827 | 878 |
| 879 SendNodesRemovedEvent(&cache->tree, deleted_node_ids_); | |
| 880 deleted_node_ids_.clear(); | |
| 881 | |
| 828 v8::Isolate* isolate = GetIsolate(); | 882 v8::Isolate* isolate = GetIsolate(); |
| 829 v8::HandleScope handle_scope(isolate); | 883 v8::HandleScope handle_scope(isolate); |
| 830 v8::Context::Scope context_scope(context()->v8_context()); | 884 v8::Context::Scope context_scope(context()->v8_context()); |
| 831 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 1U)); | 885 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 1U)); |
| 832 v8::Local<v8::Object> event_params(v8::Object::New(GetIsolate())); | 886 v8::Local<v8::Object> event_params(v8::Object::New(GetIsolate())); |
| 833 event_params->Set(CreateV8String(isolate, "treeID"), | 887 event_params->Set(CreateV8String(isolate, "treeID"), |
| 834 v8::Integer::New(GetIsolate(), params.tree_id)); | 888 v8::Integer::New(GetIsolate(), params.tree_id)); |
| 835 event_params->Set(CreateV8String(isolate, "targetID"), | 889 event_params->Set(CreateV8String(isolate, "targetID"), |
| 836 v8::Integer::New(GetIsolate(), params.id)); | 890 v8::Integer::New(GetIsolate(), params.id)); |
| 837 event_params->Set(CreateV8String(isolate, "eventType"), | 891 event_params->Set(CreateV8String(isolate, "eventType"), |
| 838 CreateV8String(isolate, ToString(params.event_type))); | 892 CreateV8String(isolate, ToString(params.event_type))); |
| 839 args->Set(0U, event_params); | 893 args->Set(0U, event_params); |
| 840 context()->DispatchEvent("automationInternal.onAccessibilityEvent", args); | 894 context()->DispatchEvent("automationInternal.onAccessibilityEvent", args); |
| 841 } | 895 } |
| 842 | 896 |
| 843 void AutomationInternalCustomBindings::OnTreeDataChanged(ui::AXTree* tree) {} | 897 void AutomationInternalCustomBindings::OnTreeDataChanged(ui::AXTree* tree) {} |
| 844 | 898 |
| 845 void AutomationInternalCustomBindings::OnNodeWillBeDeleted(ui::AXTree* tree, | 899 void AutomationInternalCustomBindings::OnNodeWillBeDeleted(ui::AXTree* tree, |
| 846 ui::AXNode* node) { | 900 ui::AXNode* node) { |
| 847 SendTreeChangeEvent( | 901 SendTreeChangeEvent( |
| 848 api::automation::TREE_CHANGE_TYPE_NODEREMOVED, | 902 api::automation::TREE_CHANGE_TYPE_NODEREMOVED, |
| 849 tree, node); | 903 tree, node); |
| 904 deleted_node_ids_.push_back(node->id()); | |
| 850 } | 905 } |
| 851 | 906 |
| 852 void AutomationInternalCustomBindings::OnSubtreeWillBeDeleted( | 907 void AutomationInternalCustomBindings::OnSubtreeWillBeDeleted( |
| 853 ui::AXTree* tree, | 908 ui::AXTree* tree, |
| 854 ui::AXNode* node) { | 909 ui::AXNode* node) { |
| 855 // This isn't strictly needed, as OnNodeWillBeDeleted will already be | 910 // This isn't strictly needed, as OnNodeWillBeDeleted will already be |
| 856 // called. We could send a JS event for this only if it turns out to | 911 // called. We could send a JS event for this only if it turns out to |
| 857 // be needed for something. | 912 // be needed for something. |
| 858 } | 913 } |
| 859 | 914 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 902 } | 957 } |
| 903 | 958 |
| 904 void AutomationInternalCustomBindings::SendTreeChangeEvent( | 959 void AutomationInternalCustomBindings::SendTreeChangeEvent( |
| 905 api::automation::TreeChangeType change_type, | 960 api::automation::TreeChangeType change_type, |
| 906 ui::AXTree* tree, | 961 ui::AXTree* tree, |
| 907 ui::AXNode* node) { | 962 ui::AXNode* node) { |
| 908 // Don't send tree change events when it's not the active profile. | 963 // Don't send tree change events when it's not the active profile. |
| 909 if (!is_active_profile_) | 964 if (!is_active_profile_) |
| 910 return; | 965 return; |
| 911 | 966 |
| 967 // Always notify the custom bindings when there's a node with a child tree | |
| 968 // ID that might need to be loaded. | |
| 969 if (node->data().HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) | |
| 970 SendChildTreeIDEvent(tree, node); | |
| 971 | |
| 972 switch (tree_change_observer_overall_filter_) { | |
| 973 case api::automation::TREE_CHANGE_OBSERVER_FILTER_NOTREECHANGES: | |
| 974 default: | |
| 975 return; | |
| 976 case api::automation::TREE_CHANGE_OBSERVER_FILTER_LIVEREGIONTREECHANGES: | |
| 977 if (!node->data().HasStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS) && | |
| 978 node->data().role != ui::AX_ROLE_ALERT) { | |
| 979 return; | |
| 980 } | |
| 981 break; | |
| 982 case api::automation::TREE_CHANGE_OBSERVER_FILTER_ALLTREECHANGES: | |
| 983 break; | |
| 984 } | |
| 985 | |
| 912 auto iter = axtree_to_tree_cache_map_.find(tree); | 986 auto iter = axtree_to_tree_cache_map_.find(tree); |
| 913 if (iter == axtree_to_tree_cache_map_.end()) | 987 if (iter == axtree_to_tree_cache_map_.end()) |
| 914 return; | 988 return; |
| 989 | |
| 990 int tree_id = iter->second->tree_id; | |
| 991 | |
| 992 v8::Isolate* isolate = GetIsolate(); | |
| 993 v8::HandleScope handle_scope(isolate); | |
| 994 v8::Context::Scope context_scope(context()->v8_context()); | |
| 995 | |
| 996 for (const auto& observer : tree_change_observers_) { | |
| 997 switch (observer.filter) { | |
| 998 case api::automation::TREE_CHANGE_OBSERVER_FILTER_NOTREECHANGES: | |
| 999 default: | |
| 1000 continue; | |
| 1001 case api::automation::TREE_CHANGE_OBSERVER_FILTER_LIVEREGIONTREECHANGES: | |
| 1002 if (!node->data().HasStringAttribute( | |
| 1003 ui::AX_ATTR_CONTAINER_LIVE_STATUS) && | |
| 1004 node->data().role != ui::AX_ROLE_ALERT) { | |
| 1005 continue; | |
| 1006 } | |
| 1007 break; | |
| 1008 case api::automation::TREE_CHANGE_OBSERVER_FILTER_ALLTREECHANGES: | |
| 1009 break; | |
| 1010 } | |
| 1011 | |
| 1012 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 4U)); | |
| 1013 args->Set(0U, v8::Integer::New(GetIsolate(), observer.id)); | |
| 1014 args->Set(1U, v8::Integer::New(GetIsolate(), tree_id)); | |
| 1015 args->Set(2U, v8::Integer::New(GetIsolate(), node->id())); | |
| 1016 args->Set(3U, CreateV8String(isolate, ToString(change_type))); | |
| 1017 context()->DispatchEvent("automationInternal.onTreeChange", args); | |
| 1018 } | |
| 1019 } | |
| 1020 | |
| 1021 void AutomationInternalCustomBindings::SendChildTreeIDEvent(ui::AXTree* tree, | |
| 1022 ui::AXNode* node) { | |
| 1023 auto iter = axtree_to_tree_cache_map_.find(tree); | |
| 1024 if (iter == axtree_to_tree_cache_map_.end()) | |
| 1025 return; | |
| 915 | 1026 |
| 916 int tree_id = iter->second->tree_id; | 1027 int tree_id = iter->second->tree_id; |
| 917 | 1028 |
| 918 v8::Isolate* isolate = GetIsolate(); | 1029 v8::Isolate* isolate = GetIsolate(); |
| 919 v8::HandleScope handle_scope(isolate); | 1030 v8::HandleScope handle_scope(isolate); |
| 920 v8::Context::Scope context_scope(context()->v8_context()); | 1031 v8::Context::Scope context_scope(context()->v8_context()); |
| 921 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 3U)); | 1032 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 2U)); |
| 922 args->Set(0U, v8::Integer::New(GetIsolate(), tree_id)); | 1033 args->Set(0U, v8::Integer::New(GetIsolate(), tree_id)); |
| 923 args->Set(1U, v8::Integer::New(GetIsolate(), node->id())); | 1034 args->Set(1U, v8::Integer::New(GetIsolate(), node->id())); |
| 924 args->Set(2U, CreateV8String(isolate, ToString(change_type))); | 1035 context()->DispatchEvent("automationInternal.onChildTreeID", args); |
| 925 context()->DispatchEvent("automationInternal.onTreeChange", args); | 1036 } |
| 1037 | |
| 1038 void AutomationInternalCustomBindings::SendNodesRemovedEvent( | |
| 1039 ui::AXTree* tree, | |
| 1040 const std::vector<int>& ids) { | |
| 1041 auto iter = axtree_to_tree_cache_map_.find(tree); | |
| 1042 if (iter == axtree_to_tree_cache_map_.end()) | |
| 1043 return; | |
| 1044 | |
| 1045 int tree_id = iter->second->tree_id; | |
| 1046 | |
| 1047 v8::Isolate* isolate = GetIsolate(); | |
| 1048 v8::HandleScope handle_scope(isolate); | |
| 1049 v8::Context::Scope context_scope(context()->v8_context()); | |
| 1050 v8::Local<v8::Array> args(v8::Array::New(GetIsolate(), 2U)); | |
| 1051 args->Set(0U, v8::Integer::New(GetIsolate(), tree_id)); | |
| 1052 v8::Local<v8::Array> nodes(v8::Array::New(GetIsolate(), ids.size())); | |
| 1053 args->Set(1U, nodes); | |
| 1054 for (size_t i = 0; i < ids.size(); ++i) | |
| 1055 nodes->Set(i, v8::Integer::New(GetIsolate(), ids[i])); | |
| 1056 context()->DispatchEvent("automationInternal.onNodesRemoved", args); | |
| 926 } | 1057 } |
| 927 | 1058 |
| 928 } // namespace extensions | 1059 } // namespace extensions |
| OLD | NEW |