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

Unified Diff: Source/modules/accessibility/AXNodeObject.cpp

Issue 1301993003: Last few steps of text alternative computation algorithm (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Rename isSameLayoutBox and fix infinite loop for label wrapped Created 5 years, 4 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: Source/modules/accessibility/AXNodeObject.cpp
diff --git a/Source/modules/accessibility/AXNodeObject.cpp b/Source/modules/accessibility/AXNodeObject.cpp
index cebfae8fc3569c106e8850435ea596f25a634808..b48bf894227ad946e7eeb07a48fc73c8926de044 100644
--- a/Source/modules/accessibility/AXNodeObject.cpp
+++ b/Source/modules/accessibility/AXNodeObject.cpp
@@ -1,30 +1,30 @@
/*
-* Copyright (C) 2012, Google Inc. All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions
-* are met:
-*
-* 1. Redistributions of source code must retain the above copyright
-* notice, this list of conditions and the following disclaimer.
-* 2. Redistributions in binary form must reproduce the above copyright
-* notice, this list of conditions and the following disclaimer in the
-* documentation and/or other materials provided with the distribution.
-* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
-* its contributors may be used to endorse or promote products derived
-* from this software without specific prior written permission.
-*
-* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
-* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
+ * Copyright (C) 2012, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
#include "config.h"
#include "modules/accessibility/AXNodeObject.h"
@@ -32,6 +32,7 @@
#include "core/InputTypeNames.h"
#include "core/dom/NodeTraversal.h"
#include "core/dom/Text.h"
+#include "core/dom/shadow/ComposedTreeTraversal.h"
#include "core/html/HTMLDListElement.h"
#include "core/html/HTMLFieldSetElement.h"
#include "core/html/HTMLFrameElementBase.h"
@@ -51,9 +52,11 @@
#include "core/html/HTMLTextAreaElement.h"
#include "core/html/parser/HTMLParserIdioms.h"
#include "core/html/shadow/MediaControlElements.h"
+#include "core/layout/LayoutBlockFlow.h"
#include "core/layout/LayoutObject.h"
#include "modules/accessibility/AXObjectCacheImpl.h"
#include "platform/UserGestureIndicator.h"
+#include "platform/text/PlatformLocale.h"
#include "wtf/text/StringBuilder.h"
@@ -250,7 +253,7 @@ static bool isRequiredOwnedElement(AXObject* parent, AccessibilityRole currentRo
return isListElement(parentNode);
if (currentRole == ListMarkerRole)
return isHTMLLIElement(*parentNode);
- if (currentRole == MenuItemCheckBoxRole || currentRole == MenuItemRole || currentRole == MenuItemRadioRole)
+ if (currentRole == MenuItemCheckBoxRole || currentRole == MenuItemRole || currentRole == MenuItemRadioRole)
return isHTMLMenuElement(*parentNode);
if (!currentElement)
@@ -267,7 +270,6 @@ static bool isRequiredOwnedElement(AXObject* parent, AccessibilityRole currentRo
return false;
}
-
const AXObject* AXNodeObject::inheritsPresentationalRoleFrom() const
{
// ARIA states if an item can get focus, it should not be presentational.
@@ -336,7 +338,7 @@ AccessibilityRole AXNodeObject::determineAccessibilityRoleUtil()
return DetailsRole;
if (isHTMLSummaryElement(*node())) {
- if (node()->parentNode() && isHTMLDetailsElement(node()->parentNode()))
+ if (ComposedTreeTraversal::parent(*node()) && isHTMLDetailsElement(ComposedTreeTraversal::parent(*node())))
esprehn 2015/08/30 00:07:47 ComposedTreeTraversal::parent is not cheap enough
aboxhall 2015/08/30 22:25:21 Done.
return DisclosureTriangleRole;
return UnknownRole;
}
@@ -1539,14 +1541,34 @@ static bool shouldUseAccessibilityObjectInnerText(AXObject* obj)
return true;
}
-// Returns true if |r1| and |r2| are both non-null and are contained within the
-// same LayoutBox.
-static bool isSameLayoutBox(LayoutObject* r1, LayoutObject* r2)
+// Returns the nearest LayoutBlockFlow ancestor which does not have an
+// inlineBoxWrapper - i.e. is not itself an inline object.
+static LayoutBlockFlow* nonInlineBlockFlow(LayoutObject* obj)
esprehn 2015/08/30 00:07:48 object
+{
+ LayoutObject* curr = obj;
esprehn 2015/08/30 00:07:47 current, we don't abbreviate like this now.
+ while (curr) {
+ if (curr->isLayoutBlockFlow()) {
+ LayoutBlockFlow* lbf = toLayoutBlockFlow(curr);
esprehn 2015/08/30 00:07:47 blockFlow
+ if (!lbf->inlineBoxWrapper())
+ return lbf;
+ }
+ curr = curr->parent();
+ }
+
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+// Returns true if |r1| and |r2| are both non-null, both inline, and are contained
+// within the same non-inline LayoutBlockFlow.
+static bool isSameNonInlineBlockFlow(LayoutObject* r1, LayoutObject* r2)
esprehn 2015/08/30 00:07:47 isInSameNonInlineBlockFlow? isSame makes me think
aboxhall 2015/08/30 22:25:21 Done.
{
if (!r1 || !r2)
return false;
- LayoutBox* b1 = r1->enclosingBox();
- LayoutBox* b2 = r2->enclosingBox();
+ if (!r1->isInline() || !r2->isInline())
+ return false;
+ LayoutBlockFlow* b1 = nonInlineBlockFlow(r1);
+ LayoutBlockFlow* b2 = nonInlineBlockFlow(r2);
return b1 && b2 && b1 == b2;
}
@@ -1579,7 +1601,7 @@ String AXNodeObject::deprecatedTextUnderElement(TextUnderElementMode mode) const
// so we should return "HelloWorld", but given <div>Hello</div><div>World</div> the
// strings are in separate boxes so we should return "Hello World".
if (previous && builder.length() && !isHTMLSpace(builder[builder.length() - 1])) {
- if (!isSameLayoutBox(child->layoutObject(), previous->layoutObject()))
+ if (!isSameNonInlineBlockFlow(child->layoutObject(), previous->layoutObject()))
builder.append(' ');
}
@@ -1778,8 +1800,12 @@ String AXNodeObject::computedName() const
// New AX name calculation.
//
-String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraversal, AXObjectSet& visited, AXNameFrom& nameFrom, AXObjectVector& nameObjects, NameSources* nameSources) const
+String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraversal, AXObjectSet& visited, AXNameFrom& nameFrom, AXObjectVector* nameObjects, NameSources* nameSources) const
{
+ // If nameSources is non-null, nameObjects is used in filling it in, so it must be non-null as well.
+ if (nameSources)
+ assert(nameObjects);
+
bool alreadyVisited = visited.contains(this);
bool foundTextAlternative = false;
visited.add(this);
@@ -1814,7 +1840,7 @@ String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraver
if (nameSources) {
NameSource& source = nameSources->last();
source.type = nameFrom;
- source.nameObjects = nameObjects;
+ source.nameObjects = *nameObjects;
source.text = textAlternative;
foundTextAlternative = true;
} else {
@@ -1854,7 +1880,16 @@ String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraver
return textAlternative;
// 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()) {
+ if (hasAttribute(aria_valuetextAttr))
+ return getAttribute(aria_valuetextAttr).string();
esprehn 2015/08/30 00:07:47 calling hasAttribute and then getAttribute will be
aboxhall 2015/08/30 22:25:21 Done.
+ return String::number(valueForRange());
+ }
+ }
// Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1
if (recursive || nameFromContents()) {
@@ -1870,22 +1905,45 @@ String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraver
else
textAlternative = textFromDescendants(visited);
- if (nameSources) {
- foundTextAlternative = true;
- nameSources->last().text = textAlternative;
- } else {
- return textAlternative;
+ if (!textAlternative.isEmpty()) {
+ if (nameSources) {
+ foundTextAlternative = true;
+ nameSources->last().text = textAlternative;
+ } else {
+ return textAlternative;
+ }
+ }
+ }
+
+ // Step 2H from: http://www.w3.org/TR/accname-aam-1.1
+ nameFrom = AXNameFromAttribute;
+ if (nameSources) {
+ nameSources->append(NameSource(foundTextAlternative, titleAttr));
+ nameSources->last().type = nameFrom;
+ }
+ if (hasAttribute(titleAttr)) {
esprehn 2015/08/30 00:07:47 ditto
aboxhall 2015/08/30 22:25:22 Done.
+ const AtomicString& title = getAttribute(titleAttr);
+ if (!title.isEmpty()) {
+ textAlternative = title;
+ if (nameSources) {
+ foundTextAlternative = true;
+ nameSources->last().text = textAlternative;
+ } else {
+ return textAlternative;
+ }
}
}
nameFrom = AXNameFromUninitialized;
- if (nameSources && !nameSources->isEmpty()) {
+ if (foundTextAlternative) {
for (size_t i = 0; i < nameSources->size(); ++i) {
if (!(*nameSources)[i].text.isNull() && !(*nameSources)[i].superseded) {
- nameFrom = (*nameSources)[i].type;
- nameObjects = (*nameSources)[i].nameObjects;
- return (*nameSources)[i].text;
+ NameSource& nameSource = (*nameSources)[i];
+ nameFrom = nameSource.type;
+ if (!nameSource.nameObjects.isEmpty())
+ *nameObjects = nameSource.nameObjects;
+ return nameSource.text;
}
}
}
@@ -1904,13 +1962,11 @@ String AXNodeObject::textFromDescendants(AXObjectSet& visited) const
// so we should return "HelloWorld", but given <div>Hello</div><div>World</div> the
// strings are in separate boxes so we should return "Hello World".
if (previous && accumulatedText.length() && !isHTMLSpace(accumulatedText[accumulatedText.length() - 1])) {
- if (!isSameLayoutBox(child->layoutObject(), previous->layoutObject()))
+ if (!isSameNonInlineBlockFlow(child->layoutObject(), previous->layoutObject()))
accumulatedText.append(' ');
}
- AXNameFrom nameFrom;
- AXObjectVector nameObjects;
- String result = child->textAlternative(true, false, visited, nameFrom, nameObjects, nullptr);
+ String result = recursiveTextAlternative(*child, false, visited);
accumulatedText.append(result);
previous = child;
}
@@ -1918,7 +1974,7 @@ String AXNodeObject::textFromDescendants(AXObjectSet& visited) const
return accumulatedText.toString();
}
-String AXNodeObject::textFromElements(bool inAriaLabelledbyTraversal, AXObjectSet& visited, WillBeHeapVector<RawPtrWillBeMember<Element>>& elements, AXObjectVector& nameObjects) const
+String AXNodeObject::textFromElements(bool inAriaLabelledbyTraversal, AXObjectSet& visited, WillBeHeapVector<RawPtrWillBeMember<Element>>& elements, AXObjectVector* nameObjects) const
{
StringBuilder accumulatedText;
bool foundValidElement = false;
@@ -1940,11 +1996,12 @@ String AXNodeObject::textFromElements(bool inAriaLabelledbyTraversal, AXObjectSe
}
if (!foundValidElement)
return String();
- nameObjects = localNameObjects;
+ if (nameObjects)
+ *nameObjects = localNameObjects;
esprehn 2015/08/30 00:07:47 I'm not a huge fan of this kind of optional out pa
aboxhall 2015/08/30 22:25:22 In recursive calls, nameObjects will always be nul
return accumulatedText.toString();
}
-String AXNodeObject::textFromAriaLabelledby(AXObjectSet& visited, AXObjectVector& nameObjects) const
+String AXNodeObject::textFromAriaLabelledby(AXObjectSet& visited, AXObjectVector* nameObjects) const
{
WillBeHeapVector<RawPtrWillBeMember<Element>> elements;
ariaLabelledbyElements(elements);
@@ -2147,8 +2204,7 @@ Element* AXNodeObject::actionElement() const
if (isHTMLInputElement(*node)) {
HTMLInputElement& input = toHTMLInputElement(*node);
- if (!input.isDisabledFormControl() && (isCheckboxOrRadio() || input.isTextButton()
- || input.type() == InputTypeNames::file))
+ if (!input.isDisabledFormControl() && (isCheckboxOrRadio() || input.isTextButton() || input.type() == InputTypeNames::file))
return &input;
} else if (isHTMLButtonElement(*node)) {
return toElement(node);
@@ -2454,11 +2510,15 @@ void AXNodeObject::deprecatedAriaLabelledbyText(WillBeHeapVector<OwnPtrWillBeMem
}
// Based on http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible-name-and-description-calculation
-String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nameFrom, AXObjectVector& nameObjects, NameSources* nameSources, bool* foundTextAlternative) const
+String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nameFrom, AXObjectVector* nameObjects, NameSources* nameSources, bool* foundTextAlternative) const
{
if (!node())
return String();
+ // If nameSources is non-null, nameObjects is used in filling it in, so it must be non-null as well.
+ if (nameSources)
+ assert(nameObjects);
+
String textAlternative;
AXObjectVector localNameObjects;
@@ -2466,6 +2526,46 @@ String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam
if (isHTMLInputElement(node()))
inputElement = toHTMLInputElement(node());
+ // 5.1/5.5 Text inputs, Other labelable Elements
+ HTMLElement* htmlElement = nullptr;
+ if (node()->isHTMLElement())
+ htmlElement = toHTMLElement(node());
+ if (htmlElement && htmlElement->isLabelable()) {
+ // label
+ nameFrom = AXNameFromRelatedElement;
+ if (nameSources) {
+ nameSources->append(NameSource(*foundTextAlternative));
+ nameSources->last().type = nameFrom;
+ nameSources->last().nativeSource = AXTextFromNativeHTMLLabel;
+ }
+ HTMLLabelElement* label = labelForElement(htmlElement);
+ if (label) {
+ RefPtrWillBeRawPtr<AXObject> labelAXObject = axObjectCache().getOrCreate(label);
+ // Avoid an infinite loop for label wrapped
+ if (labelAXObject && !visited.contains(labelAXObject.get())) {
+ if (nameObjects) {
esprehn 2015/08/30 00:07:48 having both nameSources and nameObjects is confusi
aboxhall 2015/08/30 22:25:21 nameSources will be used by devtools frontend to d
+ localNameObjects.append(labelAXObject.get());
+ *nameObjects = localNameObjects;
+ localNameObjects.clear();
+ }
+ textAlternative = recursiveTextAlternative(*labelAXObject, false, visited);
+
+ if (nameSources) {
+ NameSource& source = nameSources->last();
+ source.nameObjects = *nameObjects;
+ source.text = textAlternative;
+ if (label->getAttribute(forAttr).isNull())
+ source.nativeSource = AXTextFromNativeHTMLLabelWrapped;
+ else
+ source.nativeSource = AXTextFromNativeHTMLLabelFor;
+ *foundTextAlternative = true;
+ } else {
+ return textAlternative;
+ }
+ }
+ }
+ }
+
// 5.2 input type="button", input type="submit" and input type="reset"
if (inputElement && inputElement->isTextButton()) {
// value attribue
@@ -2485,23 +2585,6 @@ String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam
return textAlternative;
}
}
-
- // localised default value ("Submit" or "Reset")
- String defaultValue = inputElement->defaultValue();
- if (!defaultValue.isNull()) {
- // defaultValue is always set for submit and reset buttons, and never set for anything else.
- nameFrom = AXNameFromAttribute;
- textAlternative = defaultValue;
- if (nameSources) {
- nameSources->append(NameSource(*foundTextAlternative, typeAttr));
- NameSource& source = nameSources->last();
- source.attributeValue = inputElement->getAttribute(typeAttr);
- source.text = textAlternative;
- *foundTextAlternative = true;
- } else {
- return textAlternative;
- }
- }
return textAlternative;
}
@@ -2544,37 +2627,39 @@ String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam
}
}
+ // localised default value ("Submit")
+ nameFrom = AXNameFromAttribute;
+ textAlternative = inputElement->locale().queryString(WebLocalizedString::SubmitButtonDefaultLabel);
+ if (nameSources) {
+ nameSources->append(NameSource(*foundTextAlternative, typeAttr));
+ NameSource& source = nameSources->last();
+ source.attributeValue = inputElement->getAttribute(typeAttr);
+ source.type = nameFrom;
+ source.text = textAlternative;
+ *foundTextAlternative = true;
+ } else {
+ return textAlternative;
+ }
return textAlternative;
}
- // 5.5 Other labelable Elements
- if (node()->isHTMLElement() && toHTMLElement(node())->isLabelable()) {
- // label
- nameFrom = AXNameFromRelatedElement;
+ // 5.1 Text inputs - step 3 (placeholder attribute)
+ if (htmlElement && htmlElement->isTextFormControl()) {
+ nameFrom = AXNameFromPlaceholder;
if (nameSources) {
- nameSources->append(NameSource(*foundTextAlternative));
- nameSources->last().type = nameFrom;
- nameSources->last().nativeSource = AXTextFromNativeHTMLLabel;
+ nameSources->append(NameSource(*foundTextAlternative, placeholderAttr));
+ NameSource& source = nameSources->last();
+ source.type = nameFrom;
}
- HTMLLabelElement* label = labelForElement(toHTMLElement(node()));
- if (label) {
- RefPtrWillBeRawPtr<AXObject> labelAXObject = axObjectCache().getOrCreate(label);
- if (labelAXObject) {
- localNameObjects.append(labelAXObject.get());
- nameObjects = localNameObjects;
- localNameObjects.clear();
-
- textAlternative = recursiveTextAlternative(*labelAXObject, false, visited);
-
+ HTMLElement* element = toHTMLElement(node());
+ if (element->fastHasAttribute(placeholderAttr)) {
esprehn 2015/08/30 00:07:47 checking has and then get is slower than just get
aboxhall 2015/08/30 22:25:21 Done.
+ const AtomicString& placeholder = element->fastGetAttribute(placeholderAttr);
+ if (!placeholder.isEmpty()) {
+ textAlternative = placeholder;
if (nameSources) {
NameSource& source = nameSources->last();
- source.nameObjects = nameObjects;
source.text = textAlternative;
- if (label->getAttribute(forAttr).isNull())
- source.nativeSource = AXTextFromNativeHTMLLabelWrapped;
- else
- source.nativeSource = AXTextFromNativeHTMLLabelFor;
- *foundTextAlternative = true;
+ source.attributeValue = placeholder;
} else {
return textAlternative;
}
@@ -2602,15 +2687,17 @@ String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam
if (figcaption) {
RefPtrWillBeRawPtr<AXObject> figcaptionAXObject = axObjectCache().getOrCreate(figcaption);
if (figcaptionAXObject) {
- localNameObjects.append(figcaptionAXObject.get());
- nameObjects = localNameObjects;
- localNameObjects.clear();
+ if (nameObjects) {
+ localNameObjects.append(figcaptionAXObject.get());
+ *nameObjects = localNameObjects;
+ localNameObjects.clear();
+ }
textAlternative = recursiveTextAlternative(*figcaptionAXObject, false, visited);
if (nameSources) {
NameSource& source = nameSources->last();
- source.nameObjects = nameObjects;
+ source.nameObjects = *nameObjects;
source.text = textAlternative;
} else {
return textAlternative;
@@ -2622,16 +2709,14 @@ String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam
// 5.8 img Element
if (isHTMLImageElement(node())) {
- HTMLImageElement* imgElement = toHTMLImageElement(node());
-
// alt
nameFrom = AXNameFromAttribute;
if (nameSources) {
nameSources->append(NameSource(*foundTextAlternative, altAttr));
nameSources->last().type = nameFrom;
}
- if (imgElement->hasAttribute(altAttr)) {
- AtomicString alt = imgElement->getAttribute(altAttr);
+ if (hasAttribute(altAttr)) {
+ AtomicString alt = getAttribute(altAttr);
textAlternative = alt;
if (nameSources) {
NameSource& source = nameSources->last();
@@ -2660,20 +2745,42 @@ String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam
if (caption) {
RefPtrWillBeRawPtr<AXObject> captionAXObject = axObjectCache().getOrCreate(caption);
if (captionAXObject) {
- localNameObjects.append(captionAXObject.get());
- nameObjects = localNameObjects;
- localNameObjects.clear();
+ if (nameObjects) {
+ localNameObjects.append(captionAXObject.get());
+ *nameObjects = localNameObjects;
+ localNameObjects.clear();
+ }
textAlternative = recursiveTextAlternative(*captionAXObject, false, visited);
if (nameSources) {
NameSource& source = nameSources->last();
- source.nameObjects = nameObjects;
+ source.nameObjects = *nameObjects;
source.text = textAlternative;
} else {
return textAlternative;
}
}
}
+
+ // summary
+ nameFrom = AXNameFromAttribute;
+ if (nameSources) {
+ nameSources->append(NameSource(*foundTextAlternative));
+ nameSources->last().type = nameFrom;
+ }
+ if (hasAttribute(summaryAttr)) {
+ AtomicString summary = getAttribute(summaryAttr);
esprehn 2015/08/30 00:07:47 ditto
aboxhall 2015/08/30 22:25:21 Done.
+ textAlternative = summary;
+ if (nameSources) {
+ NameSource& source = nameSources->last();
+ source.attributeValue = summary;
+ source.text = textAlternative;
+ *foundTextAlternative = true;
+ } else {
+ return textAlternative;
+ }
+ }
+
return textAlternative;
}

Powered by Google App Engine
This is Rietveld 408576698