Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2008, 2009, 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 "WebKitDLL.h"
     28 #include "AccessibleBase.h"
     29 
     30 #include "AccessibleImage.h"
     31 #include "WebView.h"
     32 #include <WebCore/AccessibilityListBox.h>
     33 #include <WebCore/AccessibilityMenuListPopup.h>
     34 #include <WebCore/AccessibilityObject.h>
     35 #include <WebCore/AXObjectCache.h>
     36 #include <WebCore/BString.h>
     37 #include <WebCore/Element.h>
     38 #include <WebCore/EventHandler.h>
     39 #include <WebCore/FrameView.h>
     40 #include <WebCore/HostWindow.h>
     41 #include <WebCore/HTMLNames.h>
     42 #include <WebCore/HTMLFrameElementBase.h>
     43 #include <WebCore/HTMLInputElement.h>
     44 #include <WebCore/IntRect.h>
     45 #include <WebCore/PlatformKeyboardEvent.h>
     46 #include <WebCore/RenderFrame.h>
     47 #include <WebCore/RenderObject.h>
     48 #include <WebCore/RenderView.h>
     49 #include <oleacc.h>
     50 #include <wtf/RefPtr.h>
     51 
     52 using namespace WebCore;
     53 
     54 AccessibleBase::AccessibleBase(AccessibilityObject* obj)
     55     : AccessibilityObjectWrapper(obj)
     56     , m_refCount(0)
     57 {
     58     ASSERT_ARG(obj, obj);
     59     m_object->setWrapper(this);
     60     ++gClassCount;
     61     gClassNameCount.add("AccessibleBase");
     62 }
     63 
     64 AccessibleBase::~AccessibleBase()
     65 {
     66     --gClassCount;
     67     gClassNameCount.remove("AccessibleBase");
     68 }
     69 
     70 AccessibleBase* AccessibleBase::createInstance(AccessibilityObject* obj)
     71 {
     72     ASSERT_ARG(obj, obj);
     73 
     74     if (obj->isImage())
     75         return new AccessibleImage(obj);
     76 
     77     return new AccessibleBase(obj);
     78 }
     79 
     80 HRESULT AccessibleBase::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
     81 {
     82     if (!IsEqualGUID(guidService, SID_AccessibleComparable)) {
     83         *ppvObject = 0;
     84         return E_INVALIDARG;
     85     }
     86     return QueryInterface(riid, ppvObject);
     87 }
     88 
     89 // IUnknown
     90 HRESULT STDMETHODCALLTYPE AccessibleBase::QueryInterface(REFIID riid, void** ppvObject)
     91 {
     92     if (IsEqualGUID(riid, __uuidof(IAccessible)))
     93         *ppvObject = static_cast<IAccessible*>(this);
     94     else if (IsEqualGUID(riid, __uuidof(IDispatch)))
     95         *ppvObject = static_cast<IAccessible*>(this);
     96     else if (IsEqualGUID(riid, __uuidof(IUnknown)))
     97         *ppvObject = static_cast<IAccessible*>(this);
     98     else if (IsEqualGUID(riid, __uuidof(IAccessibleComparable)))
     99         *ppvObject = static_cast<IAccessibleComparable*>(this);
    100     else if (IsEqualGUID(riid, __uuidof(IServiceProvider)))
    101         *ppvObject = static_cast<IServiceProvider*>(this);
    102     else if (IsEqualGUID(riid, __uuidof(AccessibleBase)))
    103         *ppvObject = static_cast<AccessibleBase*>(this);
    104     else {
    105         *ppvObject = 0;
    106         return E_NOINTERFACE;
    107     }
    108     AddRef();
    109     return S_OK;
    110 }
    111 
    112 ULONG STDMETHODCALLTYPE AccessibleBase::Release(void)
    113 {
    114     ASSERT(m_refCount > 0);
    115     if (--m_refCount)
    116         return m_refCount;
    117     delete this;
    118     return 0;
    119 }
    120 
    121 // IAccessible
    122 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accParent(IDispatch** parent)
    123 {
    124     *parent = 0;
    125 
    126     if (!m_object)
    127         return E_FAIL;
    128 
    129     AccessibilityObject* parentObject = m_object->parentObjectUnignored();
    130     if (parentObject) {
    131         *parent = wrapper(parentObject);
    132         (*parent)->AddRef();
    133         return S_OK;
    134     }
    135 
    136     if (!m_object->topDocumentFrameView())
    137         return E_FAIL;
    138 
    139     return WebView::AccessibleObjectFromWindow(m_object->topDocumentFrameView()->hostWindow()->platformPageClient(),
    140         OBJID_WINDOW, __uuidof(IAccessible), reinterpret_cast<void**>(parent));
    141 }
    142 
    143 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accChildCount(long* count)
    144 {
    145     if (!m_object)
    146         return E_FAIL;
    147     if (!count)
    148         return E_POINTER;
    149     *count = static_cast<long>(m_object->children().size());
    150     return S_OK;
    151 }
    152 
    153 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accChild(VARIANT vChild, IDispatch** ppChild)
    154 {
    155     if (!ppChild)
    156         return E_POINTER;
    157 
    158     *ppChild = 0;
    159 
    160     AccessibilityObject* childObj;
    161 
    162     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
    163     if (FAILED(hr))
    164         return hr;
    165 
    166     *ppChild = static_cast<IDispatch*>(wrapper(childObj));
    167     (*ppChild)->AddRef();
    168     return S_OK;
    169 }
    170 
    171 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accName(VARIANT vChild, BSTR* name)
    172 {
    173     if (!name)
    174         return E_POINTER;
    175 
    176     *name = 0;
    177 
    178     AccessibilityObject* childObj;
    179     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
    180 
    181     if (FAILED(hr))
    182         return hr;
    183 
    184     if (*name = BString(wrapper(childObj)->name()).release())
    185         return S_OK;
    186     return S_FALSE;
    187 }
    188 
    189 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accValue(VARIANT vChild, BSTR* value)
    190 {
    191     if (!value)
    192         return E_POINTER;
    193 
    194     *value = 0;
    195 
    196     AccessibilityObject* childObj;
    197     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
    198 
    199     if (FAILED(hr))
    200         return hr;
    201 
    202     if (*value = BString(wrapper(childObj)->value()).release())
    203         return S_OK;
    204     return S_FALSE;
    205 }
    206 
    207 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accDescription(VARIANT vChild, BSTR* description)
    208 {
    209     if (!description)
    210         return E_POINTER;
    211 
    212     *description = 0;
    213 
    214     AccessibilityObject* childObj;
    215     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
    216 
    217     if (FAILED(hr))
    218         return hr;
    219 
    220     if (*description = BString(childObj->descriptionForMSAA()).release())
    221         return S_OK;
    222 
    223     return S_FALSE;
    224 }
    225 
    226 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accRole(VARIANT vChild, VARIANT* pvRole)
    227 {
    228     if (!pvRole)
    229         return E_POINTER;
    230 
    231     ::VariantInit(pvRole);
    232 
    233     AccessibilityObject* childObj;
    234     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
    235 
    236     if (FAILED(hr))
    237         return hr;
    238 
    239     String roleString = childObj->stringRoleForMSAA();
    240     if (!roleString.isEmpty()) {
    241         V_VT(pvRole) = VT_BSTR;
    242         V_BSTR(pvRole) = BString(roleString).release();
    243         return S_OK;
    244     }
    245 
    246     pvRole->vt = VT_I4;
    247     pvRole->lVal = wrapper(childObj)->role();
    248     return S_OK;
    249 }
    250 
    251 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accState(VARIANT vChild, VARIANT* pvState)
    252 {
    253     if (!pvState)
    254         return E_POINTER;
    255 
    256     ::VariantInit(pvState);
    257 
    258     AccessibilityObject* childObj;
    259     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
    260 
    261     if (FAILED(hr))
    262         return hr;
    263 
    264     pvState->vt = VT_I4;
    265     pvState->lVal = 0;
    266 
    267     if (childObj->isLinked())
    268         pvState->lVal |= STATE_SYSTEM_LINKED;
    269 
    270     if (childObj->isHovered())
    271         pvState->lVal |= STATE_SYSTEM_HOTTRACKED;
    272 
    273     if (!childObj->isEnabled())
    274         pvState->lVal |= STATE_SYSTEM_UNAVAILABLE;
    275 
    276     if (childObj->isReadOnly())
    277         pvState->lVal |= STATE_SYSTEM_READONLY;
    278 
    279     if (childObj->isOffScreen())
    280         pvState->lVal |= STATE_SYSTEM_OFFSCREEN;
    281 
    282     if (childObj->isPasswordField())
    283         pvState->lVal |= STATE_SYSTEM_PROTECTED;
    284 
    285     if (childObj->isIndeterminate())
    286         pvState->lVal |= STATE_SYSTEM_INDETERMINATE;
    287 
    288     if (childObj->isChecked())
    289         pvState->lVal |= STATE_SYSTEM_CHECKED;
    290 
    291     if (childObj->isPressed())
    292         pvState->lVal |= STATE_SYSTEM_PRESSED;
    293 
    294     if (childObj->isFocused())
    295         pvState->lVal |= STATE_SYSTEM_FOCUSED;
    296 
    297     if (childObj->isVisited())
    298         pvState->lVal |= STATE_SYSTEM_TRAVERSED;
    299 
    300     if (childObj->canSetFocusAttribute())
    301         pvState->lVal |= STATE_SYSTEM_FOCUSABLE;
    302 
    303     if (childObj->isSelected())
    304         pvState->lVal |= STATE_SYSTEM_SELECTED;
    305 
    306     if (childObj->canSetSelectedAttribute())
    307         pvState->lVal |= STATE_SYSTEM_SELECTABLE;
    308 
    309     if (childObj->isMultiSelectable())
    310         pvState->lVal |= STATE_SYSTEM_EXTSELECTABLE | STATE_SYSTEM_MULTISELECTABLE;
    311 
    312     if (!childObj->isVisible())
    313         pvState->lVal |= STATE_SYSTEM_INVISIBLE;
    314 
    315     if (childObj->isCollapsed())
    316         pvState->lVal |= STATE_SYSTEM_COLLAPSED;
    317 
    318     if (childObj->roleValue() == PopUpButtonRole) {
    319         pvState->lVal |= STATE_SYSTEM_HASPOPUP;
    320 
    321         if (!childObj->isCollapsed())
    322             pvState->lVal |= STATE_SYSTEM_EXPANDED;
    323     }
    324 
    325     return S_OK;
    326 }
    327 
    328 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accHelp(VARIANT vChild, BSTR* helpText)
    329 {
    330     if (!helpText)
    331         return E_POINTER;
    332 
    333     *helpText = 0;
    334 
    335     AccessibilityObject* childObj;
    336     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
    337 
    338     if (FAILED(hr))
    339         return hr;
    340 
    341     if (*helpText = BString(childObj->helpText()).release())
    342         return S_OK;
    343     return S_FALSE;
    344 }
    345 
    346 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accKeyboardShortcut(VARIANT vChild, BSTR* shortcut)
    347 {
    348     if (!shortcut)
    349         return E_POINTER;
    350 
    351     *shortcut = 0;
    352 
    353     AccessibilityObject* childObj;
    354     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
    355 
    356     if (FAILED(hr))
    357         return hr;
    358 
    359     String accessKey = childObj->accessKey();
    360     if (accessKey.isNull())
    361         return S_FALSE;
    362 
    363     static String accessKeyModifiers;
    364     if (accessKeyModifiers.isNull()) {
    365         unsigned modifiers = EventHandler::accessKeyModifiers();
    366         // Follow the same order as Mozilla MSAA implementation:
    367         // Ctrl+Alt+Shift+Meta+key. MSDN states that keyboard shortcut strings
    368         // should not be localized and defines the separator as "+".
    369         if (modifiers & PlatformKeyboardEvent::CtrlKey)
    370             accessKeyModifiers += "Ctrl+";
    371         if (modifiers & PlatformKeyboardEvent::AltKey)
    372             accessKeyModifiers += "Alt+";
    373         if (modifiers & PlatformKeyboardEvent::ShiftKey)
    374             accessKeyModifiers += "Shift+";
    375         if (modifiers & PlatformKeyboardEvent::MetaKey)
    376             accessKeyModifiers += "Win+";
    377     }
    378     *shortcut = BString(accessKeyModifiers + accessKey).release();
    379     return S_OK;
    380 }
    381 
    382 HRESULT STDMETHODCALLTYPE AccessibleBase::accSelect(long selectionFlags, VARIANT vChild)
    383 {
    384     // According to MSDN, these combinations are invalid.
    385     if (((selectionFlags & (SELFLAG_ADDSELECTION | SELFLAG_REMOVESELECTION)) == (SELFLAG_ADDSELECTION | SELFLAG_REMOVESELECTION))
    386         || ((selectionFlags & (SELFLAG_ADDSELECTION | SELFLAG_TAKESELECTION)) == (SELFLAG_ADDSELECTION | SELFLAG_TAKESELECTION))
    387         || ((selectionFlags & (SELFLAG_REMOVESELECTION | SELFLAG_TAKESELECTION)) == (SELFLAG_REMOVESELECTION | SELFLAG_TAKESELECTION))
    388         || ((selectionFlags & (SELFLAG_EXTENDSELECTION | SELFLAG_TAKESELECTION)) == (SELFLAG_EXTENDSELECTION | SELFLAG_TAKESELECTION)))
    389         return E_INVALIDARG;
    390 
    391     AccessibilityObject* childObject;
    392     HRESULT hr = getAccessibilityObjectForChild(vChild, childObject);
    393 
    394     if (FAILED(hr))
    395         return hr;
    396 
    397     if (selectionFlags & SELFLAG_TAKEFOCUS)
    398         childObject->setFocused(true);
    399 
    400     AccessibilityObject* parentObject = childObject->parentObject();
    401     if (!parentObject)
    402         return E_INVALIDARG;
    403 
    404     if (selectionFlags & SELFLAG_TAKESELECTION) {
    405         if (parentObject->isListBox()) {
    406             Vector<RefPtr<AccessibilityObject> > selectedChildren(1);
    407             selectedChildren[0] = childObject;
    408             static_cast<AccessibilityListBox*>(parentObject)->setSelectedChildren(selectedChildren);
    409         } else { // any element may be selectable by virtue of it having the aria-selected property
    410             ASSERT(!parentObject->isMultiSelectable());
    411             childObject->setSelected(true);
    412         }
    413     }
    414 
    415     // MSDN says that ADD, REMOVE, and EXTENDSELECTION with no other flags are invalid for
    416     // single-select.
    417     const long allSELFLAGs = SELFLAG_TAKEFOCUS | SELFLAG_TAKESELECTION | SELFLAG_EXTENDSELECTION | SELFLAG_ADDSELECTION | SELFLAG_REMOVESELECTION;
    418     if (!parentObject->isMultiSelectable()
    419         && (((selectionFlags & allSELFLAGs) == SELFLAG_ADDSELECTION)
    420         || ((selectionFlags & allSELFLAGs) == SELFLAG_REMOVESELECTION)
    421         || ((selectionFlags & allSELFLAGs) == SELFLAG_EXTENDSELECTION)))
    422         return E_INVALIDARG;
    423 
    424     if (selectionFlags & SELFLAG_ADDSELECTION)
    425         childObject->setSelected(true);
    426 
    427     if (selectionFlags & SELFLAG_REMOVESELECTION)
    428         childObject->setSelected(false);
    429 
    430     // FIXME: Should implement SELFLAG_EXTENDSELECTION. For now, we just return
    431     // S_OK, matching Firefox.
    432 
    433     return S_OK;
    434 }
    435 
    436 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accSelection(VARIANT*)
    437 {
    438     return E_NOTIMPL;
    439 }
    440 
    441 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accFocus(VARIANT* pvFocusedChild)
    442 {
    443     if (!pvFocusedChild)
    444         return E_POINTER;
    445 
    446     ::VariantInit(pvFocusedChild);
    447 
    448     if (!m_object)
    449         return E_FAIL;
    450 
    451     AccessibilityObject* focusedObj = m_object->focusedUIElement();
    452     if (!focusedObj)
    453         return S_FALSE;
    454 
    455     if (focusedObj == m_object) {
    456         V_VT(pvFocusedChild) = VT_I4;
    457         V_I4(pvFocusedChild) = CHILDID_SELF;
    458         return S_OK;
    459     }
    460 
    461     V_VT(pvFocusedChild) = VT_DISPATCH;
    462     V_DISPATCH(pvFocusedChild) = wrapper(focusedObj);
    463     V_DISPATCH(pvFocusedChild)->AddRef();
    464     return S_OK;
    465 }
    466 
    467 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accDefaultAction(VARIANT vChild, BSTR* action)
    468 {
    469     if (!action)
    470         return E_POINTER;
    471 
    472     *action = 0;
    473 
    474     AccessibilityObject* childObj;
    475     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
    476 
    477     if (FAILED(hr))
    478         return hr;
    479 
    480     if (*action = BString(childObj->actionVerb()).release())
    481         return S_OK;
    482     return S_FALSE;
    483 }
    484 
    485 HRESULT STDMETHODCALLTYPE AccessibleBase::accLocation(long* left, long* top, long* width, long* height, VARIANT vChild)
    486 {
    487     if (!left || !top || !width || !height)
    488         return E_POINTER;
    489 
    490     *left = *top = *width = *height = 0;
    491 
    492     AccessibilityObject* childObj;
    493     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
    494 
    495     if (FAILED(hr))
    496         return hr;
    497 
    498     if (!childObj->documentFrameView())
    499         return E_FAIL;
    500 
    501     IntRect screenRect(childObj->documentFrameView()->contentsToScreen(childObj->elementRect()));
    502     *left = screenRect.x();
    503     *top = screenRect.y();
    504     *width = screenRect.width();
    505     *height = screenRect.height();
    506     return S_OK;
    507 }
    508 
    509 HRESULT STDMETHODCALLTYPE AccessibleBase::accNavigate(long direction, VARIANT vFromChild, VARIANT* pvNavigatedTo)
    510 {
    511     if (!pvNavigatedTo)
    512         return E_POINTER;
    513 
    514     ::VariantInit(pvNavigatedTo);
    515 
    516     AccessibilityObject* childObj = 0;
    517 
    518     switch (direction) {
    519         case NAVDIR_DOWN:
    520         case NAVDIR_UP:
    521         case NAVDIR_LEFT:
    522         case NAVDIR_RIGHT:
    523             // These directions are not implemented, matching Mozilla and IE.
    524             return E_NOTIMPL;
    525         case NAVDIR_LASTCHILD:
    526         case NAVDIR_FIRSTCHILD:
    527             // MSDN states that navigating to first/last child can only be from self.
    528             if (vFromChild.lVal != CHILDID_SELF)
    529                 return E_INVALIDARG;
    530 
    531             if (!m_object)
    532                 return E_FAIL;
    533 
    534             if (direction == NAVDIR_FIRSTCHILD)
    535                 childObj = m_object->firstChild();
    536             else
    537                 childObj = m_object->lastChild();
    538             break;
    539         case NAVDIR_NEXT:
    540         case NAVDIR_PREVIOUS: {
    541             // Navigating to next and previous is allowed from self or any of our children.
    542             HRESULT hr = getAccessibilityObjectForChild(vFromChild, childObj);
    543             if (FAILED(hr))
    544                 return hr;
    545 
    546             if (direction == NAVDIR_NEXT)
    547                 childObj = childObj->nextSibling();
    548             else
    549                 childObj = childObj->previousSibling();
    550             break;
    551         }
    552         default:
    553             ASSERT_NOT_REACHED();
    554             return E_INVALIDARG;
    555     }
    556 
    557     if (!childObj)
    558         return S_FALSE;
    559 
    560     V_VT(pvNavigatedTo) = VT_DISPATCH;
    561     V_DISPATCH(pvNavigatedTo) = wrapper(childObj);
    562     V_DISPATCH(pvNavigatedTo)->AddRef();
    563     return S_OK;
    564 }
    565 
    566 HRESULT STDMETHODCALLTYPE AccessibleBase::accHitTest(long x, long y, VARIANT* pvChildAtPoint)
    567 {
    568     if (!pvChildAtPoint)
    569         return E_POINTER;
    570 
    571     ::VariantInit(pvChildAtPoint);
    572 
    573     if (!m_object || !m_object->documentFrameView())
    574         return E_FAIL;
    575 
    576     IntPoint point = m_object->documentFrameView()->screenToContents(IntPoint(x, y));
    577     AccessibilityObject* childObj = m_object->accessibilityHitTest(point);
    578 
    579     if (!childObj) {
    580         // If we did not hit any child objects, test whether the point hit us, and
    581         // report that.
    582         if (!m_object->boundingBoxRect().contains(point))
    583             return S_FALSE;
    584         childObj = m_object;
    585     }
    586 
    587     if (childObj == m_object) {
    588         V_VT(pvChildAtPoint) = VT_I4;
    589         V_I4(pvChildAtPoint) = CHILDID_SELF;
    590     } else {
    591         V_VT(pvChildAtPoint) = VT_DISPATCH;
    592         V_DISPATCH(pvChildAtPoint) = static_cast<IDispatch*>(wrapper(childObj));
    593         V_DISPATCH(pvChildAtPoint)->AddRef();
    594     }
    595     return S_OK;
    596 }
    597 
    598 HRESULT STDMETHODCALLTYPE AccessibleBase::accDoDefaultAction(VARIANT vChild)
    599 {
    600     AccessibilityObject* childObj;
    601     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
    602 
    603     if (FAILED(hr))
    604         return hr;
    605 
    606     if (!childObj->performDefaultAction())
    607         return S_FALSE;
    608 
    609     return S_OK;
    610 }
    611 
    612 // AccessibleBase
    613 String AccessibleBase::name() const
    614 {
    615     return m_object->nameForMSAA();
    616 }
    617 
    618 String AccessibleBase::value() const
    619 {
    620     return m_object->stringValueForMSAA();
    621 }
    622 
    623 static long MSAARole(AccessibilityRole role)
    624 {
    625     switch (role) {
    626         case WebCore::ButtonRole:
    627             return ROLE_SYSTEM_PUSHBUTTON;
    628         case WebCore::RadioButtonRole:
    629             return ROLE_SYSTEM_RADIOBUTTON;
    630         case WebCore::CheckBoxRole:
    631             return ROLE_SYSTEM_CHECKBUTTON;
    632         case WebCore::SliderRole:
    633             return ROLE_SYSTEM_SLIDER;
    634         case WebCore::TabGroupRole:
    635             return ROLE_SYSTEM_PAGETABLIST;
    636         case WebCore::TextFieldRole:
    637         case WebCore::TextAreaRole:
    638         case WebCore::EditableTextRole:
    639             return ROLE_SYSTEM_TEXT;
    640         case WebCore::ListMarkerRole:
    641         case WebCore::StaticTextRole:
    642             return ROLE_SYSTEM_STATICTEXT;
    643         case WebCore::OutlineRole:
    644             return ROLE_SYSTEM_OUTLINE;
    645         case WebCore::ColumnRole:
    646             return ROLE_SYSTEM_COLUMN;
    647         case WebCore::RowRole:
    648             return ROLE_SYSTEM_ROW;
    649         case WebCore::GroupRole:
    650             return ROLE_SYSTEM_GROUPING;
    651         case WebCore::ListRole:
    652         case WebCore::ListBoxRole:
    653         case WebCore::MenuListPopupRole:
    654             return ROLE_SYSTEM_LIST;
    655         case WebCore::TableRole:
    656             return ROLE_SYSTEM_TABLE;
    657         case WebCore::LinkRole:
    658         case WebCore::WebCoreLinkRole:
    659             return ROLE_SYSTEM_LINK;
    660         case WebCore::ImageMapRole:
    661         case WebCore::ImageRole:
    662             return ROLE_SYSTEM_GRAPHIC;
    663         case WebCore::MenuListOptionRole:
    664         case WebCore::ListItemRole:
    665         case WebCore::ListBoxOptionRole:
    666             return ROLE_SYSTEM_LISTITEM;
    667         case WebCore::PopUpButtonRole:
    668             return ROLE_SYSTEM_COMBOBOX;
    669         default:
    670             // This is the default role for MSAA.
    671             return ROLE_SYSTEM_CLIENT;
    672     }
    673 }
    674 
    675 long AccessibleBase::role() const
    676 {
    677     return MSAARole(m_object->roleValueForMSAA());
    678 }
    679 
    680 HRESULT AccessibleBase::getAccessibilityObjectForChild(VARIANT vChild, AccessibilityObject*& childObj) const
    681 {
    682     childObj = 0;
    683 
    684     if (!m_object)
    685         return E_FAIL;
    686 
    687     if (vChild.vt != VT_I4)
    688         return E_INVALIDARG;
    689 
    690     if (vChild.lVal == CHILDID_SELF)
    691         childObj = m_object;
    692     else if (vChild.lVal < 0) {
    693         // When broadcasting MSAA events, we negate the AXID and pass it as the
    694         // child ID.
    695         Document* document = m_object->document();
    696         if (!document)
    697             return E_FAIL;
    698 
    699         childObj = document->axObjectCache()->objectFromAXID(-vChild.lVal);
    700     } else {
    701         size_t childIndex = static_cast<size_t>(vChild.lVal - 1);
    702 
    703         if (childIndex >= m_object->children().size())
    704             return E_FAIL;
    705         childObj = m_object->children().at(childIndex).get();
    706     }
    707 
    708     if (!childObj)
    709         return E_FAIL;
    710 
    711     return S_OK;
    712 }
    713 
    714 AccessibleBase* AccessibleBase::wrapper(AccessibilityObject* obj)
    715 {
    716     AccessibleBase* result = static_cast<AccessibleBase*>(obj->wrapper());
    717     if (!result)
    718         result = createInstance(obj);
    719     return result;
    720 }
    721 
    722 HRESULT AccessibleBase::isSameObject(IAccessibleComparable* other, BOOL* result)
    723 {
    724     COMPtr<AccessibleBase> otherAccessibleBase(Query, other);
    725     *result = (otherAccessibleBase == this || otherAccessibleBase->m_object == m_object);
    726     return S_OK;
    727 }
    728