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 |