Chromium Code Reviews

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

Issue 1417213006: Switch all LayoutTests to use new AX name calculation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix canvas-fallback-content-labels-expected.txt Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
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
(...skipping 12 matching lines...)
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/Element.h"
33 #include "core/dom/NodeTraversal.h" 34 #include "core/dom/NodeTraversal.h"
34 #include "core/dom/Text.h" 35 #include "core/dom/Text.h"
35 #include "core/dom/shadow/ComposedTreeTraversal.h" 36 #include "core/dom/shadow/ComposedTreeTraversal.h"
36 #include "core/html/HTMLDListElement.h" 37 #include "core/html/HTMLDListElement.h"
37 #include "core/html/HTMLFieldSetElement.h" 38 #include "core/html/HTMLFieldSetElement.h"
38 #include "core/html/HTMLFrameElementBase.h" 39 #include "core/html/HTMLFrameElementBase.h"
39 #include "core/html/HTMLImageElement.h" 40 #include "core/html/HTMLImageElement.h"
40 #include "core/html/HTMLInputElement.h" 41 #include "core/html/HTMLInputElement.h"
41 #include "core/html/HTMLLabelElement.h" 42 #include "core/html/HTMLLabelElement.h"
42 #include "core/html/HTMLLegendElement.h" 43 #include "core/html/HTMLLegendElement.h"
(...skipping 1449 matching lines...)
1492 if (ariaRoleAttribute() == StaticTextRole) { 1493 if (ariaRoleAttribute() == StaticTextRole) {
1493 String staticText = text(); 1494 String staticText = text();
1494 if (!staticText.length()) 1495 if (!staticText.length())
1495 staticText = deprecatedTextUnderElement(TextUnderElementAll); 1496 staticText = deprecatedTextUnderElement(TextUnderElementAll);
1496 return staticText; 1497 return staticText;
1497 } 1498 }
1498 1499
1499 if (node->isTextNode()) 1500 if (node->isTextNode())
1500 return deprecatedTextUnderElement(TextUnderElementAll); 1501 return deprecatedTextUnderElement(TextUnderElementAll);
1501 1502
1503 return stringValueOfControl();
1504 }
1505
1506 String AXNodeObject::stringValueOfControl() const
1507 {
1508 Node* node = this->node();
1509 if (!node)
1510 return String();
1511
1502 if (isHTMLSelectElement(*node)) { 1512 if (isHTMLSelectElement(*node)) {
1503 HTMLSelectElement& selectElement = toHTMLSelectElement(*node); 1513 HTMLSelectElement& selectElement = toHTMLSelectElement(*node);
1504 int selectedIndex = selectElement.selectedIndex(); 1514 int selectedIndex = selectElement.selectedIndex();
1505 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& listItems = sel ectElement.listItems(); 1515 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& listItems = sel ectElement.listItems();
1506 if (selectedIndex >= 0 && static_cast<size_t>(selectedIndex) < listItems .size()) { 1516 if (selectedIndex >= 0 && static_cast<size_t>(selectedIndex) < listItems .size()) {
1507 const AtomicString& overriddenDescription = listItems[selectedIndex] ->fastGetAttribute(aria_labelAttr); 1517 const AtomicString& overriddenDescription = listItems[selectedIndex] ->fastGetAttribute(aria_labelAttr);
1508 if (!overriddenDescription.isNull()) 1518 if (!overriddenDescription.isNull())
1509 return overriddenDescription; 1519 return overriddenDescription;
1510 } 1520 }
1511 if (!selectElement.multiple()) 1521 if (!selectElement.multiple())
1512 return selectElement.value(); 1522 return selectElement.value();
1513 return String(); 1523 return String();
1514 } 1524 }
1515 1525
1516 if (isNativeTextControl()) 1526 if (isNativeTextControl())
1517 return text(); 1527 return text();
1518 1528
1519 // FIXME: We might need to implement a value here for more types 1529 // Handle other HTML input elements that aren't text controls, like date and time
1520 // FIXME: It would be better not to advertise a value at all for the types f or which we don't implement one; 1530 // controls, by returning the string value, with the exception of checkboxes
1521 // this would require subclassing or making accessibilityAttributeNames do s omething other than return a 1531 // and radio buttons (which would return "on").
1522 // single static array. 1532 if (isHTMLInputElement(node)) {
1533 HTMLInputElement* input = toHTMLInputElement(node);
1534 if (input->type() != InputTypeNames::checkbox && input->type() != InputT ypeNames::radio)
1535 return input->value();
1536 }
1537
1523 return String(); 1538 return String();
1524 } 1539 }
1525 1540
1526 String AXNodeObject::ariaDescribedByAttribute() const 1541 String AXNodeObject::ariaDescribedByAttribute() const
1527 { 1542 {
1528 WillBeHeapVector<RawPtrWillBeMember<Element>> elements; 1543 WillBeHeapVector<RawPtrWillBeMember<Element>> elements;
1529 elementsFromAttribute(elements, aria_describedbyAttr); 1544 elementsFromAttribute(elements, aria_describedbyAttr);
1530 1545
1531 return accessibilityDescriptionForElements(elements); 1546 return accessibilityDescriptionForElements(elements);
1532 } 1547 }
(...skipping 385 matching lines...)
1918 } 1933 }
1919 1934
1920 // Step 2D from: http://www.w3.org/TR/accname-aam-1.1 1935 // Step 2D from: http://www.w3.org/TR/accname-aam-1.1
1921 textAlternative = nativeTextAlternative(visited, nameFrom, relatedObjects, n ameSources, &foundTextAlternative); 1936 textAlternative = nativeTextAlternative(visited, nameFrom, relatedObjects, n ameSources, &foundTextAlternative);
1922 if (!textAlternative.isNull() && !nameSources) 1937 if (!textAlternative.isNull() && !nameSources)
1923 return textAlternative; 1938 return textAlternative;
1924 1939
1925 // Step 2E from: http://www.w3.org/TR/accname-aam-1.1 1940 // Step 2E from: http://www.w3.org/TR/accname-aam-1.1
1926 if (recursive && !inAriaLabelledByTraversal && isControl()) { 1941 if (recursive && !inAriaLabelledByTraversal && isControl()) {
1927 // No need to set any name source info in a recursive call. 1942 // No need to set any name source info in a recursive call.
1928 if (roleValue() == TextFieldRole || roleValue() == ComboBoxRole)
1929 return text();
1930 if (isRange()) { 1943 if (isRange()) {
1931 const AtomicString& ariaValuetext = getAttribute(aria_valuetextAttr) ; 1944 const AtomicString& ariaValuetext = getAttribute(aria_valuetextAttr) ;
1932 if (!ariaValuetext.isNull()) 1945 if (!ariaValuetext.isNull())
1933 return ariaValuetext.string(); 1946 return ariaValuetext.string();
1934 return String::number(valueForRange()); 1947 return String::number(valueForRange());
1935 } 1948 }
1949
1950 return stringValueOfControl();
1936 } 1951 }
1937 1952
1938 // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1 1953 // Step 2F / 2G from: http://www.w3.org/TR/accname-aam-1.1
1939 if (recursive || nameFromContents()) { 1954 if (recursive || nameFromContents()) {
1940 nameFrom = AXNameFromContents; 1955 nameFrom = AXNameFromContents;
1941 if (nameSources) { 1956 if (nameSources) {
1942 nameSources->append(NameSource(foundTextAlternative)); 1957 nameSources->append(NameSource(foundTextAlternative));
1943 nameSources->last().type = nameFrom; 1958 nameSources->last().type = nameFrom;
1944 } 1959 }
1945 1960
1946 Node* node = this->node(); 1961 Node* node = this->node();
1947 if (node && node->isTextNode()) 1962 if (node && node->isTextNode())
1948 textAlternative = toText(node)->wholeText(); 1963 textAlternative = toText(node)->wholeText();
1964 else if (isHTMLBRElement(node))
1965 textAlternative = String("\n");
1949 else 1966 else
1950 textAlternative = textFromDescendants(visited); 1967 textAlternative = textFromDescendants(visited);
1951 1968
1952 if (!textAlternative.isEmpty()) { 1969 if (!textAlternative.isEmpty()) {
1953 if (nameSources) { 1970 if (nameSources) {
1954 foundTextAlternative = true; 1971 foundTextAlternative = true;
1955 nameSources->last().text = textAlternative; 1972 nameSources->last().text = textAlternative;
1956 } else { 1973 } else {
1957 return textAlternative; 1974 return textAlternative;
1958 } 1975 }
(...skipping 32 matching lines...)
1991 } 2008 }
1992 2009
1993 return String(); 2010 return String();
1994 } 2011 }
1995 2012
1996 String AXNodeObject::textFromDescendants(AXObjectSet& visited) const 2013 String AXNodeObject::textFromDescendants(AXObjectSet& visited) const
1997 { 2014 {
1998 StringBuilder accumulatedText; 2015 StringBuilder accumulatedText;
1999 AXObject* previous = nullptr; 2016 AXObject* previous = nullptr;
2000 for (AXObject* child = firstChild(); child; child = child->nextSibling()) { 2017 for (AXObject* child = firstChild(); child; child = child->nextSibling()) {
2018 // Skip hidden children
2019 if (child->isInertOrAriaHidden())
2020 continue;
2021
2001 // If we're going between two layoutObjects that are in separate LayoutB oxes, add 2022 // If we're going between two layoutObjects that are in separate LayoutB oxes, add
2002 // whitespace if it wasn't there already. Intuitively if you have 2023 // whitespace if it wasn't there already. Intuitively if you have
2003 // <span>Hello</span><span>World</span>, those are part of the same Layo utBox 2024 // <span>Hello</span><span>World</span>, those are part of the same Layo utBox
2004 // so we should return "HelloWorld", but given <div>Hello</div><div>Worl d</div> the 2025 // so we should return "HelloWorld", but given <div>Hello</div><div>Worl d</div> the
2005 // strings are in separate boxes so we should return "Hello World". 2026 // strings are in separate boxes so we should return "Hello World".
2006 if (previous && accumulatedText.length() && !isHTMLSpace(accumulatedText [accumulatedText.length() - 1])) { 2027 if (previous && accumulatedText.length() && !isHTMLSpace(accumulatedText [accumulatedText.length() - 1])) {
2007 if (!isInSameNonInlineBlockFlow(child->layoutObject(), previous->lay outObject())) 2028 if (!isInSameNonInlineBlockFlow(child->layoutObject(), previous->lay outObject()))
2008 accumulatedText.append(' '); 2029 accumulatedText.append(' ');
2009 } 2030 }
2010 2031
(...skipping 207 matching lines...)
2218 } 2239 }
2219 2240
2220 bool AXNodeObject::canHaveChildren() const 2241 bool AXNodeObject::canHaveChildren() const
2221 { 2242 {
2222 // If this is an AXLayoutObject, then it's okay if this object 2243 // If this is an AXLayoutObject, then it's okay if this object
2223 // doesn't have a node - there are some layoutObjects that don't have associ ated 2244 // doesn't have a node - there are some layoutObjects that don't have associ ated
2224 // nodes, like scroll areas and css-generated text. 2245 // nodes, like scroll areas and css-generated text.
2225 if (!node() && !isAXLayoutObject()) 2246 if (!node() && !isAXLayoutObject())
2226 return false; 2247 return false;
2227 2248
2249 if (node() && isHTMLMapElement(node()))
2250 return false;
2251
2228 // Elements that should not have children 2252 // Elements that should not have children
2229 switch (roleValue()) { 2253 switch (roleValue()) {
2230 case ImageRole: 2254 case ImageRole:
2231 case ButtonRole: 2255 case ButtonRole:
2232 case PopUpButtonRole: 2256 case PopUpButtonRole:
2233 case CheckBoxRole: 2257 case CheckBoxRole:
2234 case RadioButtonRole: 2258 case RadioButtonRole:
2235 case SwitchRole: 2259 case SwitchRole:
2236 case TabRole: 2260 case TabRole:
2237 case ToggleButtonRole: 2261 case ToggleButtonRole:
(...skipping 517 matching lines...)
2755 source.text = textAlternative; 2779 source.text = textAlternative;
2756 *foundTextAlternative = true; 2780 *foundTextAlternative = true;
2757 } else { 2781 } else {
2758 return textAlternative; 2782 return textAlternative;
2759 } 2783 }
2760 } 2784 }
2761 } 2785 }
2762 return textAlternative; 2786 return textAlternative;
2763 } 2787 }
2764 2788
2765 // 5.8 img Element 2789 // 5.8 img or area Element
2766 if (isHTMLImageElement(node())) { 2790 if (isHTMLImageElement(node()) || isHTMLAreaElement(node()) || (layoutObject () && layoutObject()->isSVGImage())) {
2767 // alt 2791 // alt
2768 nameFrom = AXNameFromAttribute; 2792 nameFrom = AXNameFromAttribute;
2769 if (nameSources) { 2793 if (nameSources) {
2770 nameSources->append(NameSource(*foundTextAlternative, altAttr)); 2794 nameSources->append(NameSource(*foundTextAlternative, altAttr));
2771 nameSources->last().type = nameFrom; 2795 nameSources->last().type = nameFrom;
2772 } 2796 }
2773 const AtomicString& alt = getAttribute(altAttr); 2797 const AtomicString& alt = getAttribute(altAttr);
2774 if (!alt.isNull()) { 2798 if (!alt.isNull()) {
2775 textAlternative = alt; 2799 textAlternative = alt;
2776 if (nameSources) { 2800 if (nameSources) {
(...skipping 56 matching lines...)
2833 source.text = textAlternative; 2857 source.text = textAlternative;
2834 *foundTextAlternative = true; 2858 *foundTextAlternative = true;
2835 } else { 2859 } else {
2836 return textAlternative; 2860 return textAlternative;
2837 } 2861 }
2838 } 2862 }
2839 2863
2840 return textAlternative; 2864 return textAlternative;
2841 } 2865 }
2842 2866
2867 // Fieldset / legend.
2868 if (isHTMLFieldSetElement(node())) {
2869 nameFrom = AXNameFromRelatedElement;
2870 if (nameSources) {
2871 nameSources->append(NameSource(*foundTextAlternative));
2872 nameSources->last().type = nameFrom;
2873 nameSources->last().nativeSource = AXTextFromNativeHTMLLegend;
2874 }
2875 HTMLElement* legend = toHTMLFieldSetElement(node())->legend();
2876 if (legend) {
2877 AXObject* legendAXObject = axObjectCache().getOrCreate(legend);
2878 // Avoid an infinite loop
2879 if (legendAXObject && !visited.contains(legendAXObject)) {
2880 textAlternative = recursiveTextAlternative(*legendAXObject, fals e, visited);
2881
2882 if (relatedObjects) {
2883 localRelatedObjects.append(new NameSourceRelatedObject(legen dAXObject, textAlternative));
2884 *relatedObjects = localRelatedObjects;
2885 localRelatedObjects.clear();
2886 }
2887
2888 if (nameSources) {
2889 NameSource& source = nameSources->last();
2890 source.relatedObjects = *relatedObjects;
2891 source.text = textAlternative;
2892 *foundTextAlternative = true;
2893 } else {
2894 return textAlternative;
2895 }
2896 }
2897 }
2898 }
2899
2843 return textAlternative; 2900 return textAlternative;
2844 } 2901 }
2845 2902
2846 String AXNodeObject::description(AXNameFrom nameFrom, AXDescriptionFrom& descrip tionFrom, AXObjectVector* descriptionObjects) const 2903 String AXNodeObject::description(AXNameFrom nameFrom, AXDescriptionFrom& descrip tionFrom, AXObjectVector* descriptionObjects) const
2847 { 2904 {
2848 AXRelatedObjectVector relatedObjects; 2905 AXRelatedObjectVector relatedObjects;
2849 String result = description(nameFrom, descriptionFrom, nullptr, &relatedObje cts); 2906 String result = description(nameFrom, descriptionFrom, nullptr, &relatedObje cts);
2850 if (descriptionObjects) { 2907 if (descriptionObjects) {
2851 descriptionObjects->clear(); 2908 descriptionObjects->clear();
2852 for (size_t i = 0; i < relatedObjects.size(); i++) 2909 for (size_t i = 0; i < relatedObjects.size(); i++)
(...skipping 159 matching lines...)
3012 description = title; 3069 description = title;
3013 if (descriptionSources) { 3070 if (descriptionSources) {
3014 foundDescription = true; 3071 foundDescription = true;
3015 descriptionSources->last().text = description; 3072 descriptionSources->last().text = description;
3016 } else { 3073 } else {
3017 return description; 3074 return description;
3018 } 3075 }
3019 } 3076 }
3020 } 3077 }
3021 3078
3079 // aria-help.
3080 // FIXME: this is not part of the official standard, but it's needed because the built-in date/time controls use it.
3081 descriptionFrom = AXDescriptionFromAttribute;
3082 if (descriptionSources) {
3083 descriptionSources->append(DescriptionSource(foundDescription, aria_help Attr));
3084 descriptionSources->last().type = descriptionFrom;
3085 }
3086 const AtomicString& help = getAttribute(aria_helpAttr);
3087 if (!help.isEmpty()) {
3088 description = help;
3089 if (descriptionSources) {
3090 foundDescription = true;
3091 descriptionSources->last().text = description;
3092 } else {
3093 return description;
3094 }
3095 }
3096
3022 descriptionFrom = AXDescriptionFromUninitialized; 3097 descriptionFrom = AXDescriptionFromUninitialized;
3023 3098
3024 if (foundDescription) { 3099 if (foundDescription) {
3025 for (size_t i = 0; i < descriptionSources->size(); ++i) { 3100 for (size_t i = 0; i < descriptionSources->size(); ++i) {
3026 if (!(*descriptionSources)[i].text.isNull() && !(*descriptionSources )[i].superseded) { 3101 if (!(*descriptionSources)[i].text.isNull() && !(*descriptionSources )[i].superseded) {
3027 DescriptionSource& descriptionSource = (*descriptionSources)[i]; 3102 DescriptionSource& descriptionSource = (*descriptionSources)[i];
3028 descriptionFrom = descriptionSource.type; 3103 descriptionFrom = descriptionSource.type;
3029 if (!descriptionSource.relatedObjects.isEmpty()) 3104 if (!descriptionSource.relatedObjects.isEmpty())
3030 *relatedObjects = descriptionSource.relatedObjects; 3105 *relatedObjects = descriptionSource.relatedObjects;
3031 return descriptionSource.text; 3106 return descriptionSource.text;
3032 } 3107 }
3033 } 3108 }
3034 } 3109 }
3035 3110
3036 return String(); 3111 return String();
3037 } 3112 }
3038 3113
3039 DEFINE_TRACE(AXNodeObject) 3114 DEFINE_TRACE(AXNodeObject)
3040 { 3115 {
3041 visitor->trace(m_node); 3116 visitor->trace(m_node);
3042 AXObject::trace(visitor); 3117 AXObject::trace(visitor);
3043 } 3118 }
3044 3119
3045 } // namespace blink 3120 } // namespace blin
OLDNEW

Powered by Google App Engine