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

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

Issue 2390783006: [DevTools] Accessibility: Show siblings and children of selected node (Closed)
Patch Set: Ready for a first look Created 4 years, 2 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
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 0d7ac6ba8ff4044ffa0f1f26b66fe6f6a7ba8f16..a94638bcb3df2566ea4a94d06f0bfabd2c0a4817 100644
--- a/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp
@@ -8,6 +8,8 @@
#include "core/dom/AXObjectCache.h"
#include "core/dom/DOMNodeIds.h"
#include "core/dom/Element.h"
+#include "core/dom/Node.h"
+#include "core/dom/NodeList.h"
#include "core/inspector/IdentifiersFactory.h"
#include "core/inspector/InspectorDOMAgent.h"
#include "core/inspector/InspectorStyleSheet.h"
@@ -36,98 +38,76 @@ using namespace HTMLNames;
namespace {
-void fillCoreProperties(AXObject* axObject, AXNode* nodeObject) {
- // Description (secondary to the accessible name).
- AXNameFrom nameFrom;
- AXObject::AXObjectVector nameObjects;
- axObject->name(nameFrom, &nameObjects);
- AXDescriptionFrom descriptionFrom;
- AXObject::AXObjectVector descriptionObjects;
- String description =
- axObject->description(nameFrom, descriptionFrom, &descriptionObjects);
- if (!description.isEmpty())
- nodeObject->setDescription(
- createValue(description, AXValueTypeEnum::ComputedString));
-
- // Value.
- if (axObject->supportsRangeValue()) {
- nodeObject->setValue(createValue(axObject->valueForRange()));
- } else {
- String stringValue = axObject->stringValue();
- if (!stringValue.isEmpty())
- nodeObject->setValue(createValue(stringValue));
- }
-}
-
-void fillLiveRegionProperties(AXObject* axObject,
- protocol::Array<AXProperty>* properties) {
- if (!axObject->liveRegionRoot())
+void fillLiveRegionProperties(AXObject& axObject,
+ protocol::Array<AXProperty>& properties) {
+ if (!axObject.liveRegionRoot())
return;
- properties->addItem(
+ properties.addItem(
createProperty(AXLiveRegionAttributesEnum::Live,
- createValue(axObject->containerLiveRegionStatus(),
+ createValue(axObject.containerLiveRegionStatus(),
AXValueTypeEnum::Token)));
- properties->addItem(createProperty(
- AXLiveRegionAttributesEnum::Atomic,
- createBooleanValue(axObject->containerLiveRegionAtomic())));
- properties->addItem(
+ properties.addItem(
+ createProperty(AXLiveRegionAttributesEnum::Atomic,
+ createBooleanValue(axObject.containerLiveRegionAtomic())));
+ properties.addItem(
createProperty(AXLiveRegionAttributesEnum::Relevant,
- createValue(axObject->containerLiveRegionRelevant(),
+ createValue(axObject.containerLiveRegionRelevant(),
AXValueTypeEnum::TokenList)));
- properties->addItem(
+ properties.addItem(
createProperty(AXLiveRegionAttributesEnum::Busy,
- createBooleanValue(axObject->containerLiveRegionBusy())));
+ createBooleanValue(axObject.containerLiveRegionBusy())));
- if (!axObject->isLiveRegion())
- properties->addItem(
- createProperty(AXLiveRegionAttributesEnum::Root,
- createRelatedNodeListValue(axObject->liveRegionRoot())));
+ if (!axObject.isLiveRegion()) {
+ properties.addItem(createProperty(
+ AXLiveRegionAttributesEnum::Root,
+ createRelatedNodeListValue(*(axObject.liveRegionRoot()))));
+ }
}
-void fillGlobalStates(AXObject* axObject,
- protocol::Array<AXProperty>* properties) {
- if (!axObject->isEnabled())
- properties->addItem(
+void fillGlobalStates(AXObject& axObject,
+ protocol::Array<AXProperty>& properties) {
+ if (!axObject.isEnabled())
+ properties.addItem(
createProperty(AXGlobalStatesEnum::Disabled, createBooleanValue(true)));
- if (const AXObject* hiddenRoot = axObject->ariaHiddenRoot()) {
- properties->addItem(
+ if (const AXObject* hiddenRoot = axObject.ariaHiddenRoot()) {
+ properties.addItem(
createProperty(AXGlobalStatesEnum::Hidden, createBooleanValue(true)));
- properties->addItem(createProperty(AXGlobalStatesEnum::HiddenRoot,
- createRelatedNodeListValue(hiddenRoot)));
+ properties.addItem(createProperty(AXGlobalStatesEnum::HiddenRoot,
+ createRelatedNodeListValue(*hiddenRoot)));
}
- InvalidState invalidState = axObject->getInvalidState();
+ InvalidState invalidState = axObject.getInvalidState();
switch (invalidState) {
case InvalidStateUndefined:
break;
case InvalidStateFalse:
- properties->addItem(
+ properties.addItem(
createProperty(AXGlobalStatesEnum::Invalid,
createValue("false", AXValueTypeEnum::Token)));
break;
case InvalidStateTrue:
- properties->addItem(
+ properties.addItem(
createProperty(AXGlobalStatesEnum::Invalid,
createValue("true", AXValueTypeEnum::Token)));
break;
case InvalidStateSpelling:
- properties->addItem(
+ properties.addItem(
createProperty(AXGlobalStatesEnum::Invalid,
createValue("spelling", AXValueTypeEnum::Token)));
break;
case InvalidStateGrammar:
- properties->addItem(
+ properties.addItem(
createProperty(AXGlobalStatesEnum::Invalid,
createValue("grammar", AXValueTypeEnum::Token)));
break;
default:
// TODO(aboxhall): expose invalid: <nothing> and source: aria-invalid as
// invalid value
- properties->addItem(createProperty(
+ properties.addItem(createProperty(
AXGlobalStatesEnum::Invalid,
- createValue(axObject->ariaInvalidValue(), AXValueTypeEnum::String)));
+ createValue(axObject.ariaInvalidValue(), AXValueTypeEnum::String)));
break;
}
}
@@ -173,47 +153,49 @@ bool roleAllowsSelected(AccessibilityRole role) {
role == RowHeaderRole || role == TreeItemRole;
}
-void fillWidgetProperties(AXObject* axObject,
- protocol::Array<AXProperty>* properties) {
- AccessibilityRole role = axObject->roleValue();
- String autocomplete = axObject->ariaAutoComplete();
+void fillWidgetProperties(AXObject& axObject,
dmazzoni 2016/10/19 16:33:49 You could land a quick change to replace pointers
aboxhall 2016/10/19 23:49:05 Done.
+ protocol::Array<AXProperty>& properties) {
+ AccessibilityRole role = axObject.roleValue();
+ String autocomplete = axObject.ariaAutoComplete();
if (!autocomplete.isEmpty())
- properties->addItem(
+ properties.addItem(
createProperty(AXWidgetAttributesEnum::Autocomplete,
createValue(autocomplete, AXValueTypeEnum::Token)));
- if (axObject->hasAttribute(HTMLNames::aria_haspopupAttr)) {
- bool hasPopup = axObject->ariaHasPopup();
- properties->addItem(createProperty(AXWidgetAttributesEnum::Haspopup,
- createBooleanValue(hasPopup)));
+ if (axObject.hasAttribute(HTMLNames::aria_haspopupAttr)) {
+ bool hasPopup = axObject.ariaHasPopup();
+ properties.addItem(createProperty(AXWidgetAttributesEnum::Haspopup,
+ createBooleanValue(hasPopup)));
}
- int headingLevel = axObject->headingLevel();
- if (headingLevel > 0)
- properties->addItem(createProperty(AXWidgetAttributesEnum::Level,
- createValue(headingLevel)));
- int hierarchicalLevel = axObject->hierarchicalLevel();
+ int headingLevel = axObject.headingLevel();
+ if (headingLevel > 0) {
dmazzoni 2016/10/19 16:33:49 Did this come from "git cl format" or some other a
aboxhall 2016/10/19 23:49:05 Done.
+ properties.addItem(createProperty(AXWidgetAttributesEnum::Level,
+ createValue(headingLevel)));
+ }
+ int hierarchicalLevel = axObject.hierarchicalLevel();
if (hierarchicalLevel > 0 ||
- axObject->hasAttribute(HTMLNames::aria_levelAttr))
- properties->addItem(createProperty(AXWidgetAttributesEnum::Level,
- createValue(hierarchicalLevel)));
+ axObject.hasAttribute(HTMLNames::aria_levelAttr)) {
+ properties.addItem(createProperty(AXWidgetAttributesEnum::Level,
+ createValue(hierarchicalLevel)));
+ }
if (roleAllowsMultiselectable(role)) {
- bool multiselectable = axObject->isMultiSelectable();
- properties->addItem(createProperty(AXWidgetAttributesEnum::Multiselectable,
- createBooleanValue(multiselectable)));
+ bool multiselectable = axObject.isMultiSelectable();
+ properties.addItem(createProperty(AXWidgetAttributesEnum::Multiselectable,
+ createBooleanValue(multiselectable)));
}
if (roleAllowsOrientation(role)) {
- AccessibilityOrientation orientation = axObject->orientation();
+ AccessibilityOrientation orientation = axObject.orientation();
switch (orientation) {
case AccessibilityOrientationVertical:
- properties->addItem(
+ properties.addItem(
createProperty(AXWidgetAttributesEnum::Orientation,
createValue("vertical", AXValueTypeEnum::Token)));
break;
case AccessibilityOrientationHorizontal:
- properties->addItem(
+ properties.addItem(
createProperty(AXWidgetAttributesEnum::Orientation,
createValue("horizontal", AXValueTypeEnum::Token)));
break;
@@ -222,103 +204,104 @@ void fillWidgetProperties(AXObject* axObject,
}
}
- if (role == TextFieldRole)
- properties->addItem(
+ if (role == TextFieldRole) {
+ properties.addItem(
createProperty(AXWidgetAttributesEnum::Multiline,
- createBooleanValue(axObject->isMultiline())));
+ createBooleanValue(axObject.isMultiline())));
+ }
if (roleAllowsReadonly(role)) {
- properties->addItem(
+ properties.addItem(
createProperty(AXWidgetAttributesEnum::Readonly,
- createBooleanValue(axObject->isReadOnly())));
+ createBooleanValue(axObject.isReadOnly())));
}
if (roleAllowsRequired(role)) {
- properties->addItem(
+ properties.addItem(
createProperty(AXWidgetAttributesEnum::Required,
- createBooleanValue(axObject->isRequired())));
+ createBooleanValue(axObject.isRequired())));
}
if (roleAllowsSort(role)) {
// TODO(aboxhall): sort
}
- if (axObject->isRange()) {
- properties->addItem(
+ if (axObject.isRange()) {
+ properties.addItem(
createProperty(AXWidgetAttributesEnum::Valuemin,
- createValue(axObject->minValueForRange())));
- properties->addItem(
+ createValue(axObject.minValueForRange())));
+ properties.addItem(
createProperty(AXWidgetAttributesEnum::Valuemax,
- createValue(axObject->maxValueForRange())));
- properties->addItem(
+ createValue(axObject.maxValueForRange())));
+ properties.addItem(
createProperty(AXWidgetAttributesEnum::Valuetext,
- createValue(axObject->valueDescription())));
+ createValue(axObject.valueDescription())));
}
}
-void fillWidgetStates(AXObject* axObject,
- protocol::Array<AXProperty>* properties) {
- AccessibilityRole role = axObject->roleValue();
+void fillWidgetStates(AXObject& axObject,
+ protocol::Array<AXProperty>& properties) {
+ AccessibilityRole role = axObject.roleValue();
if (roleAllowsChecked(role)) {
- AccessibilityButtonState checked = axObject->checkboxOrRadioValue();
+ AccessibilityButtonState checked = axObject.checkboxOrRadioValue();
switch (checked) {
case ButtonStateOff:
- properties->addItem(
+ properties.addItem(
createProperty(AXWidgetStatesEnum::Checked,
createValue("false", AXValueTypeEnum::Tristate)));
break;
case ButtonStateOn:
- properties->addItem(
+ properties.addItem(
createProperty(AXWidgetStatesEnum::Checked,
createValue("true", AXValueTypeEnum::Tristate)));
break;
case ButtonStateMixed:
- properties->addItem(
+ properties.addItem(
createProperty(AXWidgetStatesEnum::Checked,
createValue("mixed", AXValueTypeEnum::Tristate)));
break;
}
}
- AccessibilityExpanded expanded = axObject->isExpanded();
+ AccessibilityExpanded expanded = axObject.isExpanded();
switch (expanded) {
case ExpandedUndefined:
break;
case ExpandedCollapsed:
- properties->addItem(createProperty(
+ properties.addItem(createProperty(
AXWidgetStatesEnum::Expanded,
createBooleanValue(false, AXValueTypeEnum::BooleanOrUndefined)));
break;
case ExpandedExpanded:
- properties->addItem(createProperty(
+ properties.addItem(createProperty(
AXWidgetStatesEnum::Expanded,
createBooleanValue(true, AXValueTypeEnum::BooleanOrUndefined)));
break;
}
if (role == ToggleButtonRole) {
- if (!axObject->isPressed()) {
- properties->addItem(
+ if (!axObject.isPressed()) {
+ properties.addItem(
createProperty(AXWidgetStatesEnum::Pressed,
createValue("false", AXValueTypeEnum::Tristate)));
} else {
const AtomicString& pressedAttr =
- axObject->getAttribute(HTMLNames::aria_pressedAttr);
+ axObject.getAttribute(HTMLNames::aria_pressedAttr);
if (equalIgnoringCase(pressedAttr, "mixed"))
- properties->addItem(
+ properties.addItem(
createProperty(AXWidgetStatesEnum::Pressed,
createValue("mixed", AXValueTypeEnum::Tristate)));
else
- properties->addItem(
+ properties.addItem(
createProperty(AXWidgetStatesEnum::Pressed,
createValue("true", AXValueTypeEnum::Tristate)));
}
}
if (roleAllowsSelected(role)) {
- properties->addItem(
+ properties.addItem(
createProperty(AXWidgetStatesEnum::Selected,
- createBooleanValue(axObject->isSelected())));
+ createBooleanValue(axObject.isSelected())));
}
}
@@ -334,46 +317,46 @@ std::unique_ptr<AXProperty> createRelatedNodeListProperty(
const String& key,
AXObject::AXObjectVector& nodes,
const QualifiedName& attr,
- AXObject* axObject) {
+ AXObject& axObject) {
std::unique_ptr<AXValue> nodeListValue = createRelatedNodeListValue(nodes);
- const AtomicString& attrValue = axObject->getAttribute(attr);
+ const AtomicString& attrValue = axObject.getAttribute(attr);
nodeListValue->setValue(protocol::StringValue::create(attrValue));
return createProperty(key, std::move(nodeListValue));
}
-void fillRelationships(AXObject* axObject,
- protocol::Array<AXProperty>* properties) {
- if (AXObject* activeDescendant = axObject->activeDescendant()) {
- properties->addItem(
+void fillRelationships(AXObject& axObject,
+ protocol::Array<AXProperty>& properties) {
+ if (AXObject* activeDescendant = axObject.activeDescendant()) {
+ properties.addItem(
createProperty(AXRelationshipAttributesEnum::Activedescendant,
- createRelatedNodeListValue(activeDescendant)));
+ createRelatedNodeListValue(*activeDescendant)));
}
AXObject::AXObjectVector results;
- axObject->ariaFlowToElements(results);
+ axObject.ariaFlowToElements(results);
if (!results.isEmpty())
- properties->addItem(
+ properties.addItem(
createRelatedNodeListProperty(AXRelationshipAttributesEnum::Flowto,
results, aria_flowtoAttr, axObject));
results.clear();
- axObject->ariaControlsElements(results);
+ axObject.ariaControlsElements(results);
if (!results.isEmpty())
- properties->addItem(
+ properties.addItem(
createRelatedNodeListProperty(AXRelationshipAttributesEnum::Controls,
results, aria_controlsAttr, axObject));
results.clear();
- axObject->ariaDescribedbyElements(results);
+ axObject.ariaDescribedbyElements(results);
if (!results.isEmpty())
- properties->addItem(
+ properties.addItem(
createRelatedNodeListProperty(AXRelationshipAttributesEnum::Describedby,
results, aria_describedbyAttr, axObject));
results.clear();
- axObject->ariaOwnsElements(results);
+ axObject.ariaOwnsElements(results);
if (!results.isEmpty())
- properties->addItem(createRelatedNodeListProperty(
+ properties.addItem(createRelatedNodeListProperty(
AXRelationshipAttributesEnum::Owns, results, aria_ownsAttr, axObject));
results.clear();
}
@@ -390,22 +373,109 @@ std::unique_ptr<AXValue> createRoleNameValue(AccessibilityRole role) {
return roleNameValue;
}
-std::unique_ptr<AXNode> buildObjectForIgnoredNode(Node* node,
- const AXObject* axObject) {
+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(
+ Page* page,
+ InspectorDOMAgent* domAgent)
+ : m_page(page), m_domAgent(domAgent) {}
+
+void InspectorAccessibilityAgent::getPartialAXTree(
+ ErrorString* errorString,
+ int domNodeId,
+ std::unique_ptr<protocol::Array<AXNode>>* nodes) {
+ if (!m_domAgent->enabled()) {
+ *errorString = "DOM agent must be enabled";
+ return;
+ }
+ Node* domNode = m_domAgent->assertNode(errorString, domNodeId);
+ if (!domNode)
+ return;
+
+ Document& document = domNode->document();
+ document.updateStyleAndLayoutIgnorePendingStylesheets();
+ DocumentLifecycle::DisallowTransitionScope disallowTransition(
+ document.lifecycle());
+ LocalFrame* localFrame = document.frame();
+ if (!localFrame) {
+ *errorString = "Frame is detached.";
+ return;
+ }
+ std::unique_ptr<ScopedAXObjectCache> scopedCache =
+ ScopedAXObjectCache::create(document);
+ AXObjectCacheImpl* cache = toAXObjectCacheImpl(scopedCache->get());
+
+ AXObject* inspectedAXObject = cache->getOrCreate(domNode);
+ *nodes = protocol::Array<protocol::Accessibility::AXNode>::create();
+ if (!inspectedAXObject || inspectedAXObject->accessibilityIsIgnored()) {
+ (*nodes)->addItem(
+ buildObjectForIgnoredNode(domNode, inspectedAXObject, *nodes, *cache));
+ } else {
+ (*nodes)->addItem(buildProtocolAXObject(*inspectedAXObject,
+ inspectedAXObject, *nodes, *cache));
+ }
+
+ if (!inspectedAXObject)
+ return;
+
+ AXObject* parent = inspectedAXObject->parentObjectUnignored();
dmazzoni 2016/10/19 16:33:48 Will it be confusing if you can click on a node an
aboxhall 2016/10/19 23:49:05 Yeah, I think it's either that (i.e. show ignored
+ if (!parent)
+ return;
+
+ std::unique_ptr<AXNode> parentNodeObject =
+ buildProtocolAXObject(*parent, inspectedAXObject, *nodes, *cache);
+
+ (*nodes)->addItem(std::move(parentNodeObject));
dmazzoni 2016/10/19 16:33:48 Are you using parentNodeObject? If not, maybe just
aboxhall 2016/10/19 23:49:05 Done.
+ AXObject* ancestor = parent->parentObjectUnignored();
+ while (ancestor) {
+ (*nodes)->addItem(
+ buildProtocolAXObject(*ancestor, inspectedAXObject, *nodes, *cache));
dmazzoni 2016/10/19 16:33:48 I think you can eliminate a few lines of code here
aboxhall 2016/10/19 23:49:05 Done (yeah, it was originally special-casing the p
+ ancestor = ancestor->parentObjectUnignored();
+ }
+}
+
+std::unique_ptr<AXNode> InspectorAccessibilityAgent::buildObjectForIgnoredNode(
+ Node* domNode,
+ AXObject* axObject,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
AXObject::IgnoredReasons ignoredReasons;
AXID axID = 0;
+ if (axObject)
+ axID = axObject->axObjectID();
std::unique_ptr<AXNode> ignoredNodeObject =
AXNode::create().setNodeId(String::number(axID)).setIgnored(true).build();
if (axObject) {
axObject->computeAccessibilityIsIgnored(&ignoredReasons);
axID = axObject->axObjectID();
dmazzoni 2016/10/19 16:33:49 Duplicate, you just computed it above
aboxhall 2016/10/19 23:49:05 Done.
- AccessibilityRole role = axObject->roleValue();
+ AccessibilityRole role = AccessibilityRole::IgnoredRole;
ignoredNodeObject->setRole(createRoleNameValue(role));
- } else if (node && !node->layoutObject()) {
+
+ populateRelatives(*axObject, axObject, *(ignoredNodeObject.get()), nodes,
+ cache);
+ } else if (domNode && !domNode->layoutObject()) {
+ populateDOMNodeRelatives(*domNode, *(ignoredNodeObject.get()), nodes,
+ cache);
ignoredReasons.append(IgnoredReason(AXNotRendered));
}
+ if (domNode)
+ ignoredNodeObject->setDomNodeId(DOMNodeIds::idForNode(domNode));
+
std::unique_ptr<protocol::Array<AXProperty>> ignoredReasonProperties =
protocol::Array<AXProperty>::create();
for (size_t i = 0; i < ignoredReasons.size(); i++)
@@ -415,25 +485,95 @@ std::unique_ptr<AXNode> buildObjectForIgnoredNode(Node* node,
return ignoredNodeObject;
}
-std::unique_ptr<AXNode> buildProtocolAXObject(AXObject* axObject) {
- AccessibilityRole role = axObject->roleValue();
+void InspectorAccessibilityAgent::populateDOMNodeRelatives(
+ Node& inspectedDOMNode,
+ AXNode& nodeObject,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
+ // Walk up parents until an AXObject can be found.
+ Node* parentNode = inspectedDOMNode.parentNode();
dmazzoni 2016/10/19 16:33:48 I'm not an expert at all, but I suspect you may wa
aboxhall 2016/10/19 23:49:05 That makes sense, thanks for catching.
+ AXObject* parentAXObject = cache.getOrCreate(parentNode);
+ while (!parentAXObject) {
+ parentNode = parentNode->parentNode();
+ parentAXObject = cache.getOrCreate(parentNode);
+ };
+ if (parentAXObject) {
+ // Populate parent and siblings.
+ nodeObject.setParentId(String::number(parentAXObject->axObjectID()));
+ std::unique_ptr<AXNode> parentNodeObject =
+ buildProtocolAXObject(*parentAXObject, nullptr, 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));
+ }
+ // Then populate children.
+ std::unique_ptr<protocol::Array<AXNodeId>> childIds =
+ protocol::Array<AXNodeId>::create();
+ findDOMNodeChildren(childIds, inspectedDOMNode, inspectedDOMNode, 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(0));
dmazzoni 2016/10/19 16:33:48 Can you document this magic number? Why is the ins
aboxhall 2016/10/19 23:49:05 It doesn't have an actual id - there is no AXNode
+ continue;
+ }
+ AXObject* childAXObject = cache.getOrCreate(childNode);
+ if (childAXObject && !childAXObject->accessibilityIsIgnored()) {
+ 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.
dmazzoni 2016/10/19 16:33:48 Reading through all of the special cases for build
aboxhall 2016/10/19 23:49:05 Not quite accurate - this is only called if there
aboxhall 2016/10/21 17:28:23 Ok, I tried that out and it actually doesn't buy u
+ 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,
+ AXObject* inspectedAXObject,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
+ AccessibilityRole role = axObject.roleValue();
std::unique_ptr<AXNode> nodeObject =
AXNode::create()
- .setNodeId(String::number(axObject->axObjectID()))
+ .setNodeId(String::number(axObject.axObjectID()))
.setIgnored(false)
.build();
nodeObject->setRole(createRoleNameValue(role));
std::unique_ptr<protocol::Array<AXProperty>> properties =
protocol::Array<AXProperty>::create();
- fillLiveRegionProperties(axObject, properties.get());
- fillGlobalStates(axObject, properties.get());
- fillWidgetProperties(axObject, properties.get());
- fillWidgetStates(axObject, properties.get());
- fillRelationships(axObject, properties.get());
+ fillLiveRegionProperties(axObject, *(properties.get()));
+ fillGlobalStates(axObject, *(properties.get()));
+ fillWidgetProperties(axObject, *(properties.get()));
+ fillWidgetStates(axObject, *(properties.get()));
+ fillRelationships(axObject, *(properties.get()));
AXObject::NameSources nameSources;
- String computedName = axObject->name(&nameSources);
+ String computedName = axObject.name(&nameSources);
if (!nameSources.isEmpty()) {
std::unique_ptr<AXValue> name =
createValue(computedName, AXValueTypeEnum::ComputedString);
@@ -459,55 +599,132 @@ std::unique_ptr<AXNode> buildProtocolAXObject(AXObject* axObject) {
nodeObject->setProperties(std::move(properties));
}
- fillCoreProperties(axObject, nodeObject.get());
+ fillCoreProperties(axObject, inspectedAXObject, *(nodeObject.get()), nodes,
+ cache);
return nodeObject;
}
-} // namespace
-
-InspectorAccessibilityAgent::InspectorAccessibilityAgent(
- Page* page,
- InspectorDOMAgent* domAgent)
- : m_page(page), m_domAgent(domAgent) {}
+void InspectorAccessibilityAgent::fillCoreProperties(
+ AXObject& axObject,
+ AXObject* inspectedAXObject,
+ AXNode& nodeObject,
+ std::unique_ptr<protocol::Array<AXNode>>& nodes,
+ AXObjectCacheImpl& cache) const {
+ AXNameFrom nameFrom;
+ AXObject::AXObjectVector nameObjects;
+ axObject.name(nameFrom, &nameObjects);
-void InspectorAccessibilityAgent::getAXNodeChain(
- ErrorString* errorString,
- int domNodeId,
- bool fetchAncestors,
- std::unique_ptr<protocol::Array<protocol::Accessibility::AXNode>>* nodes) {
- if (!m_domAgent->enabled()) {
- *errorString = "DOM agent must be enabled";
- return;
+ AXDescriptionFrom descriptionFrom;
+ AXObject::AXObjectVector descriptionObjects;
+ String description =
+ axObject.description(nameFrom, descriptionFrom, &descriptionObjects);
+ if (!description.isEmpty()) {
+ nodeObject.setDescription(
+ createValue(description, AXValueTypeEnum::ComputedString));
+ }
+ // Value.
+ if (axObject.supportsRangeValue()) {
+ nodeObject.setValue(createValue(axObject.valueForRange()));
+ } else {
+ String stringValue = axObject.stringValue();
+ if (!stringValue.isEmpty())
+ nodeObject.setValue(createValue(stringValue));
}
- Node* node = m_domAgent->assertNode(errorString, domNodeId);
- if (!node)
- return;
- Document& document = node->document();
- document.updateStyleAndLayoutIgnorePendingStylesheets();
- DocumentLifecycle::DisallowTransitionScope disallowTransition(
- document.lifecycle());
- LocalFrame* localFrame = document.frame();
- if (!localFrame) {
- *errorString = "Frame is detached.";
+ populateRelatives(axObject, inspectedAXObject, nodeObject, nodes, cache);
+
+ Node* node = axObject.getNode();
+ if (node)
+ nodeObject.setDomNodeId(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();
+ }
+ if (parentObject)
+ nodeObject.setParentId(String::number(parentObject->axObjectID()));
+
+ std::unique_ptr<protocol::Array<AXNodeId>> childIds =
+ protocol::Array<AXNodeId>::create();
+ if (!inspectedAXObject) {
+ // If there is no AXObject for the inspected node, the caller will populate
+ // its relatives.
return;
}
- std::unique_ptr<ScopedAXObjectCache> scopedCache =
- ScopedAXObjectCache::create(document);
- AXObjectCacheImpl* cache = toAXObjectCacheImpl(scopedCache->get());
- AXObject* axObject = cache->getOrCreate(node);
- *nodes = protocol::Array<protocol::Accessibility::AXNode>::create();
- if (!axObject || axObject->accessibilityIsIgnored()) {
- (*nodes)->addItem(buildObjectForIgnoredNode(node, axObject));
+
+ if (&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 {
- (*nodes)->addItem(buildProtocolAXObject(axObject));
+ 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 != inspectedAXObject &&
+ childAXObject->accessibilityIsIgnored()) {
+ 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);
+ }
+ continue;
+ }
+ addChild(childIds, *childAXObject, 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, nodes, cache));
+}
- if (fetchAncestors && axObject) {
- AXObject* parent = axObject->parentObjectUnignored();
- while (parent) {
- (*nodes)->addItem(buildProtocolAXObject(parent));
- parent = parent->parentObjectUnignored();
+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 (&axObject == &inspectedAXObject ||
+ &axObject == inspectedAXObject.parentObjectUnignored()) {
+ // Only add children/siblings of inspected node to returned nodes.
+ nodes->addItem(buildProtocolAXObject(childAXObject, &inspectedAXObject,
+ nodes, cache));
}
}
}

Powered by Google App Engine
This is Rietveld 408576698