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

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: Testing all the special cases Created 5 years, 4 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
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"
54 #include "core/layout/LayoutObject.h" 55 #include "core/layout/LayoutObject.h"
55 #include "modules/accessibility/AXObjectCacheImpl.h" 56 #include "modules/accessibility/AXObjectCacheImpl.h"
56 #include "platform/UserGestureIndicator.h" 57 #include "platform/UserGestureIndicator.h"
58 #include "platform/text/PlatformLocale.h"
57 #include "wtf/text/StringBuilder.h" 59 #include "wtf/text/StringBuilder.h"
58 60
59 61
60 namespace blink { 62 namespace blink {
61 63
62 using namespace HTMLNames; 64 using namespace HTMLNames;
63 65
64 AXNodeObject::AXNodeObject(Node* node, AXObjectCacheImpl& axObjectCache) 66 AXNodeObject::AXNodeObject(Node* node, AXObjectCacheImpl& axObjectCache)
65 : AXObject(axObjectCache) 67 : AXObject(axObjectCache)
66 , m_ariaRole(UnknownRole) 68 , 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) 245 static bool isRequiredOwnedElement(AXObject* parent, AccessibilityRole currentRo le, HTMLElement* currentElement)
244 { 246 {
245 Node* parentNode = parent->node(); 247 Node* parentNode = parent->node();
246 if (!parentNode || !parentNode->isHTMLElement()) 248 if (!parentNode || !parentNode->isHTMLElement())
247 return false; 249 return false;
248 250
249 if (currentRole == ListItemRole) 251 if (currentRole == ListItemRole)
250 return isListElement(parentNode); 252 return isListElement(parentNode);
251 if (currentRole == ListMarkerRole) 253 if (currentRole == ListMarkerRole)
252 return isHTMLLIElement(*parentNode); 254 return isHTMLLIElement(*parentNode);
253 if (currentRole == MenuItemCheckBoxRole || currentRole == MenuItemRole || c urrentRole == MenuItemRadioRole) 255 if (currentRole == MenuItemCheckBoxRole || currentRole == MenuItemRole || cu rrentRole == MenuItemRadioRole)
254 return isHTMLMenuElement(*parentNode); 256 return isHTMLMenuElement(*parentNode);
255 257
256 if (!currentElement) 258 if (!currentElement)
257 return false; 259 return false;
258 if (isHTMLTableCellElement(*currentElement)) 260 if (isHTMLTableCellElement(*currentElement))
259 return isHTMLTableRowElement(*parentNode); 261 return isHTMLTableRowElement(*parentNode);
260 if (isHTMLTableRowElement(*currentElement)) 262 if (isHTMLTableRowElement(*currentElement))
261 return isHTMLTableSectionElement(toHTMLElement(*parentNode)); 263 return isHTMLTableSectionElement(toHTMLElement(*parentNode));
262 264
263 // In case of ListboxRole and it's child, ListBoxOptionRole, 265 // In case of ListboxRole and it's child, ListBoxOptionRole,
264 // Inheritance of presentation role is handled in AXListBoxOption 266 // Inheritance of presentation role is handled in AXListBoxOption
265 // Because ListBoxOption Role doesn't have any child. 267 // 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. 268 // If it's just ignored because of presentation, we can't see any AX tree re lated to ListBoxOption.
267 return false; 269 return false;
268 } 270 }
269 271
270
271 const AXObject* AXNodeObject::inheritsPresentationalRoleFrom() const 272 const AXObject* AXNodeObject::inheritsPresentationalRoleFrom() const
272 { 273 {
273 // ARIA states if an item can get focus, it should not be presentational. 274 // ARIA states if an item can get focus, it should not be presentational.
274 if (canSetFocusAttribute()) 275 if (canSetFocusAttribute())
275 return 0; 276 return 0;
276 277
277 if (isPresentational()) 278 if (isPresentational())
278 return this; 279 return this;
279 280
280 // http://www.w3.org/TR/wai-aria/complete#presentation 281 // 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())) 330 if (node()->isLink() || (isHTMLAnchorElement(*node()) && isClickable()))
330 return LinkRole; 331 return LinkRole;
331 332
332 if (isHTMLButtonElement(*node())) 333 if (isHTMLButtonElement(*node()))
333 return buttonRoleType(); 334 return buttonRoleType();
334 335
335 if (isHTMLDetailsElement(*node())) 336 if (isHTMLDetailsElement(*node()))
336 return DetailsRole; 337 return DetailsRole;
337 338
338 if (isHTMLSummaryElement(*node())) { 339 if (isHTMLSummaryElement(*node())) {
339 if (node()->parentNode() && isHTMLDetailsElement(node()->parentNode())) 340 if (ComposedTreeTraversal::parent(*node()) && isHTMLDetailsElement(Compo sedTreeTraversal::parent(*node())))
340 return DisclosureTriangleRole; 341 return DisclosureTriangleRole;
341 return UnknownRole; 342 return UnknownRole;
342 } 343 }
343 344
344 if (isHTMLInputElement(*node())) { 345 if (isHTMLInputElement(*node())) {
345 HTMLInputElement& input = toHTMLInputElement(*node()); 346 HTMLInputElement& input = toHTMLInputElement(*node());
346 const AtomicString& type = input.type(); 347 const AtomicString& type = input.type();
347 if (input.dataList()) 348 if (input.dataList())
348 return ComboBoxRole; 349 return ComboBoxRole;
349 if (type == InputTypeNames::button) { 350 if (type == InputTypeNames::button) {
(...skipping 1421 matching lines...) Expand 10 before | Expand all | Expand 10 after
1771 return placeholder; 1772 return placeholder;
1772 } 1773 }
1773 1774
1774 return String(); 1775 return String();
1775 } 1776 }
1776 1777
1777 // 1778 //
1778 // New AX name calculation. 1779 // New AX name calculation.
1779 // 1780 //
1780 1781
1781 String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraver sal, AXObjectSet& visited, AXNameFrom& nameFrom, AXObjectVector& nameObjects, Na meSources* nameSources) const 1782 String AXNodeObject::textAlternative(bool recursive, bool inAriaLabelledByTraver sal, AXObjectSet& visited, AXNameFrom& nameFrom, AXObjectVector* nameObjects, Na meSources* nameSources) const
1782 { 1783 {
1784 // If nameSources is non-null, nameObjects is used in filling it in, so it m ust be non-null as well.
1785 if (nameSources)
1786 assert(nameObjects);
1787
1783 bool alreadyVisited = visited.contains(this); 1788 bool alreadyVisited = visited.contains(this);
1784 bool foundTextAlternative = false; 1789 bool foundTextAlternative = false;
1785 visited.add(this); 1790 visited.add(this);
1786 String textAlternative; 1791 String textAlternative;
1787 1792
1788 if (!node() && !layoutObject()) 1793 if (!node() && !layoutObject())
1789 return String(); 1794 return String();
1790 1795
1791 // Step 2A from: http://www.w3.org/TR/accname-aam-1.1 1796 // Step 2A from: http://www.w3.org/TR/accname-aam-1.1
1792 if (!recursive && layoutObject() 1797 if (!recursive && layoutObject()
(...skipping 14 matching lines...) Expand all
1807 if (hasAttribute(attr)) { 1812 if (hasAttribute(attr)) {
1808 if (nameSources) 1813 if (nameSources)
1809 nameSources->last().attributeValue = getAttribute(attr); 1814 nameSources->last().attributeValue = getAttribute(attr);
1810 1815
1811 textAlternative = textFromAriaLabelledby(visited, nameObjects); 1816 textAlternative = textFromAriaLabelledby(visited, nameObjects);
1812 1817
1813 if (!textAlternative.isNull()) { 1818 if (!textAlternative.isNull()) {
1814 if (nameSources) { 1819 if (nameSources) {
1815 NameSource& source = nameSources->last(); 1820 NameSource& source = nameSources->last();
1816 source.type = nameFrom; 1821 source.type = nameFrom;
1817 source.nameObjects = nameObjects; 1822 source.nameObjects = *nameObjects;
1818 source.text = textAlternative; 1823 source.text = textAlternative;
1819 foundTextAlternative = true; 1824 foundTextAlternative = true;
1820 } else { 1825 } else {
1821 return textAlternative; 1826 return textAlternative;
1822 } 1827 }
1823 } else if (nameSources) { 1828 } else if (nameSources) {
1824 nameSources->last().invalid = true; 1829 nameSources->last().invalid = true;
1825 } 1830 }
1826 } 1831 }
1827 } 1832 }
(...skipping 19 matching lines...) Expand all
1847 } 1852 }
1848 } 1853 }
1849 } 1854 }
1850 1855
1851 // Step 2D from: http://www.w3.org/TR/accname-aam-1.1 1856 // Step 2D from: http://www.w3.org/TR/accname-aam-1.1
1852 textAlternative = nativeTextAlternative(visited, nameFrom, nameObjects, name Sources, &foundTextAlternative); 1857 textAlternative = nativeTextAlternative(visited, nameFrom, nameObjects, name Sources, &foundTextAlternative);
1853 if (!textAlternative.isNull() && !nameSources) 1858 if (!textAlternative.isNull() && !nameSources)
1854 return textAlternative; 1859 return textAlternative;
1855 1860
1856 // Step 2E from: http://www.w3.org/TR/accname-aam-1.1 1861 // Step 2E from: http://www.w3.org/TR/accname-aam-1.1
1857 1862 if (recursive && !inAriaLabelledByTraversal && isControl()) {
1863 // No need to set any name source info in a recursive call.
1864 if (roleValue() == TextFieldRole || roleValue() == ComboBoxRole)
1865 return text();
1866 if (isRange()) {
1867 if (hasAttribute(aria_valuetextAttr))
1868 return getAttribute(aria_valuetextAttr).string();
1869 return String::number(valueForRange());
1870 }
1871 }
1858 1872
1859 // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1 1873 // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1
1860 if (recursive || nameFromContents()) { 1874 if (recursive || nameFromContents()) {
1861 nameFrom = AXNameFromContents; 1875 nameFrom = AXNameFromContents;
1862 if (nameSources) { 1876 if (nameSources) {
1863 nameSources->append(NameSource(foundTextAlternative)); 1877 nameSources->append(NameSource(foundTextAlternative));
1864 nameSources->last().type = nameFrom; 1878 nameSources->last().type = nameFrom;
1865 } 1879 }
1866 1880
1867 Node* node = this->node(); 1881 Node* node = this->node();
1868 if (node && node->isTextNode()) 1882 if (node && node->isTextNode())
1869 textAlternative = toText(node)->wholeText(); 1883 textAlternative = toText(node)->wholeText();
1870 else 1884 else
1871 textAlternative = textFromDescendants(visited); 1885 textAlternative = textFromDescendants(visited);
1872 1886
1873 if (nameSources) { 1887 if (!textAlternative.isEmpty()) {
1874 foundTextAlternative = true; 1888 if (nameSources) {
1875 nameSources->last().text = textAlternative; 1889 foundTextAlternative = true;
1876 } else { 1890 nameSources->last().text = textAlternative;
1877 return textAlternative; 1891 } else {
1892 return textAlternative;
1893 }
1894 }
1895 }
1896
1897 // Step 2H from: http://www.w3.org/TR/accname-aam-1.1
1898 nameFrom = AXNameFromAttribute;
1899 if (nameSources) {
1900 nameSources->append(NameSource(foundTextAlternative, titleAttr));
1901 nameSources->last().type = nameFrom;
1902 }
1903 if (hasAttribute(titleAttr)) {
1904 const AtomicString& title = getAttribute(titleAttr);
1905 if (!title.isEmpty()) {
1906 textAlternative = title;
1907 if (nameSources) {
1908 foundTextAlternative = true;
1909 nameSources->last().text = textAlternative;
1910 } else {
1911 return textAlternative;
1912 }
1878 } 1913 }
1879 } 1914 }
1880 1915
1881 nameFrom = AXNameFromUninitialized; 1916 nameFrom = AXNameFromUninitialized;
1882 1917
1883 if (nameSources && !nameSources->isEmpty()) { 1918 if (foundTextAlternative) {
1884 for (size_t i = 0; i < nameSources->size(); ++i) { 1919 for (size_t i = 0; i < nameSources->size(); ++i) {
1885 if (!(*nameSources)[i].text.isNull() && !(*nameSources)[i].supersede d) { 1920 if (!(*nameSources)[i].text.isNull() && !(*nameSources)[i].supersede d) {
1886 nameFrom = (*nameSources)[i].type; 1921 NameSource& nameSource = (*nameSources)[i];
1887 nameObjects = (*nameSources)[i].nameObjects; 1922 nameFrom = nameSource.type;
1888 return (*nameSources)[i].text; 1923 if (!nameSource.nameObjects.isEmpty())
1924 *nameObjects = nameSource.nameObjects;
1925 return nameSource.text;
1889 } 1926 }
1890 } 1927 }
1891 } 1928 }
1892 1929
1893 return String(); 1930 return String();
1894 } 1931 }
1895 1932
1896 String AXNodeObject::textFromDescendants(AXObjectSet& visited) const 1933 String AXNodeObject::textFromDescendants(AXObjectSet& visited) const
1897 { 1934 {
1898 StringBuilder accumulatedText; 1935 StringBuilder accumulatedText;
1899 AXObject* previous = nullptr; 1936 AXObject* previous = nullptr;
1900 for (AXObject* child = firstChild(); child; child = child->nextSibling()) { 1937 for (AXObject* child = firstChild(); child; child = child->nextSibling()) {
1901 // If we're going between two layoutObjects that are in separate LayoutB oxes, add 1938 // 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 1939 // 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 1940 // <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 1941 // 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". 1942 // strings are in separate boxes so we should return "Hello World".
1906 if (previous && accumulatedText.length() && !isHTMLSpace(accumulatedText [accumulatedText.length() - 1])) { 1943 if (previous && accumulatedText.length() && !isHTMLSpace(accumulatedText [accumulatedText.length() - 1])) {
1907 if (!isSameLayoutBox(child->layoutObject(), previous->layoutObject() )) 1944 if (!isSameLayoutBox(child->layoutObject(), previous->layoutObject() ))
1908 accumulatedText.append(' '); 1945 accumulatedText.append(' ');
1909 } 1946 }
1910 1947
1911 AXNameFrom nameFrom; 1948 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); 1949 accumulatedText.append(result);
1915 previous = child; 1950 previous = child;
1916 } 1951 }
1917 1952
1918 return accumulatedText.toString(); 1953 return accumulatedText.toString();
1919 } 1954 }
1920 1955
1921 String AXNodeObject::textFromElements(bool inAriaLabelledbyTraversal, AXObjectSe t& visited, WillBeHeapVector<RawPtrWillBeMember<Element>>& elements, AXObjectVec tor& nameObjects) const 1956 String AXNodeObject::textFromElements(bool inAriaLabelledbyTraversal, AXObjectSe t& visited, WillBeHeapVector<RawPtrWillBeMember<Element>>& elements, AXObjectVec tor* nameObjects) const
1922 { 1957 {
1923 StringBuilder accumulatedText; 1958 StringBuilder accumulatedText;
1924 bool foundValidElement = false; 1959 bool foundValidElement = false;
1925 AXObjectVector localNameObjects; 1960 AXObjectVector localNameObjects;
1926 1961
1927 for (const auto& element : elements) { 1962 for (const auto& element : elements) {
1928 RefPtrWillBeRawPtr<AXObject> axElement = axObjectCache().getOrCreate(ele ment); 1963 RefPtrWillBeRawPtr<AXObject> axElement = axObjectCache().getOrCreate(ele ment);
1929 if (axElement) { 1964 if (axElement) {
1930 foundValidElement = true; 1965 foundValidElement = true;
1931 localNameObjects.append(axElement.get()); 1966 localNameObjects.append(axElement.get());
1932 1967
1933 String result = recursiveTextAlternative(*axElement, inAriaLabelledb yTraversal, visited); 1968 String result = recursiveTextAlternative(*axElement, inAriaLabelledb yTraversal, visited);
1934 if (!result.isEmpty()) { 1969 if (!result.isEmpty()) {
1935 if (!accumulatedText.isEmpty()) 1970 if (!accumulatedText.isEmpty())
1936 accumulatedText.append(" "); 1971 accumulatedText.append(" ");
1937 accumulatedText.append(result); 1972 accumulatedText.append(result);
1938 } 1973 }
1939 } 1974 }
1940 } 1975 }
1941 if (!foundValidElement) 1976 if (!foundValidElement)
1942 return String(); 1977 return String();
1943 nameObjects = localNameObjects; 1978 if (nameObjects)
1979 *nameObjects = localNameObjects;
1944 return accumulatedText.toString(); 1980 return accumulatedText.toString();
1945 } 1981 }
1946 1982
1947 String AXNodeObject::textFromAriaLabelledby(AXObjectSet& visited, AXObjectVector & nameObjects) const 1983 String AXNodeObject::textFromAriaLabelledby(AXObjectSet& visited, AXObjectVector * nameObjects) const
1948 { 1984 {
1949 WillBeHeapVector<RawPtrWillBeMember<Element>> elements; 1985 WillBeHeapVector<RawPtrWillBeMember<Element>> elements;
1950 ariaLabelledbyElements(elements); 1986 ariaLabelledbyElements(elements);
1951 return textFromElements(true, visited, elements, nameObjects); 1987 return textFromElements(true, visited, elements, nameObjects);
1952 } 1988 }
1953 1989
1954 LayoutRect AXNodeObject::elementRect() const 1990 LayoutRect AXNodeObject::elementRect() const
1955 { 1991 {
1956 // First check if it has a custom rect, for example if this element is tied to a canvas path. 1992 // First check if it has a custom rect, for example if this element is tied to a canvas path.
1957 if (!m_explicitElementRect.isEmpty()) 1993 if (!m_explicitElementRect.isEmpty())
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
2140 } 2176 }
2141 2177
2142 Element* AXNodeObject::actionElement() const 2178 Element* AXNodeObject::actionElement() const
2143 { 2179 {
2144 Node* node = this->node(); 2180 Node* node = this->node();
2145 if (!node) 2181 if (!node)
2146 return 0; 2182 return 0;
2147 2183
2148 if (isHTMLInputElement(*node)) { 2184 if (isHTMLInputElement(*node)) {
2149 HTMLInputElement& input = toHTMLInputElement(*node); 2185 HTMLInputElement& input = toHTMLInputElement(*node);
2150 if (!input.isDisabledFormControl() && (isCheckboxOrRadio() || input.isTe xtButton() 2186 if (!input.isDisabledFormControl() && (isCheckboxOrRadio() || input.isTe xtButton() || input.type() == InputTypeNames::file))
2151 || input.type() == InputTypeNames::file))
2152 return &input; 2187 return &input;
2153 } else if (isHTMLButtonElement(*node)) { 2188 } else if (isHTMLButtonElement(*node)) {
2154 return toElement(node); 2189 return toElement(node);
2155 } 2190 }
2156 2191
2157 if (AXObject::isARIAInput(ariaRoleAttribute())) 2192 if (AXObject::isARIAInput(ariaRoleAttribute()))
2158 return toElement(node); 2193 return toElement(node);
2159 2194
2160 if (isImageButton()) 2195 if (isImageButton())
2161 return toElement(node); 2196 return toElement(node);
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
2447 ariaLabelledbyElements(elements); 2482 ariaLabelledbyElements(elements);
2448 2483
2449 for (const auto& element : elements) { 2484 for (const auto& element : elements) {
2450 RefPtrWillBeRawPtr<AXObject> axElement = axObjectCache().getOrCreate (element); 2485 RefPtrWillBeRawPtr<AXObject> axElement = axObjectCache().getOrCreate (element);
2451 textOrder.append(AccessibilityText::create(ariaLabelledby, Alternati veText, axElement)); 2486 textOrder.append(AccessibilityText::create(ariaLabelledby, Alternati veText, axElement));
2452 } 2487 }
2453 } 2488 }
2454 } 2489 }
2455 2490
2456 // Based on http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible- name-and-description-calculation 2491 // 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 2492 String AXNodeObject::nativeTextAlternative(AXObjectSet& visited, AXNameFrom& nam eFrom, AXObjectVector* nameObjects, NameSources* nameSources, bool* foundTextAlt ernative) const
2458 { 2493 {
2459 if (!node()) 2494 if (!node())
2460 return String(); 2495 return String();
2461 2496
2497 // If nameSources is non-null, nameObjects is used in filling it in, so it m ust be non-null as well.
2498 if (nameSources)
2499 assert(nameObjects);
2500
2462 String textAlternative; 2501 String textAlternative;
2463 AXObjectVector localNameObjects; 2502 AXObjectVector localNameObjects;
2464 2503
2465 const HTMLInputElement* inputElement = nullptr; 2504 const HTMLInputElement* inputElement = nullptr;
2466 if (isHTMLInputElement(node())) 2505 if (isHTMLInputElement(node()))
2467 inputElement = toHTMLInputElement(node()); 2506 inputElement = toHTMLInputElement(node());
2468 2507
2508 // 5.1/5.5 Text inputs, Other labelable Elements
2509 HTMLElement* htmlElement = nullptr;
2510 if (node()->isHTMLElement())
2511 htmlElement = toHTMLElement(node());
2512 if (htmlElement && htmlElement->isLabelable()) {
2513 // label
2514 nameFrom = AXNameFromRelatedElement;
2515 if (nameSources) {
2516 nameSources->append(NameSource(*foundTextAlternative));
2517 nameSources->last().type = nameFrom;
2518 nameSources->last().nativeSource = AXTextFromNativeHTMLLabel;
2519 }
2520 HTMLLabelElement* label = labelForElement(htmlElement);
2521 if (label) {
2522 RefPtrWillBeRawPtr<AXObject> labelAXObject = axObjectCache().getOrCr eate(label);
2523 if (labelAXObject) {
2524 if (nameObjects) {
2525 localNameObjects.append(labelAXObject.get());
2526 *nameObjects = localNameObjects;
2527 localNameObjects.clear();
2528 }
2529 textAlternative = recursiveTextAlternative(*labelAXObject, false , visited);
2530
2531 if (nameSources) {
2532 NameSource& source = nameSources->last();
2533 source.nameObjects = *nameObjects;
2534 source.text = textAlternative;
2535 if (label->getAttribute(forAttr).isNull())
2536 source.nativeSource = AXTextFromNativeHTMLLabelWrapped;
2537 else
2538 source.nativeSource = AXTextFromNativeHTMLLabelFor;
2539 *foundTextAlternative = true;
2540 } else {
2541 return textAlternative;
2542 }
2543 }
2544 }
2545 }
2546
2469 // 5.2 input type="button", input type="submit" and input type="reset" 2547 // 5.2 input type="button", input type="submit" and input type="reset"
2470 if (inputElement && inputElement->isTextButton()) { 2548 if (inputElement && inputElement->isTextButton()) {
2471 // value attribue 2549 // value attribue
2472 nameFrom = AXNameFromAttribute; 2550 nameFrom = AXNameFromAttribute;
2473 if (nameSources) { 2551 if (nameSources) {
2474 nameSources->append(NameSource(*foundTextAlternative, valueAttr)); 2552 nameSources->append(NameSource(*foundTextAlternative, valueAttr));
2475 nameSources->last().type = nameFrom; 2553 nameSources->last().type = nameFrom;
2476 } 2554 }
2477 String value = inputElement->value(); 2555 String value = inputElement->value();
2478 if (!value.isNull()) { 2556 if (!value.isNull()) {
2479 textAlternative = value; 2557 textAlternative = value;
2480 if (nameSources) { 2558 if (nameSources) {
2481 NameSource& source = nameSources->last(); 2559 NameSource& source = nameSources->last();
2482 source.text = textAlternative; 2560 source.text = textAlternative;
2483 *foundTextAlternative = true; 2561 *foundTextAlternative = true;
2484 } else { 2562 } else {
2485 return textAlternative; 2563 return textAlternative;
2486 } 2564 }
2487 } 2565 }
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; 2566 return textAlternative;
2506 } 2567 }
2507 2568
2508 // 5.3 input type="image" 2569 // 5.3 input type="image"
2509 if (inputElement && inputElement->getAttribute(typeAttr) == InputTypeNames:: image) { 2570 if (inputElement && inputElement->getAttribute(typeAttr) == InputTypeNames:: image) {
2510 // alt attr 2571 // alt attr
2511 nameFrom = AXNameFromAttribute; 2572 nameFrom = AXNameFromAttribute;
2512 if (nameSources) { 2573 if (nameSources) {
2513 nameSources->append(NameSource(*foundTextAlternative, altAttr)); 2574 nameSources->append(NameSource(*foundTextAlternative, altAttr));
2514 nameSources->last().type = nameFrom; 2575 nameSources->last().type = nameFrom;
(...skipping 22 matching lines...) Expand all
2537 textAlternative = value; 2598 textAlternative = value;
2538 if (nameSources) { 2599 if (nameSources) {
2539 NameSource& source = nameSources->last(); 2600 NameSource& source = nameSources->last();
2540 source.text = textAlternative; 2601 source.text = textAlternative;
2541 *foundTextAlternative = true; 2602 *foundTextAlternative = true;
2542 } else { 2603 } else {
2543 return textAlternative; 2604 return textAlternative;
2544 } 2605 }
2545 } 2606 }
2546 2607
2608 // localised default value ("Submit")
dmazzoni 2015/08/24 18:02:03 Oh, got it - <input type=image> implies a Submit b
2609 nameFrom = AXNameFromAttribute;
2610 textAlternative = inputElement->locale().queryString(WebLocalizedString: :SubmitButtonDefaultLabel);
2611 if (nameSources) {
2612 nameSources->append(NameSource(*foundTextAlternative, typeAttr));
2613 NameSource& source = nameSources->last();
2614 source.attributeValue = inputElement->getAttribute(typeAttr);
2615 source.type = nameFrom;
2616 source.text = textAlternative;
2617 *foundTextAlternative = true;
2618 } else {
2619 return textAlternative;
2620 }
2547 return textAlternative; 2621 return textAlternative;
2548 } 2622 }
2549 2623
2550 // 5.5 Other labelable Elements 2624 // 5.1 Text inputs - step 3 (placeholder attribute)
2551 if (node()->isHTMLElement() && toHTMLElement(node())->isLabelable()) { 2625 if (htmlElement && htmlElement->isTextFormControl()) {
2552 // label 2626 nameFrom = AXNameFromPlaceholder;
2553 nameFrom = AXNameFromRelatedElement;
2554 if (nameSources) { 2627 if (nameSources) {
2555 nameSources->append(NameSource(*foundTextAlternative)); 2628 nameSources->append(NameSource(*foundTextAlternative, placeholderAtt r));
2556 nameSources->last().type = nameFrom; 2629 NameSource& source = nameSources->last();
2557 nameSources->last().nativeSource = AXTextFromNativeHTMLLabel; 2630 source.type = nameFrom;
2558 } 2631 }
2559 HTMLLabelElement* label = labelForElement(toHTMLElement(node())); 2632 HTMLElement* element = toHTMLElement(node());
2560 if (label) { 2633 if (element->fastHasAttribute(placeholderAttr)) {
2561 RefPtrWillBeRawPtr<AXObject> labelAXObject = axObjectCache().getOrCr eate(label); 2634 const AtomicString& placeholder = element->fastGetAttribute(placehol derAttr);
2562 if (labelAXObject) { 2635 if (!placeholder.isEmpty()) {
2563 localNameObjects.append(labelAXObject.get()); 2636 textAlternative = placeholder;
2564 nameObjects = localNameObjects;
2565 localNameObjects.clear();
2566
2567 textAlternative = recursiveTextAlternative(*labelAXObject, false , visited);
2568
2569 if (nameSources) { 2637 if (nameSources) {
2570 NameSource& source = nameSources->last(); 2638 NameSource& source = nameSources->last();
2571 source.nameObjects = nameObjects;
2572 source.text = textAlternative; 2639 source.text = textAlternative;
2573 if (label->getAttribute(forAttr).isNull()) 2640 source.attributeValue = placeholder;
2574 source.nativeSource = AXTextFromNativeHTMLLabelWrapped;
2575 else
2576 source.nativeSource = AXTextFromNativeHTMLLabelFor;
2577 *foundTextAlternative = true;
2578 } else { 2641 } else {
2579 return textAlternative; 2642 return textAlternative;
2580 } 2643 }
2581 } 2644 }
2582 } 2645 }
2583 return textAlternative; 2646 return textAlternative;
2584 } 2647 }
2585 2648
2586 // 5.7 figure and figcaption Elements 2649 // 5.7 figure and figcaption Elements
2587 if (node()->hasTagName(figureTag)) { 2650 if (node()->hasTagName(figureTag)) {
2588 // figcaption 2651 // figcaption
2589 nameFrom = AXNameFromRelatedElement; 2652 nameFrom = AXNameFromRelatedElement;
2590 if (nameSources) { 2653 if (nameSources) {
2591 nameSources->append(NameSource(*foundTextAlternative)); 2654 nameSources->append(NameSource(*foundTextAlternative));
2592 nameSources->last().type = nameFrom; 2655 nameSources->last().type = nameFrom;
2593 nameSources->last().nativeSource = AXTextFromNativeHTMLFigcaption; 2656 nameSources->last().nativeSource = AXTextFromNativeHTMLFigcaption;
2594 } 2657 }
2595 Element* figcaption = nullptr; 2658 Element* figcaption = nullptr;
2596 for (Element& element : ElementTraversal::descendantsOf(*(node()))) { 2659 for (Element& element : ElementTraversal::descendantsOf(*(node()))) {
2597 if (element.hasTagName(figcaptionTag)) { 2660 if (element.hasTagName(figcaptionTag)) {
2598 figcaption = &element; 2661 figcaption = &element;
2599 break; 2662 break;
2600 } 2663 }
2601 } 2664 }
2602 if (figcaption) { 2665 if (figcaption) {
2603 RefPtrWillBeRawPtr<AXObject> figcaptionAXObject = axObjectCache().ge tOrCreate(figcaption); 2666 RefPtrWillBeRawPtr<AXObject> figcaptionAXObject = axObjectCache().ge tOrCreate(figcaption);
2604 if (figcaptionAXObject) { 2667 if (figcaptionAXObject) {
2605 localNameObjects.append(figcaptionAXObject.get()); 2668 if (nameObjects) {
2606 nameObjects = localNameObjects; 2669 localNameObjects.append(figcaptionAXObject.get());
2607 localNameObjects.clear(); 2670 *nameObjects = localNameObjects;
2671 localNameObjects.clear();
2672 }
2608 2673
2609 textAlternative = recursiveTextAlternative(*figcaptionAXObject, false, visited); 2674 textAlternative = recursiveTextAlternative(*figcaptionAXObject, false, visited);
2610 2675
2611 if (nameSources) { 2676 if (nameSources) {
2612 NameSource& source = nameSources->last(); 2677 NameSource& source = nameSources->last();
2613 source.nameObjects = nameObjects; 2678 source.nameObjects = *nameObjects;
2614 source.text = textAlternative; 2679 source.text = textAlternative;
2615 } else { 2680 } else {
2616 return textAlternative; 2681 return textAlternative;
2617 } 2682 }
2618 } 2683 }
2619 } 2684 }
2620 return textAlternative; 2685 return textAlternative;
2621 } 2686 }
2622 2687
2623 // 5.8 img Element 2688 // 5.8 img Element
2624 if (isHTMLImageElement(node())) { 2689 if (isHTMLImageElement(node())) {
2625 HTMLImageElement* imgElement = toHTMLImageElement(node());
2626
2627 // alt 2690 // alt
2628 nameFrom = AXNameFromAttribute; 2691 nameFrom = AXNameFromAttribute;
2629 if (nameSources) { 2692 if (nameSources) {
2630 nameSources->append(NameSource(*foundTextAlternative, altAttr)); 2693 nameSources->append(NameSource(*foundTextAlternative, altAttr));
2631 nameSources->last().type = nameFrom; 2694 nameSources->last().type = nameFrom;
2632 } 2695 }
2633 if (imgElement->hasAttribute(altAttr)) { 2696 if (hasAttribute(altAttr)) {
2634 AtomicString alt = imgElement->getAttribute(altAttr); 2697 AtomicString alt = getAttribute(altAttr);
2635 textAlternative = alt; 2698 textAlternative = alt;
2636 if (nameSources) { 2699 if (nameSources) {
2637 NameSource& source = nameSources->last(); 2700 NameSource& source = nameSources->last();
2638 source.attributeValue = alt; 2701 source.attributeValue = alt;
2639 source.text = textAlternative; 2702 source.text = textAlternative;
2640 *foundTextAlternative = true; 2703 *foundTextAlternative = true;
2641 } else { 2704 } else {
2642 return textAlternative; 2705 return textAlternative;
2643 } 2706 }
2644 } 2707 }
2645 return textAlternative; 2708 return textAlternative;
2646 } 2709 }
2647 2710
2648 // 5.9 table Element 2711 // 5.9 table Element
2649 if (isHTMLTableElement(node())) { 2712 if (isHTMLTableElement(node())) {
2650 HTMLTableElement* tableElement = toHTMLTableElement(node()); 2713 HTMLTableElement* tableElement = toHTMLTableElement(node());
2651 2714
2652 // caption 2715 // caption
2653 nameFrom = AXNameFromRelatedElement; 2716 nameFrom = AXNameFromRelatedElement;
2654 if (nameSources) { 2717 if (nameSources) {
2655 nameSources->append(NameSource(*foundTextAlternative)); 2718 nameSources->append(NameSource(*foundTextAlternative));
2656 nameSources->last().type = nameFrom; 2719 nameSources->last().type = nameFrom;
2657 nameSources->last().nativeSource = AXTextFromNativeHTMLTableCaption; 2720 nameSources->last().nativeSource = AXTextFromNativeHTMLTableCaption;
2658 } 2721 }
2659 HTMLTableCaptionElement* caption = tableElement->caption(); 2722 HTMLTableCaptionElement* caption = tableElement->caption();
2660 if (caption) { 2723 if (caption) {
2661 RefPtrWillBeRawPtr<AXObject> captionAXObject = axObjectCache().getOr Create(caption); 2724 RefPtrWillBeRawPtr<AXObject> captionAXObject = axObjectCache().getOr Create(caption);
2662 if (captionAXObject) { 2725 if (captionAXObject) {
2663 localNameObjects.append(captionAXObject.get()); 2726 if (nameObjects) {
2664 nameObjects = localNameObjects; 2727 localNameObjects.append(captionAXObject.get());
2665 localNameObjects.clear(); 2728 *nameObjects = localNameObjects;
2729 localNameObjects.clear();
2730 }
2666 2731
2667 textAlternative = recursiveTextAlternative(*captionAXObject, fal se, visited); 2732 textAlternative = recursiveTextAlternative(*captionAXObject, fal se, visited);
2668 if (nameSources) { 2733 if (nameSources) {
2669 NameSource& source = nameSources->last(); 2734 NameSource& source = nameSources->last();
2670 source.nameObjects = nameObjects; 2735 source.nameObjects = *nameObjects;
2671 source.text = textAlternative; 2736 source.text = textAlternative;
2672 } else { 2737 } else {
2673 return textAlternative; 2738 return textAlternative;
2674 } 2739 }
2675 } 2740 }
2676 } 2741 }
2742
2743 // summary
2744 nameFrom = AXNameFromAttribute;
2745 if (nameSources) {
2746 nameSources->append(NameSource(*foundTextAlternative));
2747 nameSources->last().type = nameFrom;
2748 }
2749 if (hasAttribute(summaryAttr)) {
2750 AtomicString summary = getAttribute(summaryAttr);
2751 textAlternative = summary;
2752 if (nameSources) {
2753 NameSource& source = nameSources->last();
2754 source.attributeValue = summary;
2755 source.text = textAlternative;
2756 *foundTextAlternative = true;
2757 } else {
2758 return textAlternative;
2759 }
2760 }
2761
2677 return textAlternative; 2762 return textAlternative;
2678 } 2763 }
2679 2764
2680 return textAlternative; 2765 return textAlternative;
2681 } 2766 }
2682 2767
2683 DEFINE_TRACE(AXNodeObject) 2768 DEFINE_TRACE(AXNodeObject)
2684 { 2769 {
2685 visitor->trace(m_node); 2770 visitor->trace(m_node);
2686 AXObject::trace(visitor); 2771 AXObject::trace(visitor);
2687 } 2772 }
2688 2773
2689 } // namespace blink 2774 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698