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 |
11 * notice, this list of conditions and the following disclaimer in the | 11 * notice, this list of conditions and the following disclaimer in the |
12 * documentation and/or other materials provided with the distribution. | 12 * documentation and/or other materials provided with the distribution. |
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
14 * its contributors may be used to endorse or promote products derived | 14 * its contributors may be used to endorse or promote products derived |
15 * from this software without specific prior written permission. | 15 * from this software without specific prior written permission. |
16 * | 16 * |
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 */ | 27 */ |
28 | 28 |
29 #include "config.h" | 29 #include "config.h" |
30 #include "modules/accessibility/AXNodeObject.h" | 30 #include "modules/accessibility/AXNodeObject.h" |
31 | 31 |
32 #include "core/InputTypeNames.h" | 32 #include "core/InputTypeNames.h" |
33 #include "core/dom/NodeTraversal.h" | 33 #include "core/dom/NodeTraversal.h" |
34 #include "core/dom/Text.h" | 34 #include "core/dom/Text.h" |
| 35 #include "core/dom/shadow/ComposedTreeTraversal.h" |
35 #include "core/html/HTMLDListElement.h" | 36 #include "core/html/HTMLDListElement.h" |
36 #include "core/html/HTMLFieldSetElement.h" | 37 #include "core/html/HTMLFieldSetElement.h" |
37 #include "core/html/HTMLFrameElementBase.h" | 38 #include "core/html/HTMLFrameElementBase.h" |
38 #include "core/html/HTMLImageElement.h" | 39 #include "core/html/HTMLImageElement.h" |
39 #include "core/html/HTMLInputElement.h" | 40 #include "core/html/HTMLInputElement.h" |
40 #include "core/html/HTMLLabelElement.h" | 41 #include "core/html/HTMLLabelElement.h" |
41 #include "core/html/HTMLLegendElement.h" | 42 #include "core/html/HTMLLegendElement.h" |
42 #include "core/html/HTMLMediaElement.h" | 43 #include "core/html/HTMLMediaElement.h" |
43 #include "core/html/HTMLMeterElement.h" | 44 #include "core/html/HTMLMeterElement.h" |
44 #include "core/html/HTMLPlugInElement.h" | 45 #include "core/html/HTMLPlugInElement.h" |
45 #include "core/html/HTMLSelectElement.h" | 46 #include "core/html/HTMLSelectElement.h" |
46 #include "core/html/HTMLTableCaptionElement.h" | 47 #include "core/html/HTMLTableCaptionElement.h" |
47 #include "core/html/HTMLTableCellElement.h" | 48 #include "core/html/HTMLTableCellElement.h" |
48 #include "core/html/HTMLTableElement.h" | 49 #include "core/html/HTMLTableElement.h" |
49 #include "core/html/HTMLTableRowElement.h" | 50 #include "core/html/HTMLTableRowElement.h" |
50 #include "core/html/HTMLTableSectionElement.h" | 51 #include "core/html/HTMLTableSectionElement.h" |
51 #include "core/html/HTMLTextAreaElement.h" | 52 #include "core/html/HTMLTextAreaElement.h" |
52 #include "core/html/parser/HTMLParserIdioms.h" | 53 #include "core/html/parser/HTMLParserIdioms.h" |
53 #include "core/html/shadow/MediaControlElements.h" | 54 #include "core/html/shadow/MediaControlElements.h" |
| 55 #include "core/layout/LayoutBlockFlow.h" |
54 #include "core/layout/LayoutObject.h" | 56 #include "core/layout/LayoutObject.h" |
55 #include "modules/accessibility/AXObjectCacheImpl.h" | 57 #include "modules/accessibility/AXObjectCacheImpl.h" |
56 #include "platform/UserGestureIndicator.h" | 58 #include "platform/UserGestureIndicator.h" |
| 59 #include "platform/text/PlatformLocale.h" |
57 #include "wtf/text/StringBuilder.h" | 60 #include "wtf/text/StringBuilder.h" |
58 | 61 |
59 | 62 |
60 namespace blink { | 63 namespace blink { |
61 | 64 |
62 using namespace HTMLNames; | 65 using namespace HTMLNames; |
63 | 66 |
64 AXNodeObject::AXNodeObject(Node* node, AXObjectCacheImpl& axObjectCache) | 67 AXNodeObject::AXNodeObject(Node* node, AXObjectCacheImpl& axObjectCache) |
65 : AXObject(axObjectCache) | 68 : AXObject(axObjectCache) |
66 , m_ariaRole(UnknownRole) | 69 , m_ariaRole(UnknownRole) |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 static bool isRequiredOwnedElement(AXObject* parent, AccessibilityRole currentRo
le, HTMLElement* currentElement) | 246 static bool isRequiredOwnedElement(AXObject* parent, AccessibilityRole currentRo
le, HTMLElement* currentElement) |
244 { | 247 { |
245 Node* parentNode = parent->node(); | 248 Node* parentNode = parent->node(); |
246 if (!parentNode || !parentNode->isHTMLElement()) | 249 if (!parentNode || !parentNode->isHTMLElement()) |
247 return false; | 250 return false; |
248 | 251 |
249 if (currentRole == ListItemRole) | 252 if (currentRole == ListItemRole) |
250 return isListElement(parentNode); | 253 return isListElement(parentNode); |
251 if (currentRole == ListMarkerRole) | 254 if (currentRole == ListMarkerRole) |
252 return isHTMLLIElement(*parentNode); | 255 return isHTMLLIElement(*parentNode); |
253 if (currentRole == MenuItemCheckBoxRole || currentRole == MenuItemRole || c
urrentRole == MenuItemRadioRole) | 256 if (currentRole == MenuItemCheckBoxRole || currentRole == MenuItemRole || cu
rrentRole == MenuItemRadioRole) |
254 return isHTMLMenuElement(*parentNode); | 257 return isHTMLMenuElement(*parentNode); |
255 | 258 |
256 if (!currentElement) | 259 if (!currentElement) |
257 return false; | 260 return false; |
258 if (isHTMLTableCellElement(*currentElement)) | 261 if (isHTMLTableCellElement(*currentElement)) |
259 return isHTMLTableRowElement(*parentNode); | 262 return isHTMLTableRowElement(*parentNode); |
260 if (isHTMLTableRowElement(*currentElement)) | 263 if (isHTMLTableRowElement(*currentElement)) |
261 return isHTMLTableSectionElement(toHTMLElement(*parentNode)); | 264 return isHTMLTableSectionElement(toHTMLElement(*parentNode)); |
262 | 265 |
263 // In case of ListboxRole and it's child, ListBoxOptionRole, | 266 // In case of ListboxRole and it's child, ListBoxOptionRole, |
264 // Inheritance of presentation role is handled in AXListBoxOption | 267 // Inheritance of presentation role is handled in AXListBoxOption |
265 // Because ListBoxOption Role doesn't have any child. | 268 // Because ListBoxOption Role doesn't have any child. |
266 // If it's just ignored because of presentation, we can't see any AX tree re
lated to ListBoxOption. | 269 // If it's just ignored because of presentation, we can't see any AX tree re
lated to ListBoxOption. |
267 return false; | 270 return false; |
268 } | 271 } |
269 | 272 |
270 | |
271 const AXObject* AXNodeObject::inheritsPresentationalRoleFrom() const | 273 const AXObject* AXNodeObject::inheritsPresentationalRoleFrom() const |
272 { | 274 { |
273 // ARIA states if an item can get focus, it should not be presentational. | 275 // ARIA states if an item can get focus, it should not be presentational. |
274 if (canSetFocusAttribute()) | 276 if (canSetFocusAttribute()) |
275 return 0; | 277 return 0; |
276 | 278 |
277 if (isPresentational()) | 279 if (isPresentational()) |
278 return this; | 280 return this; |
279 | 281 |
280 // http://www.w3.org/TR/wai-aria/complete#presentation | 282 // http://www.w3.org/TR/wai-aria/complete#presentation |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 if (node()->isLink() || (isHTMLAnchorElement(*node()) && isClickable())) | 331 if (node()->isLink() || (isHTMLAnchorElement(*node()) && isClickable())) |
330 return LinkRole; | 332 return LinkRole; |
331 | 333 |
332 if (isHTMLButtonElement(*node())) | 334 if (isHTMLButtonElement(*node())) |
333 return buttonRoleType(); | 335 return buttonRoleType(); |
334 | 336 |
335 if (isHTMLDetailsElement(*node())) | 337 if (isHTMLDetailsElement(*node())) |
336 return DetailsRole; | 338 return DetailsRole; |
337 | 339 |
338 if (isHTMLSummaryElement(*node())) { | 340 if (isHTMLSummaryElement(*node())) { |
339 if (node()->parentNode() && isHTMLDetailsElement(node()->parentNode())) | 341 ContainerNode* parent = ComposedTreeTraversal::parent(*node()); |
| 342 if (parent && isHTMLDetailsElement(parent)) |
340 return DisclosureTriangleRole; | 343 return DisclosureTriangleRole; |
341 return UnknownRole; | 344 return UnknownRole; |
342 } | 345 } |
343 | 346 |
344 if (isHTMLInputElement(*node())) { | 347 if (isHTMLInputElement(*node())) { |
345 HTMLInputElement& input = toHTMLInputElement(*node()); | 348 HTMLInputElement& input = toHTMLInputElement(*node()); |
346 const AtomicString& type = input.type(); | 349 const AtomicString& type = input.type(); |
347 if (input.dataList()) | 350 if (input.dataList()) |
348 return ComboBoxRole; | 351 return ComboBoxRole; |
349 if (type == InputTypeNames::button) { | 352 if (type == InputTypeNames::button) { |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 if (AXObject* child = cache.getOrCreate(element)) | 585 if (AXObject* child = cache.getOrCreate(element)) |
583 children.append(child); | 586 children.append(child); |
584 } | 587 } |
585 } | 588 } |
586 | 589 |
587 // This only returns true if this is the element that actually has the | 590 // This only returns true if this is the element that actually has the |
588 // contentEditable attribute set, unlike node->hasEditableStyle() which will | 591 // contentEditable attribute set, unlike node->hasEditableStyle() which will |
589 // also return true if an ancestor is editable. | 592 // also return true if an ancestor is editable. |
590 bool AXNodeObject::hasContentEditableAttributeSet() const | 593 bool AXNodeObject::hasContentEditableAttributeSet() const |
591 { | 594 { |
592 if (!hasAttribute(contenteditableAttr)) | 595 const AtomicString& contentEditableValue = getAttribute(contenteditableAttr)
; |
| 596 if (contentEditableValue.isNull()) |
593 return false; | 597 return false; |
594 const AtomicString& contentEditableValue = getAttribute(contenteditableAttr)
; | |
595 // Both "true" (case-insensitive) and the empty string count as true. | 598 // Both "true" (case-insensitive) and the empty string count as true. |
596 return contentEditableValue.isEmpty() || equalIgnoringCase(contentEditableVa
lue, "true"); | 599 return contentEditableValue.isEmpty() || equalIgnoringCase(contentEditableVa
lue, "true"); |
597 } | 600 } |
598 | 601 |
599 bool AXNodeObject::isTextControl() const | 602 bool AXNodeObject::isTextControl() const |
600 { | 603 { |
601 if (hasContentEditableAttributeSet()) | 604 if (hasContentEditableAttributeSet()) |
602 return true; | 605 return true; |
603 | 606 |
604 switch (roleValue()) { | 607 switch (roleValue()) { |
(...skipping 927 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1532 if (obj->canSetFocusAttribute()) | 1535 if (obj->canSetFocusAttribute()) |
1533 return false; | 1536 return false; |
1534 | 1537 |
1535 // Skip big container elements like lists, tables, etc. | 1538 // Skip big container elements like lists, tables, etc. |
1536 if (obj->isList() || obj->isAXTable() || obj->isTree() || obj->isCanvas()) | 1539 if (obj->isList() || obj->isAXTable() || obj->isTree() || obj->isCanvas()) |
1537 return false; | 1540 return false; |
1538 | 1541 |
1539 return true; | 1542 return true; |
1540 } | 1543 } |
1541 | 1544 |
1542 // Returns true if |r1| and |r2| are both non-null and are contained within the | 1545 // Returns the nearest LayoutBlockFlow ancestor which does not have an |
1543 // same LayoutBox. | 1546 // inlineBoxWrapper - i.e. is not itself an inline object. |
1544 static bool isSameLayoutBox(LayoutObject* r1, LayoutObject* r2) | 1547 static LayoutBlockFlow* nonInlineBlockFlow(LayoutObject* object) |
| 1548 { |
| 1549 LayoutObject* current = object; |
| 1550 while (current) { |
| 1551 if (current->isLayoutBlockFlow()) { |
| 1552 LayoutBlockFlow* blockFlow = toLayoutBlockFlow(current); |
| 1553 if (!blockFlow->inlineBoxWrapper()) |
| 1554 return blockFlow; |
| 1555 } |
| 1556 current = current->parent(); |
| 1557 } |
| 1558 |
| 1559 ASSERT_NOT_REACHED(); |
| 1560 return nullptr; |
| 1561 } |
| 1562 |
| 1563 // Returns true if |r1| and |r2| are both non-null, both inline, and are contain
ed |
| 1564 // within the same non-inline LayoutBlockFlow. |
| 1565 static bool isInSameNonInlineBlockFlow(LayoutObject* r1, LayoutObject* r2) |
1545 { | 1566 { |
1546 if (!r1 || !r2) | 1567 if (!r1 || !r2) |
1547 return false; | 1568 return false; |
1548 LayoutBox* b1 = r1->enclosingBox(); | 1569 if (!r1->isInline() || !r2->isInline()) |
1549 LayoutBox* b2 = r2->enclosingBox(); | 1570 return false; |
| 1571 LayoutBlockFlow* b1 = nonInlineBlockFlow(r1); |
| 1572 LayoutBlockFlow* b2 = nonInlineBlockFlow(r2); |
1550 return b1 && b2 && b1 == b2; | 1573 return b1 && b2 && b1 == b2; |
1551 } | 1574 } |
1552 | 1575 |
1553 String AXNodeObject::deprecatedTextUnderElement(TextUnderElementMode mode) const | 1576 String AXNodeObject::deprecatedTextUnderElement(TextUnderElementMode mode) const |
1554 { | 1577 { |
1555 Node* node = this->node(); | 1578 Node* node = this->node(); |
1556 if (node && node->isTextNode()) | 1579 if (node && node->isTextNode()) |
1557 return toText(node)->wholeText(); | 1580 return toText(node)->wholeText(); |
1558 | 1581 |
1559 StringBuilder builder; | 1582 StringBuilder builder; |
(...skipping 12 matching lines...) Expand all Loading... |
1572 continue; | 1595 continue; |
1573 } | 1596 } |
1574 } | 1597 } |
1575 | 1598 |
1576 // If we're going between two layoutObjects that are in separate LayoutB
oxes, add | 1599 // If we're going between two layoutObjects that are in separate LayoutB
oxes, add |
1577 // whitespace if it wasn't there already. Intuitively if you have | 1600 // whitespace if it wasn't there already. Intuitively if you have |
1578 // <span>Hello</span><span>World</span>, those are part of the same Layo
utBox | 1601 // <span>Hello</span><span>World</span>, those are part of the same Layo
utBox |
1579 // so we should return "HelloWorld", but given <div>Hello</div><div>Worl
d</div> the | 1602 // so we should return "HelloWorld", but given <div>Hello</div><div>Worl
d</div> the |
1580 // strings are in separate boxes so we should return "Hello World". | 1603 // strings are in separate boxes so we should return "Hello World". |
1581 if (previous && builder.length() && !isHTMLSpace(builder[builder.length(
) - 1])) { | 1604 if (previous && builder.length() && !isHTMLSpace(builder[builder.length(
) - 1])) { |
1582 if (!isSameLayoutBox(child->layoutObject(), previous->layoutObject()
)) | 1605 if (!isInSameNonInlineBlockFlow(child->layoutObject(), previous->lay
outObject())) |
1583 builder.append(' '); | 1606 builder.append(' '); |
1584 } | 1607 } |
1585 | 1608 |
1586 builder.append(child->deprecatedTextUnderElement(mode)); | 1609 builder.append(child->deprecatedTextUnderElement(mode)); |
1587 previous = child; | 1610 previous = child; |
1588 | 1611 |
1589 if (mode == TextUnderElementAny && !builder.isEmpty()) | 1612 if (mode == TextUnderElementAny && !builder.isEmpty()) |
1590 break; | 1613 break; |
1591 } | 1614 } |
1592 | 1615 |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1771 return placeholder; | 1794 return placeholder; |
1772 } | 1795 } |
1773 | 1796 |
1774 return String(); | 1797 return String(); |
1775 } | 1798 } |
1776 | 1799 |
1777 // | 1800 // |
1778 // New AX name calculation. | 1801 // New AX name calculation. |
1779 // | 1802 // |
1780 | 1803 |
1781 String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraver
sal, AXObjectSet& visited, AXNameFrom& nameFrom, AXObjectVector& nameObjects, Na
meSources* nameSources) const | 1804 String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraver
sal, AXObjectSet& visited, AXNameFrom& nameFrom, AXObjectVector* nameObjects, Na
meSources* nameSources) const |
1782 { | 1805 { |
| 1806 // If nameSources is non-null, nameObjects is used in filling it in, so it m
ust be non-null as well. |
| 1807 if (nameSources) |
| 1808 assert(nameObjects); |
| 1809 |
1783 bool alreadyVisited = visited.contains(this); | 1810 bool alreadyVisited = visited.contains(this); |
1784 bool foundTextAlternative = false; | 1811 bool foundTextAlternative = false; |
1785 visited.add(this); | 1812 visited.add(this); |
1786 String textAlternative; | 1813 String textAlternative; |
1787 | 1814 |
1788 if (!node() && !layoutObject()) | 1815 if (!node() && !layoutObject()) |
1789 return String(); | 1816 return String(); |
1790 | 1817 |
1791 // Step 2A from: http://www.w3.org/TR/accname-aam-1.1 | 1818 // Step 2A from: http://www.w3.org/TR/accname-aam-1.1 |
1792 if (!recursive && layoutObject() | 1819 if (!recursive && layoutObject() |
1793 && layoutObject()->style()->visibility() != VISIBLE | 1820 && layoutObject()->style()->visibility() != VISIBLE |
1794 && !equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) { | 1821 && !equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) { |
1795 return String(); | 1822 return String(); |
1796 } | 1823 } |
1797 | 1824 |
1798 // Step 2B from: http://www.w3.org/TR/accname-aam-1.1 | 1825 // Step 2B from: http://www.w3.org/TR/accname-aam-1.1 |
1799 if (!inAriaLabelledByTraversal && !alreadyVisited) { | 1826 if (!inAriaLabelledByTraversal && !alreadyVisited) { |
1800 const QualifiedName& attr = hasAttribute(aria_labeledbyAttr) && !hasAttr
ibute(aria_labelledbyAttr) ? aria_labeledbyAttr : aria_labelledbyAttr; | 1827 const QualifiedName& attr = hasAttribute(aria_labeledbyAttr) && !hasAttr
ibute(aria_labelledbyAttr) ? aria_labeledbyAttr : aria_labelledbyAttr; |
1801 nameFrom = AXNameFromRelatedElement; | 1828 nameFrom = AXNameFromRelatedElement; |
1802 if (nameSources) { | 1829 if (nameSources) { |
1803 nameSources->append(NameSource(foundTextAlternative, attr)); | 1830 nameSources->append(NameSource(foundTextAlternative, attr)); |
1804 nameSources->last().type = nameFrom; | 1831 nameSources->last().type = nameFrom; |
1805 } | 1832 } |
1806 | 1833 |
1807 if (hasAttribute(attr)) { | 1834 const AtomicString& ariaLabelledby = getAttribute(attr); |
| 1835 if (!ariaLabelledby.isNull()) { |
1808 if (nameSources) | 1836 if (nameSources) |
1809 nameSources->last().attributeValue = getAttribute(attr); | 1837 nameSources->last().attributeValue = ariaLabelledby; |
1810 | 1838 |
1811 textAlternative = textFromAriaLabelledby(visited, nameObjects); | 1839 textAlternative = textFromAriaLabelledby(visited, nameObjects); |
1812 | 1840 |
1813 if (!textAlternative.isNull()) { | 1841 if (!textAlternative.isNull()) { |
1814 if (nameSources) { | 1842 if (nameSources) { |
1815 NameSource& source = nameSources->last(); | 1843 NameSource& source = nameSources->last(); |
1816 source.type = nameFrom; | 1844 source.type = nameFrom; |
1817 source.nameObjects = nameObjects; | 1845 source.nameObjects = *nameObjects; |
1818 source.text = textAlternative; | 1846 source.text = textAlternative; |
1819 foundTextAlternative = true; | 1847 foundTextAlternative = true; |
1820 } else { | 1848 } else { |
1821 return textAlternative; | 1849 return textAlternative; |
1822 } | 1850 } |
1823 } else if (nameSources) { | 1851 } else if (nameSources) { |
1824 nameSources->last().invalid = true; | 1852 nameSources->last().invalid = true; |
1825 } | 1853 } |
1826 } | 1854 } |
1827 } | 1855 } |
1828 | 1856 |
1829 // Step 2C from: http://www.w3.org/TR/accname-aam-1.1 | 1857 // Step 2C from: http://www.w3.org/TR/accname-aam-1.1 |
1830 nameFrom = AXNameFromAttribute; | 1858 nameFrom = AXNameFromAttribute; |
1831 if (nameSources) { | 1859 if (nameSources) { |
1832 nameSources->append(NameSource(foundTextAlternative, aria_labelAttr)); | 1860 nameSources->append(NameSource(foundTextAlternative, aria_labelAttr)); |
1833 nameSources->last().type = nameFrom; | 1861 nameSources->last().type = nameFrom; |
1834 } | 1862 } |
1835 if (hasAttribute(aria_labelAttr)) { | 1863 const AtomicString& ariaLabel = getAttribute(aria_labelAttr); |
1836 const AtomicString& ariaLabel = getAttribute(aria_labelAttr); | 1864 if (!ariaLabel.isEmpty()) { |
1837 if (!ariaLabel.isEmpty()) { | 1865 textAlternative = ariaLabel; |
1838 textAlternative = ariaLabel; | |
1839 | 1866 |
1840 if (nameSources) { | 1867 if (nameSources) { |
1841 NameSource& source = nameSources->last(); | 1868 NameSource& source = nameSources->last(); |
1842 source.text = textAlternative; | 1869 source.text = textAlternative; |
1843 source.attributeValue = ariaLabel; | 1870 source.attributeValue = ariaLabel; |
1844 foundTextAlternative = true; | 1871 foundTextAlternative = true; |
1845 } else { | 1872 } else { |
1846 return textAlternative; | 1873 return textAlternative; |
1847 } | |
1848 } | 1874 } |
1849 } | 1875 } |
1850 | 1876 |
1851 // Step 2D from: http://www.w3.org/TR/accname-aam-1.1 | 1877 // Step 2D from: http://www.w3.org/TR/accname-aam-1.1 |
1852 textAlternative = nativeTextAlternative(visited, nameFrom, nameObjects, name
Sources, &foundTextAlternative); | 1878 textAlternative = nativeTextAlternative(visited, nameFrom, nameObjects, name
Sources, &foundTextAlternative); |
1853 if (!textAlternative.isNull() && !nameSources) | 1879 if (!textAlternative.isNull() && !nameSources) |
1854 return textAlternative; | 1880 return textAlternative; |
1855 | 1881 |
1856 // Step 2E from: http://www.w3.org/TR/accname-aam-1.1 | 1882 // Step 2E from: http://www.w3.org/TR/accname-aam-1.1 |
1857 | 1883 if (recursive && !inAriaLabelledByTraversal && isControl()) { |
| 1884 // No need to set any name source info in a recursive call. |
| 1885 if (roleValue() == TextFieldRole || roleValue() == ComboBoxRole) |
| 1886 return text(); |
| 1887 if (isRange()) { |
| 1888 const AtomicString& ariaValuetext = getAttribute(aria_valuetextAttr)
; |
| 1889 if (!ariaValuetext.isNull()) |
| 1890 return ariaValuetext.string(); |
| 1891 return String::number(valueForRange()); |
| 1892 } |
| 1893 } |
1858 | 1894 |
1859 // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1 | 1895 // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1 |
1860 if (recursive || nameFromContents()) { | 1896 if (recursive || nameFromContents()) { |
1861 nameFrom = AXNameFromContents; | 1897 nameFrom = AXNameFromContents; |
1862 if (nameSources) { | 1898 if (nameSources) { |
1863 nameSources->append(NameSource(foundTextAlternative)); | 1899 nameSources->append(NameSource(foundTextAlternative)); |
1864 nameSources->last().type = nameFrom; | 1900 nameSources->last().type = nameFrom; |
1865 } | 1901 } |
1866 | 1902 |
1867 Node* node = this->node(); | 1903 Node* node = this->node(); |
1868 if (node && node->isTextNode()) | 1904 if (node && node->isTextNode()) |
1869 textAlternative = toText(node)->wholeText(); | 1905 textAlternative = toText(node)->wholeText(); |
1870 else | 1906 else |
1871 textAlternative = textFromDescendants(visited); | 1907 textAlternative = textFromDescendants(visited); |
1872 | 1908 |
| 1909 if (!textAlternative.isEmpty()) { |
| 1910 if (nameSources) { |
| 1911 foundTextAlternative = true; |
| 1912 nameSources->last().text = textAlternative; |
| 1913 } else { |
| 1914 return textAlternative; |
| 1915 } |
| 1916 } |
| 1917 } |
| 1918 |
| 1919 // Step 2H from: http://www.w3.org/TR/accname-aam-1.1 |
| 1920 nameFrom = AXNameFromAttribute; |
| 1921 if (nameSources) { |
| 1922 nameSources->append(NameSource(foundTextAlternative, titleAttr)); |
| 1923 nameSources->last().type = nameFrom; |
| 1924 } |
| 1925 const AtomicString& title = getAttribute(titleAttr); |
| 1926 if (!title.isEmpty()) { |
| 1927 textAlternative = title; |
1873 if (nameSources) { | 1928 if (nameSources) { |
1874 foundTextAlternative = true; | 1929 foundTextAlternative = true; |
1875 nameSources->last().text = textAlternative; | 1930 nameSources->last().text = textAlternative; |
1876 } else { | 1931 } else { |
1877 return textAlternative; | 1932 return textAlternative; |
1878 } | 1933 } |
1879 } | 1934 } |
1880 | 1935 |
1881 nameFrom = AXNameFromUninitialized; | 1936 nameFrom = AXNameFromUninitialized; |
1882 | 1937 |
1883 if (nameSources && !nameSources->isEmpty()) { | 1938 if (foundTextAlternative) { |
1884 for (size_t i = 0; i < nameSources->size(); ++i) { | 1939 for (size_t i = 0; i < nameSources->size(); ++i) { |
1885 if (!(*nameSources)[i].text.isNull() && !(*nameSources)[i].supersede
d) { | 1940 if (!(*nameSources)[i].text.isNull() && !(*nameSources)[i].supersede
d) { |
1886 nameFrom = (*nameSources)[i].type; | 1941 NameSource& nameSource = (*nameSources)[i]; |
1887 nameObjects = (*nameSources)[i].nameObjects; | 1942 nameFrom = nameSource.type; |
1888 return (*nameSources)[i].text; | 1943 if (!nameSource.nameObjects.isEmpty()) |
| 1944 *nameObjects = nameSource.nameObjects; |
| 1945 return nameSource.text; |
1889 } | 1946 } |
1890 } | 1947 } |
1891 } | 1948 } |
1892 | 1949 |
1893 return String(); | 1950 return String(); |
1894 } | 1951 } |
1895 | 1952 |
1896 String AXNodeObject::textFromDescendants(AXObjectSet& visited) const | 1953 String AXNodeObject::textFromDescendants(AXObjectSet& visited) const |
1897 { | 1954 { |
1898 StringBuilder accumulatedText; | 1955 StringBuilder accumulatedText; |
1899 AXObject* previous = nullptr; | 1956 AXObject* previous = nullptr; |
1900 for (AXObject* child = firstChild(); child; child = child->nextSibling()) { | 1957 for (AXObject* child = firstChild(); child; child = child->nextSibling()) { |
1901 // If we're going between two layoutObjects that are in separate LayoutB
oxes, add | 1958 // If we're going between two layoutObjects that are in separate LayoutB
oxes, add |
1902 // whitespace if it wasn't there already. Intuitively if you have | 1959 // whitespace if it wasn't there already. Intuitively if you have |
1903 // <span>Hello</span><span>World</span>, those are part of the same Layo
utBox | 1960 // <span>Hello</span><span>World</span>, those are part of the same Layo
utBox |
1904 // so we should return "HelloWorld", but given <div>Hello</div><div>Worl
d</div> the | 1961 // so we should return "HelloWorld", but given <div>Hello</div><div>Worl
d</div> the |
1905 // strings are in separate boxes so we should return "Hello World". | 1962 // strings are in separate boxes so we should return "Hello World". |
1906 if (previous && accumulatedText.length() && !isHTMLSpace(accumulatedText
[accumulatedText.length() - 1])) { | 1963 if (previous && accumulatedText.length() && !isHTMLSpace(accumulatedText
[accumulatedText.length() - 1])) { |
1907 if (!isSameLayoutBox(child->layoutObject(), previous->layoutObject()
)) | 1964 if (!isInSameNonInlineBlockFlow(child->layoutObject(), previous->lay
outObject())) |
1908 accumulatedText.append(' '); | 1965 accumulatedText.append(' '); |
1909 } | 1966 } |
1910 | 1967 |
1911 AXNameFrom nameFrom; | 1968 String result = recursiveTextAlternative(*child, false, visited); |
1912 AXObjectVector nameObjects; | |
1913 String result = child->textAlternative(true, false, visited, nameFrom, n
ameObjects, nullptr); | |
1914 accumulatedText.append(result); | 1969 accumulatedText.append(result); |
1915 previous = child; | 1970 previous = child; |
1916 } | 1971 } |
1917 | 1972 |
1918 return accumulatedText.toString(); | 1973 return accumulatedText.toString(); |
1919 } | 1974 } |
1920 | 1975 |
1921 String AXNodeObject::textFromElements(bool inAriaLabelledbyTraversal, AXObjectSe
t& visited, WillBeHeapVector<RawPtrWillBeMember<Element>>& elements, AXObjectVec
tor& nameObjects) const | 1976 String AXNodeObject::textFromElements(bool inAriaLabelledbyTraversal, AXObjectSe
t& visited, WillBeHeapVector<RawPtrWillBeMember<Element>>& elements, AXObjectVec
tor* nameObjects) const |
1922 { | 1977 { |
1923 StringBuilder accumulatedText; | 1978 StringBuilder accumulatedText; |
1924 bool foundValidElement = false; | 1979 bool foundValidElement = false; |
1925 AXObjectVector localNameObjects; | 1980 AXObjectVector localNameObjects; |
1926 | 1981 |
1927 for (const auto& element : elements) { | 1982 for (const auto& element : elements) { |
1928 RefPtrWillBeRawPtr<AXObject> axElement = axObjectCache().getOrCreate(ele
ment); | 1983 RefPtrWillBeRawPtr<AXObject> axElement = axObjectCache().getOrCreate(ele
ment); |
1929 if (axElement) { | 1984 if (axElement) { |
1930 foundValidElement = true; | 1985 foundValidElement = true; |
1931 localNameObjects.append(axElement.get()); | 1986 localNameObjects.append(axElement.get()); |
1932 | 1987 |
1933 String result = recursiveTextAlternative(*axElement, inAriaLabelledb
yTraversal, visited); | 1988 String result = recursiveTextAlternative(*axElement, inAriaLabelledb
yTraversal, visited); |
1934 if (!result.isEmpty()) { | 1989 if (!result.isEmpty()) { |
1935 if (!accumulatedText.isEmpty()) | 1990 if (!accumulatedText.isEmpty()) |
1936 accumulatedText.append(" "); | 1991 accumulatedText.append(" "); |
1937 accumulatedText.append(result); | 1992 accumulatedText.append(result); |
1938 } | 1993 } |
1939 } | 1994 } |
1940 } | 1995 } |
1941 if (!foundValidElement) | 1996 if (!foundValidElement) |
1942 return String(); | 1997 return String(); |
1943 nameObjects = localNameObjects; | 1998 if (nameObjects) |
| 1999 *nameObjects = localNameObjects; |
1944 return accumulatedText.toString(); | 2000 return accumulatedText.toString(); |
1945 } | 2001 } |
1946 | 2002 |
1947 String AXNodeObject::textFromAriaLabelledby(AXObjectSet& visited, AXObjectVector
& nameObjects) const | 2003 String AXNodeObject::textFromAriaLabelledby(AXObjectSet& visited, AXObjectVector
* nameObjects) const |
1948 { | 2004 { |
1949 WillBeHeapVector<RawPtrWillBeMember<Element>> elements; | 2005 WillBeHeapVector<RawPtrWillBeMember<Element>> elements; |
1950 ariaLabelledbyElements(elements); | 2006 ariaLabelledbyElements(elements); |
1951 return textFromElements(true, visited, elements, nameObjects); | 2007 return textFromElements(true, visited, elements, nameObjects); |
1952 } | 2008 } |
1953 | 2009 |
1954 LayoutRect AXNodeObject::elementRect() const | 2010 LayoutRect AXNodeObject::elementRect() const |
1955 { | 2011 { |
1956 // First check if it has a custom rect, for example if this element is tied
to a canvas path. | 2012 // First check if it has a custom rect, for example if this element is tied
to a canvas path. |
1957 if (!m_explicitElementRect.isEmpty()) | 2013 if (!m_explicitElementRect.isEmpty()) |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2140 } | 2196 } |
2141 | 2197 |
2142 Element* AXNodeObject::actionElement() const | 2198 Element* AXNodeObject::actionElement() const |
2143 { | 2199 { |
2144 Node* node = this->node(); | 2200 Node* node = this->node(); |
2145 if (!node) | 2201 if (!node) |
2146 return 0; | 2202 return 0; |
2147 | 2203 |
2148 if (isHTMLInputElement(*node)) { | 2204 if (isHTMLInputElement(*node)) { |
2149 HTMLInputElement& input = toHTMLInputElement(*node); | 2205 HTMLInputElement& input = toHTMLInputElement(*node); |
2150 if (!input.isDisabledFormControl() && (isCheckboxOrRadio() || input.isTe
xtButton() | 2206 if (!input.isDisabledFormControl() && (isCheckboxOrRadio() || input.isTe
xtButton() || input.type() == InputTypeNames::file)) |
2151 || input.type() == InputTypeNames::file)) | |
2152 return &input; | 2207 return &input; |
2153 } else if (isHTMLButtonElement(*node)) { | 2208 } else if (isHTMLButtonElement(*node)) { |
2154 return toElement(node); | 2209 return toElement(node); |
2155 } | 2210 } |
2156 | 2211 |
2157 if (AXObject::isARIAInput(ariaRoleAttribute())) | 2212 if (AXObject::isARIAInput(ariaRoleAttribute())) |
2158 return toElement(node); | 2213 return toElement(node); |
2159 | 2214 |
2160 if (isImageButton()) | 2215 if (isImageButton()) |
2161 return toElement(node); | 2216 return toElement(node); |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2447 ariaLabelledbyElements(elements); | 2502 ariaLabelledbyElements(elements); |
2448 | 2503 |
2449 for (const auto& element : elements) { | 2504 for (const auto& element : elements) { |
2450 RefPtrWillBeRawPtr<AXObject> axElement = axObjectCache().getOrCreate
(element); | 2505 RefPtrWillBeRawPtr<AXObject> axElement = axObjectCache().getOrCreate
(element); |
2451 textOrder.append(AccessibilityText::create(ariaLabelledby, Alternati
veText, axElement)); | 2506 textOrder.append(AccessibilityText::create(ariaLabelledby, Alternati
veText, axElement)); |
2452 } | 2507 } |
2453 } | 2508 } |
2454 } | 2509 } |
2455 | 2510 |
2456 // Based on http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible-
name-and-description-calculation | 2511 // Based on http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible-
name-and-description-calculation |
2457 String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam
eFrom, AXObjectVector& nameObjects, NameSources* nameSources, bool* foundTextAlt
ernative) const | 2512 String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam
eFrom, AXObjectVector* nameObjects, NameSources* nameSources, bool* foundTextAlt
ernative) const |
2458 { | 2513 { |
2459 if (!node()) | 2514 if (!node()) |
2460 return String(); | 2515 return String(); |
2461 | 2516 |
| 2517 // If nameSources is non-null, nameObjects is used in filling it in, so it m
ust be non-null as well. |
| 2518 if (nameSources) |
| 2519 assert(nameObjects); |
| 2520 |
2462 String textAlternative; | 2521 String textAlternative; |
2463 AXObjectVector localNameObjects; | 2522 AXObjectVector localNameObjects; |
2464 | 2523 |
2465 const HTMLInputElement* inputElement = nullptr; | 2524 const HTMLInputElement* inputElement = nullptr; |
2466 if (isHTMLInputElement(node())) | 2525 if (isHTMLInputElement(node())) |
2467 inputElement = toHTMLInputElement(node()); | 2526 inputElement = toHTMLInputElement(node()); |
2468 | 2527 |
| 2528 // 5.1/5.5 Text inputs, Other labelable Elements |
| 2529 HTMLElement* htmlElement = nullptr; |
| 2530 if (node()->isHTMLElement()) |
| 2531 htmlElement = toHTMLElement(node()); |
| 2532 if (htmlElement && htmlElement->isLabelable()) { |
| 2533 // label |
| 2534 nameFrom = AXNameFromRelatedElement; |
| 2535 if (nameSources) { |
| 2536 nameSources->append(NameSource(*foundTextAlternative)); |
| 2537 nameSources->last().type = nameFrom; |
| 2538 nameSources->last().nativeSource = AXTextFromNativeHTMLLabel; |
| 2539 } |
| 2540 HTMLLabelElement* label = labelForElement(htmlElement); |
| 2541 if (label) { |
| 2542 RefPtrWillBeRawPtr<AXObject> labelAXObject = axObjectCache().getOrCr
eate(label); |
| 2543 // Avoid an infinite loop for label wrapped |
| 2544 if (labelAXObject && !visited.contains(labelAXObject.get())) { |
| 2545 if (nameObjects) { |
| 2546 localNameObjects.append(labelAXObject.get()); |
| 2547 *nameObjects = localNameObjects; |
| 2548 localNameObjects.clear(); |
| 2549 } |
| 2550 textAlternative = recursiveTextAlternative(*labelAXObject, false
, visited); |
| 2551 |
| 2552 if (nameSources) { |
| 2553 NameSource& source = nameSources->last(); |
| 2554 source.nameObjects = *nameObjects; |
| 2555 source.text = textAlternative; |
| 2556 if (label->getAttribute(forAttr).isNull()) |
| 2557 source.nativeSource = AXTextFromNativeHTMLLabelWrapped; |
| 2558 else |
| 2559 source.nativeSource = AXTextFromNativeHTMLLabelFor; |
| 2560 *foundTextAlternative = true; |
| 2561 } else { |
| 2562 return textAlternative; |
| 2563 } |
| 2564 } |
| 2565 } |
| 2566 } |
| 2567 |
2469 // 5.2 input type="button", input type="submit" and input type="reset" | 2568 // 5.2 input type="button", input type="submit" and input type="reset" |
2470 if (inputElement && inputElement->isTextButton()) { | 2569 if (inputElement && inputElement->isTextButton()) { |
2471 // value attribue | 2570 // value attribue |
2472 nameFrom = AXNameFromAttribute; | 2571 nameFrom = AXNameFromAttribute; |
2473 if (nameSources) { | 2572 if (nameSources) { |
2474 nameSources->append(NameSource(*foundTextAlternative, valueAttr)); | 2573 nameSources->append(NameSource(*foundTextAlternative, valueAttr)); |
2475 nameSources->last().type = nameFrom; | 2574 nameSources->last().type = nameFrom; |
2476 } | 2575 } |
2477 String value = inputElement->value(); | 2576 String value = inputElement->value(); |
2478 if (!value.isNull()) { | 2577 if (!value.isNull()) { |
2479 textAlternative = value; | 2578 textAlternative = value; |
2480 if (nameSources) { | 2579 if (nameSources) { |
2481 NameSource& source = nameSources->last(); | 2580 NameSource& source = nameSources->last(); |
2482 source.text = textAlternative; | 2581 source.text = textAlternative; |
2483 *foundTextAlternative = true; | 2582 *foundTextAlternative = true; |
2484 } else { | 2583 } else { |
2485 return textAlternative; | 2584 return textAlternative; |
2486 } | 2585 } |
2487 } | 2586 } |
2488 | |
2489 // localised default value ("Submit" or "Reset") | |
2490 String defaultValue = inputElement->defaultValue(); | |
2491 if (!defaultValue.isNull()) { | |
2492 // defaultValue is always set for submit and reset buttons, and neve
r set for anything else. | |
2493 nameFrom = AXNameFromAttribute; | |
2494 textAlternative = defaultValue; | |
2495 if (nameSources) { | |
2496 nameSources->append(NameSource(*foundTextAlternative, typeAttr))
; | |
2497 NameSource& source = nameSources->last(); | |
2498 source.attributeValue = inputElement->getAttribute(typeAttr); | |
2499 source.text = textAlternative; | |
2500 *foundTextAlternative = true; | |
2501 } else { | |
2502 return textAlternative; | |
2503 } | |
2504 } | |
2505 return textAlternative; | 2587 return textAlternative; |
2506 } | 2588 } |
2507 | 2589 |
2508 // 5.3 input type="image" | 2590 // 5.3 input type="image" |
2509 if (inputElement && inputElement->getAttribute(typeAttr) == InputTypeNames::
image) { | 2591 if (inputElement && inputElement->getAttribute(typeAttr) == InputTypeNames::
image) { |
2510 // alt attr | 2592 // alt attr |
2511 nameFrom = AXNameFromAttribute; | 2593 nameFrom = AXNameFromAttribute; |
2512 if (nameSources) { | 2594 if (nameSources) { |
2513 nameSources->append(NameSource(*foundTextAlternative, altAttr)); | 2595 nameSources->append(NameSource(*foundTextAlternative, altAttr)); |
2514 nameSources->last().type = nameFrom; | 2596 nameSources->last().type = nameFrom; |
2515 } | 2597 } |
2516 if (inputElement->hasAttribute(altAttr)) { | 2598 const AtomicString& alt = inputElement->getAttribute(altAttr); |
2517 AtomicString alt = inputElement->getAttribute(altAttr); | 2599 if (!alt.isNull()) { |
2518 textAlternative = alt; | 2600 textAlternative = alt; |
2519 if (nameSources) { | 2601 if (nameSources) { |
2520 NameSource& source = nameSources->last(); | 2602 NameSource& source = nameSources->last(); |
2521 source.attributeValue = alt; | 2603 source.attributeValue = alt; |
2522 source.text = textAlternative; | 2604 source.text = textAlternative; |
2523 *foundTextAlternative = true; | 2605 *foundTextAlternative = true; |
2524 } else { | 2606 } else { |
2525 return textAlternative; | 2607 return textAlternative; |
2526 } | 2608 } |
2527 } | 2609 } |
2528 | 2610 |
2529 // value attr | 2611 // value attr |
2530 if (nameSources) { | 2612 if (nameSources) { |
2531 nameSources->append(NameSource(*foundTextAlternative, valueAttr)); | 2613 nameSources->append(NameSource(*foundTextAlternative, valueAttr)); |
2532 nameSources->last().type = nameFrom; | 2614 nameSources->last().type = nameFrom; |
2533 } | 2615 } |
2534 nameFrom = AXNameFromAttribute; | 2616 nameFrom = AXNameFromAttribute; |
2535 String value = inputElement->value(); | 2617 String value = inputElement->value(); |
2536 if (!value.isNull()) { | 2618 if (!value.isNull()) { |
2537 textAlternative = value; | 2619 textAlternative = value; |
2538 if (nameSources) { | 2620 if (nameSources) { |
2539 NameSource& source = nameSources->last(); | 2621 NameSource& source = nameSources->last(); |
2540 source.text = textAlternative; | 2622 source.text = textAlternative; |
2541 *foundTextAlternative = true; | 2623 *foundTextAlternative = true; |
2542 } else { | 2624 } else { |
2543 return textAlternative; | 2625 return textAlternative; |
2544 } | 2626 } |
2545 } | 2627 } |
2546 | 2628 |
| 2629 // localised default value ("Submit") |
| 2630 nameFrom = AXNameFromAttribute; |
| 2631 textAlternative = inputElement->locale().queryString(WebLocalizedString:
:SubmitButtonDefaultLabel); |
| 2632 if (nameSources) { |
| 2633 nameSources->append(NameSource(*foundTextAlternative, typeAttr)); |
| 2634 NameSource& source = nameSources->last(); |
| 2635 source.attributeValue = inputElement->getAttribute(typeAttr); |
| 2636 source.type = nameFrom; |
| 2637 source.text = textAlternative; |
| 2638 *foundTextAlternative = true; |
| 2639 } else { |
| 2640 return textAlternative; |
| 2641 } |
2547 return textAlternative; | 2642 return textAlternative; |
2548 } | 2643 } |
2549 | 2644 |
2550 // 5.5 Other labelable Elements | 2645 // 5.1 Text inputs - step 3 (placeholder attribute) |
2551 if (node()->isHTMLElement() && toHTMLElement(node())->isLabelable()) { | 2646 if (htmlElement && htmlElement->isTextFormControl()) { |
2552 // label | 2647 nameFrom = AXNameFromPlaceholder; |
2553 nameFrom = AXNameFromRelatedElement; | |
2554 if (nameSources) { | 2648 if (nameSources) { |
2555 nameSources->append(NameSource(*foundTextAlternative)); | 2649 nameSources->append(NameSource(*foundTextAlternative, placeholderAtt
r)); |
2556 nameSources->last().type = nameFrom; | 2650 NameSource& source = nameSources->last(); |
2557 nameSources->last().nativeSource = AXTextFromNativeHTMLLabel; | 2651 source.type = nameFrom; |
2558 } | 2652 } |
2559 HTMLLabelElement* label = labelForElement(toHTMLElement(node())); | 2653 HTMLElement* element = toHTMLElement(node()); |
2560 if (label) { | 2654 const AtomicString& placeholder = element->fastGetAttribute(placeholderA
ttr); |
2561 RefPtrWillBeRawPtr<AXObject> labelAXObject = axObjectCache().getOrCr
eate(label); | 2655 if (!placeholder.isEmpty()) { |
2562 if (labelAXObject) { | 2656 textAlternative = placeholder; |
2563 localNameObjects.append(labelAXObject.get()); | 2657 if (nameSources) { |
2564 nameObjects = localNameObjects; | 2658 NameSource& source = nameSources->last(); |
2565 localNameObjects.clear(); | 2659 source.text = textAlternative; |
2566 | 2660 source.attributeValue = placeholder; |
2567 textAlternative = recursiveTextAlternative(*labelAXObject, false
, visited); | 2661 } else { |
2568 | 2662 return textAlternative; |
2569 if (nameSources) { | |
2570 NameSource& source = nameSources->last(); | |
2571 source.nameObjects = nameObjects; | |
2572 source.text = textAlternative; | |
2573 if (label->getAttribute(forAttr).isNull()) | |
2574 source.nativeSource = AXTextFromNativeHTMLLabelWrapped; | |
2575 else | |
2576 source.nativeSource = AXTextFromNativeHTMLLabelFor; | |
2577 *foundTextAlternative = true; | |
2578 } else { | |
2579 return textAlternative; | |
2580 } | |
2581 } | 2663 } |
2582 } | 2664 } |
2583 return textAlternative; | 2665 return textAlternative; |
2584 } | 2666 } |
2585 | 2667 |
2586 // 5.7 figure and figcaption Elements | 2668 // 5.7 figure and figcaption Elements |
2587 if (node()->hasTagName(figureTag)) { | 2669 if (node()->hasTagName(figureTag)) { |
2588 // figcaption | 2670 // figcaption |
2589 nameFrom = AXNameFromRelatedElement; | 2671 nameFrom = AXNameFromRelatedElement; |
2590 if (nameSources) { | 2672 if (nameSources) { |
2591 nameSources->append(NameSource(*foundTextAlternative)); | 2673 nameSources->append(NameSource(*foundTextAlternative)); |
2592 nameSources->last().type = nameFrom; | 2674 nameSources->last().type = nameFrom; |
2593 nameSources->last().nativeSource = AXTextFromNativeHTMLFigcaption; | 2675 nameSources->last().nativeSource = AXTextFromNativeHTMLFigcaption; |
2594 } | 2676 } |
2595 Element* figcaption = nullptr; | 2677 Element* figcaption = nullptr; |
2596 for (Element& element : ElementTraversal::descendantsOf(*(node()))) { | 2678 for (Element& element : ElementTraversal::descendantsOf(*(node()))) { |
2597 if (element.hasTagName(figcaptionTag)) { | 2679 if (element.hasTagName(figcaptionTag)) { |
2598 figcaption = &element; | 2680 figcaption = &element; |
2599 break; | 2681 break; |
2600 } | 2682 } |
2601 } | 2683 } |
2602 if (figcaption) { | 2684 if (figcaption) { |
2603 RefPtrWillBeRawPtr<AXObject> figcaptionAXObject = axObjectCache().ge
tOrCreate(figcaption); | 2685 RefPtrWillBeRawPtr<AXObject> figcaptionAXObject = axObjectCache().ge
tOrCreate(figcaption); |
2604 if (figcaptionAXObject) { | 2686 if (figcaptionAXObject) { |
2605 localNameObjects.append(figcaptionAXObject.get()); | 2687 if (nameObjects) { |
2606 nameObjects = localNameObjects; | 2688 localNameObjects.append(figcaptionAXObject.get()); |
2607 localNameObjects.clear(); | 2689 *nameObjects = localNameObjects; |
| 2690 localNameObjects.clear(); |
| 2691 } |
2608 | 2692 |
2609 textAlternative = recursiveTextAlternative(*figcaptionAXObject,
false, visited); | 2693 textAlternative = recursiveTextAlternative(*figcaptionAXObject,
false, visited); |
2610 | 2694 |
2611 if (nameSources) { | 2695 if (nameSources) { |
2612 NameSource& source = nameSources->last(); | 2696 NameSource& source = nameSources->last(); |
2613 source.nameObjects = nameObjects; | 2697 source.nameObjects = *nameObjects; |
2614 source.text = textAlternative; | 2698 source.text = textAlternative; |
2615 } else { | 2699 } else { |
2616 return textAlternative; | 2700 return textAlternative; |
2617 } | 2701 } |
2618 } | 2702 } |
2619 } | 2703 } |
2620 return textAlternative; | 2704 return textAlternative; |
2621 } | 2705 } |
2622 | 2706 |
2623 // 5.8 img Element | 2707 // 5.8 img Element |
2624 if (isHTMLImageElement(node())) { | 2708 if (isHTMLImageElement(node())) { |
2625 HTMLImageElement* imgElement = toHTMLImageElement(node()); | |
2626 | |
2627 // alt | 2709 // alt |
2628 nameFrom = AXNameFromAttribute; | 2710 nameFrom = AXNameFromAttribute; |
2629 if (nameSources) { | 2711 if (nameSources) { |
2630 nameSources->append(NameSource(*foundTextAlternative, altAttr)); | 2712 nameSources->append(NameSource(*foundTextAlternative, altAttr)); |
2631 nameSources->last().type = nameFrom; | 2713 nameSources->last().type = nameFrom; |
2632 } | 2714 } |
2633 if (imgElement->hasAttribute(altAttr)) { | 2715 const AtomicString& alt = getAttribute(altAttr); |
2634 AtomicString alt = imgElement->getAttribute(altAttr); | 2716 if (!alt.isNull()) { |
2635 textAlternative = alt; | 2717 textAlternative = alt; |
2636 if (nameSources) { | 2718 if (nameSources) { |
2637 NameSource& source = nameSources->last(); | 2719 NameSource& source = nameSources->last(); |
2638 source.attributeValue = alt; | 2720 source.attributeValue = alt; |
2639 source.text = textAlternative; | 2721 source.text = textAlternative; |
2640 *foundTextAlternative = true; | 2722 *foundTextAlternative = true; |
2641 } else { | 2723 } else { |
2642 return textAlternative; | 2724 return textAlternative; |
2643 } | 2725 } |
2644 } | 2726 } |
2645 return textAlternative; | 2727 return textAlternative; |
2646 } | 2728 } |
2647 | 2729 |
2648 // 5.9 table Element | 2730 // 5.9 table Element |
2649 if (isHTMLTableElement(node())) { | 2731 if (isHTMLTableElement(node())) { |
2650 HTMLTableElement* tableElement = toHTMLTableElement(node()); | 2732 HTMLTableElement* tableElement = toHTMLTableElement(node()); |
2651 | 2733 |
2652 // caption | 2734 // caption |
2653 nameFrom = AXNameFromRelatedElement; | 2735 nameFrom = AXNameFromRelatedElement; |
2654 if (nameSources) { | 2736 if (nameSources) { |
2655 nameSources->append(NameSource(*foundTextAlternative)); | 2737 nameSources->append(NameSource(*foundTextAlternative)); |
2656 nameSources->last().type = nameFrom; | 2738 nameSources->last().type = nameFrom; |
2657 nameSources->last().nativeSource = AXTextFromNativeHTMLTableCaption; | 2739 nameSources->last().nativeSource = AXTextFromNativeHTMLTableCaption; |
2658 } | 2740 } |
2659 HTMLTableCaptionElement* caption = tableElement->caption(); | 2741 HTMLTableCaptionElement* caption = tableElement->caption(); |
2660 if (caption) { | 2742 if (caption) { |
2661 RefPtrWillBeRawPtr<AXObject> captionAXObject = axObjectCache().getOr
Create(caption); | 2743 RefPtrWillBeRawPtr<AXObject> captionAXObject = axObjectCache().getOr
Create(caption); |
2662 if (captionAXObject) { | 2744 if (captionAXObject) { |
2663 localNameObjects.append(captionAXObject.get()); | 2745 if (nameObjects) { |
2664 nameObjects = localNameObjects; | 2746 localNameObjects.append(captionAXObject.get()); |
2665 localNameObjects.clear(); | 2747 *nameObjects = localNameObjects; |
| 2748 localNameObjects.clear(); |
| 2749 } |
2666 | 2750 |
2667 textAlternative = recursiveTextAlternative(*captionAXObject, fal
se, visited); | 2751 textAlternative = recursiveTextAlternative(*captionAXObject, fal
se, visited); |
2668 if (nameSources) { | 2752 if (nameSources) { |
2669 NameSource& source = nameSources->last(); | 2753 NameSource& source = nameSources->last(); |
2670 source.nameObjects = nameObjects; | 2754 source.nameObjects = *nameObjects; |
2671 source.text = textAlternative; | 2755 source.text = textAlternative; |
2672 } else { | 2756 } else { |
2673 return textAlternative; | 2757 return textAlternative; |
2674 } | 2758 } |
2675 } | 2759 } |
2676 } | 2760 } |
| 2761 |
| 2762 // summary |
| 2763 nameFrom = AXNameFromAttribute; |
| 2764 if (nameSources) { |
| 2765 nameSources->append(NameSource(*foundTextAlternative)); |
| 2766 nameSources->last().type = nameFrom; |
| 2767 } |
| 2768 const AtomicString& summary = getAttribute(summaryAttr); |
| 2769 if (!summary.isNull()) { |
| 2770 textAlternative = summary; |
| 2771 if (nameSources) { |
| 2772 NameSource& source = nameSources->last(); |
| 2773 source.attributeValue = summary; |
| 2774 source.text = textAlternative; |
| 2775 *foundTextAlternative = true; |
| 2776 } else { |
| 2777 return textAlternative; |
| 2778 } |
| 2779 } |
| 2780 |
2677 return textAlternative; | 2781 return textAlternative; |
2678 } | 2782 } |
2679 | 2783 |
2680 return textAlternative; | 2784 return textAlternative; |
2681 } | 2785 } |
2682 | 2786 |
2683 DEFINE_TRACE(AXNodeObject) | 2787 DEFINE_TRACE(AXNodeObject) |
2684 { | 2788 { |
2685 visitor->trace(m_node); | 2789 visitor->trace(m_node); |
2686 AXObject::trace(visitor); | 2790 AXObject::trace(visitor); |
2687 } | 2791 } |
2688 | 2792 |
2689 } // namespace blink | 2793 } // namespace blink |
OLD | NEW |