| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2012, Google Inc. All rights reserved. | 2 * Copyright (C) 2012, Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 #if ENABLE(ASSERT) | 127 #if ENABLE(ASSERT) |
| 128 // Double-check that an AXObject is never accessed before | 128 // Double-check that an AXObject is never accessed before |
| 129 // it's been initialized. | 129 // it's been initialized. |
| 130 ASSERT(m_initialized); | 130 ASSERT(m_initialized); |
| 131 #endif | 131 #endif |
| 132 | 132 |
| 133 // If this element is within a parent that cannot have children, it should not | 133 // If this element is within a parent that cannot have children, it should not |
| 134 // be exposed. | 134 // be exposed. |
| 135 if (isDescendantOfLeafNode()) { | 135 if (isDescendantOfLeafNode()) { |
| 136 if (ignoredReasons) | 136 if (ignoredReasons) |
| 137 ignoredReasons->append( | 137 ignoredReasons->push_back( |
| 138 IgnoredReason(AXAncestorIsLeafNode, leafNodeAncestor())); | 138 IgnoredReason(AXAncestorIsLeafNode, leafNodeAncestor())); |
| 139 return true; | 139 return true; |
| 140 } | 140 } |
| 141 | 141 |
| 142 // Ignore labels that are already referenced by a control. | 142 // Ignore labels that are already referenced by a control. |
| 143 AXObject* controlObject = correspondingControlForLabelElement(); | 143 AXObject* controlObject = correspondingControlForLabelElement(); |
| 144 if (controlObject && controlObject->isCheckboxOrRadio() && | 144 if (controlObject && controlObject->isCheckboxOrRadio() && |
| 145 controlObject->nameFromLabelElement()) { | 145 controlObject->nameFromLabelElement()) { |
| 146 if (ignoredReasons) { | 146 if (ignoredReasons) { |
| 147 HTMLLabelElement* label = labelElementContainer(); | 147 HTMLLabelElement* label = labelElementContainer(); |
| 148 if (label && label != getNode()) { | 148 if (label && label != getNode()) { |
| 149 AXObject* labelAXObject = axObjectCache().getOrCreate(label); | 149 AXObject* labelAXObject = axObjectCache().getOrCreate(label); |
| 150 ignoredReasons->append(IgnoredReason(AXLabelContainer, labelAXObject)); | 150 ignoredReasons->push_back( |
| 151 IgnoredReason(AXLabelContainer, labelAXObject)); |
| 151 } | 152 } |
| 152 | 153 |
| 153 ignoredReasons->append(IgnoredReason(AXLabelFor, controlObject)); | 154 ignoredReasons->push_back(IgnoredReason(AXLabelFor, controlObject)); |
| 154 } | 155 } |
| 155 return true; | 156 return true; |
| 156 } | 157 } |
| 157 | 158 |
| 158 Element* element = getNode()->isElementNode() ? toElement(getNode()) | 159 Element* element = getNode()->isElementNode() ? toElement(getNode()) |
| 159 : getNode()->parentElement(); | 160 : getNode()->parentElement(); |
| 160 if (!getLayoutObject() && (!element || !element->isInCanvasSubtree()) && | 161 if (!getLayoutObject() && (!element || !element->isInCanvasSubtree()) && |
| 161 !equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) { | 162 !equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) { |
| 162 if (ignoredReasons) | 163 if (ignoredReasons) |
| 163 ignoredReasons->append(IgnoredReason(AXNotRendered)); | 164 ignoredReasons->push_back(IgnoredReason(AXNotRendered)); |
| 164 return true; | 165 return true; |
| 165 } | 166 } |
| 166 | 167 |
| 167 if (m_role == UnknownRole) { | 168 if (m_role == UnknownRole) { |
| 168 if (ignoredReasons) | 169 if (ignoredReasons) |
| 169 ignoredReasons->append(IgnoredReason(AXUninteresting)); | 170 ignoredReasons->push_back(IgnoredReason(AXUninteresting)); |
| 170 return true; | 171 return true; |
| 171 } | 172 } |
| 172 return false; | 173 return false; |
| 173 } | 174 } |
| 174 | 175 |
| 175 static bool isListElement(Node* node) { | 176 static bool isListElement(Node* node) { |
| 176 return isHTMLUListElement(*node) || isHTMLOListElement(*node) || | 177 return isHTMLUListElement(*node) || isHTMLOListElement(*node) || |
| 177 isHTMLDListElement(*node); | 178 isHTMLDListElement(*node); |
| 178 } | 179 } |
| 179 | 180 |
| (...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 567 elementsFromAttribute(elements, attr); | 568 elementsFromAttribute(elements, attr); |
| 568 | 569 |
| 569 AXObjectCacheImpl& cache = axObjectCache(); | 570 AXObjectCacheImpl& cache = axObjectCache(); |
| 570 for (const auto& element : elements) { | 571 for (const auto& element : elements) { |
| 571 if (AXObject* child = cache.getOrCreate(element)) { | 572 if (AXObject* child = cache.getOrCreate(element)) { |
| 572 // Only aria-labelledby and aria-describedby can target hidden elements. | 573 // Only aria-labelledby and aria-describedby can target hidden elements. |
| 573 if (child->accessibilityIsIgnored() && attr != aria_labelledbyAttr && | 574 if (child->accessibilityIsIgnored() && attr != aria_labelledbyAttr && |
| 574 attr != aria_labeledbyAttr && attr != aria_describedbyAttr) { | 575 attr != aria_labeledbyAttr && attr != aria_describedbyAttr) { |
| 575 continue; | 576 continue; |
| 576 } | 577 } |
| 577 children.append(child); | 578 children.push_back(child); |
| 578 } | 579 } |
| 579 } | 580 } |
| 580 } | 581 } |
| 581 | 582 |
| 582 // This only returns true if this is the element that actually has the | 583 // This only returns true if this is the element that actually has the |
| 583 // contentEditable attribute set, unlike node->hasEditableStyle() which will | 584 // contentEditable attribute set, unlike node->hasEditableStyle() which will |
| 584 // also return true if an ancestor is editable. | 585 // also return true if an ancestor is editable. |
| 585 bool AXNodeObject::hasContentEditableAttributeSet() const { | 586 bool AXNodeObject::hasContentEditableAttributeSet() const { |
| 586 const AtomicString& contentEditableValue = getAttribute(contenteditableAttr); | 587 const AtomicString& contentEditableValue = getAttribute(contenteditableAttr); |
| 587 if (contentEditableValue.isNull()) | 588 if (contentEditableValue.isNull()) |
| (...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1200 return; | 1201 return; |
| 1201 | 1202 |
| 1202 DocumentMarkerController& markerController = getDocument()->markers(); | 1203 DocumentMarkerController& markerController = getDocument()->markers(); |
| 1203 DocumentMarkerVector markers = markerController.markersFor(getNode()); | 1204 DocumentMarkerVector markers = markerController.markersFor(getNode()); |
| 1204 for (size_t i = 0; i < markers.size(); ++i) { | 1205 for (size_t i = 0; i < markers.size(); ++i) { |
| 1205 DocumentMarker* marker = markers[i]; | 1206 DocumentMarker* marker = markers[i]; |
| 1206 switch (marker->type()) { | 1207 switch (marker->type()) { |
| 1207 case DocumentMarker::Spelling: | 1208 case DocumentMarker::Spelling: |
| 1208 case DocumentMarker::Grammar: | 1209 case DocumentMarker::Grammar: |
| 1209 case DocumentMarker::TextMatch: | 1210 case DocumentMarker::TextMatch: |
| 1210 markerTypes.append(marker->type()); | 1211 markerTypes.push_back(marker->type()); |
| 1211 markerRanges.append( | 1212 markerRanges.push_back( |
| 1212 AXRange(marker->startOffset(), marker->endOffset())); | 1213 AXRange(marker->startOffset(), marker->endOffset())); |
| 1213 break; | 1214 break; |
| 1214 case DocumentMarker::InvisibleSpellcheck: | 1215 case DocumentMarker::InvisibleSpellcheck: |
| 1215 case DocumentMarker::Composition: | 1216 case DocumentMarker::Composition: |
| 1216 // No need for accessibility to know about these marker types. | 1217 // No need for accessibility to know about these marker types. |
| 1217 break; | 1218 break; |
| 1218 } | 1219 } |
| 1219 } | 1220 } |
| 1220 } | 1221 } |
| 1221 | 1222 |
| (...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1580 // Step 2D from: http://www.w3.org/TR/accname-aam-1.1 | 1581 // Step 2D from: http://www.w3.org/TR/accname-aam-1.1 |
| 1581 textAlternative = nativeTextAlternative(visited, nameFrom, relatedObjects, | 1582 textAlternative = nativeTextAlternative(visited, nameFrom, relatedObjects, |
| 1582 nameSources, &foundTextAlternative); | 1583 nameSources, &foundTextAlternative); |
| 1583 if (!textAlternative.isEmpty() && !nameSources) | 1584 if (!textAlternative.isEmpty() && !nameSources) |
| 1584 return textAlternative; | 1585 return textAlternative; |
| 1585 | 1586 |
| 1586 // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1 | 1587 // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1 |
| 1587 if (recursive || nameFromContents()) { | 1588 if (recursive || nameFromContents()) { |
| 1588 nameFrom = AXNameFromContents; | 1589 nameFrom = AXNameFromContents; |
| 1589 if (nameSources) { | 1590 if (nameSources) { |
| 1590 nameSources->append(NameSource(foundTextAlternative)); | 1591 nameSources->push_back(NameSource(foundTextAlternative)); |
| 1591 nameSources->back().type = nameFrom; | 1592 nameSources->back().type = nameFrom; |
| 1592 } | 1593 } |
| 1593 | 1594 |
| 1594 Node* node = this->getNode(); | 1595 Node* node = this->getNode(); |
| 1595 if (node && node->isTextNode()) | 1596 if (node && node->isTextNode()) |
| 1596 textAlternative = toText(node)->wholeText(); | 1597 textAlternative = toText(node)->wholeText(); |
| 1597 else if (isHTMLBRElement(node)) | 1598 else if (isHTMLBRElement(node)) |
| 1598 textAlternative = String("\n"); | 1599 textAlternative = String("\n"); |
| 1599 else | 1600 else |
| 1600 textAlternative = textFromDescendants(visited, false); | 1601 textAlternative = textFromDescendants(visited, false); |
| 1601 | 1602 |
| 1602 if (!textAlternative.isEmpty()) { | 1603 if (!textAlternative.isEmpty()) { |
| 1603 if (nameSources) { | 1604 if (nameSources) { |
| 1604 foundTextAlternative = true; | 1605 foundTextAlternative = true; |
| 1605 nameSources->back().text = textAlternative; | 1606 nameSources->back().text = textAlternative; |
| 1606 } else { | 1607 } else { |
| 1607 return textAlternative; | 1608 return textAlternative; |
| 1608 } | 1609 } |
| 1609 } | 1610 } |
| 1610 } | 1611 } |
| 1611 | 1612 |
| 1612 // Step 2H from: http://www.w3.org/TR/accname-aam-1.1 | 1613 // Step 2H from: http://www.w3.org/TR/accname-aam-1.1 |
| 1613 nameFrom = AXNameFromTitle; | 1614 nameFrom = AXNameFromTitle; |
| 1614 if (nameSources) { | 1615 if (nameSources) { |
| 1615 nameSources->append(NameSource(foundTextAlternative, titleAttr)); | 1616 nameSources->push_back(NameSource(foundTextAlternative, titleAttr)); |
| 1616 nameSources->back().type = nameFrom; | 1617 nameSources->back().type = nameFrom; |
| 1617 } | 1618 } |
| 1618 const AtomicString& title = getAttribute(titleAttr); | 1619 const AtomicString& title = getAttribute(titleAttr); |
| 1619 if (!title.isEmpty()) { | 1620 if (!title.isEmpty()) { |
| 1620 textAlternative = title; | 1621 textAlternative = title; |
| 1621 if (nameSources) { | 1622 if (nameSources) { |
| 1622 foundTextAlternative = true; | 1623 foundTextAlternative = true; |
| 1623 nameSources->back().text = textAlternative; | 1624 nameSources->back().text = textAlternative; |
| 1624 } else { | 1625 } else { |
| 1625 return textAlternative; | 1626 return textAlternative; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1650 | 1651 |
| 1651 StringBuilder accumulatedText; | 1652 StringBuilder accumulatedText; |
| 1652 AXObject* previous = nullptr; | 1653 AXObject* previous = nullptr; |
| 1653 | 1654 |
| 1654 AXObjectVector children; | 1655 AXObjectVector children; |
| 1655 | 1656 |
| 1656 HeapVector<Member<AXObject>> ownedChildren; | 1657 HeapVector<Member<AXObject>> ownedChildren; |
| 1657 computeAriaOwnsChildren(ownedChildren); | 1658 computeAriaOwnsChildren(ownedChildren); |
| 1658 for (AXObject* obj = rawFirstChild(); obj; obj = obj->rawNextSibling()) { | 1659 for (AXObject* obj = rawFirstChild(); obj; obj = obj->rawNextSibling()) { |
| 1659 if (!axObjectCache().isAriaOwned(obj)) | 1660 if (!axObjectCache().isAriaOwned(obj)) |
| 1660 children.append(obj); | 1661 children.push_back(obj); |
| 1661 } | 1662 } |
| 1662 for (const auto& ownedChild : ownedChildren) | 1663 for (const auto& ownedChild : ownedChildren) |
| 1663 children.append(ownedChild); | 1664 children.push_back(ownedChild); |
| 1664 | 1665 |
| 1665 for (AXObject* child : children) { | 1666 for (AXObject* child : children) { |
| 1666 // Don't recurse into children that are explicitly marked as aria-hidden. | 1667 // Don't recurse into children that are explicitly marked as aria-hidden. |
| 1667 // Note that we don't call isInertOrAriaHidden because that would return | 1668 // Note that we don't call isInertOrAriaHidden because that would return |
| 1668 // true if any ancestor is hidden, but we need to be able to compute the | 1669 // true if any ancestor is hidden, but we need to be able to compute the |
| 1669 // accessible name of object inside hidden subtrees (for example, if | 1670 // accessible name of object inside hidden subtrees (for example, if |
| 1670 // aria-labelledby points to an object that's hidden). | 1671 // aria-labelledby points to an object that's hidden). |
| 1671 if (equalIgnoringCase(child->getAttribute(aria_hiddenAttr), "true")) | 1672 if (equalIgnoringCase(child->getAttribute(aria_hiddenAttr), "true")) |
| 1672 continue; | 1673 continue; |
| 1673 | 1674 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1765 if (getNode()->parentElement()->isInCanvasSubtree()) { | 1766 if (getNode()->parentElement()->isInCanvasSubtree()) { |
| 1766 Vector<FloatRect> rects; | 1767 Vector<FloatRect> rects; |
| 1767 for (Node& child : NodeTraversal::childrenOf(*getNode())) { | 1768 for (Node& child : NodeTraversal::childrenOf(*getNode())) { |
| 1768 if (child.isHTMLElement()) { | 1769 if (child.isHTMLElement()) { |
| 1769 if (AXObject* obj = axObjectCache().get(&child)) { | 1770 if (AXObject* obj = axObjectCache().get(&child)) { |
| 1770 AXObject* container; | 1771 AXObject* container; |
| 1771 FloatRect bounds; | 1772 FloatRect bounds; |
| 1772 obj->getRelativeBounds(&container, bounds, outContainerTransform); | 1773 obj->getRelativeBounds(&container, bounds, outContainerTransform); |
| 1773 if (container) { | 1774 if (container) { |
| 1774 *outContainer = container; | 1775 *outContainer = container; |
| 1775 rects.append(bounds); | 1776 rects.push_back(bounds); |
| 1776 } | 1777 } |
| 1777 } | 1778 } |
| 1778 } | 1779 } |
| 1779 } | 1780 } |
| 1780 | 1781 |
| 1781 if (*outContainer) { | 1782 if (*outContainer) { |
| 1782 outBoundsInContainer = unionRect(rects); | 1783 outBoundsInContainer = unionRect(rects); |
| 1783 return; | 1784 return; |
| 1784 } | 1785 } |
| 1785 } | 1786 } |
| (...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2239 | 2240 |
| 2240 // 5.1/5.5 Text inputs, Other labelable Elements | 2241 // 5.1/5.5 Text inputs, Other labelable Elements |
| 2241 // If you change this logic, update AXNodeObject::nameFromLabelElement, too. | 2242 // If you change this logic, update AXNodeObject::nameFromLabelElement, too. |
| 2242 HTMLElement* htmlElement = nullptr; | 2243 HTMLElement* htmlElement = nullptr; |
| 2243 if (getNode()->isHTMLElement()) | 2244 if (getNode()->isHTMLElement()) |
| 2244 htmlElement = toHTMLElement(getNode()); | 2245 htmlElement = toHTMLElement(getNode()); |
| 2245 | 2246 |
| 2246 if (htmlElement && htmlElement->isLabelable()) { | 2247 if (htmlElement && htmlElement->isLabelable()) { |
| 2247 nameFrom = AXNameFromRelatedElement; | 2248 nameFrom = AXNameFromRelatedElement; |
| 2248 if (nameSources) { | 2249 if (nameSources) { |
| 2249 nameSources->append(NameSource(*foundTextAlternative)); | 2250 nameSources->push_back(NameSource(*foundTextAlternative)); |
| 2250 nameSources->back().type = nameFrom; | 2251 nameSources->back().type = nameFrom; |
| 2251 nameSources->back().nativeSource = AXTextFromNativeHTMLLabel; | 2252 nameSources->back().nativeSource = AXTextFromNativeHTMLLabel; |
| 2252 } | 2253 } |
| 2253 | 2254 |
| 2254 LabelsNodeList* labels = toLabelableElement(htmlElement)->labels(); | 2255 LabelsNodeList* labels = toLabelableElement(htmlElement)->labels(); |
| 2255 if (labels && labels->length() > 0) { | 2256 if (labels && labels->length() > 0) { |
| 2256 HeapVector<Member<Element>> labelElements; | 2257 HeapVector<Member<Element>> labelElements; |
| 2257 for (unsigned labelIndex = 0; labelIndex < labels->length(); | 2258 for (unsigned labelIndex = 0; labelIndex < labels->length(); |
| 2258 ++labelIndex) { | 2259 ++labelIndex) { |
| 2259 Element* label = labels->item(labelIndex); | 2260 Element* label = labels->item(labelIndex); |
| 2260 if (nameSources) { | 2261 if (nameSources) { |
| 2261 if (label->getAttribute(forAttr) == htmlElement->getIdAttribute()) | 2262 if (label->getAttribute(forAttr) == htmlElement->getIdAttribute()) |
| 2262 nameSources->back().nativeSource = AXTextFromNativeHTMLLabelFor; | 2263 nameSources->back().nativeSource = AXTextFromNativeHTMLLabelFor; |
| 2263 else | 2264 else |
| 2264 nameSources->back().nativeSource = AXTextFromNativeHTMLLabelWrapped; | 2265 nameSources->back().nativeSource = AXTextFromNativeHTMLLabelWrapped; |
| 2265 } | 2266 } |
| 2266 labelElements.append(label); | 2267 labelElements.push_back(label); |
| 2267 } | 2268 } |
| 2268 | 2269 |
| 2269 textAlternative = | 2270 textAlternative = |
| 2270 textFromElements(false, visited, labelElements, relatedObjects); | 2271 textFromElements(false, visited, labelElements, relatedObjects); |
| 2271 if (!textAlternative.isNull()) { | 2272 if (!textAlternative.isNull()) { |
| 2272 *foundTextAlternative = true; | 2273 *foundTextAlternative = true; |
| 2273 if (nameSources) { | 2274 if (nameSources) { |
| 2274 NameSource& source = nameSources->back(); | 2275 NameSource& source = nameSources->back(); |
| 2275 source.relatedObjects = *relatedObjects; | 2276 source.relatedObjects = *relatedObjects; |
| 2276 source.text = textAlternative; | 2277 source.text = textAlternative; |
| 2277 } else { | 2278 } else { |
| 2278 return textAlternative; | 2279 return textAlternative; |
| 2279 } | 2280 } |
| 2280 } else if (nameSources) { | 2281 } else if (nameSources) { |
| 2281 nameSources->back().invalid = true; | 2282 nameSources->back().invalid = true; |
| 2282 } | 2283 } |
| 2283 } | 2284 } |
| 2284 } | 2285 } |
| 2285 | 2286 |
| 2286 // 5.2 input type="button", input type="submit" and input type="reset" | 2287 // 5.2 input type="button", input type="submit" and input type="reset" |
| 2287 if (inputElement && inputElement->isTextButton()) { | 2288 if (inputElement && inputElement->isTextButton()) { |
| 2288 // value attribue | 2289 // value attribue |
| 2289 nameFrom = AXNameFromValue; | 2290 nameFrom = AXNameFromValue; |
| 2290 if (nameSources) { | 2291 if (nameSources) { |
| 2291 nameSources->append(NameSource(*foundTextAlternative, valueAttr)); | 2292 nameSources->push_back(NameSource(*foundTextAlternative, valueAttr)); |
| 2292 nameSources->back().type = nameFrom; | 2293 nameSources->back().type = nameFrom; |
| 2293 } | 2294 } |
| 2294 String value = inputElement->value(); | 2295 String value = inputElement->value(); |
| 2295 if (!value.isNull()) { | 2296 if (!value.isNull()) { |
| 2296 textAlternative = value; | 2297 textAlternative = value; |
| 2297 if (nameSources) { | 2298 if (nameSources) { |
| 2298 NameSource& source = nameSources->back(); | 2299 NameSource& source = nameSources->back(); |
| 2299 source.text = textAlternative; | 2300 source.text = textAlternative; |
| 2300 *foundTextAlternative = true; | 2301 *foundTextAlternative = true; |
| 2301 } else { | 2302 } else { |
| 2302 return textAlternative; | 2303 return textAlternative; |
| 2303 } | 2304 } |
| 2304 } | 2305 } |
| 2305 return textAlternative; | 2306 return textAlternative; |
| 2306 } | 2307 } |
| 2307 | 2308 |
| 2308 // 5.3 input type="image" | 2309 // 5.3 input type="image" |
| 2309 if (inputElement && | 2310 if (inputElement && |
| 2310 inputElement->getAttribute(typeAttr) == InputTypeNames::image) { | 2311 inputElement->getAttribute(typeAttr) == InputTypeNames::image) { |
| 2311 // alt attr | 2312 // alt attr |
| 2312 nameFrom = AXNameFromAttribute; | 2313 nameFrom = AXNameFromAttribute; |
| 2313 if (nameSources) { | 2314 if (nameSources) { |
| 2314 nameSources->append(NameSource(*foundTextAlternative, altAttr)); | 2315 nameSources->push_back(NameSource(*foundTextAlternative, altAttr)); |
| 2315 nameSources->back().type = nameFrom; | 2316 nameSources->back().type = nameFrom; |
| 2316 } | 2317 } |
| 2317 const AtomicString& alt = inputElement->getAttribute(altAttr); | 2318 const AtomicString& alt = inputElement->getAttribute(altAttr); |
| 2318 if (!alt.isNull()) { | 2319 if (!alt.isNull()) { |
| 2319 textAlternative = alt; | 2320 textAlternative = alt; |
| 2320 if (nameSources) { | 2321 if (nameSources) { |
| 2321 NameSource& source = nameSources->back(); | 2322 NameSource& source = nameSources->back(); |
| 2322 source.attributeValue = alt; | 2323 source.attributeValue = alt; |
| 2323 source.text = textAlternative; | 2324 source.text = textAlternative; |
| 2324 *foundTextAlternative = true; | 2325 *foundTextAlternative = true; |
| 2325 } else { | 2326 } else { |
| 2326 return textAlternative; | 2327 return textAlternative; |
| 2327 } | 2328 } |
| 2328 } | 2329 } |
| 2329 | 2330 |
| 2330 // value attr | 2331 // value attr |
| 2331 if (nameSources) { | 2332 if (nameSources) { |
| 2332 nameSources->append(NameSource(*foundTextAlternative, valueAttr)); | 2333 nameSources->push_back(NameSource(*foundTextAlternative, valueAttr)); |
| 2333 nameSources->back().type = nameFrom; | 2334 nameSources->back().type = nameFrom; |
| 2334 } | 2335 } |
| 2335 nameFrom = AXNameFromAttribute; | 2336 nameFrom = AXNameFromAttribute; |
| 2336 String value = inputElement->value(); | 2337 String value = inputElement->value(); |
| 2337 if (!value.isNull()) { | 2338 if (!value.isNull()) { |
| 2338 textAlternative = value; | 2339 textAlternative = value; |
| 2339 if (nameSources) { | 2340 if (nameSources) { |
| 2340 NameSource& source = nameSources->back(); | 2341 NameSource& source = nameSources->back(); |
| 2341 source.text = textAlternative; | 2342 source.text = textAlternative; |
| 2342 *foundTextAlternative = true; | 2343 *foundTextAlternative = true; |
| 2343 } else { | 2344 } else { |
| 2344 return textAlternative; | 2345 return textAlternative; |
| 2345 } | 2346 } |
| 2346 } | 2347 } |
| 2347 | 2348 |
| 2348 // localised default value ("Submit") | 2349 // localised default value ("Submit") |
| 2349 nameFrom = AXNameFromValue; | 2350 nameFrom = AXNameFromValue; |
| 2350 textAlternative = inputElement->locale().queryString( | 2351 textAlternative = inputElement->locale().queryString( |
| 2351 WebLocalizedString::SubmitButtonDefaultLabel); | 2352 WebLocalizedString::SubmitButtonDefaultLabel); |
| 2352 if (nameSources) { | 2353 if (nameSources) { |
| 2353 nameSources->append(NameSource(*foundTextAlternative, typeAttr)); | 2354 nameSources->push_back(NameSource(*foundTextAlternative, typeAttr)); |
| 2354 NameSource& source = nameSources->back(); | 2355 NameSource& source = nameSources->back(); |
| 2355 source.attributeValue = inputElement->getAttribute(typeAttr); | 2356 source.attributeValue = inputElement->getAttribute(typeAttr); |
| 2356 source.type = nameFrom; | 2357 source.type = nameFrom; |
| 2357 source.text = textAlternative; | 2358 source.text = textAlternative; |
| 2358 *foundTextAlternative = true; | 2359 *foundTextAlternative = true; |
| 2359 } else { | 2360 } else { |
| 2360 return textAlternative; | 2361 return textAlternative; |
| 2361 } | 2362 } |
| 2362 return textAlternative; | 2363 return textAlternative; |
| 2363 } | 2364 } |
| 2364 | 2365 |
| 2365 // 5.1 Text inputs - step 3 (placeholder attribute) | 2366 // 5.1 Text inputs - step 3 (placeholder attribute) |
| 2366 if (htmlElement && htmlElement->isTextControl()) { | 2367 if (htmlElement && htmlElement->isTextControl()) { |
| 2367 nameFrom = AXNameFromPlaceholder; | 2368 nameFrom = AXNameFromPlaceholder; |
| 2368 if (nameSources) { | 2369 if (nameSources) { |
| 2369 nameSources->append(NameSource(*foundTextAlternative, placeholderAttr)); | 2370 nameSources->push_back( |
| 2371 NameSource(*foundTextAlternative, placeholderAttr)); |
| 2370 NameSource& source = nameSources->back(); | 2372 NameSource& source = nameSources->back(); |
| 2371 source.type = nameFrom; | 2373 source.type = nameFrom; |
| 2372 } | 2374 } |
| 2373 const String placeholder = placeholderFromNativeAttribute(); | 2375 const String placeholder = placeholderFromNativeAttribute(); |
| 2374 if (!placeholder.isEmpty()) { | 2376 if (!placeholder.isEmpty()) { |
| 2375 textAlternative = placeholder; | 2377 textAlternative = placeholder; |
| 2376 if (nameSources) { | 2378 if (nameSources) { |
| 2377 NameSource& source = nameSources->back(); | 2379 NameSource& source = nameSources->back(); |
| 2378 source.text = textAlternative; | 2380 source.text = textAlternative; |
| 2379 source.attributeValue = htmlElement->fastGetAttribute(placeholderAttr); | 2381 source.attributeValue = htmlElement->fastGetAttribute(placeholderAttr); |
| 2380 *foundTextAlternative = true; | 2382 *foundTextAlternative = true; |
| 2381 } else { | 2383 } else { |
| 2382 return textAlternative; | 2384 return textAlternative; |
| 2383 } | 2385 } |
| 2384 } | 2386 } |
| 2385 | 2387 |
| 2386 // Also check for aria-placeholder. | 2388 // Also check for aria-placeholder. |
| 2387 nameFrom = AXNameFromPlaceholder; | 2389 nameFrom = AXNameFromPlaceholder; |
| 2388 if (nameSources) { | 2390 if (nameSources) { |
| 2389 nameSources->append( | 2391 nameSources->push_back( |
| 2390 NameSource(*foundTextAlternative, aria_placeholderAttr)); | 2392 NameSource(*foundTextAlternative, aria_placeholderAttr)); |
| 2391 NameSource& source = nameSources->back(); | 2393 NameSource& source = nameSources->back(); |
| 2392 source.type = nameFrom; | 2394 source.type = nameFrom; |
| 2393 } | 2395 } |
| 2394 const AtomicString& ariaPlaceholder = | 2396 const AtomicString& ariaPlaceholder = |
| 2395 htmlElement->fastGetAttribute(aria_placeholderAttr); | 2397 htmlElement->fastGetAttribute(aria_placeholderAttr); |
| 2396 if (!ariaPlaceholder.isEmpty()) { | 2398 if (!ariaPlaceholder.isEmpty()) { |
| 2397 textAlternative = ariaPlaceholder; | 2399 textAlternative = ariaPlaceholder; |
| 2398 if (nameSources) { | 2400 if (nameSources) { |
| 2399 NameSource& source = nameSources->back(); | 2401 NameSource& source = nameSources->back(); |
| 2400 source.text = textAlternative; | 2402 source.text = textAlternative; |
| 2401 source.attributeValue = ariaPlaceholder; | 2403 source.attributeValue = ariaPlaceholder; |
| 2402 *foundTextAlternative = true; | 2404 *foundTextAlternative = true; |
| 2403 } else { | 2405 } else { |
| 2404 return textAlternative; | 2406 return textAlternative; |
| 2405 } | 2407 } |
| 2406 } | 2408 } |
| 2407 | 2409 |
| 2408 return textAlternative; | 2410 return textAlternative; |
| 2409 } | 2411 } |
| 2410 | 2412 |
| 2411 // 5.7 figure and figcaption Elements | 2413 // 5.7 figure and figcaption Elements |
| 2412 if (getNode()->hasTagName(figureTag)) { | 2414 if (getNode()->hasTagName(figureTag)) { |
| 2413 // figcaption | 2415 // figcaption |
| 2414 nameFrom = AXNameFromRelatedElement; | 2416 nameFrom = AXNameFromRelatedElement; |
| 2415 if (nameSources) { | 2417 if (nameSources) { |
| 2416 nameSources->append(NameSource(*foundTextAlternative)); | 2418 nameSources->push_back(NameSource(*foundTextAlternative)); |
| 2417 nameSources->back().type = nameFrom; | 2419 nameSources->back().type = nameFrom; |
| 2418 nameSources->back().nativeSource = AXTextFromNativeHTMLFigcaption; | 2420 nameSources->back().nativeSource = AXTextFromNativeHTMLFigcaption; |
| 2419 } | 2421 } |
| 2420 Element* figcaption = nullptr; | 2422 Element* figcaption = nullptr; |
| 2421 for (Element& element : ElementTraversal::descendantsOf(*(getNode()))) { | 2423 for (Element& element : ElementTraversal::descendantsOf(*(getNode()))) { |
| 2422 if (element.hasTagName(figcaptionTag)) { | 2424 if (element.hasTagName(figcaptionTag)) { |
| 2423 figcaption = &element; | 2425 figcaption = &element; |
| 2424 break; | 2426 break; |
| 2425 } | 2427 } |
| 2426 } | 2428 } |
| 2427 if (figcaption) { | 2429 if (figcaption) { |
| 2428 AXObject* figcaptionAXObject = axObjectCache().getOrCreate(figcaption); | 2430 AXObject* figcaptionAXObject = axObjectCache().getOrCreate(figcaption); |
| 2429 if (figcaptionAXObject) { | 2431 if (figcaptionAXObject) { |
| 2430 textAlternative = | 2432 textAlternative = |
| 2431 recursiveTextAlternative(*figcaptionAXObject, false, visited); | 2433 recursiveTextAlternative(*figcaptionAXObject, false, visited); |
| 2432 | 2434 |
| 2433 if (relatedObjects) { | 2435 if (relatedObjects) { |
| 2434 localRelatedObjects.append( | 2436 localRelatedObjects.push_back( |
| 2435 new NameSourceRelatedObject(figcaptionAXObject, textAlternative)); | 2437 new NameSourceRelatedObject(figcaptionAXObject, textAlternative)); |
| 2436 *relatedObjects = localRelatedObjects; | 2438 *relatedObjects = localRelatedObjects; |
| 2437 localRelatedObjects.clear(); | 2439 localRelatedObjects.clear(); |
| 2438 } | 2440 } |
| 2439 | 2441 |
| 2440 if (nameSources) { | 2442 if (nameSources) { |
| 2441 NameSource& source = nameSources->back(); | 2443 NameSource& source = nameSources->back(); |
| 2442 source.relatedObjects = *relatedObjects; | 2444 source.relatedObjects = *relatedObjects; |
| 2443 source.text = textAlternative; | 2445 source.text = textAlternative; |
| 2444 *foundTextAlternative = true; | 2446 *foundTextAlternative = true; |
| 2445 } else { | 2447 } else { |
| 2446 return textAlternative; | 2448 return textAlternative; |
| 2447 } | 2449 } |
| 2448 } | 2450 } |
| 2449 } | 2451 } |
| 2450 return textAlternative; | 2452 return textAlternative; |
| 2451 } | 2453 } |
| 2452 | 2454 |
| 2453 // 5.8 img or area Element | 2455 // 5.8 img or area Element |
| 2454 if (isHTMLImageElement(getNode()) || isHTMLAreaElement(getNode()) || | 2456 if (isHTMLImageElement(getNode()) || isHTMLAreaElement(getNode()) || |
| 2455 (getLayoutObject() && getLayoutObject()->isSVGImage())) { | 2457 (getLayoutObject() && getLayoutObject()->isSVGImage())) { |
| 2456 // alt | 2458 // alt |
| 2457 nameFrom = AXNameFromAttribute; | 2459 nameFrom = AXNameFromAttribute; |
| 2458 if (nameSources) { | 2460 if (nameSources) { |
| 2459 nameSources->append(NameSource(*foundTextAlternative, altAttr)); | 2461 nameSources->push_back(NameSource(*foundTextAlternative, altAttr)); |
| 2460 nameSources->back().type = nameFrom; | 2462 nameSources->back().type = nameFrom; |
| 2461 } | 2463 } |
| 2462 const AtomicString& alt = getAttribute(altAttr); | 2464 const AtomicString& alt = getAttribute(altAttr); |
| 2463 if (!alt.isNull()) { | 2465 if (!alt.isNull()) { |
| 2464 textAlternative = alt; | 2466 textAlternative = alt; |
| 2465 if (nameSources) { | 2467 if (nameSources) { |
| 2466 NameSource& source = nameSources->back(); | 2468 NameSource& source = nameSources->back(); |
| 2467 source.attributeValue = alt; | 2469 source.attributeValue = alt; |
| 2468 source.text = textAlternative; | 2470 source.text = textAlternative; |
| 2469 *foundTextAlternative = true; | 2471 *foundTextAlternative = true; |
| 2470 } else { | 2472 } else { |
| 2471 return textAlternative; | 2473 return textAlternative; |
| 2472 } | 2474 } |
| 2473 } | 2475 } |
| 2474 return textAlternative; | 2476 return textAlternative; |
| 2475 } | 2477 } |
| 2476 | 2478 |
| 2477 // 5.9 table Element | 2479 // 5.9 table Element |
| 2478 if (isHTMLTableElement(getNode())) { | 2480 if (isHTMLTableElement(getNode())) { |
| 2479 HTMLTableElement* tableElement = toHTMLTableElement(getNode()); | 2481 HTMLTableElement* tableElement = toHTMLTableElement(getNode()); |
| 2480 | 2482 |
| 2481 // caption | 2483 // caption |
| 2482 nameFrom = AXNameFromCaption; | 2484 nameFrom = AXNameFromCaption; |
| 2483 if (nameSources) { | 2485 if (nameSources) { |
| 2484 nameSources->append(NameSource(*foundTextAlternative)); | 2486 nameSources->push_back(NameSource(*foundTextAlternative)); |
| 2485 nameSources->back().type = nameFrom; | 2487 nameSources->back().type = nameFrom; |
| 2486 nameSources->back().nativeSource = AXTextFromNativeHTMLTableCaption; | 2488 nameSources->back().nativeSource = AXTextFromNativeHTMLTableCaption; |
| 2487 } | 2489 } |
| 2488 HTMLTableCaptionElement* caption = tableElement->caption(); | 2490 HTMLTableCaptionElement* caption = tableElement->caption(); |
| 2489 if (caption) { | 2491 if (caption) { |
| 2490 AXObject* captionAXObject = axObjectCache().getOrCreate(caption); | 2492 AXObject* captionAXObject = axObjectCache().getOrCreate(caption); |
| 2491 if (captionAXObject) { | 2493 if (captionAXObject) { |
| 2492 textAlternative = | 2494 textAlternative = |
| 2493 recursiveTextAlternative(*captionAXObject, false, visited); | 2495 recursiveTextAlternative(*captionAXObject, false, visited); |
| 2494 if (relatedObjects) { | 2496 if (relatedObjects) { |
| 2495 localRelatedObjects.append( | 2497 localRelatedObjects.push_back( |
| 2496 new NameSourceRelatedObject(captionAXObject, textAlternative)); | 2498 new NameSourceRelatedObject(captionAXObject, textAlternative)); |
| 2497 *relatedObjects = localRelatedObjects; | 2499 *relatedObjects = localRelatedObjects; |
| 2498 localRelatedObjects.clear(); | 2500 localRelatedObjects.clear(); |
| 2499 } | 2501 } |
| 2500 | 2502 |
| 2501 if (nameSources) { | 2503 if (nameSources) { |
| 2502 NameSource& source = nameSources->back(); | 2504 NameSource& source = nameSources->back(); |
| 2503 source.relatedObjects = *relatedObjects; | 2505 source.relatedObjects = *relatedObjects; |
| 2504 source.text = textAlternative; | 2506 source.text = textAlternative; |
| 2505 *foundTextAlternative = true; | 2507 *foundTextAlternative = true; |
| 2506 } else { | 2508 } else { |
| 2507 return textAlternative; | 2509 return textAlternative; |
| 2508 } | 2510 } |
| 2509 } | 2511 } |
| 2510 } | 2512 } |
| 2511 | 2513 |
| 2512 // summary | 2514 // summary |
| 2513 nameFrom = AXNameFromAttribute; | 2515 nameFrom = AXNameFromAttribute; |
| 2514 if (nameSources) { | 2516 if (nameSources) { |
| 2515 nameSources->append(NameSource(*foundTextAlternative, summaryAttr)); | 2517 nameSources->push_back(NameSource(*foundTextAlternative, summaryAttr)); |
| 2516 nameSources->back().type = nameFrom; | 2518 nameSources->back().type = nameFrom; |
| 2517 } | 2519 } |
| 2518 const AtomicString& summary = getAttribute(summaryAttr); | 2520 const AtomicString& summary = getAttribute(summaryAttr); |
| 2519 if (!summary.isNull()) { | 2521 if (!summary.isNull()) { |
| 2520 textAlternative = summary; | 2522 textAlternative = summary; |
| 2521 if (nameSources) { | 2523 if (nameSources) { |
| 2522 NameSource& source = nameSources->back(); | 2524 NameSource& source = nameSources->back(); |
| 2523 source.attributeValue = summary; | 2525 source.attributeValue = summary; |
| 2524 source.text = textAlternative; | 2526 source.text = textAlternative; |
| 2525 *foundTextAlternative = true; | 2527 *foundTextAlternative = true; |
| 2526 } else { | 2528 } else { |
| 2527 return textAlternative; | 2529 return textAlternative; |
| 2528 } | 2530 } |
| 2529 } | 2531 } |
| 2530 | 2532 |
| 2531 return textAlternative; | 2533 return textAlternative; |
| 2532 } | 2534 } |
| 2533 | 2535 |
| 2534 // Per SVG AAM 1.0's modifications to 2D of this algorithm. | 2536 // Per SVG AAM 1.0's modifications to 2D of this algorithm. |
| 2535 if (getNode()->isSVGElement()) { | 2537 if (getNode()->isSVGElement()) { |
| 2536 nameFrom = AXNameFromRelatedElement; | 2538 nameFrom = AXNameFromRelatedElement; |
| 2537 if (nameSources) { | 2539 if (nameSources) { |
| 2538 nameSources->append(NameSource(*foundTextAlternative)); | 2540 nameSources->push_back(NameSource(*foundTextAlternative)); |
| 2539 nameSources->back().type = nameFrom; | 2541 nameSources->back().type = nameFrom; |
| 2540 nameSources->back().nativeSource = AXTextFromNativeHTMLTitleElement; | 2542 nameSources->back().nativeSource = AXTextFromNativeHTMLTitleElement; |
| 2541 } | 2543 } |
| 2542 ASSERT(getNode()->isContainerNode()); | 2544 ASSERT(getNode()->isContainerNode()); |
| 2543 Element* title = ElementTraversal::firstChild( | 2545 Element* title = ElementTraversal::firstChild( |
| 2544 toContainerNode(*(getNode())), HasTagName(SVGNames::titleTag)); | 2546 toContainerNode(*(getNode())), HasTagName(SVGNames::titleTag)); |
| 2545 | 2547 |
| 2546 if (title) { | 2548 if (title) { |
| 2547 AXObject* titleAXObject = axObjectCache().getOrCreate(title); | 2549 AXObject* titleAXObject = axObjectCache().getOrCreate(title); |
| 2548 if (titleAXObject && !visited.contains(titleAXObject)) { | 2550 if (titleAXObject && !visited.contains(titleAXObject)) { |
| 2549 textAlternative = | 2551 textAlternative = |
| 2550 recursiveTextAlternative(*titleAXObject, false, visited); | 2552 recursiveTextAlternative(*titleAXObject, false, visited); |
| 2551 if (relatedObjects) { | 2553 if (relatedObjects) { |
| 2552 localRelatedObjects.append( | 2554 localRelatedObjects.push_back( |
| 2553 new NameSourceRelatedObject(titleAXObject, textAlternative)); | 2555 new NameSourceRelatedObject(titleAXObject, textAlternative)); |
| 2554 *relatedObjects = localRelatedObjects; | 2556 *relatedObjects = localRelatedObjects; |
| 2555 localRelatedObjects.clear(); | 2557 localRelatedObjects.clear(); |
| 2556 } | 2558 } |
| 2557 } | 2559 } |
| 2558 if (nameSources) { | 2560 if (nameSources) { |
| 2559 NameSource& source = nameSources->back(); | 2561 NameSource& source = nameSources->back(); |
| 2560 source.text = textAlternative; | 2562 source.text = textAlternative; |
| 2561 source.relatedObjects = *relatedObjects; | 2563 source.relatedObjects = *relatedObjects; |
| 2562 *foundTextAlternative = true; | 2564 *foundTextAlternative = true; |
| 2563 } else { | 2565 } else { |
| 2564 return textAlternative; | 2566 return textAlternative; |
| 2565 } | 2567 } |
| 2566 } | 2568 } |
| 2567 } | 2569 } |
| 2568 | 2570 |
| 2569 // Fieldset / legend. | 2571 // Fieldset / legend. |
| 2570 if (isHTMLFieldSetElement(getNode())) { | 2572 if (isHTMLFieldSetElement(getNode())) { |
| 2571 nameFrom = AXNameFromRelatedElement; | 2573 nameFrom = AXNameFromRelatedElement; |
| 2572 if (nameSources) { | 2574 if (nameSources) { |
| 2573 nameSources->append(NameSource(*foundTextAlternative)); | 2575 nameSources->push_back(NameSource(*foundTextAlternative)); |
| 2574 nameSources->back().type = nameFrom; | 2576 nameSources->back().type = nameFrom; |
| 2575 nameSources->back().nativeSource = AXTextFromNativeHTMLLegend; | 2577 nameSources->back().nativeSource = AXTextFromNativeHTMLLegend; |
| 2576 } | 2578 } |
| 2577 HTMLElement* legend = toHTMLFieldSetElement(getNode())->legend(); | 2579 HTMLElement* legend = toHTMLFieldSetElement(getNode())->legend(); |
| 2578 if (legend) { | 2580 if (legend) { |
| 2579 AXObject* legendAXObject = axObjectCache().getOrCreate(legend); | 2581 AXObject* legendAXObject = axObjectCache().getOrCreate(legend); |
| 2580 // Avoid an infinite loop | 2582 // Avoid an infinite loop |
| 2581 if (legendAXObject && !visited.contains(legendAXObject)) { | 2583 if (legendAXObject && !visited.contains(legendAXObject)) { |
| 2582 textAlternative = | 2584 textAlternative = |
| 2583 recursiveTextAlternative(*legendAXObject, false, visited); | 2585 recursiveTextAlternative(*legendAXObject, false, visited); |
| 2584 | 2586 |
| 2585 if (relatedObjects) { | 2587 if (relatedObjects) { |
| 2586 localRelatedObjects.append( | 2588 localRelatedObjects.push_back( |
| 2587 new NameSourceRelatedObject(legendAXObject, textAlternative)); | 2589 new NameSourceRelatedObject(legendAXObject, textAlternative)); |
| 2588 *relatedObjects = localRelatedObjects; | 2590 *relatedObjects = localRelatedObjects; |
| 2589 localRelatedObjects.clear(); | 2591 localRelatedObjects.clear(); |
| 2590 } | 2592 } |
| 2591 | 2593 |
| 2592 if (nameSources) { | 2594 if (nameSources) { |
| 2593 NameSource& source = nameSources->back(); | 2595 NameSource& source = nameSources->back(); |
| 2594 source.relatedObjects = *relatedObjects; | 2596 source.relatedObjects = *relatedObjects; |
| 2595 source.text = textAlternative; | 2597 source.text = textAlternative; |
| 2596 *foundTextAlternative = true; | 2598 *foundTextAlternative = true; |
| 2597 } else { | 2599 } else { |
| 2598 return textAlternative; | 2600 return textAlternative; |
| 2599 } | 2601 } |
| 2600 } | 2602 } |
| 2601 } | 2603 } |
| 2602 } | 2604 } |
| 2603 | 2605 |
| 2604 // Document. | 2606 // Document. |
| 2605 if (isWebArea()) { | 2607 if (isWebArea()) { |
| 2606 Document* document = this->getDocument(); | 2608 Document* document = this->getDocument(); |
| 2607 if (document) { | 2609 if (document) { |
| 2608 nameFrom = AXNameFromAttribute; | 2610 nameFrom = AXNameFromAttribute; |
| 2609 if (nameSources) { | 2611 if (nameSources) { |
| 2610 nameSources->append(NameSource(foundTextAlternative, aria_labelAttr)); | 2612 nameSources->push_back( |
| 2613 NameSource(foundTextAlternative, aria_labelAttr)); |
| 2611 nameSources->back().type = nameFrom; | 2614 nameSources->back().type = nameFrom; |
| 2612 } | 2615 } |
| 2613 if (Element* documentElement = document->documentElement()) { | 2616 if (Element* documentElement = document->documentElement()) { |
| 2614 const AtomicString& ariaLabel = | 2617 const AtomicString& ariaLabel = |
| 2615 documentElement->getAttribute(aria_labelAttr); | 2618 documentElement->getAttribute(aria_labelAttr); |
| 2616 if (!ariaLabel.isEmpty()) { | 2619 if (!ariaLabel.isEmpty()) { |
| 2617 textAlternative = ariaLabel; | 2620 textAlternative = ariaLabel; |
| 2618 | 2621 |
| 2619 if (nameSources) { | 2622 if (nameSources) { |
| 2620 NameSource& source = nameSources->back(); | 2623 NameSource& source = nameSources->back(); |
| 2621 source.text = textAlternative; | 2624 source.text = textAlternative; |
| 2622 source.attributeValue = ariaLabel; | 2625 source.attributeValue = ariaLabel; |
| 2623 *foundTextAlternative = true; | 2626 *foundTextAlternative = true; |
| 2624 } else { | 2627 } else { |
| 2625 return textAlternative; | 2628 return textAlternative; |
| 2626 } | 2629 } |
| 2627 } | 2630 } |
| 2628 } | 2631 } |
| 2629 | 2632 |
| 2630 nameFrom = AXNameFromRelatedElement; | 2633 nameFrom = AXNameFromRelatedElement; |
| 2631 if (nameSources) { | 2634 if (nameSources) { |
| 2632 nameSources->append(NameSource(*foundTextAlternative)); | 2635 nameSources->push_back(NameSource(*foundTextAlternative)); |
| 2633 nameSources->back().type = nameFrom; | 2636 nameSources->back().type = nameFrom; |
| 2634 nameSources->back().nativeSource = AXTextFromNativeHTMLTitleElement; | 2637 nameSources->back().nativeSource = AXTextFromNativeHTMLTitleElement; |
| 2635 } | 2638 } |
| 2636 | 2639 |
| 2637 textAlternative = document->title(); | 2640 textAlternative = document->title(); |
| 2638 | 2641 |
| 2639 Element* titleElement = document->titleElement(); | 2642 Element* titleElement = document->titleElement(); |
| 2640 AXObject* titleAXObject = axObjectCache().getOrCreate(titleElement); | 2643 AXObject* titleAXObject = axObjectCache().getOrCreate(titleElement); |
| 2641 if (titleAXObject) { | 2644 if (titleAXObject) { |
| 2642 if (relatedObjects) { | 2645 if (relatedObjects) { |
| 2643 localRelatedObjects.append( | 2646 localRelatedObjects.push_back( |
| 2644 new NameSourceRelatedObject(titleAXObject, textAlternative)); | 2647 new NameSourceRelatedObject(titleAXObject, textAlternative)); |
| 2645 *relatedObjects = localRelatedObjects; | 2648 *relatedObjects = localRelatedObjects; |
| 2646 localRelatedObjects.clear(); | 2649 localRelatedObjects.clear(); |
| 2647 } | 2650 } |
| 2648 | 2651 |
| 2649 if (nameSources) { | 2652 if (nameSources) { |
| 2650 NameSource& source = nameSources->back(); | 2653 NameSource& source = nameSources->back(); |
| 2651 source.relatedObjects = *relatedObjects; | 2654 source.relatedObjects = *relatedObjects; |
| 2652 source.text = textAlternative; | 2655 source.text = textAlternative; |
| 2653 *foundTextAlternative = true; | 2656 *foundTextAlternative = true; |
| 2654 } else { | 2657 } else { |
| 2655 return textAlternative; | 2658 return textAlternative; |
| 2656 } | 2659 } |
| 2657 } | 2660 } |
| 2658 } | 2661 } |
| 2659 } | 2662 } |
| 2660 | 2663 |
| 2661 return textAlternative; | 2664 return textAlternative; |
| 2662 } | 2665 } |
| 2663 | 2666 |
| 2664 String AXNodeObject::description(AXNameFrom nameFrom, | 2667 String AXNodeObject::description(AXNameFrom nameFrom, |
| 2665 AXDescriptionFrom& descriptionFrom, | 2668 AXDescriptionFrom& descriptionFrom, |
| 2666 AXObjectVector* descriptionObjects) const { | 2669 AXObjectVector* descriptionObjects) const { |
| 2667 AXRelatedObjectVector relatedObjects; | 2670 AXRelatedObjectVector relatedObjects; |
| 2668 String result = | 2671 String result = |
| 2669 description(nameFrom, descriptionFrom, nullptr, &relatedObjects); | 2672 description(nameFrom, descriptionFrom, nullptr, &relatedObjects); |
| 2670 if (descriptionObjects) { | 2673 if (descriptionObjects) { |
| 2671 descriptionObjects->clear(); | 2674 descriptionObjects->clear(); |
| 2672 for (size_t i = 0; i < relatedObjects.size(); i++) | 2675 for (size_t i = 0; i < relatedObjects.size(); i++) |
| 2673 descriptionObjects->append(relatedObjects[i]->object); | 2676 descriptionObjects->push_back(relatedObjects[i]->object); |
| 2674 } | 2677 } |
| 2675 | 2678 |
| 2676 return collapseWhitespace(result); | 2679 return collapseWhitespace(result); |
| 2677 } | 2680 } |
| 2678 | 2681 |
| 2679 // Based on | 2682 // Based on |
| 2680 // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible-name-and-
description-calculation | 2683 // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible-name-and-
description-calculation |
| 2681 String AXNodeObject::description(AXNameFrom nameFrom, | 2684 String AXNodeObject::description(AXNameFrom nameFrom, |
| 2682 AXDescriptionFrom& descriptionFrom, | 2685 AXDescriptionFrom& descriptionFrom, |
| 2683 DescriptionSources* descriptionSources, | 2686 DescriptionSources* descriptionSources, |
| 2684 AXRelatedObjectVector* relatedObjects) const { | 2687 AXRelatedObjectVector* relatedObjects) const { |
| 2685 // If descriptionSources is non-null, relatedObjects is used in filling it in, | 2688 // If descriptionSources is non-null, relatedObjects is used in filling it in, |
| 2686 // so it must be non-null as well. | 2689 // so it must be non-null as well. |
| 2687 if (descriptionSources) | 2690 if (descriptionSources) |
| 2688 ASSERT(relatedObjects); | 2691 ASSERT(relatedObjects); |
| 2689 | 2692 |
| 2690 if (!getNode()) | 2693 if (!getNode()) |
| 2691 return String(); | 2694 return String(); |
| 2692 | 2695 |
| 2693 String description; | 2696 String description; |
| 2694 bool foundDescription = false; | 2697 bool foundDescription = false; |
| 2695 | 2698 |
| 2696 descriptionFrom = AXDescriptionFromRelatedElement; | 2699 descriptionFrom = AXDescriptionFromRelatedElement; |
| 2697 if (descriptionSources) { | 2700 if (descriptionSources) { |
| 2698 descriptionSources->append( | 2701 descriptionSources->push_back( |
| 2699 DescriptionSource(foundDescription, aria_describedbyAttr)); | 2702 DescriptionSource(foundDescription, aria_describedbyAttr)); |
| 2700 descriptionSources->back().type = descriptionFrom; | 2703 descriptionSources->back().type = descriptionFrom; |
| 2701 } | 2704 } |
| 2702 | 2705 |
| 2703 // aria-describedby overrides any other accessible description, from: | 2706 // aria-describedby overrides any other accessible description, from: |
| 2704 // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html | 2707 // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html |
| 2705 const AtomicString& ariaDescribedby = getAttribute(aria_describedbyAttr); | 2708 const AtomicString& ariaDescribedby = getAttribute(aria_describedbyAttr); |
| 2706 if (!ariaDescribedby.isNull()) { | 2709 if (!ariaDescribedby.isNull()) { |
| 2707 if (descriptionSources) | 2710 if (descriptionSources) |
| 2708 descriptionSources->back().attributeValue = ariaDescribedby; | 2711 descriptionSources->back().attributeValue = ariaDescribedby; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2726 | 2729 |
| 2727 const HTMLInputElement* inputElement = nullptr; | 2730 const HTMLInputElement* inputElement = nullptr; |
| 2728 if (isHTMLInputElement(getNode())) | 2731 if (isHTMLInputElement(getNode())) |
| 2729 inputElement = toHTMLInputElement(getNode()); | 2732 inputElement = toHTMLInputElement(getNode()); |
| 2730 | 2733 |
| 2731 // value, 5.2.2 from: http://rawgit.com/w3c/aria/master/html-aam/html-aam.html | 2734 // value, 5.2.2 from: http://rawgit.com/w3c/aria/master/html-aam/html-aam.html |
| 2732 if (nameFrom != AXNameFromValue && inputElement && | 2735 if (nameFrom != AXNameFromValue && inputElement && |
| 2733 inputElement->isTextButton()) { | 2736 inputElement->isTextButton()) { |
| 2734 descriptionFrom = AXDescriptionFromAttribute; | 2737 descriptionFrom = AXDescriptionFromAttribute; |
| 2735 if (descriptionSources) { | 2738 if (descriptionSources) { |
| 2736 descriptionSources->append( | 2739 descriptionSources->push_back( |
| 2737 DescriptionSource(foundDescription, valueAttr)); | 2740 DescriptionSource(foundDescription, valueAttr)); |
| 2738 descriptionSources->back().type = descriptionFrom; | 2741 descriptionSources->back().type = descriptionFrom; |
| 2739 } | 2742 } |
| 2740 String value = inputElement->value(); | 2743 String value = inputElement->value(); |
| 2741 if (!value.isNull()) { | 2744 if (!value.isNull()) { |
| 2742 description = value; | 2745 description = value; |
| 2743 if (descriptionSources) { | 2746 if (descriptionSources) { |
| 2744 DescriptionSource& source = descriptionSources->back(); | 2747 DescriptionSource& source = descriptionSources->back(); |
| 2745 source.text = description; | 2748 source.text = description; |
| 2746 foundDescription = true; | 2749 foundDescription = true; |
| 2747 } else { | 2750 } else { |
| 2748 return description; | 2751 return description; |
| 2749 } | 2752 } |
| 2750 } | 2753 } |
| 2751 } | 2754 } |
| 2752 | 2755 |
| 2753 // table caption, 5.9.2 from: | 2756 // table caption, 5.9.2 from: |
| 2754 // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html | 2757 // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html |
| 2755 if (nameFrom != AXNameFromCaption && isHTMLTableElement(getNode())) { | 2758 if (nameFrom != AXNameFromCaption && isHTMLTableElement(getNode())) { |
| 2756 HTMLTableElement* tableElement = toHTMLTableElement(getNode()); | 2759 HTMLTableElement* tableElement = toHTMLTableElement(getNode()); |
| 2757 | 2760 |
| 2758 descriptionFrom = AXDescriptionFromRelatedElement; | 2761 descriptionFrom = AXDescriptionFromRelatedElement; |
| 2759 if (descriptionSources) { | 2762 if (descriptionSources) { |
| 2760 descriptionSources->append(DescriptionSource(foundDescription)); | 2763 descriptionSources->push_back(DescriptionSource(foundDescription)); |
| 2761 descriptionSources->back().type = descriptionFrom; | 2764 descriptionSources->back().type = descriptionFrom; |
| 2762 descriptionSources->back().nativeSource = | 2765 descriptionSources->back().nativeSource = |
| 2763 AXTextFromNativeHTMLTableCaption; | 2766 AXTextFromNativeHTMLTableCaption; |
| 2764 } | 2767 } |
| 2765 HTMLTableCaptionElement* caption = tableElement->caption(); | 2768 HTMLTableCaptionElement* caption = tableElement->caption(); |
| 2766 if (caption) { | 2769 if (caption) { |
| 2767 AXObject* captionAXObject = axObjectCache().getOrCreate(caption); | 2770 AXObject* captionAXObject = axObjectCache().getOrCreate(caption); |
| 2768 if (captionAXObject) { | 2771 if (captionAXObject) { |
| 2769 AXObjectSet visited; | 2772 AXObjectSet visited; |
| 2770 description = | 2773 description = |
| 2771 recursiveTextAlternative(*captionAXObject, false, visited); | 2774 recursiveTextAlternative(*captionAXObject, false, visited); |
| 2772 if (relatedObjects) | 2775 if (relatedObjects) |
| 2773 relatedObjects->append( | 2776 relatedObjects->push_back( |
| 2774 new NameSourceRelatedObject(captionAXObject, description)); | 2777 new NameSourceRelatedObject(captionAXObject, description)); |
| 2775 | 2778 |
| 2776 if (descriptionSources) { | 2779 if (descriptionSources) { |
| 2777 DescriptionSource& source = descriptionSources->back(); | 2780 DescriptionSource& source = descriptionSources->back(); |
| 2778 source.relatedObjects = *relatedObjects; | 2781 source.relatedObjects = *relatedObjects; |
| 2779 source.text = description; | 2782 source.text = description; |
| 2780 foundDescription = true; | 2783 foundDescription = true; |
| 2781 } else { | 2784 } else { |
| 2782 return description; | 2785 return description; |
| 2783 } | 2786 } |
| 2784 } | 2787 } |
| 2785 } | 2788 } |
| 2786 } | 2789 } |
| 2787 | 2790 |
| 2788 // summary, 5.6.2 from: | 2791 // summary, 5.6.2 from: |
| 2789 // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html | 2792 // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html |
| 2790 if (nameFrom != AXNameFromContents && isHTMLSummaryElement(getNode())) { | 2793 if (nameFrom != AXNameFromContents && isHTMLSummaryElement(getNode())) { |
| 2791 descriptionFrom = AXDescriptionFromContents; | 2794 descriptionFrom = AXDescriptionFromContents; |
| 2792 if (descriptionSources) { | 2795 if (descriptionSources) { |
| 2793 descriptionSources->append(DescriptionSource(foundDescription)); | 2796 descriptionSources->push_back(DescriptionSource(foundDescription)); |
| 2794 descriptionSources->back().type = descriptionFrom; | 2797 descriptionSources->back().type = descriptionFrom; |
| 2795 } | 2798 } |
| 2796 | 2799 |
| 2797 AXObjectSet visited; | 2800 AXObjectSet visited; |
| 2798 description = textFromDescendants(visited, false); | 2801 description = textFromDescendants(visited, false); |
| 2799 | 2802 |
| 2800 if (!description.isEmpty()) { | 2803 if (!description.isEmpty()) { |
| 2801 if (descriptionSources) { | 2804 if (descriptionSources) { |
| 2802 foundDescription = true; | 2805 foundDescription = true; |
| 2803 descriptionSources->back().text = description; | 2806 descriptionSources->back().text = description; |
| 2804 } else { | 2807 } else { |
| 2805 return description; | 2808 return description; |
| 2806 } | 2809 } |
| 2807 } | 2810 } |
| 2808 } | 2811 } |
| 2809 | 2812 |
| 2810 // title attribute, from: | 2813 // title attribute, from: |
| 2811 // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html | 2814 // http://rawgit.com/w3c/aria/master/html-aam/html-aam.html |
| 2812 if (nameFrom != AXNameFromTitle) { | 2815 if (nameFrom != AXNameFromTitle) { |
| 2813 descriptionFrom = AXDescriptionFromAttribute; | 2816 descriptionFrom = AXDescriptionFromAttribute; |
| 2814 if (descriptionSources) { | 2817 if (descriptionSources) { |
| 2815 descriptionSources->append( | 2818 descriptionSources->push_back( |
| 2816 DescriptionSource(foundDescription, titleAttr)); | 2819 DescriptionSource(foundDescription, titleAttr)); |
| 2817 descriptionSources->back().type = descriptionFrom; | 2820 descriptionSources->back().type = descriptionFrom; |
| 2818 } | 2821 } |
| 2819 const AtomicString& title = getAttribute(titleAttr); | 2822 const AtomicString& title = getAttribute(titleAttr); |
| 2820 if (!title.isEmpty()) { | 2823 if (!title.isEmpty()) { |
| 2821 description = title; | 2824 description = title; |
| 2822 if (descriptionSources) { | 2825 if (descriptionSources) { |
| 2823 foundDescription = true; | 2826 foundDescription = true; |
| 2824 descriptionSources->back().text = description; | 2827 descriptionSources->back().text = description; |
| 2825 } else { | 2828 } else { |
| 2826 return description; | 2829 return description; |
| 2827 } | 2830 } |
| 2828 } | 2831 } |
| 2829 } | 2832 } |
| 2830 | 2833 |
| 2831 // aria-help. | 2834 // aria-help. |
| 2832 // FIXME: this is not part of the official standard, but it's needed because | 2835 // FIXME: this is not part of the official standard, but it's needed because |
| 2833 // the built-in date/time controls use it. | 2836 // the built-in date/time controls use it. |
| 2834 descriptionFrom = AXDescriptionFromAttribute; | 2837 descriptionFrom = AXDescriptionFromAttribute; |
| 2835 if (descriptionSources) { | 2838 if (descriptionSources) { |
| 2836 descriptionSources->append( | 2839 descriptionSources->push_back( |
| 2837 DescriptionSource(foundDescription, aria_helpAttr)); | 2840 DescriptionSource(foundDescription, aria_helpAttr)); |
| 2838 descriptionSources->back().type = descriptionFrom; | 2841 descriptionSources->back().type = descriptionFrom; |
| 2839 } | 2842 } |
| 2840 const AtomicString& help = getAttribute(aria_helpAttr); | 2843 const AtomicString& help = getAttribute(aria_helpAttr); |
| 2841 if (!help.isEmpty()) { | 2844 if (!help.isEmpty()) { |
| 2842 description = help; | 2845 description = help; |
| 2843 if (descriptionSources) { | 2846 if (descriptionSources) { |
| 2844 foundDescription = true; | 2847 foundDescription = true; |
| 2845 descriptionSources->back().text = description; | 2848 descriptionSources->back().text = description; |
| 2846 } else { | 2849 } else { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2892 return String(); | 2895 return String(); |
| 2893 return toTextControlElement(node)->strippedPlaceholder(); | 2896 return toTextControlElement(node)->strippedPlaceholder(); |
| 2894 } | 2897 } |
| 2895 | 2898 |
| 2896 DEFINE_TRACE(AXNodeObject) { | 2899 DEFINE_TRACE(AXNodeObject) { |
| 2897 visitor->trace(m_node); | 2900 visitor->trace(m_node); |
| 2898 AXObject::trace(visitor); | 2901 AXObject::trace(visitor); |
| 2899 } | 2902 } |
| 2900 | 2903 |
| 2901 } // namespace blink | 2904 } // namespace blink |
| OLD | NEW |