WebKit/win/AccessibleBase.cpp
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebKit/win/AccessibleBase.cpp	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,727 @@
+/*
+ * Copyright (C) 2008, 2009, 2010 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
+ * 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 "WebKitDLL.h"
+#include "AccessibleBase.h"
+
+#include "AccessibleImage.h"
+#include "WebView.h"
+#include <WebCore/AccessibilityListBox.h>
+#include <WebCore/AccessibilityMenuListPopup.h>
+#include <WebCore/AccessibilityObject.h>
+#include <WebCore/AXObjectCache.h>
+#include <WebCore/BString.h>
+#include <WebCore/Element.h>
+#include <WebCore/EventHandler.h>
+#include <WebCore/FrameView.h>
+#include <WebCore/HostWindow.h>
+#include <WebCore/HTMLNames.h>
+#include <WebCore/HTMLFrameElementBase.h>
+#include <WebCore/HTMLInputElement.h>
+#include <WebCore/IntRect.h>
+#include <WebCore/PlatformKeyboardEvent.h>
+#include <WebCore/RenderFrame.h>
+#include <WebCore/RenderObject.h>
+#include <WebCore/RenderView.h>
+#include <oleacc.h>
+#include <wtf/RefPtr.h>
+
+using namespace WebCore;
+
+AccessibleBase::AccessibleBase(AccessibilityObject* obj)
+    : AccessibilityObjectWrapper(obj)
+    , m_refCount(0)
+{
+    ASSERT_ARG(obj, obj);
+    m_object->setWrapper(this);
+    ++gClassCount;
+    gClassNameCount.add("AccessibleBase");
+}
+
+AccessibleBase::~AccessibleBase()
+{
+    --gClassCount;
+    gClassNameCount.remove("AccessibleBase");
+}
+
+AccessibleBase* AccessibleBase::createInstance(AccessibilityObject* obj)
+{
+    ASSERT_ARG(obj, obj);
+
+    if (obj->isImage())
+        return new AccessibleImage(obj);
+
+    return new AccessibleBase(obj);
+}
+
+HRESULT AccessibleBase::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
+{
+    if (!IsEqualGUID(guidService, SID_AccessibleComparable)) {
+        *ppvObject = 0;
+        return E_INVALIDARG;
+    }
+    return QueryInterface(riid, ppvObject);
+}
+
+// IUnknown
+HRESULT STDMETHODCALLTYPE AccessibleBase::QueryInterface(REFIID riid, void** ppvObject)
+{
+    if (IsEqualGUID(riid, __uuidof(IAccessible)))
+        *ppvObject = static_cast<IAccessible*>(this);
+    else if (IsEqualGUID(riid, __uuidof(IDispatch)))
+        *ppvObject = static_cast<IAccessible*>(this);
+    else if (IsEqualGUID(riid, __uuidof(IUnknown)))
+        *ppvObject = static_cast<IAccessible*>(this);
+    else if (IsEqualGUID(riid, __uuidof(IAccessibleComparable)))
+        *ppvObject = static_cast<IAccessibleComparable*>(this);
+    else if (IsEqualGUID(riid, __uuidof(IServiceProvider)))
+        *ppvObject = static_cast<IServiceProvider*>(this);
+    else if (IsEqualGUID(riid, __uuidof(AccessibleBase)))
+        *ppvObject = static_cast<AccessibleBase*>(this);
+    else {
+        *ppvObject = 0;
+        return E_NOINTERFACE;
+    }
+    AddRef();
+    return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE AccessibleBase::Release(void)
+{
+    ASSERT(m_refCount > 0);
+    if (--m_refCount)
+        return m_refCount;
+    delete this;
+    return 0;
+}
+
+// IAccessible
+HRESULT STDMETHODCALLTYPE AccessibleBase::get_accParent(IDispatch** parent)
+{
+    *parent = 0;
+
+    if (!m_object)
+        return E_FAIL;
+
+    AccessibilityObject* parentObject = m_object->parentObjectUnignored();
+    if (parentObject) {
+        *parent = wrapper(parentObject);
+        (*parent)->AddRef();
+        return S_OK;
+    }
+
+    if (!m_object->topDocumentFrameView())
+        return E_FAIL;
+
+    return WebView::AccessibleObjectFromWindow(m_object->topDocumentFrameView()->hostWindow()->platformPageClient(),
+        OBJID_WINDOW, __uuidof(IAccessible), reinterpret_cast<void**>(parent));
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::get_accChildCount(long* count)
+{
+    if (!m_object)
+        return E_FAIL;
+    if (!count)
+        return E_POINTER;
+    *count = static_cast<long>(m_object->children().size());
+    return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::get_accChild(VARIANT vChild, IDispatch** ppChild)
+{
+    if (!ppChild)
+        return E_POINTER;
+
+    *ppChild = 0;
+
+    AccessibilityObject* childObj;
+
+    HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
+    if (FAILED(hr))
+        return hr;
+
+    *ppChild = static_cast<IDispatch*>(wrapper(childObj));
+    (*ppChild)->AddRef();
+    return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::get_accName(VARIANT vChild, BSTR* name)
+{
+    if (!name)
+        return E_POINTER;
+
+    *name = 0;
+
+    AccessibilityObject* childObj;
+    HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (*name = BString(wrapper(childObj)->name()).release())
+        return S_OK;
+    return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::get_accValue(VARIANT vChild, BSTR* value)
+{
+    if (!value)
+        return E_POINTER;
+
+    *value = 0;
+
+    AccessibilityObject* childObj;
+    HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (*value = BString(wrapper(childObj)->value()).release())
+        return S_OK;
+    return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::get_accDescription(VARIANT vChild, BSTR* description)
+{
+    if (!description)
+        return E_POINTER;
+
+    *description = 0;
+
+    AccessibilityObject* childObj;
+    HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (*description = BString(childObj->descriptionForMSAA()).release())
+        return S_OK;
+
+    return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::get_accRole(VARIANT vChild, VARIANT* pvRole)
+{
+    if (!pvRole)
+        return E_POINTER;
+
+    ::VariantInit(pvRole);
+
+    AccessibilityObject* childObj;
+    HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
+
+    if (FAILED(hr))
+        return hr;
+
+    String roleString = childObj->stringRoleForMSAA();
+    if (!roleString.isEmpty()) {
+        V_VT(pvRole) = VT_BSTR;
+        V_BSTR(pvRole) = BString(roleString).release();
+        return S_OK;
+    }
+
+    pvRole->vt = VT_I4;
+    pvRole->lVal = wrapper(childObj)->role();
+    return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::get_accState(VARIANT vChild, VARIANT* pvState)
+{
+    if (!pvState)
+        return E_POINTER;
+
+    ::VariantInit(pvState);
+
+    AccessibilityObject* childObj;
+    HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
+
+    if (FAILED(hr))
+        return hr;
+
+    pvState->vt = VT_I4;
+    pvState->lVal = 0;
+
+    if (childObj->isLinked())
+        pvState->lVal |= STATE_SYSTEM_LINKED;
+
+    if (childObj->isHovered())
+        pvState->lVal |= STATE_SYSTEM_HOTTRACKED;
+
+    if (!childObj->isEnabled())
+        pvState->lVal |= STATE_SYSTEM_UNAVAILABLE;
+
+    if (childObj->isReadOnly())
+        pvState->lVal |= STATE_SYSTEM_READONLY;
+
+    if (childObj->isOffScreen())
+        pvState->lVal |= STATE_SYSTEM_OFFSCREEN;
+
+    if (childObj->isPasswordField())
+        pvState->lVal |= STATE_SYSTEM_PROTECTED;
+
+    if (childObj->isIndeterminate())
+        pvState->lVal |= STATE_SYSTEM_INDETERMINATE;
+
+    if (childObj->isChecked())
+        pvState->lVal |= STATE_SYSTEM_CHECKED;
+
+    if (childObj->isPressed())
+        pvState->lVal |= STATE_SYSTEM_PRESSED;
+
+    if (childObj->isFocused())
+        pvState->lVal |= STATE_SYSTEM_FOCUSED;
+
+    if (childObj->isVisited())
+        pvState->lVal |= STATE_SYSTEM_TRAVERSED;
+
+    if (childObj->canSetFocusAttribute())
+        pvState->lVal |= STATE_SYSTEM_FOCUSABLE;
+
+    if (childObj->isSelected())
+        pvState->lVal |= STATE_SYSTEM_SELECTED;
+
+    if (childObj->canSetSelectedAttribute())
+        pvState->lVal |= STATE_SYSTEM_SELECTABLE;
+
+    if (childObj->isMultiSelectable())
+        pvState->lVal |= STATE_SYSTEM_EXTSELECTABLE | STATE_SYSTEM_MULTISELECTABLE;
+
+    if (!childObj->isVisible())
+        pvState->lVal |= STATE_SYSTEM_INVISIBLE;
+
+    if (childObj->isCollapsed())
+        pvState->lVal |= STATE_SYSTEM_COLLAPSED;
+
+    if (childObj->roleValue() == PopUpButtonRole) {
+        pvState->lVal |= STATE_SYSTEM_HASPOPUP;
+
+        if (!childObj->isCollapsed())
+            pvState->lVal |= STATE_SYSTEM_EXPANDED;
+    }
+
+    return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::get_accHelp(VARIANT vChild, BSTR* helpText)
+{
+    if (!helpText)
+        return E_POINTER;
+
+    *helpText = 0;
+
+    AccessibilityObject* childObj;
+    HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (*helpText = BString(childObj->helpText()).release())
+        return S_OK;
+    return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::get_accKeyboardShortcut(VARIANT vChild, BSTR* shortcut)
+{
+    if (!shortcut)
+        return E_POINTER;
+
+    *shortcut = 0;
+
+    AccessibilityObject* childObj;
+    HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
+
+    if (FAILED(hr))
+        return hr;
+
+    String accessKey = childObj->accessKey();
+    if (accessKey.isNull())
+        return S_FALSE;
+
+    static String accessKeyModifiers;
+    if (accessKeyModifiers.isNull()) {
+        unsigned modifiers = EventHandler::accessKeyModifiers();
+        // Follow the same order as Mozilla MSAA implementation:
+        // Ctrl+Alt+Shift+Meta+key. MSDN states that keyboard shortcut strings
+        // should not be localized and defines the separator as "+".
+        if (modifiers & PlatformKeyboardEvent::CtrlKey)
+            accessKeyModifiers += "Ctrl+";
+        if (modifiers & PlatformKeyboardEvent::AltKey)
+            accessKeyModifiers += "Alt+";
+        if (modifiers & PlatformKeyboardEvent::ShiftKey)
+            accessKeyModifiers += "Shift+";
+        if (modifiers & PlatformKeyboardEvent::MetaKey)
+            accessKeyModifiers += "Win+";
+    }
+    *shortcut = BString(accessKeyModifiers + accessKey).release();
+    return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::accSelect(long selectionFlags, VARIANT vChild)
+{
+    // According to MSDN, these combinations are invalid.
+    if (((selectionFlags & (SELFLAG_ADDSELECTION | SELFLAG_REMOVESELECTION)) == (SELFLAG_ADDSELECTION | SELFLAG_REMOVESELECTION))
+        || ((selectionFlags & (SELFLAG_ADDSELECTION | SELFLAG_TAKESELECTION)) == (SELFLAG_ADDSELECTION | SELFLAG_TAKESELECTION))
+        || ((selectionFlags & (SELFLAG_REMOVESELECTION | SELFLAG_TAKESELECTION)) == (SELFLAG_REMOVESELECTION | SELFLAG_TAKESELECTION))
+        || ((selectionFlags & (SELFLAG_EXTENDSELECTION | SELFLAG_TAKESELECTION)) == (SELFLAG_EXTENDSELECTION | SELFLAG_TAKESELECTION)))
+        return E_INVALIDARG;
+
+    AccessibilityObject* childObject;
+    HRESULT hr = getAccessibilityObjectForChild(vChild, childObject);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (selectionFlags & SELFLAG_TAKEFOCUS)
+        childObject->setFocused(true);
+
+    AccessibilityObject* parentObject = childObject->parentObject();
+    if (!parentObject)
+        return E_INVALIDARG;
+
+    if (selectionFlags & SELFLAG_TAKESELECTION) {
+        if (parentObject->isListBox()) {
+            Vector<RefPtr<AccessibilityObject> > selectedChildren(1);
+            selectedChildren[0] = childObject;
+            static_cast<AccessibilityListBox*>(parentObject)->setSelectedChildren(selectedChildren);
+        } else { // any element may be selectable by virtue of it having the aria-selected property
+            ASSERT(!parentObject->isMultiSelectable());
+            childObject->setSelected(true);
+        }
+    }
+
+    // MSDN says that ADD, REMOVE, and EXTENDSELECTION with no other flags are invalid for
+    // single-select.
+    const long allSELFLAGs = SELFLAG_TAKEFOCUS | SELFLAG_TAKESELECTION | SELFLAG_EXTENDSELECTION | SELFLAG_ADDSELECTION | SELFLAG_REMOVESELECTION;
+    if (!parentObject->isMultiSelectable()
+        && (((selectionFlags & allSELFLAGs) == SELFLAG_ADDSELECTION)
+        || ((selectionFlags & allSELFLAGs) == SELFLAG_REMOVESELECTION)
+        || ((selectionFlags & allSELFLAGs) == SELFLAG_EXTENDSELECTION)))
+        return E_INVALIDARG;
+
+    if (selectionFlags & SELFLAG_ADDSELECTION)
+        childObject->setSelected(true);
+
+    if (selectionFlags & SELFLAG_REMOVESELECTION)
+        childObject->setSelected(false);
+
+    // FIXME: Should implement SELFLAG_EXTENDSELECTION. For now, we just return
+    // S_OK, matching Firefox.
+
+    return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::get_accSelection(VARIANT*)
+{
+    return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::get_accFocus(VARIANT* pvFocusedChild)
+{
+    if (!pvFocusedChild)
+        return E_POINTER;
+
+    ::VariantInit(pvFocusedChild);
+
+    if (!m_object)
+        return E_FAIL;
+
+    AccessibilityObject* focusedObj = m_object->focusedUIElement();
+    if (!focusedObj)
+        return S_FALSE;
+
+    if (focusedObj == m_object) {
+        V_VT(pvFocusedChild) = VT_I4;
+        V_I4(pvFocusedChild) = CHILDID_SELF;
+        return S_OK;
+    }
+
+    V_VT(pvFocusedChild) = VT_DISPATCH;
+    V_DISPATCH(pvFocusedChild) = wrapper(focusedObj);
+    V_DISPATCH(pvFocusedChild)->AddRef();
+    return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::get_accDefaultAction(VARIANT vChild, BSTR* action)
+{
+    if (!action)
+        return E_POINTER;
+
+    *action = 0;
+
+    AccessibilityObject* childObj;
+    HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (*action = BString(childObj->actionVerb()).release())
+        return S_OK;
+    return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::accLocation(long* left, long* top, long* width, long* height, VARIANT vChild)
+{
+    if (!left || !top || !width || !height)
+        return E_POINTER;
+
+    *left = *top = *width = *height = 0;
+
+    AccessibilityObject* childObj;
+    HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (!childObj->documentFrameView())
+        return E_FAIL;
+
+    IntRect screenRect(childObj->documentFrameView()->contentsToScreen(childObj->elementRect()));
+    *left = screenRect.x();
+    *top = screenRect.y();
+    *width = screenRect.width();
+    *height = screenRect.height();
+    return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::accNavigate(long direction, VARIANT vFromChild, VARIANT* pvNavigatedTo)
+{
+    if (!pvNavigatedTo)
+        return E_POINTER;
+
+    ::VariantInit(pvNavigatedTo);
+
+    AccessibilityObject* childObj = 0;
+
+    switch (direction) {
+        case NAVDIR_DOWN:
+        case NAVDIR_UP:
+        case NAVDIR_LEFT:
+        case NAVDIR_RIGHT:
+            // These directions are not implemented, matching Mozilla and IE.
+            return E_NOTIMPL;
+        case NAVDIR_LASTCHILD:
+        case NAVDIR_FIRSTCHILD:
+            // MSDN states that navigating to first/last child can only be from self.
+            if (vFromChild.lVal != CHILDID_SELF)
+                return E_INVALIDARG;
+
+            if (!m_object)
+                return E_FAIL;
+
+            if (direction == NAVDIR_FIRSTCHILD)
+                childObj = m_object->firstChild();
+            else
+                childObj = m_object->lastChild();
+            break;
+        case NAVDIR_NEXT:
+        case NAVDIR_PREVIOUS: {
+            // Navigating to next and previous is allowed from self or any of our children.
+            HRESULT hr = getAccessibilityObjectForChild(vFromChild, childObj);
+            if (FAILED(hr))
+                return hr;
+
+            if (direction == NAVDIR_NEXT)
+                childObj = childObj->nextSibling();
+            else
+                childObj = childObj->previousSibling();
+            break;
+        }
+        default:
+            ASSERT_NOT_REACHED();
+            return E_INVALIDARG;
+    }
+
+    if (!childObj)
+        return S_FALSE;
+
+    V_VT(pvNavigatedTo) = VT_DISPATCH;
+    V_DISPATCH(pvNavigatedTo) = wrapper(childObj);
+    V_DISPATCH(pvNavigatedTo)->AddRef();
+    return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::accHitTest(long x, long y, VARIANT* pvChildAtPoint)
+{
+    if (!pvChildAtPoint)
+        return E_POINTER;
+
+    ::VariantInit(pvChildAtPoint);
+
+    if (!m_object || !m_object->documentFrameView())
+        return E_FAIL;
+
+    IntPoint point = m_object->documentFrameView()->screenToContents(IntPoint(x, y));
+    AccessibilityObject* childObj = m_object->doAccessibilityHitTest(point);
+
+    if (!childObj) {
+        // If we did not hit any child objects, test whether the point hit us, and
+        // report that.
+        if (!m_object->boundingBoxRect().contains(point))
+            return S_FALSE;
+        childObj = m_object;
+    }
+
+    if (childObj == m_object) {
+        V_VT(pvChildAtPoint) = VT_I4;
+        V_I4(pvChildAtPoint) = CHILDID_SELF;
+    } else {
+        V_VT(pvChildAtPoint) = VT_DISPATCH;
+        V_DISPATCH(pvChildAtPoint) = static_cast<IDispatch*>(wrapper(childObj));
+        V_DISPATCH(pvChildAtPoint)->AddRef();
+    }
+    return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE AccessibleBase::accDoDefaultAction(VARIANT vChild)
+{
+    AccessibilityObject* childObj;
+    HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (!childObj->performDefaultAction())
+        return S_FALSE;
+
+    return S_OK;
+}
+
+// AccessibleBase
+String AccessibleBase::name() const
+{
+    return m_object->nameForMSAA();
+}
+
+String AccessibleBase::value() const
+{
+    return m_object->stringValueForMSAA();
+}
+
+static long MSAARole(AccessibilityRole role)
+{
+    switch (role) {
+        case WebCore::ButtonRole:
+            return ROLE_SYSTEM_PUSHBUTTON;
+        case WebCore::RadioButtonRole:
+            return ROLE_SYSTEM_RADIOBUTTON;
+        case WebCore::CheckBoxRole:
+            return ROLE_SYSTEM_CHECKBUTTON;
+        case WebCore::SliderRole:
+            return ROLE_SYSTEM_SLIDER;
+        case WebCore::TabGroupRole:
+            return ROLE_SYSTEM_PAGETABLIST;
+        case WebCore::TextFieldRole:
+        case WebCore::TextAreaRole:
+        case WebCore::EditableTextRole:
+            return ROLE_SYSTEM_TEXT;
+        case WebCore::ListMarkerRole:
+        case WebCore::StaticTextRole:
+            return ROLE_SYSTEM_STATICTEXT;
+        case WebCore::OutlineRole:
+            return ROLE_SYSTEM_OUTLINE;
+        case WebCore::ColumnRole:
+            return ROLE_SYSTEM_COLUMN;
+        case WebCore::RowRole:
+            return ROLE_SYSTEM_ROW;
+        case WebCore::GroupRole:
+            return ROLE_SYSTEM_GROUPING;
+        case WebCore::ListRole:
+        case WebCore::ListBoxRole:
+        case WebCore::MenuListPopupRole:
+            return ROLE_SYSTEM_LIST;
+        case WebCore::TableRole:
+            return ROLE_SYSTEM_TABLE;
+        case WebCore::LinkRole:
+        case WebCore::WebCoreLinkRole:
+            return ROLE_SYSTEM_LINK;
+        case WebCore::ImageMapRole:
+        case WebCore::ImageRole:
+            return ROLE_SYSTEM_GRAPHIC;
+        case WebCore::MenuListOptionRole:
+        case WebCore::ListItemRole:
+        case WebCore::ListBoxOptionRole:
+            return ROLE_SYSTEM_LISTITEM;
+        case WebCore::PopUpButtonRole:
+            return ROLE_SYSTEM_COMBOBOX;
+        default:
+            // This is the default role for MSAA.
+            return ROLE_SYSTEM_CLIENT;
+    }
+}
+
+long AccessibleBase::role() const
+{
+    return MSAARole(m_object->roleValueForMSAA());
+}
+
+HRESULT AccessibleBase::getAccessibilityObjectForChild(VARIANT vChild, AccessibilityObject*& childObj) const
+{
+    childObj = 0;
+
+    if (!m_object)
+        return E_FAIL;
+
+    if (vChild.vt != VT_I4)
+        return E_INVALIDARG;
+
+    if (vChild.lVal == CHILDID_SELF)
+        childObj = m_object;
+    else if (vChild.lVal < 0) {
+        // When broadcasting MSAA events, we negate the AXID and pass it as the
+        // child ID.
+        Document* document = m_object->document();
+        if (!document)
+            return E_FAIL;
+
+        childObj = document->axObjectCache()->objectFromAXID(-vChild.lVal);
+    } else {
+        size_t childIndex = static_cast<size_t>(vChild.lVal - 1);
+
+        if (childIndex >= m_object->children().size())
+            return E_FAIL;
+        childObj = m_object->children().at(childIndex).get();
+    }
+
+    if (!childObj)
+        return E_FAIL;
+
+    return S_OK;
+}
+
+AccessibleBase* AccessibleBase::wrapper(AccessibilityObject* obj)
+{
+    AccessibleBase* result = static_cast<AccessibleBase*>(obj->wrapper());
+    if (!result)
+        result = createInstance(obj);
+    return result;
+}
+
+HRESULT AccessibleBase::isSameObject(IAccessibleComparable* other, BOOL* result)
+{
+    COMPtr<AccessibleBase> otherAccessibleBase(Query, other);
+    *result = (otherAccessibleBase == this || otherAccessibleBase->m_object == m_object);
+    return S_OK;
+}