/* * Copyright (C) 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "AXObjectCache.h" #include "AccessibilityList.h" #include "AccessibilityListBox.h" #include "AccessibilityListBoxOption.h" #include "AccessibilityImageMapLink.h" #include "AccessibilityRenderObject.h" #include "AccessibilityTable.h" #include "AccessibilityTableCell.h" #include "AccessibilityTableColumn.h" #include "AccessibilityTableHeaderContainer.h" #include "AccessibilityTableRow.h" #include "HTMLNames.h" #include "RenderObject.h" #include namespace WebCore { using namespace HTMLNames; bool AXObjectCache::gAccessibilityEnabled = false; bool AXObjectCache::gAccessibilityEnhancedUserInterfaceEnabled = false; AXObjectCache::~AXObjectCache() { HashMap >::iterator end = m_objects.end(); for (HashMap >::iterator it = m_objects.begin(); it != end; ++it) { AccessibilityObject* obj = (*it).second.get(); detachWrapper(obj); obj->detach(); } } AccessibilityObject* AXObjectCache::get(RenderObject* renderer) { if (!renderer) return 0; RefPtr obj = 0; AXID axID = m_renderObjectMapping.get(renderer); ASSERT(!HashTraits::isDeletedValue(axID)); if (axID) obj = m_objects.get(axID).get(); Node* element = renderer->element(); if (!obj) { if (renderer->isListBox()) obj = AccessibilityListBox::create(renderer); else if (element && (element->hasTagName(ulTag) || element->hasTagName(olTag) || element->hasTagName(dlTag))) obj = AccessibilityList::create(renderer); else if (renderer->isTable()) obj = AccessibilityTable::create(renderer); else if (renderer->isTableRow()) obj = AccessibilityTableRow::create(renderer); else if (renderer->isTableCell()) obj = AccessibilityTableCell::create(renderer); else obj = AccessibilityRenderObject::create(renderer); getAXID(obj.get()); m_renderObjectMapping.set(renderer, obj.get()->axObjectID()); m_objects.set(obj.get()->axObjectID(), obj); attachWrapper(obj.get()); } return obj.get(); } AccessibilityObject* AXObjectCache::get(AccessibilityRole role) { RefPtr obj = 0; // will be filled in... switch (role) { case ListBoxOptionRole: obj = AccessibilityListBoxOption::create(); break; case ImageMapLinkRole: obj = AccessibilityImageMapLink::create(); break; case ColumnRole: obj = AccessibilityTableColumn::create(); break; case TableHeaderContainerRole: obj = AccessibilityTableHeaderContainer::create(); break; default: obj = 0; } if (obj) getAXID(obj.get()); else return 0; m_objects.set(obj->axObjectID(), obj); attachWrapper(obj.get()); return obj.get(); } void AXObjectCache::remove(AXID axID) { if (!axID) return; // first fetch object to operate some cleanup functions on it AccessibilityObject* obj = m_objects.get(axID).get(); if (!obj) return; detachWrapper(obj); obj->detach(); removeAXID(obj); // finally remove the object if (!m_objects.take(axID)) { return; } ASSERT(m_objects.size() >= m_idsInUse.size()); } void AXObjectCache::remove(RenderObject* renderer) { if (!renderer) return; AXID axID = m_renderObjectMapping.get(renderer); remove(axID); m_renderObjectMapping.remove(renderer); } AXID AXObjectCache::getAXID(AccessibilityObject* obj) { // check for already-assigned ID AXID objID = obj->axObjectID(); if (objID) { ASSERT(m_idsInUse.contains(objID)); return objID; } // generate a new ID static AXID lastUsedID = 0; objID = lastUsedID; do ++objID; while (objID == 0 || HashTraits::isDeletedValue(objID) || m_idsInUse.contains(objID)); m_idsInUse.add(objID); lastUsedID = objID; obj->setAXObjectID(objID); return objID; } void AXObjectCache::removeAXID(AccessibilityObject* obj) { AXID objID = obj->axObjectID(); if (objID == 0) return; ASSERT(!HashTraits::isDeletedValue(objID)); ASSERT(m_idsInUse.contains(objID)); obj->setAXObjectID(0); m_idsInUse.remove(objID); } void AXObjectCache::childrenChanged(RenderObject* renderer) { if (!renderer) return; AXID axID = m_renderObjectMapping.get(renderer); if (!axID) return; AccessibilityObject* obj = m_objects.get(axID).get(); if (obj) obj->childrenChanged(); } #if HAVE(ACCESSIBILITY) void AXObjectCache::selectedChildrenChanged(RenderObject* renderer) { postNotificationToElement(renderer, "AXSelectedChildrenChanged"); } #endif #if HAVE(ACCESSIBILITY) void AXObjectCache::handleActiveDescendantChanged(RenderObject* renderer) { if (!renderer) return; AccessibilityObject* obj = get(renderer); if (obj) obj->handleActiveDescendantChanged(); } void AXObjectCache::handleAriaRoleChanged(RenderObject* renderer) { if (!renderer) return; AccessibilityObject* obj = get(renderer); if (obj && obj->isAccessibilityRenderObject()) static_cast(obj)->setAriaRole(); } #endif } // namespace WebCore