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