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

Unified Diff: third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp

Issue 2390783006: [DevTools] Accessibility: Show siblings and children of selected node (Closed)
Patch Set: Rebase tests again and be consistent about backendDOMNodeId Created 4 years, 1 month 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: third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp
diff --git a/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp b/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp
index 5d3737cc53ce60ff3655fb128402bc3b6aee262d..ace24ad3ead43568754da86e591101a32ea3f2c0 100644
--- a/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp
@@ -38,6 +38,8 @@ using namespace HTMLNames;
namespace {
+static const AXID kIDForInspectedNodeWithNoAXNode = 0;
+
void fillLiveRegionProperties(AXObject& axObject,
protocol::Array<AXProperty>& properties) {
if (!axObject.liveRegionRoot())
@@ -373,6 +375,19 @@ std::unique_ptr<AXValue> createRoleNameValue(AccessibilityRole role) {
return roleNameValue;
}
+bool isAncestorOf(AXObject* possibleAncestor, AXObject* descendant) {
+ if (!possibleAncestor || !descendant)
+ return false;
+
+ AXObject* ancestor = descendant;
+ while (ancestor) {
+ if (ancestor == possibleAncestor)
+ return true;
+ ancestor = ancestor->parentObject();
+ }
+ return false;
+}
+
} // namespace
InspectorAccessibilityAgent::InspectorAccessibilityAgent(
@@ -380,10 +395,10 @@ InspectorAccessibilityAgent::InspectorAccessibilityAgent(
InspectorDOMAgent* domAgent)
: m_page(page), m_domAgent(domAgent) {}
-Response InspectorAccessibilityAgent::getAXNodeChain(
+Response InspectorAccessibilityAgent::getPartialAXTree(
int domNodeId,
- bool fetchAncestors,
- std::unique_ptr<protocol::Array<protocol::Accessibility::AXNode>>* nodes) {
+ Maybe<bool> fetchRelatives,
+ std::unique_ptr<protocol::Array<AXNode>>* nodes) {
if (!m_domAgent->enabled())
return Response::Error("DOM agent must be enabled");
Node* domNode = nullptr;
@@ -405,40 +420,74 @@ Response InspectorAccessibilityAgent::getAXNodeChain(
AXObject* inspectedAXObject = cache->getOrCreate(domNode);
*nodes = protocol::Array<protocol::Accessibility::AXNode>::create();
if (!inspectedAXObject || inspectedAXObject->accessibilityIsIgnored()) {
- (*nodes)->addItem(buildObjectForIgnoredNode(domNode, inspectedAXObject));
+ (*nodes)->addItem(buildObjectForIgnoredNode(domNode, inspectedAXObject,
+ fetchRelatives.fromMaybe(true),
+ *nodes, *cache));
} else {
- (*nodes)->addItem(buildProtocolAXObject(*inspectedAXObject));
+ (*nodes)->addItem(
+ buildProtocolAXObject(*inspectedAXObject, inspectedAXObject,
+ fetchRelatives.fromMaybe(true), *nodes, *cache));
}
- if (fetchAncestors && inspectedAXObject) {
- AXObject* parent = inspectedAXObject->parentObjectUnignored();
- while (parent) {
- (*nodes)->addItem(buildProtocolAXObject(*parent));
- parent = parent->parentObjectUnignored();
- }
- }
+ if (!inspectedAXObject || !inspectedAXObject->isAXLayoutObject())
+ return Response::OK();
+
+ AXObject* parent = inspectedAXObject->parentObjectUnignored();
+ if (!parent)
+ return Response::OK();
+
+ if (fetchRelatives.fromMaybe(true))
+ addAncestors(*parent, inspectedAXObject, *nodes, *cache);
+
return Response::OK();
}
+void InspectorAccessibilityAgent::addAncestors(
+ AXObject& firstAncestor,
+ AXObject* inspectedAXObject,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
+ AXObject* ancestor = &firstAncestor;
+ while (ancestor) {
+ nodes->addItem(buildProtocolAXObject(*ancestor, inspectedAXObject, true,
+ nodes, cache));
+ ancestor = ancestor->parentObjectUnignored();
+ }
+}
+
std::unique_ptr<AXNode> InspectorAccessibilityAgent::buildObjectForIgnoredNode(
Node* domNode,
- AXObject* axObject) const {
+ AXObject* axObject,
+ bool fetchRelatives,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
AXObject::IgnoredReasons ignoredReasons;
-
- AXID axID = 0;
- if (axObject)
+ AXID axID = kIDForInspectedNodeWithNoAXNode;
+ if (axObject && axObject->isAXLayoutObject())
axID = axObject->axObjectID();
std::unique_ptr<AXNode> ignoredNodeObject =
AXNode::create().setNodeId(String::number(axID)).setIgnored(true).build();
- if (axObject) {
+ AccessibilityRole role = AccessibilityRole::IgnoredRole;
+ ignoredNodeObject->setRole(createRoleNameValue(role));
+
+ if (axObject && axObject->isAXLayoutObject()) {
axObject->computeAccessibilityIsIgnored(&ignoredReasons);
- axID = axObject->axObjectID();
- AccessibilityRole role = axObject->roleValue();
- ignoredNodeObject->setRole(createRoleNameValue(role));
+
+ if (fetchRelatives) {
+ populateRelatives(*axObject, axObject, *(ignoredNodeObject.get()), nodes,
+ cache);
+ }
} else if (domNode && !domNode->layoutObject()) {
+ if (fetchRelatives) {
+ populateDOMNodeRelatives(*domNode, *(ignoredNodeObject.get()), nodes,
+ cache);
+ }
ignoredReasons.append(IgnoredReason(AXNotRendered));
}
+ if (domNode)
+ ignoredNodeObject->setBackendDOMNodeId(DOMNodeIds::idForNode(domNode));
+
std::unique_ptr<protocol::Array<AXProperty>> ignoredReasonProperties =
protocol::Array<AXProperty>::create();
for (size_t i = 0; i < ignoredReasons.size(); i++)
@@ -448,8 +497,97 @@ std::unique_ptr<AXNode> InspectorAccessibilityAgent::buildObjectForIgnoredNode(
return ignoredNodeObject;
}
+void InspectorAccessibilityAgent::populateDOMNodeRelatives(
+ Node& inspectedDOMNode,
+ AXNode& nodeObject,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
+ // Populate children.
+ std::unique_ptr<protocol::Array<AXNodeId>> childIds =
+ protocol::Array<AXNodeId>::create();
+ findDOMNodeChildren(childIds, inspectedDOMNode, inspectedDOMNode, nodes,
+ cache);
+ nodeObject.setChildIds(std::move(childIds));
+
+ // Walk up parents until an AXObject can be found.
+ Node* parentNode = FlatTreeTraversal::parent(inspectedDOMNode);
+ AXObject* parentAXObject = cache.getOrCreate(parentNode);
+ while (parentNode && !parentAXObject) {
+ parentNode = FlatTreeTraversal::parent(inspectedDOMNode);
+ parentAXObject = cache.getOrCreate(parentNode);
+ };
+
+ if (!parentAXObject)
+ return;
+
+ if (parentAXObject->accessibilityIsIgnored())
+ parentAXObject = parentAXObject->parentObjectUnignored();
+ if (!parentAXObject)
+ return;
+
+ // Populate parent, ancestors and siblings.
+ std::unique_ptr<AXNode> parentNodeObject =
+ buildProtocolAXObject(*parentAXObject, nullptr, true, nodes, cache);
+ std::unique_ptr<protocol::Array<AXNodeId>> siblingIds =
+ protocol::Array<AXNodeId>::create();
+ findDOMNodeChildren(siblingIds, *parentNode, inspectedDOMNode, nodes, cache);
+ parentNodeObject->setChildIds(std::move(siblingIds));
+ nodes->addItem(std::move(parentNodeObject));
+
+ AXObject* grandparentAXObject = parentAXObject->parentObjectUnignored();
+ if (grandparentAXObject)
+ addAncestors(*grandparentAXObject, nullptr, nodes, cache);
+}
+
+void InspectorAccessibilityAgent::findDOMNodeChildren(
+ std::unique_ptr<protocol::Array<AXNodeId>>& childIds,
+ Node& parentNode,
+ Node& inspectedDOMNode,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
+ NodeList* childNodes = parentNode.childNodes();
+ for (size_t i = 0; i < childNodes->length(); ++i) {
+ Node* childNode = childNodes->item(i);
+ if (childNode == &inspectedDOMNode) {
+ childIds->addItem(String::number(kIDForInspectedNodeWithNoAXNode));
+ continue;
+ }
+
+ AXObject* childAXObject = cache.getOrCreate(childNode);
+ if (childAXObject) {
+ if (childAXObject->accessibilityIsIgnored()) {
+ // search for un-ignored descendants
+ findDOMNodeChildren(childIds, *childNode, inspectedDOMNode, nodes,
+ cache);
+ } else {
+ addChild(childIds, *childAXObject, nullptr, nodes, cache);
+ }
+
+ continue;
+ }
+
+ if (!childAXObject ||
+ childNode->isShadowIncludingInclusiveAncestorOf(&inspectedDOMNode)) {
+ // If the inspected node may be a descendant of this node, keep walking
+ // recursively until we find its actual siblings.
+ findDOMNodeChildren(childIds, *childNode, inspectedDOMNode, nodes, cache);
+ continue;
+ }
+
+ // Otherwise, just add the un-ignored children.
+ const AXObject::AXObjectVector& indirectChildren =
+ childAXObject->children();
+ for (unsigned i = 0; i < indirectChildren.size(); ++i)
+ addChild(childIds, *(indirectChildren[i]), nullptr, nodes, cache);
+ }
+}
+
std::unique_ptr<AXNode> InspectorAccessibilityAgent::buildProtocolAXObject(
- AXObject& axObject) const {
+ AXObject& axObject,
+ AXObject* inspectedAXObject,
+ bool fetchRelatives,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
AccessibilityRole role = axObject.roleValue();
std::unique_ptr<AXNode> nodeObject =
AXNode::create()
@@ -493,12 +631,18 @@ std::unique_ptr<AXNode> InspectorAccessibilityAgent::buildProtocolAXObject(
nodeObject->setProperties(std::move(properties));
}
- fillCoreProperties(axObject, *(nodeObject.get()));
+ fillCoreProperties(axObject, inspectedAXObject, fetchRelatives,
+ *(nodeObject.get()), nodes, cache);
return nodeObject;
}
-void InspectorAccessibilityAgent::fillCoreProperties(AXObject& axObject,
- AXNode& nodeObject) const {
+void InspectorAccessibilityAgent::fillCoreProperties(
+ AXObject& axObject,
+ AXObject* inspectedAXObject,
+ bool fetchRelatives,
+ AXNode& nodeObject,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
AXNameFrom nameFrom;
AXObject::AXObjectVector nameObjects;
axObject.name(nameFrom, &nameObjects);
@@ -519,6 +663,107 @@ void InspectorAccessibilityAgent::fillCoreProperties(AXObject& axObject,
if (!stringValue.isEmpty())
nodeObject.setValue(createValue(stringValue));
}
+
+ if (fetchRelatives)
+ populateRelatives(axObject, inspectedAXObject, nodeObject, nodes, cache);
+
+ Node* node = axObject.getNode();
+ if (node)
+ nodeObject.setBackendDOMNodeId(DOMNodeIds::idForNode(node));
+}
+
+void InspectorAccessibilityAgent::populateRelatives(
+ AXObject& axObject,
+ AXObject* inspectedAXObject,
+ AXNode& nodeObject,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
+ AXObject* parentObject = axObject.parentObject();
+ if (parentObject && parentObject != inspectedAXObject) {
+ // Use unignored parent unless parent is inspected ignored object.
+ parentObject = axObject.parentObjectUnignored();
+ }
+
+ std::unique_ptr<protocol::Array<AXNodeId>> childIds =
+ protocol::Array<AXNodeId>::create();
+
+ if (inspectedAXObject &&
+ &axObject == inspectedAXObject->parentObjectUnignored() &&
+ inspectedAXObject->accessibilityIsIgnored()) {
+ // This is the parent of an ignored object, so search for its siblings.
+ addSiblingsOfIgnored(childIds, axObject, inspectedAXObject, nodes, cache);
+ } else {
+ addChildren(axObject, inspectedAXObject, childIds, nodes, cache);
+ }
+ nodeObject.setChildIds(std::move(childIds));
+}
+
+void InspectorAccessibilityAgent::addSiblingsOfIgnored(
+ std::unique_ptr<protocol::Array<AXNodeId>>& childIds,
+ AXObject& parentAXObject,
+ AXObject* inspectedAXObject,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
+ for (AXObject* childAXObject = parentAXObject.rawFirstChild(); childAXObject;
+ childAXObject = childAXObject->rawNextSibling()) {
+ if (!childAXObject->accessibilityIsIgnored() ||
+ childAXObject == inspectedAXObject) {
+ addChild(childIds, *childAXObject, inspectedAXObject, nodes, cache);
+ continue;
+ }
+
+ if (isAncestorOf(childAXObject, inspectedAXObject)) {
+ addSiblingsOfIgnored(childIds, *childAXObject, inspectedAXObject, nodes,
+ cache);
+ continue;
+ }
+
+ const AXObject::AXObjectVector& indirectChildren =
+ childAXObject->children();
+ for (unsigned i = 0; i < indirectChildren.size(); ++i) {
+ addChild(childIds, *(indirectChildren[i]), inspectedAXObject, nodes,
+ cache);
+ }
+ }
+}
+
+void InspectorAccessibilityAgent::addChild(
+ std::unique_ptr<protocol::Array<AXNodeId>>& childIds,
+ AXObject& childAXObject,
+ AXObject* inspectedAXObject,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
+ childIds->addItem(String::number(childAXObject.axObjectID()));
+ if (&childAXObject == inspectedAXObject)
+ return;
+ nodes->addItem(buildProtocolAXObject(childAXObject, inspectedAXObject, true,
+ nodes, cache));
+}
+
+void InspectorAccessibilityAgent::addChildren(
+ AXObject& axObject,
+ AXObject* inspectedAXObject,
+ std::unique_ptr<protocol::Array<AXNodeId>>& childIds,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
+ const AXObject::AXObjectVector& children = axObject.children();
+ for (unsigned i = 0; i < children.size(); i++) {
+ AXObject& childAXObject = *children[i].get();
+ childIds->addItem(String::number(childAXObject.axObjectID()));
+ if (&childAXObject == inspectedAXObject)
+ continue;
+ if (&axObject != inspectedAXObject) {
+ if (!inspectedAXObject)
+ continue;
+ if (&axObject != inspectedAXObject->parentObjectUnignored())
+ continue;
+ }
+
+ // Only add children/siblings of inspected node to returned nodes.
+ std::unique_ptr<AXNode> childNode = buildProtocolAXObject(
+ childAXObject, inspectedAXObject, true, nodes, cache);
+ nodes->addItem(std::move(childNode));
+ }
}
DEFINE_TRACE(InspectorAccessibilityAgent) {

Powered by Google App Engine
This is Rietveld 408576698