WebKit/win/AccessibleBase.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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->doAccessibilityHitTest(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 }