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; |
} |