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

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

Issue 1939303002: Enable accessible name of a control to include multiple <label> elements. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address feedback from aboxhall Created 4 years, 7 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 | « third_party/WebKit/Source/modules/accessibility/AXNodeObject.h ('k') | no next file » | 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
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 #include "core/html/HTMLMediaElement.h" 43 #include "core/html/HTMLMediaElement.h"
44 #include "core/html/HTMLMeterElement.h" 44 #include "core/html/HTMLMeterElement.h"
45 #include "core/html/HTMLPlugInElement.h" 45 #include "core/html/HTMLPlugInElement.h"
46 #include "core/html/HTMLSelectElement.h" 46 #include "core/html/HTMLSelectElement.h"
47 #include "core/html/HTMLTableCaptionElement.h" 47 #include "core/html/HTMLTableCaptionElement.h"
48 #include "core/html/HTMLTableCellElement.h" 48 #include "core/html/HTMLTableCellElement.h"
49 #include "core/html/HTMLTableElement.h" 49 #include "core/html/HTMLTableElement.h"
50 #include "core/html/HTMLTableRowElement.h" 50 #include "core/html/HTMLTableRowElement.h"
51 #include "core/html/HTMLTableSectionElement.h" 51 #include "core/html/HTMLTableSectionElement.h"
52 #include "core/html/HTMLTextAreaElement.h" 52 #include "core/html/HTMLTextAreaElement.h"
53 #include "core/html/LabelsNodeList.h"
53 #include "core/html/parser/HTMLParserIdioms.h" 54 #include "core/html/parser/HTMLParserIdioms.h"
54 #include "core/html/shadow/MediaControlElements.h" 55 #include "core/html/shadow/MediaControlElements.h"
55 #include "core/layout/LayoutBlockFlow.h" 56 #include "core/layout/LayoutBlockFlow.h"
56 #include "core/layout/LayoutObject.h" 57 #include "core/layout/LayoutObject.h"
57 #include "core/svg/SVGElement.h" 58 #include "core/svg/SVGElement.h"
58 #include "modules/accessibility/AXObjectCacheImpl.h" 59 #include "modules/accessibility/AXObjectCacheImpl.h"
59 #include "platform/UserGestureIndicator.h" 60 #include "platform/UserGestureIndicator.h"
60 #include "platform/text/PlatformLocale.h" 61 #include "platform/text/PlatformLocale.h"
61 #include "wtf/text/StringBuilder.h" 62 #include "wtf/text/StringBuilder.h"
62 63
(...skipping 573 matching lines...) Expand 10 before | Expand all | Expand 10 after
636 return false; 637 return false;
637 638
638 // An SVG root is focusable by default, but it's probably not interactive, s o don't 639 // An SVG root is focusable by default, but it's probably not interactive, s o don't
639 // include it. It can still be made accessible by giving it an ARIA role. 640 // include it. It can still be made accessible by giving it an ARIA role.
640 if (roleValue() == SVGRootRole) 641 if (roleValue() == SVGRootRole)
641 return false; 642 return false;
642 643
643 return true; 644 return true;
644 } 645 }
645 646
646 HTMLLabelElement* AXNodeObject::labelForElement(const Element* element) const
647 {
648 if (!element->isHTMLElement() || !toHTMLElement(element)->isLabelable())
649 return 0;
650
651 const AtomicString& id = element->getIdAttribute();
652 if (!id.isEmpty()) {
653 if (HTMLLabelElement* labelFor = element->treeScope().labelElementForId( id))
654 return labelFor;
655 }
656
657 HTMLLabelElement* labelWrappedElement = Traversal<HTMLLabelElement>::firstAn cestor(*element);
658 if (labelWrappedElement && labelWrappedElement->control() == toLabelableElem ent(element))
659 return labelWrappedElement;
660
661 return 0;
662 }
663
664 AXObject* AXNodeObject::menuButtonForMenu() const 647 AXObject* AXNodeObject::menuButtonForMenu() const
665 { 648 {
666 Element* menuItem = menuItemElementForMenu(); 649 Element* menuItem = menuItemElementForMenu();
667 650
668 if (menuItem) { 651 if (menuItem) {
669 // ARIA just has generic menu items. AppKit needs to know if this is a t op level items like MenuBarButton or MenuBarItem 652 // ARIA just has generic menu items. AppKit needs to know if this is a t op level items like MenuBarButton or MenuBarItem
670 AXObject* menuItemAX = axObjectCache().getOrCreate(menuItem); 653 AXObject* menuItemAX = axObjectCache().getOrCreate(menuItem);
671 if (menuItemAX && menuItemAX->isMenuButton()) 654 if (menuItemAX && menuItemAX->isMenuButton())
672 return menuItemAX; 655 return menuItemAX;
673 } 656 }
(...skipping 933 matching lines...) Expand 10 before | Expand all | Expand 10 after
1607 if (nameSources) { 1590 if (nameSources) {
1608 foundTextAlternative = true; 1591 foundTextAlternative = true;
1609 nameSources->last().text = textAlternative; 1592 nameSources->last().text = textAlternative;
1610 } else { 1593 } else {
1611 return textAlternative; 1594 return textAlternative;
1612 } 1595 }
1613 } 1596 }
1614 1597
1615 nameFrom = AXNameFromUninitialized; 1598 nameFrom = AXNameFromUninitialized;
1616 1599
1617 if (foundTextAlternative) { 1600 if (nameSources && foundTextAlternative) {
1618 for (size_t i = 0; i < nameSources->size(); ++i) { 1601 for (size_t i = 0; i < nameSources->size(); ++i) {
1619 if (!(*nameSources)[i].text.isNull() && !(*nameSources)[i].supersede d) { 1602 if (!(*nameSources)[i].text.isNull() && !(*nameSources)[i].supersede d) {
1620 NameSource& nameSource = (*nameSources)[i]; 1603 NameSource& nameSource = (*nameSources)[i];
1621 nameFrom = nameSource.type; 1604 nameFrom = nameSource.type;
1622 if (!nameSource.relatedObjects.isEmpty()) 1605 if (!nameSource.relatedObjects.isEmpty())
1623 *relatedObjects = nameSource.relatedObjects; 1606 *relatedObjects = nameSource.relatedObjects;
1624 return nameSource.text; 1607 return nameSource.text;
1625 } 1608 }
1626 } 1609 }
1627 } 1610 }
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1701 // Step 2C from: http://www.w3.org/TR/accname-aam-1.1 1684 // Step 2C from: http://www.w3.org/TR/accname-aam-1.1
1702 const AtomicString& ariaLabel = getAttribute(aria_labelAttr); 1685 const AtomicString& ariaLabel = getAttribute(aria_labelAttr);
1703 if (!ariaLabel.isEmpty()) 1686 if (!ariaLabel.isEmpty())
1704 return false; 1687 return false;
1705 1688
1706 // Based on http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessi ble-name-and-description-calculation 1689 // Based on http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessi ble-name-and-description-calculation
1707 // 5.1/5.5 Text inputs, Other labelable Elements 1690 // 5.1/5.5 Text inputs, Other labelable Elements
1708 HTMLElement* htmlElement = nullptr; 1691 HTMLElement* htmlElement = nullptr;
1709 if (getNode()->isHTMLElement()) 1692 if (getNode()->isHTMLElement())
1710 htmlElement = toHTMLElement(getNode()); 1693 htmlElement = toHTMLElement(getNode());
1711 if (htmlElement && htmlElement->isLabelable()) { 1694 if (htmlElement && isLabelableElement(htmlElement)) {
1712 HTMLLabelElement* label = labelForElement(htmlElement); 1695 if (toLabelableElement(htmlElement)->labels() && toLabelableElement(html Element)->labels()->length() > 0)
1713 if (label)
1714 return true; 1696 return true;
1715 } 1697 }
1716 1698
1717 return false; 1699 return false;
1718 } 1700 }
1719 1701
1720 LayoutRect AXNodeObject::elementRect() const 1702 LayoutRect AXNodeObject::elementRect() const
1721 { 1703 {
1722 // First check if it has a custom rect, for example if this element is tied to a canvas path. 1704 // First check if it has a custom rect, for example if this element is tied to a canvas path.
1723 if (!m_explicitElementRect.isEmpty()) 1705 if (!m_explicitElementRect.isEmpty())
(...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after
2170 2152
2171 const HTMLInputElement* inputElement = nullptr; 2153 const HTMLInputElement* inputElement = nullptr;
2172 if (isHTMLInputElement(getNode())) 2154 if (isHTMLInputElement(getNode()))
2173 inputElement = toHTMLInputElement(getNode()); 2155 inputElement = toHTMLInputElement(getNode());
2174 2156
2175 // 5.1/5.5 Text inputs, Other labelable Elements 2157 // 5.1/5.5 Text inputs, Other labelable Elements
2176 // If you change this logic, update AXNodeObject::nameFromLabelElement, too. 2158 // If you change this logic, update AXNodeObject::nameFromLabelElement, too.
2177 HTMLElement* htmlElement = nullptr; 2159 HTMLElement* htmlElement = nullptr;
2178 if (getNode()->isHTMLElement()) 2160 if (getNode()->isHTMLElement())
2179 htmlElement = toHTMLElement(getNode()); 2161 htmlElement = toHTMLElement(getNode());
2162
2180 if (htmlElement && htmlElement->isLabelable()) { 2163 if (htmlElement && htmlElement->isLabelable()) {
2181 // label
2182 nameFrom = AXNameFromRelatedElement; 2164 nameFrom = AXNameFromRelatedElement;
2183 if (nameSources) { 2165 if (nameSources) {
2184 nameSources->append(NameSource(*foundTextAlternative)); 2166 nameSources->append(NameSource(*foundTextAlternative));
2185 nameSources->last().type = nameFrom; 2167 nameSources->last().type = nameFrom;
2186 nameSources->last().nativeSource = AXTextFromNativeHTMLLabel; 2168 nameSources->last().nativeSource = AXTextFromNativeHTMLLabel;
2187 } 2169 }
2188 HTMLLabelElement* label = labelForElement(htmlElement);
2189 if (label) {
2190 AXObject* labelAXObject = axObjectCache().getOrCreate(label);
2191 // Avoid an infinite loop for label wrapped
2192 if (labelAXObject && !visited.contains(labelAXObject)) {
2193 textAlternative = recursiveTextAlternative(*labelAXObject, false , visited);
2194 2170
2195 if (relatedObjects) { 2171 LabelsNodeList* labels = toLabelableElement(htmlElement)->labels();
2196 localRelatedObjects.append(new NameSourceRelatedObject(label AXObject, textAlternative)); 2172 if (labels && labels->length() > 0) {
2197 *relatedObjects = localRelatedObjects; 2173 StringBuilder accumulatedText;
2198 localRelatedObjects.clear(); 2174 for (unsigned labelIndex = 0; labelIndex < labels->length(); ++label Index) {
2199 } 2175 Element* label = labels->item(labelIndex);
2176 AXObject* labelAXObject = axObjectCache().getOrCreate(label);
2177 // Avoid an infinite loop for label wrapped
2178 if (labelAXObject && !visited.contains(labelAXObject)) {
2179 *foundTextAlternative = true;
2180 String result = recursiveTextAlternative(*labelAXObject, fal se, visited);
2181 if (!result.isEmpty()) {
2182 if (!accumulatedText.isEmpty())
2183 accumulatedText.append(" ");
2184 accumulatedText.append(result);
2185 }
2200 2186
2201 if (nameSources) { 2187 if (relatedObjects) {
aboxhall 2016/05/16 17:19:01 Now that I've had a closer look, this is weird. Se
dmazzoni 2016/06/01 19:53:23 OK, ready for another look. I had this call AXObje
2202 NameSource& source = nameSources->last(); 2188 localRelatedObjects.append(new NameSourceRelatedObject(l abelAXObject, result));
2203 source.relatedObjects = *relatedObjects; 2189 *relatedObjects = localRelatedObjects;
2204 source.text = textAlternative; 2190 }
2205 if (label->getAttribute(forAttr) == htmlElement->getIdAttrib ute()) 2191
2206 source.nativeSource = AXTextFromNativeHTMLLabelFor; 2192 if (nameSources) {
2207 else 2193 NameSource& source = nameSources->last();
2208 source.nativeSource = AXTextFromNativeHTMLLabelWrapped; 2194 source.relatedObjects = *relatedObjects;
2209 *foundTextAlternative = true; 2195 source.text = textAlternative;
2210 } else { 2196 if (label->getAttribute(forAttr) == htmlElement->getIdAt tribute())
2211 return textAlternative; 2197 source.nativeSource = AXTextFromNativeHTMLLabelFor;
2198 else
2199 source.nativeSource = AXTextFromNativeHTMLLabelWrapp ed;
2200 }
2212 } 2201 }
2213 } 2202 }
2203
2204 if (relatedObjects)
2205 localRelatedObjects.clear();
2206
2207 textAlternative = accumulatedText.toString();
2208 if (!nameSources && *foundTextAlternative)
2209 return textAlternative;
2214 } 2210 }
2215 } 2211 }
2216 2212
2217 // 5.2 input type="button", input type="submit" and input type="reset" 2213 // 5.2 input type="button", input type="submit" and input type="reset"
2218 if (inputElement && inputElement->isTextButton()) { 2214 if (inputElement && inputElement->isTextButton()) {
2219 // value attribue 2215 // value attribue
2220 nameFrom = AXNameFromValue; 2216 nameFrom = AXNameFromValue;
2221 if (nameSources) { 2217 if (nameSources) {
2222 nameSources->append(NameSource(*foundTextAlternative, valueAttr)); 2218 nameSources->append(NameSource(*foundTextAlternative, valueAttr));
2223 nameSources->last().type = nameFrom; 2219 nameSources->last().type = nameFrom;
(...skipping 568 matching lines...) Expand 10 before | Expand all | Expand 10 after
2792 return placeholder; 2788 return placeholder;
2793 } 2789 }
2794 2790
2795 DEFINE_TRACE(AXNodeObject) 2791 DEFINE_TRACE(AXNodeObject)
2796 { 2792 {
2797 visitor->trace(m_node); 2793 visitor->trace(m_node);
2798 AXObject::trace(visitor); 2794 AXObject::trace(visitor);
2799 } 2795 }
2800 2796
2801 } // namespace blink 2797 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/modules/accessibility/AXNodeObject.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698