• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AccessibleBase(AccessibilityObject * obj)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 
~AccessibleBase()64 AccessibleBase::~AccessibleBase()
65 {
66     --gClassCount;
67     gClassNameCount.remove("AccessibleBase");
68 }
69 
createInstance(AccessibilityObject * obj)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 
QueryService(REFGUID guidService,REFIID riid,void ** ppvObject)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
QueryInterface(REFIID riid,void ** ppvObject)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 
Release(void)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
get_accParent(IDispatch ** parent)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 
get_accChildCount(long * count)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 
get_accChild(VARIANT vChild,IDispatch ** ppChild)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 
get_accName(VARIANT vChild,BSTR * name)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 
get_accValue(VARIANT vChild,BSTR * value)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 
get_accDescription(VARIANT vChild,BSTR * description)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 
get_accRole(VARIANT vChild,VARIANT * pvRole)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 
get_accState(VARIANT vChild,VARIANT * pvState)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 
get_accHelp(VARIANT vChild,BSTR * helpText)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 
get_accKeyboardShortcut(VARIANT vChild,BSTR * shortcut)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 
accSelect(long selectionFlags,VARIANT vChild)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 
get_accSelection(VARIANT *)436 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accSelection(VARIANT*)
437 {
438     return E_NOTIMPL;
439 }
440 
get_accFocus(VARIANT * pvFocusedChild)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 
get_accDefaultAction(VARIANT vChild,BSTR * action)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 
accLocation(long * left,long * top,long * width,long * height,VARIANT vChild)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 
accNavigate(long direction,VARIANT vFromChild,VARIANT * pvNavigatedTo)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 
accHitTest(long x,long y,VARIANT * pvChildAtPoint)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 
accDoDefaultAction(VARIANT vChild)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
name() const613 String AccessibleBase::name() const
614 {
615     return m_object->nameForMSAA();
616 }
617 
value() const618 String AccessibleBase::value() const
619 {
620     return m_object->stringValueForMSAA();
621 }
622 
MSAARole(AccessibilityRole role)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 
role() const675 long AccessibleBase::role() const
676 {
677     return MSAARole(m_object->roleValueForMSAA());
678 }
679 
getAccessibilityObjectForChild(VARIANT vChild,AccessibilityObject * & childObj) const680 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 
wrapper(AccessibilityObject * obj)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 
isSameObject(IAccessibleComparable * other,BOOL * result)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