1/* 2 * Copyright (C) 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 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 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 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 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 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 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include "AccessibilityList.h" 31 32#include "AXObjectCache.h" 33#include "HTMLElement.h" 34#include "HTMLNames.h" 35#include "RenderListItem.h" 36#include "RenderObject.h" 37#include "RenderStyle.h" 38 39namespace WebCore { 40 41using namespace HTMLNames; 42 43AccessibilityList::AccessibilityList(RenderObject* renderer) 44 : AccessibilityRenderObject(renderer) 45{ 46} 47 48AccessibilityList::~AccessibilityList() 49{ 50} 51 52PassRefPtr<AccessibilityList> AccessibilityList::create(RenderObject* renderer) 53{ 54 return adoptRef(new AccessibilityList(renderer)); 55} 56 57bool AccessibilityList::computeAccessibilityIsIgnored() const 58{ 59 return accessibilityIsIgnoredByDefault(); 60} 61 62bool AccessibilityList::isUnorderedList() const 63{ 64 if (!m_renderer) 65 return false; 66 67 Node* node = m_renderer->node(); 68 69 // The ARIA spec says the "list" role is supposed to mimic a UL or OL tag. 70 // Since it can't be both, it's probably OK to say that it's an un-ordered list. 71 // On the Mac, there's no distinction to the client. 72 if (ariaRoleAttribute() == ListRole) 73 return true; 74 75 return node && node->hasTagName(ulTag); 76} 77 78bool AccessibilityList::isOrderedList() const 79{ 80 if (!m_renderer) 81 return false; 82 83 // ARIA says a directory is like a static table of contents, which sounds like an ordered list. 84 if (ariaRoleAttribute() == DirectoryRole) 85 return true; 86 87 Node* node = m_renderer->node(); 88 return node && node->hasTagName(olTag); 89} 90 91bool AccessibilityList::isDescriptionList() const 92{ 93 if (!m_renderer) 94 return false; 95 96 Node* node = m_renderer->node(); 97 return node && node->hasTagName(dlTag); 98} 99 100AccessibilityRole AccessibilityList::determineAccessibilityRole() 101{ 102 m_ariaRole = determineAriaRoleAttribute(); 103 104 // Directory is mapped to list for now, but does not adhere to the same heuristics. 105 if (ariaRoleAttribute() == DirectoryRole) 106 return ListRole; 107 108 // Heuristic to determine if this list is being used for layout or for content. 109 // 1. If it's a named list, like ol or aria=list, then it's a list. 110 // 1a. Unless the list has no children, then it's not a list. 111 // 2. If it displays visible list markers, it's a list. 112 // 3. If it does not display list markers and has only one child, it's not a list. 113 // 4. If it does not have any listitem children, it's not a list. 114 // 5. Otherwise it's a list (for now). 115 116 AccessibilityRole role = ListRole; 117 118 // Temporarily set role so that we can query children (otherwise canHaveChildren returns false). 119 m_role = role; 120 121 unsigned listItemCount = 0; 122 bool hasVisibleMarkers = false; 123 124 const auto& children = this->children(); 125 // DescriptionLists are always semantically a description list, so do not apply heuristics. 126 if (isDescriptionList() && children.size()) 127 return DescriptionListRole; 128 129 for (const auto& child : children) { 130 if (child->ariaRoleAttribute() == ListItemRole) 131 listItemCount++; 132 else if (child->roleValue() == ListItemRole) { 133 RenderObject* listItem = child->renderer(); 134 if (listItem && listItem->isListItem()) { 135 if (listItem->style().listStyleType() != NoneListStyle || listItem->style().listStyleImage()) 136 hasVisibleMarkers = true; 137 listItemCount++; 138 } 139 } 140 } 141 142 bool unorderedList = isUnorderedList(); 143 // Non <ul> lists and ARIA lists only need to have one child. 144 // <ul> lists need to have 1 child, or visible markers. 145 if (!unorderedList || ariaRoleAttribute() != UnknownRole) { 146 if (!listItemCount) 147 role = GroupRole; 148 } else if (unorderedList && listItemCount <= 1 && !hasVisibleMarkers) 149 role = GroupRole; 150 151 return role; 152} 153 154AccessibilityRole AccessibilityList::roleValue() const 155{ 156 ASSERT(m_role != UnknownRole); 157 return m_role; 158} 159 160} // namespace WebCore 161