1/* 2 * Copyright (C) 2010 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "AccessibilityMenuList.h" 28 29#include "AXObjectCache.h" 30#include "AccessibilityMenuListPopup.h" 31#include "RenderMenuList.h" 32 33namespace WebCore { 34 35AccessibilityMenuList::AccessibilityMenuList(RenderMenuList* renderer) 36 : AccessibilityRenderObject(renderer) 37{ 38} 39 40PassRefPtr<AccessibilityMenuList> AccessibilityMenuList::create(RenderMenuList* renderer) 41{ 42 return adoptRef(new AccessibilityMenuList(renderer)); 43} 44 45bool AccessibilityMenuList::press() 46{ 47#if !PLATFORM(IOS) 48 RenderMenuList* menuList = static_cast<RenderMenuList*>(m_renderer); 49 if (menuList->popupIsVisible()) 50 menuList->hidePopup(); 51 else 52 menuList->showPopup(); 53 return true; 54#else 55 return false; 56#endif 57} 58 59void AccessibilityMenuList::addChildren() 60{ 61 m_haveChildren = true; 62 63 AXObjectCache* cache = m_renderer->document().axObjectCache(); 64 65 AccessibilityObject* list = cache->getOrCreate(MenuListPopupRole); 66 if (!list) 67 return; 68 69 toAccessibilityMockObject(list)->setParent(this); 70 if (list->accessibilityIsIgnored()) { 71 cache->remove(list->axObjectID()); 72 return; 73 } 74 75 m_children.append(list); 76 77 list->addChildren(); 78} 79 80void AccessibilityMenuList::childrenChanged() 81{ 82 if (m_children.isEmpty()) 83 return; 84 85 ASSERT(m_children.size() == 1); 86 m_children[0]->childrenChanged(); 87} 88 89bool AccessibilityMenuList::isCollapsed() const 90{ 91#if !PLATFORM(IOS) 92 return !static_cast<RenderMenuList*>(m_renderer)->popupIsVisible(); 93#else 94 return true; 95#endif 96} 97 98bool AccessibilityMenuList::canSetFocusAttribute() const 99{ 100 if (!node()) 101 return false; 102 103 return !toElement(node())->isDisabledFormControl(); 104} 105 106void AccessibilityMenuList::didUpdateActiveOption(int optionIndex) 107{ 108 Ref<Document> document(m_renderer->document()); 109 AXObjectCache* cache = document->axObjectCache(); 110 111 const auto& childObjects = children(); 112 if (!childObjects.isEmpty()) { 113 ASSERT(childObjects.size() == 1); 114 ASSERT(childObjects[0]->isMenuListPopup()); 115 116 // We might be calling this method in situations where the renderers for list items 117 // associated to the menu list have not been created (e.g. they might be rendered 118 // in the UI process, as it's the case in the GTK+ port, which uses GtkMenuItem). 119 // So, we need to make sure that the accessibility popup object has some children 120 // before asking it to update its active option, or it will read invalid memory. 121 // You can reproduce the issue in the GTK+ port by removing this check and running 122 // accessibility/insert-selected-option-into-select-causes-crash.html (will crash). 123 int popupChildrenSize = static_cast<int>(childObjects[0]->children().size()); 124 if (childObjects[0]->isMenuListPopup() && optionIndex >= 0 && optionIndex < popupChildrenSize) { 125 if (AccessibilityMenuListPopup* popup = toAccessibilityMenuListPopup(childObjects[0].get())) 126 popup->didUpdateActiveOption(optionIndex); 127 } 128 } 129 130 cache->postNotification(this, &document.get(), AXObjectCache::AXMenuListValueChanged, TargetElement, PostSynchronously); 131} 132 133} // namespace WebCore 134