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 "AccessibilityListBox.h" 31 32#include "AXObjectCache.h" 33#include "AccessibilityListBoxOption.h" 34#include "HTMLNames.h" 35#include "HTMLSelectElement.h" 36#include "HitTestResult.h" 37#include "RenderListBox.h" 38#include "RenderObject.h" 39 40namespace WebCore { 41 42using namespace HTMLNames; 43 44AccessibilityListBox::AccessibilityListBox(RenderObject* renderer) 45 : AccessibilityRenderObject(renderer) 46{ 47} 48 49AccessibilityListBox::~AccessibilityListBox() 50{ 51} 52 53PassRefPtr<AccessibilityListBox> AccessibilityListBox::create(RenderObject* renderer) 54{ 55 return adoptRef(new AccessibilityListBox(renderer)); 56} 57 58bool AccessibilityListBox::canSetSelectedChildrenAttribute() const 59{ 60 Node* selectNode = m_renderer->node(); 61 if (!selectNode) 62 return false; 63 64 return !toHTMLSelectElement(selectNode)->isDisabledFormControl(); 65} 66 67void AccessibilityListBox::addChildren() 68{ 69 Node* selectNode = m_renderer->node(); 70 if (!selectNode) 71 return; 72 73 m_haveChildren = true; 74 75 for (const auto& listItem : toHTMLSelectElement(selectNode)->listItems()) { 76 // The cast to HTMLElement below is safe because the only other possible listItem type 77 // would be a WMLElement, but WML builds don't use accessibility features at all. 78 AccessibilityObject* listOption = listBoxOptionAccessibilityObject(listItem); 79 if (listOption && !listOption->accessibilityIsIgnored()) 80 m_children.append(listOption); 81 } 82} 83 84void AccessibilityListBox::setSelectedChildren(const AccessibilityChildrenVector& children) 85{ 86 if (!canSetSelectedChildrenAttribute()) 87 return; 88 89 Node* selectNode = m_renderer->node(); 90 if (!selectNode) 91 return; 92 93 // disable any selected options 94 for (const auto& child : m_children) { 95 AccessibilityListBoxOption* listBoxOption = toAccessibilityListBoxOption(child.get()); 96 if (listBoxOption->isSelected()) 97 listBoxOption->setSelected(false); 98 } 99 100 for (const auto& obj : children) { 101 if (obj->roleValue() != ListBoxOptionRole) 102 continue; 103 104 toAccessibilityListBoxOption(obj.get())->setSelected(true); 105 } 106} 107 108void AccessibilityListBox::selectedChildren(AccessibilityChildrenVector& result) 109{ 110 ASSERT(result.isEmpty()); 111 112 if (!hasChildren()) 113 addChildren(); 114 115 for (const auto& child : m_children) { 116 if (toAccessibilityListBoxOption(child.get())->isSelected()) 117 result.append(child.get()); 118 } 119} 120 121void AccessibilityListBox::visibleChildren(AccessibilityChildrenVector& result) 122{ 123 ASSERT(result.isEmpty()); 124 125 if (!hasChildren()) 126 addChildren(); 127 128 unsigned length = m_children.size(); 129 for (unsigned i = 0; i < length; i++) { 130 if (toRenderListBox(m_renderer)->listIndexIsVisible(i)) 131 result.append(m_children[i]); 132 } 133} 134 135AccessibilityObject* AccessibilityListBox::listBoxOptionAccessibilityObject(HTMLElement* element) const 136{ 137 // skip hr elements 138 if (!element || element->hasTagName(hrTag)) 139 return 0; 140 141 AccessibilityObject* listBoxObject = m_renderer->document().axObjectCache()->getOrCreate(ListBoxOptionRole); 142 toAccessibilityListBoxOption(listBoxObject)->setHTMLElement(element); 143 144 return listBoxObject; 145} 146 147AccessibilityObject* AccessibilityListBox::elementAccessibilityHitTest(const IntPoint& point) const 148{ 149 // the internal HTMLSelectElement methods for returning a listbox option at a point 150 // ignore optgroup elements. 151 if (!m_renderer) 152 return 0; 153 154 Node* node = m_renderer->node(); 155 if (!node) 156 return 0; 157 158 LayoutRect parentRect = boundingBoxRect(); 159 160 AccessibilityObject* listBoxOption = 0; 161 unsigned length = m_children.size(); 162 for (unsigned i = 0; i < length; i++) { 163 LayoutRect rect = toRenderListBox(m_renderer)->itemBoundingBoxRect(parentRect.location(), i); 164 // The cast to HTMLElement below is safe because the only other possible listItem type 165 // would be a WMLElement, but WML builds don't use accessibility features at all. 166 if (rect.contains(point)) { 167 listBoxOption = m_children[i].get(); 168 break; 169 } 170 } 171 172 if (listBoxOption && !listBoxOption->accessibilityIsIgnored()) 173 return listBoxOption; 174 175 return axObjectCache()->getOrCreate(m_renderer); 176} 177 178} // namespace WebCore 179