Index: third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp |
diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp |
index 2dbb8dcc197598d67f259e7e2ed1ef850a66876d..e2103b1215256b8881ba5cfd1b4102b073573551 100644 |
--- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp |
+++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp |
@@ -30,6 +30,7 @@ |
#include "modules/accessibility/AXNodeObject.h" |
#include "core/InputTypeNames.h" |
+#include "core/dom/Element.h" |
#include "core/dom/NodeTraversal.h" |
#include "core/dom/Text.h" |
#include "core/dom/shadow/ComposedTreeTraversal.h" |
@@ -1499,6 +1500,15 @@ String AXNodeObject::stringValue() const |
if (node->isTextNode()) |
return deprecatedTextUnderElement(TextUnderElementAll); |
+ return stringValueOfControl(); |
+} |
+ |
+String AXNodeObject::stringValueOfControl() const |
+{ |
+ Node* node = this->node(); |
+ if (!node) |
+ return String(); |
+ |
if (isHTMLSelectElement(*node)) { |
HTMLSelectElement& selectElement = toHTMLSelectElement(*node); |
int selectedIndex = selectElement.selectedIndex(); |
@@ -1516,10 +1526,15 @@ String AXNodeObject::stringValue() const |
if (isNativeTextControl()) |
return text(); |
- // FIXME: We might need to implement a value here for more types |
- // FIXME: It would be better not to advertise a value at all for the types for which we don't implement one; |
- // this would require subclassing or making accessibilityAttributeNames do something other than return a |
- // single static array. |
+ // Handle other HTML input elements that aren't text controls, like date and time |
+ // controls, by returning the string value, with the exception of checkboxes |
+ // and radio buttons (which would return "on"). |
+ if (isHTMLInputElement(node)) { |
+ HTMLInputElement* input = toHTMLInputElement(node); |
+ if (input->type() != InputTypeNames::checkbox && input->type() != InputTypeNames::radio) |
+ return input->value(); |
+ } |
+ |
return String(); |
} |
@@ -1925,14 +1940,14 @@ String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraver |
// Step 2E from: http://www.w3.org/TR/accname-aam-1.1 |
if (recursive && !inAriaLabelledByTraversal && isControl()) { |
// No need to set any name source info in a recursive call. |
- if (roleValue() == TextFieldRole || roleValue() == ComboBoxRole) |
- return text(); |
if (isRange()) { |
const AtomicString& ariaValuetext = getAttribute(aria_valuetextAttr); |
if (!ariaValuetext.isNull()) |
return ariaValuetext.string(); |
return String::number(valueForRange()); |
} |
+ |
+ return stringValueOfControl(); |
} |
// Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1 |
@@ -1946,6 +1961,8 @@ String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraver |
Node* node = this->node(); |
if (node && node->isTextNode()) |
textAlternative = toText(node)->wholeText(); |
+ else if (isHTMLBRElement(node)) |
+ textAlternative = String("\n"); |
else |
textAlternative = textFromDescendants(visited); |
@@ -1998,6 +2015,10 @@ String AXNodeObject::textFromDescendants(AXObjectSet& visited) const |
StringBuilder accumulatedText; |
AXObject* previous = nullptr; |
for (AXObject* child = firstChild(); child; child = child->nextSibling()) { |
+ // Skip hidden children |
+ if (child->isInertOrAriaHidden()) |
+ continue; |
+ |
// If we're going between two layoutObjects that are in separate LayoutBoxes, add |
// whitespace if it wasn't there already. Intuitively if you have |
// <span>Hello</span><span>World</span>, those are part of the same LayoutBox |
@@ -2225,6 +2246,9 @@ bool AXNodeObject::canHaveChildren() const |
if (!node() && !isAXLayoutObject()) |
return false; |
+ if (node() && isHTMLMapElement(node())) |
+ return false; |
+ |
// Elements that should not have children |
switch (roleValue()) { |
case ImageRole: |
@@ -2762,8 +2786,8 @@ String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam |
return textAlternative; |
} |
- // 5.8 img Element |
- if (isHTMLImageElement(node())) { |
+ // 5.8 img or area Element |
+ if (isHTMLImageElement(node()) || isHTMLAreaElement(node()) || (layoutObject() && layoutObject()->isSVGImage())) { |
// alt |
nameFrom = AXNameFromAttribute; |
if (nameSources) { |
@@ -2840,6 +2864,39 @@ String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam |
return textAlternative; |
} |
+ // Fieldset / legend. |
+ if (isHTMLFieldSetElement(node())) { |
+ nameFrom = AXNameFromRelatedElement; |
+ if (nameSources) { |
+ nameSources->append(NameSource(*foundTextAlternative)); |
+ nameSources->last().type = nameFrom; |
+ nameSources->last().nativeSource = AXTextFromNativeHTMLLegend; |
+ } |
+ HTMLElement* legend = toHTMLFieldSetElement(node())->legend(); |
+ if (legend) { |
+ AXObject* legendAXObject = axObjectCache().getOrCreate(legend); |
+ // Avoid an infinite loop |
+ if (legendAXObject && !visited.contains(legendAXObject)) { |
+ textAlternative = recursiveTextAlternative(*legendAXObject, false, visited); |
+ |
+ if (relatedObjects) { |
+ localRelatedObjects.append(new NameSourceRelatedObject(legendAXObject, textAlternative)); |
+ *relatedObjects = localRelatedObjects; |
+ localRelatedObjects.clear(); |
+ } |
+ |
+ if (nameSources) { |
+ NameSource& source = nameSources->last(); |
+ source.relatedObjects = *relatedObjects; |
+ source.text = textAlternative; |
+ *foundTextAlternative = true; |
+ } else { |
+ return textAlternative; |
+ } |
+ } |
+ } |
+ } |
+ |
return textAlternative; |
} |
@@ -3019,6 +3076,24 @@ String AXNodeObject::description(AXNameFrom nameFrom, AXDescriptionFrom& descrip |
} |
} |
+ // aria-help. |
+ // FIXME: this is not part of the official standard, but it's needed because the built-in date/time controls use it. |
+ descriptionFrom = AXDescriptionFromAttribute; |
+ if (descriptionSources) { |
+ descriptionSources->append(DescriptionSource(foundDescription, aria_helpAttr)); |
+ descriptionSources->last().type = descriptionFrom; |
+ } |
+ const AtomicString& help = getAttribute(aria_helpAttr); |
+ if (!help.isEmpty()) { |
+ description = help; |
+ if (descriptionSources) { |
+ foundDescription = true; |
+ descriptionSources->last().text = description; |
+ } else { |
+ return description; |
+ } |
+ } |
+ |
descriptionFrom = AXDescriptionFromUninitialized; |
if (foundDescription) { |
@@ -3042,4 +3117,4 @@ DEFINE_TRACE(AXNodeObject) |
AXObject::trace(visitor); |
} |
-} // namespace blink |
+} // namespace blin |