Chromium Code Reviews| 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..75b25b8888cd937faa0083d4be8df318bb0f68b4 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" |
| @@ -1516,6 +1517,15 @@ String AXNodeObject::stringValue() const |
| if (isNativeTextControl()) |
| return text(); |
| + // 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(); |
| + } |
| + |
| // 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 |
| @@ -1925,14 +1935,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 stringValue(); |
|
aboxhall
2015/11/05 17:49:21
I'm not sure how I feel about this. It's calling i
dmazzoni
2015/11/06 00:21:17
The current code only handles the string value of
aboxhall
2015/11/06 01:11:23
Could we possibly pull out the control-related log
dmazzoni
2015/11/06 04:54:06
Good idea!
Done.
|
| } |
| // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1 |
| @@ -1946,6 +1956,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 +2010,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 +2241,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 +2781,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 +2859,40 @@ String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam |
| return textAlternative; |
| } |
| + // Fieldset / legend. |
|
aboxhall
2015/11/05 17:49:21
Wohoo! You can add http://crbug.com/550663 to the
dmazzoni
2015/11/06 00:21:17
Done.
|
| + 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; |
| + source.nativeSource = AXTextFromNativeHTMLLegend; |
|
aboxhall
2015/11/05 17:49:21
No need to re-set this.
dmazzoni
2015/11/06 00:21:17
Done.
|
| + *foundTextAlternative = true; |
| + } else { |
| + return textAlternative; |
| + } |
| + } |
| + } |
| + } |
| + |
| return textAlternative; |
| } |
| @@ -3019,6 +3072,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 +3113,4 @@ DEFINE_TRACE(AXNodeObject) |
| AXObject::trace(visitor); |
| } |
| -} // namespace blink |
| +} // namespace blin |