Commit 598dbbb6 authored by Dominic Mazzoni's avatar Dominic Mazzoni Committed by Commit Bot

Start to use AXEventGenerator in automation.

Adds support for AXEventGenerator in AutomationAXTreeWrapper, but to
be very conservative and safe, only uses it to fire "load complete"
events for now. Those events are really important and have both very
broad test coverage already, and are also easy to verify in manual tests.

In subsequent changes we'll switch over more and more events to come
from AXEventGenerator.

Bug: 699438
Change-Id: I30486c96689cc83dc24d8443b32dc4ee9069702b
Reviewed-on: https://chromium-review.googlesource.com/797214
Commit-Queue: Dominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#523035}
parent e318b791
......@@ -5,18 +5,21 @@
#ifndef CHROME_RENDERER_EXTENSIONS_AUTOMATION_AX_TREE_WRAPPER_H_
#define CHROME_RENDERER_EXTENSIONS_AUTOMATION_AX_TREE_WRAPPER_H_
#include "ui/accessibility/ax_event_generator.h"
#include "ui/accessibility/ax_tree.h"
struct ExtensionMsg_AccessibilityEventParams;
namespace extensions {
class AutomationInternalCustomBindings;
// A class that wraps one AXTree and all of the additional state
// and helper methods needed to use it for the automation API.
class AutomationAXTreeWrapper {
class AutomationAXTreeWrapper : public ui::AXEventGenerator {
public:
AutomationAXTreeWrapper(int tree_id, AutomationInternalCustomBindings* owner);
~AutomationAXTreeWrapper();
~AutomationAXTreeWrapper() override;
int32_t tree_id() const { return tree_id_; }
ui::AXTree* tree() { return &tree_; }
......@@ -28,11 +31,34 @@ class AutomationAXTreeWrapper {
int32_t host_node_id() const { return host_node_id_; }
void set_host_node_id(int32_t id) { host_node_id_ = id; }
// Called by AutomationInternalCustomBindings::OnAccessibilityEvent on
// the AutomationAXTreeWrapper instance for the correct tree corresponding
// to this event. Unserializes the tree update and calls back to
// AutomationInternalCustomBindings to fire any automation events needed.
bool OnAccessibilityEvent(const ExtensionMsg_AccessibilityEventParams& params,
bool is_active_profile);
private:
// AXEventGenerator overrides.
void OnNodeDataWillChange(ui::AXTree* tree,
const ui::AXNodeData& old_node_data,
const ui::AXNodeData& new_node_data) override;
void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnAtomicUpdateFinished(ui::AXTree* tree,
bool root_changed,
const std::vector<Change>& changes) override;
// Given an event, return true if the event is handled by
// AXEventGenerator, and false if it's not. Temporary, this will be
// removed with the AXEventGenerator refactoring is complete.
bool IsEventTypeHandledByAXEventGenerator(api::automation::EventType) const;
int32_t tree_id_;
int32_t host_node_id_;
ui::AXTree tree_;
AutomationInternalCustomBindings* owner_;
std::vector<int> deleted_node_ids_;
std::vector<int> text_changed_node_ids_;
DISALLOW_COPY_AND_ASSIGN(AutomationAXTreeWrapper);
};
......
......@@ -796,10 +796,6 @@ void AutomationInternalCustomBindings::Invalidate() {
if (message_filter_)
message_filter_->Detach();
// Delete the tree wrappers quickly by first clearing their delegates so
// we don't get a callback for every node being deleted.
for (auto& iter : tree_id_to_tree_wrapper_map_)
iter.second->tree()->SetDelegate(nullptr);
tree_id_to_tree_wrapper_map_.clear();
}
......@@ -1209,9 +1205,7 @@ void AutomationInternalCustomBindings::OnAccessibilityEvent(
tree_wrapper = iter->second.get();
}
// Update the internal state whether it's the active profile or not.
deleted_node_ids_.clear();
if (!tree_wrapper->tree()->Unserialize(params.update)) {
if (!tree_wrapper->OnAccessibilityEvent(params, is_active_profile)) {
LOG(ERROR) << tree_wrapper->tree()->error();
base::ListValue args;
args.AppendInteger(tree_id);
......@@ -1220,27 +1214,6 @@ void AutomationInternalCustomBindings::OnAccessibilityEvent(
nullptr, context());
return;
}
// Don't send any events if it's not the active profile.
if (!is_active_profile)
return;
SendNodesRemovedEvent(tree_wrapper->tree(), deleted_node_ids_);
deleted_node_ids_.clear();
{
auto event_params = base::MakeUnique<base::DictionaryValue>();
event_params->SetInteger("treeID", params.tree_id);
event_params->SetInteger("targetID", params.id);
event_params->SetString("eventType", ToString(params.event_type));
event_params->SetString("eventFrom", ToString(params.event_from));
event_params->SetInteger("mouseX", params.mouse_location.x());
event_params->SetInteger("mouseY", params.mouse_location.y());
base::ListValue args;
args.Append(std::move(event_params));
bindings_system_->DispatchEventInContext(
"automationInternal.onAccessibilityEvent", &args, nullptr, context());
}
}
void AutomationInternalCustomBindings::OnAccessibilityLocationChange(
......@@ -1258,109 +1231,6 @@ void AutomationInternalCustomBindings::OnAccessibilityLocationChange(
params.new_location.transform.get());
}
void AutomationInternalCustomBindings::OnNodeDataWillChange(
ui::AXTree* tree,
const ui::AXNodeData& old_node_data,
const ui::AXNodeData& new_node_data) {
if (old_node_data.GetStringAttribute(ui::AX_ATTR_NAME) !=
new_node_data.GetStringAttribute(ui::AX_ATTR_NAME))
text_changed_node_ids_.push_back(new_node_data.id);
}
void AutomationInternalCustomBindings::OnTreeDataChanged(
ui::AXTree* tree,
const ui::AXTreeData& old_tree_data,
const ui::AXTreeData& new_tree_data) {}
void AutomationInternalCustomBindings::OnNodeWillBeDeleted(ui::AXTree* tree,
ui::AXNode* node) {
SendTreeChangeEvent(
api::automation::TREE_CHANGE_TYPE_NODEREMOVED,
tree, node);
deleted_node_ids_.push_back(node->id());
}
void AutomationInternalCustomBindings::OnSubtreeWillBeDeleted(
ui::AXTree* tree,
ui::AXNode* node) {
// This isn't strictly needed, as OnNodeWillBeDeleted will already be
// called. We could send a JS event for this only if it turns out to
// be needed for something.
}
void AutomationInternalCustomBindings::OnNodeWillBeReparented(
ui::AXTree* tree,
ui::AXNode* node) {
// Don't do anything here since the node will soon go away and be re-created.
}
void AutomationInternalCustomBindings::OnSubtreeWillBeReparented(
ui::AXTree* tree,
ui::AXNode* node) {
// Don't do anything here since the node will soon go away and be re-created.
}
void AutomationInternalCustomBindings::OnNodeCreated(ui::AXTree* tree,
ui::AXNode* node) {
// Not needed, this is called in the middle of an update so it's not
// safe to trigger JS from here. Wait for the notification in
// OnAtomicUpdateFinished instead.
}
void AutomationInternalCustomBindings::OnNodeReparented(ui::AXTree* tree,
ui::AXNode* node) {
// Not needed, this is called in the middle of an update so it's not
// safe to trigger JS from here. Wait for the notification in
// OnAtomicUpdateFinished instead.
}
void AutomationInternalCustomBindings::OnNodeChanged(ui::AXTree* tree,
ui::AXNode* node) {
// Not needed, this is called in the middle of an update so it's not
// safe to trigger JS from here. Wait for the notification in
// OnAtomicUpdateFinished instead.
}
void AutomationInternalCustomBindings::OnAtomicUpdateFinished(
ui::AXTree* tree,
bool root_changed,
const std::vector<ui::AXTreeDelegate::Change>& changes) {
auto iter = axtree_to_tree_wrapper_map_.find(tree);
if (iter == axtree_to_tree_wrapper_map_.end())
return;
for (const auto change : changes) {
ui::AXNode* node = change.node;
switch (change.type) {
case NODE_CREATED:
SendTreeChangeEvent(
api::automation::TREE_CHANGE_TYPE_NODECREATED,
tree, node);
break;
case SUBTREE_CREATED:
SendTreeChangeEvent(
api::automation::TREE_CHANGE_TYPE_SUBTREECREATED,
tree, node);
break;
case NODE_CHANGED:
SendTreeChangeEvent(
api::automation::TREE_CHANGE_TYPE_NODECHANGED,
tree, node);
break;
// Unhandled.
case NODE_REPARENTED:
case SUBTREE_REPARENTED:
break;
}
}
for (int id : text_changed_node_ids_) {
SendTreeChangeEvent(api::automation::TREE_CHANGE_TYPE_TEXTCHANGED, tree,
tree->GetFromId(id));
}
text_changed_node_ids_.clear();
}
void AutomationInternalCustomBindings::SendTreeChangeEvent(
api::automation::TreeChangeType change_type,
ui::AXTree* tree,
......@@ -1433,6 +1303,23 @@ void AutomationInternalCustomBindings::SendTreeChangeEvent(
}
}
void AutomationInternalCustomBindings::SendAutomationEvent(
const ExtensionMsg_AccessibilityEventParams& params,
int target_id,
api::automation::EventType event_type) {
auto event_params = base::MakeUnique<base::DictionaryValue>();
event_params->SetInteger("treeID", params.tree_id);
event_params->SetInteger("targetID", target_id);
event_params->SetString("eventType", api::automation::ToString(event_type));
event_params->SetString("eventFrom", ToString(params.event_from));
event_params->SetInteger("mouseX", params.mouse_location.x());
event_params->SetInteger("mouseY", params.mouse_location.y());
base::ListValue args;
args.Append(std::move(event_params));
bindings_system_->DispatchEventInContext(
"automationInternal.onAccessibilityEvent", &args, nullptr, context());
}
void AutomationInternalCustomBindings::SendChildTreeIDEvent(ui::AXTree* tree,
ui::AXNode* node) {
auto iter = axtree_to_tree_wrapper_map_.find(tree);
......
......@@ -33,8 +33,7 @@ struct TreeChangeObserver {
// The native component of custom bindings for the chrome.automationInternal
// API.
class AutomationInternalCustomBindings : public ObjectBackedNativeHandler,
public ui::AXTreeDelegate {
class AutomationInternalCustomBindings : public ObjectBackedNativeHandler {
public:
AutomationInternalCustomBindings(ScriptContext* context,
ExtensionBindingsSystem* bindings_system);
......@@ -58,6 +57,14 @@ class AutomationInternalCustomBindings : public ObjectBackedNativeHandler,
float GetDeviceScaleFactor() const;
void SendNodesRemovedEvent(ui::AXTree* tree, const std::vector<int>& ids);
void SendTreeChangeEvent(api::automation::TreeChangeType change_type,
ui::AXTree* tree,
ui::AXNode* node);
void SendAutomationEvent(const ExtensionMsg_AccessibilityEventParams& params,
int target_id,
api::automation::EventType event_type);
private:
// ObjectBackedNativeHandler overrides:
void Invalidate() override;
......@@ -152,28 +159,7 @@ class AutomationInternalCustomBindings : public ObjectBackedNativeHandler,
void UpdateOverallTreeChangeObserverFilter();
// AXTreeDelegate implementation.
void OnNodeDataWillChange(ui::AXTree* tree,
const ui::AXNodeData& old_node_data,
const ui::AXNodeData& new_node_data) override;
void OnTreeDataChanged(ui::AXTree* tree,
const ui::AXTreeData& old_tree_data,
const ui::AXTreeData& new_tree_data) override;
void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeWillBeReparented(ui::AXTree* tree, ui::AXNode* node) override;
void OnSubtreeWillBeReparented(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeCreated(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeReparented(ui::AXTree* tree, ui::AXNode* node) override;
void OnNodeChanged(ui::AXTree* tree, ui::AXNode* node) override;
void OnAtomicUpdateFinished(ui::AXTree* tree,
bool root_changed,
const std::vector<Change>& changes) override;
void SendTreeChangeEvent(api::automation::TreeChangeType change_type,
ui::AXTree* tree,
ui::AXNode* node);
void SendChildTreeIDEvent(ui::AXTree* tree, ui::AXNode* node);
void SendNodesRemovedEvent(ui::AXTree* tree, const std::vector<int>& ids);
std::map<int, std::unique_ptr<AutomationAXTreeWrapper>>
tree_id_to_tree_wrapper_map_;
......@@ -183,8 +169,6 @@ class AutomationInternalCustomBindings : public ObjectBackedNativeHandler,
std::vector<TreeChangeObserver> tree_change_observers_;
// A bit-map of api::automation::TreeChangeObserverFilter.
int tree_change_observer_overall_filter_;
std::vector<int> deleted_node_ids_;
std::vector<int> text_changed_node_ids_;
ExtensionBindingsSystem* bindings_system_;
bool should_ignore_context_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment