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

Side by Side Diff: Source/modules/accessibility/AXNodeObject.cpp

Issue 1301993003: Last few steps of text alternative computation algorithm (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: esprehn comments Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/modules/accessibility/AXNodeObject.h ('k') | Source/modules/accessibility/AXObject.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « Source/modules/accessibility/AXNodeObject.h ('k') | Source/modules/accessibility/AXObject.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698