96f9b7517a93f731aacc1e186855619228fd303a
[WebKit-https.git] / Source / WebKit / win / AccessibleBase.cpp
1 /*
2  * Copyright (C) 2008, 2009, 2010, 2013 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2012 Serotek Corporation. All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #include "config.h"
28 #include "WebKitDLL.h"
29 #include "AccessibleBase.h"
30
31 #include "AccessibleImage.h"
32 #include "AccessibleTextImpl.h"
33 #include "WebView.h"
34 #include <WebCore/AccessibilityListBox.h>
35 #include <WebCore/AccessibilityMenuListPopup.h>
36 #include <WebCore/AccessibilityObject.h>
37 #include <WebCore/AXObjectCache.h>
38 #include <WebCore/BString.h>
39 #include <WebCore/Element.h>
40 #include <WebCore/EventHandler.h>
41 #include <WebCore/FrameView.h>
42 #include <WebCore/HostWindow.h>
43 #include <WebCore/HTMLNames.h>
44 #include <WebCore/HTMLFrameElementBase.h>
45 #include <WebCore/HTMLInputElement.h>
46 #include <WebCore/IntRect.h>
47 #include <WebCore/NotImplemented.h>
48 #include <WebCore/PlatformEvent.h>
49 #include <WebCore/RenderFrame.h>
50 #include <WebCore/RenderObject.h>
51 #include <WebCore/RenderView.h>
52 #include <comutil.h>
53 #include <oleacc.h>
54 #include <wtf/RefPtr.h>
55 #include <wtf/text/StringBuilder.h>
56
57 using namespace WebCore;
58
59 AccessibleBase::AccessibleBase(AccessibilityObject* obj, HWND window)
60     : AccessibilityObjectWrapper(obj)
61     , m_window(window)
62     , m_refCount(0)
63 {
64     ASSERT_ARG(obj, obj);
65     m_object->setWrapper(this);
66     ++gClassCount;
67     gClassNameCount().add("AccessibleBase");
68 }
69
70 AccessibleBase::~AccessibleBase()
71 {
72     --gClassCount;
73     gClassNameCount().remove("AccessibleBase");
74 }
75
76 AccessibleBase* AccessibleBase::createInstance(AccessibilityObject* obj, HWND window)
77 {
78     ASSERT_ARG(obj, obj);
79
80     if (obj->isImage())
81         return new AccessibleImage(obj, window);
82     else if (obj->isStaticText() || obj->isTextControl() || (obj->node() && obj->node()->isTextNode()))
83         return new AccessibleText(obj, window);
84
85     return new AccessibleBase(obj, window);
86 }
87
88 HRESULT AccessibleBase::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
89 {
90     if (!IsEqualGUID(guidService, SID_AccessibleComparable)
91         && !IsEqualGUID(guidService, IID_IAccessible2_2)
92         && !IsEqualGUID(guidService, IID_IAccessible2)
93         && !IsEqualGUID(guidService, IID_IAccessibleApplication)
94         && !IsEqualGUID(guidService, IID_IAccessible)
95         && !IsEqualGUID(guidService, IID_IAccessibleText)
96         && !IsEqualGUID(guidService, IID_IAccessibleText2)
97         && !IsEqualGUID(guidService, IID_IAccessibleEditableText)) {
98         *ppvObject = 0;
99         return E_INVALIDARG;
100     }
101     return QueryInterface(riid, ppvObject);
102 }
103
104 // IUnknown
105 HRESULT STDMETHODCALLTYPE AccessibleBase::QueryInterface(REFIID riid, void** ppvObject)
106 {
107     if (IsEqualGUID(riid, __uuidof(IAccessible)))
108         *ppvObject = static_cast<IAccessible*>(this);
109     else if (IsEqualGUID(riid, __uuidof(IDispatch)))
110         *ppvObject = static_cast<IAccessible*>(this);
111     else if (IsEqualGUID(riid, __uuidof(IUnknown)))
112         *ppvObject = static_cast<IAccessible*>(this);
113     else if (IsEqualGUID(riid, __uuidof(IAccessible2_2)))
114         *ppvObject = static_cast<IAccessible2_2*>(this);
115     else if (IsEqualGUID(riid, __uuidof(IAccessible2)))
116         *ppvObject = static_cast<IAccessible2*>(this);
117     else if (IsEqualGUID(riid, __uuidof(IAccessibleComparable)))
118         *ppvObject = static_cast<IAccessibleComparable*>(this);
119     else if (IsEqualGUID(riid, __uuidof(IServiceProvider)))
120         *ppvObject = static_cast<IServiceProvider*>(this);
121     else if (IsEqualGUID(riid, __uuidof(AccessibleBase)))
122         *ppvObject = static_cast<AccessibleBase*>(this);
123     else {
124         *ppvObject = 0;
125         return E_NOINTERFACE;
126     }
127     AddRef();
128     return S_OK;
129 }
130
131 ULONG STDMETHODCALLTYPE AccessibleBase::Release(void)
132 {
133     ASSERT(m_refCount > 0);
134     if (--m_refCount)
135         return m_refCount;
136     delete this;
137     return 0;
138 }
139
140 // IAccessible2_2
141 HRESULT AccessibleBase::get_attribute(BSTR key, VARIANT* value)
142 {
143     if (!value)
144         return E_POINTER;
145
146     AtomicString keyAtomic(key, ::SysStringLen(key));
147
148     accessibilityAttributeValue(keyAtomic, value);
149
150     return S_OK;
151 }
152
153 HRESULT AccessibleBase::get_accessibleWithCaret(IUnknown** accessible, long* caretOffset)
154 {
155     notImplemented();
156     return E_NOTIMPL;
157 }
158
159 HRESULT AccessibleBase::get_relationTargetsOfType(BSTR type, long maxTargets, IUnknown*** targets, long* nTargets)
160 {
161     notImplemented();
162     return E_NOTIMPL;
163 }
164
165 // IAccessible2
166 HRESULT AccessibleBase::get_nRelations(long* nRelations)
167 {
168     if (!nRelations)
169         return E_POINTER;
170
171     if (!m_object)
172         return E_FAIL;
173     notImplemented();
174     *nRelations = 0;
175     return S_OK;
176 }
177
178 HRESULT AccessibleBase::get_relation(long relationIndex, IAccessibleRelation** relation)
179 {
180     if (!relation)
181         return E_POINTER;
182
183     notImplemented();
184     return E_NOTIMPL;
185 }
186
187 HRESULT AccessibleBase::get_relations(long maxRelations, IAccessibleRelation** relations, long* nRelations)
188 {
189     if (!relations || !nRelations)
190         return E_POINTER;
191
192     notImplemented();
193     return E_NOTIMPL;
194 }
195
196 HRESULT AccessibleBase::role(long* role)
197 {
198     if (!role)
199         return E_POINTER;
200
201     if (!m_object)
202         return E_FAIL;
203
204     *role = wrapper(m_object)->role();
205     return S_OK;
206 }
207
208 HRESULT AccessibleBase::scrollTo(IA2ScrollType scrollType)
209 {
210     if (!m_object)
211         return E_FAIL;
212     return S_FALSE;
213 }
214
215 HRESULT AccessibleBase::scrollToPoint(IA2CoordinateType coordinateType, long x, long y)
216 {
217     if (!m_object)
218         return E_FAIL;
219     return S_FALSE;
220 }
221
222 HRESULT AccessibleBase::get_groupPosition(long* groupLevel, long* similarItemsInGroup, long* positionInGroup)
223 {
224     notImplemented();
225     return E_NOTIMPL;
226 }
227
228 HRESULT AccessibleBase::get_states(AccessibleStates* states)
229 {
230     if (!states)
231         return E_POINTER;
232
233     if (!m_object)
234         return E_FAIL;
235
236     *states = 0;
237     notImplemented();
238     return S_OK;
239 }
240
241 HRESULT AccessibleBase::get_extendedRole(BSTR* extendedRole)
242 {
243     if (!extendedRole)
244         return E_POINTER;
245
246     if (!m_object)
247         return E_FAIL;
248
249     notImplemented();
250     return S_FALSE;
251 }
252
253 HRESULT AccessibleBase::get_localizedExtendedRole(BSTR* localizedExtendedRole)
254 {
255     if (!localizedExtendedRole)
256         return E_POINTER;
257
258     if (!m_object)
259         return E_FAIL;
260
261     notImplemented();
262     return S_FALSE;
263 }
264
265 HRESULT AccessibleBase::get_nExtendedStates(long* nExtendedStates)
266 {
267     if (!nExtendedStates)
268         return E_POINTER;
269
270     if (!m_object)
271         return E_FAIL;
272
273     notImplemented();
274     *nExtendedStates = 0;
275     return S_OK;
276 }
277
278 HRESULT AccessibleBase::get_extendedStates(long maxExtendedStates, BSTR** extendedStates, long* nExtendedStates)
279 {
280     notImplemented();
281     return E_NOTIMPL;
282 }
283
284 HRESULT AccessibleBase::get_localizedExtendedStates(long maxLocalizedExtendedStates, BSTR** localizedExtendedStates, long* nLocalizedExtendedStates)
285 {
286     notImplemented();
287     return E_NOTIMPL;
288 }
289
290 HRESULT AccessibleBase::get_uniqueID(long* uniqueID)
291 {
292     if (!uniqueID)
293         return E_POINTER;
294
295     if (!m_object)
296         return E_FAIL;
297
298     *uniqueID = static_cast<long>(m_object->axObjectID());
299     return S_OK;
300 }
301
302 HRESULT AccessibleBase::get_windowHandle(HWND* windowHandle)
303 {
304     *windowHandle = m_window;
305     return S_OK;
306 }
307
308 HRESULT AccessibleBase::get_indexInParent(long* indexInParent)
309 {
310     return E_NOTIMPL;
311 }
312
313 HRESULT AccessibleBase::get_locale(IA2Locale* locale)
314 {
315     notImplemented();
316     return E_NOTIMPL;
317 }
318
319 HRESULT AccessibleBase::get_attributes(BSTR* attributes)
320 {
321     if (!m_object)
322         return E_FAIL;
323     notImplemented();
324     return S_FALSE;
325 }
326
327 // IAccessible
328 HRESULT AccessibleBase::get_accParent(IDispatch** parent)
329 {
330     *parent = 0;
331
332     if (!m_object)
333         return E_FAIL;
334
335     AccessibilityObject* parentObject = m_object->parentObjectUnignored();
336     if (parentObject) {
337         *parent = wrapper(parentObject);
338         (*parent)->AddRef();
339         return S_OK;
340     }
341
342     if (!m_window)
343         return E_FAIL;
344
345     return WebView::AccessibleObjectFromWindow(m_window,
346         OBJID_WINDOW, __uuidof(IAccessible), reinterpret_cast<void**>(parent));
347 }
348
349 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accChildCount(long* count)
350 {
351     if (!m_object)
352         return E_FAIL;
353     if (!count)
354         return E_POINTER;
355     *count = static_cast<long>(m_object->children().size());
356     return S_OK;
357 }
358
359 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accChild(VARIANT vChild, IDispatch** ppChild)
360 {
361     if (!ppChild)
362         return E_POINTER;
363
364     *ppChild = 0;
365
366     AccessibilityObject* childObj;
367
368     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
369     if (FAILED(hr))
370         return hr;
371
372     *ppChild = static_cast<IDispatch*>(wrapper(childObj));
373     (*ppChild)->AddRef();
374     return S_OK;
375 }
376
377 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accName(VARIANT vChild, BSTR* name)
378 {
379     if (!name)
380         return E_POINTER;
381
382     *name = 0;
383
384     AccessibilityObject* childObj;
385     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
386
387     if (FAILED(hr))
388         return hr;
389
390     if (*name = BString(wrapper(childObj)->name()).release())
391         return S_OK;
392     return S_FALSE;
393 }
394
395 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accValue(VARIANT vChild, BSTR* value)
396 {
397     if (!value)
398         return E_POINTER;
399
400     *value = 0;
401
402     AccessibilityObject* childObj;
403     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
404
405     if (FAILED(hr))
406         return hr;
407
408     if (*value = BString(wrapper(childObj)->value()).release())
409         return S_OK;
410     return S_FALSE;
411 }
412
413 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accDescription(VARIANT vChild, BSTR* description)
414 {
415     if (!description)
416         return E_POINTER;
417
418     *description = 0;
419
420     AccessibilityObject* childObj;
421     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
422
423     if (FAILED(hr))
424         return hr;
425
426     if (*description = BString(childObj->descriptionForMSAA()).release())
427         return S_OK;
428
429     return S_FALSE;
430 }
431
432 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accRole(VARIANT vChild, VARIANT* pvRole)
433 {
434     if (!pvRole)
435         return E_POINTER;
436
437     ::VariantInit(pvRole);
438
439     AccessibilityObject* childObj;
440     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
441
442     if (FAILED(hr))
443         return hr;
444
445     String roleString = childObj->stringRoleForMSAA();
446     if (!roleString.isEmpty()) {
447         V_VT(pvRole) = VT_BSTR;
448         V_BSTR(pvRole) = BString(roleString).release();
449         return S_OK;
450     }
451
452     pvRole->vt = VT_I4;
453     pvRole->lVal = wrapper(childObj)->role();
454     return S_OK;
455 }
456
457 long AccessibleBase::state() const
458 {
459     long state = 0;
460     if (m_object->isLinked())
461         state |= STATE_SYSTEM_LINKED;
462
463     if (m_object->isHovered())
464         state |= STATE_SYSTEM_HOTTRACKED;
465
466     if (!m_object->isEnabled())
467         state |= STATE_SYSTEM_UNAVAILABLE;
468
469     if (m_object->isReadOnly())
470         state |= STATE_SYSTEM_READONLY;
471
472     if (m_object->isOffScreen())
473         state |= STATE_SYSTEM_OFFSCREEN;
474
475     if (m_object->isPasswordField())
476         state |= STATE_SYSTEM_PROTECTED;
477
478     if (m_object->isIndeterminate())
479         state |= STATE_SYSTEM_INDETERMINATE;
480
481     if (m_object->isChecked())
482         state |= STATE_SYSTEM_CHECKED;
483
484     if (m_object->isPressed())
485         state |= STATE_SYSTEM_PRESSED;
486
487     if (m_object->isFocused())
488         state |= STATE_SYSTEM_FOCUSED;
489
490     if (m_object->isVisited())
491         state |= STATE_SYSTEM_TRAVERSED;
492
493     if (m_object->canSetFocusAttribute())
494         state |= STATE_SYSTEM_FOCUSABLE;
495
496     if (m_object->isSelected())
497         state |= STATE_SYSTEM_SELECTED;
498
499     if (m_object->canSetSelectedAttribute())
500         state |= STATE_SYSTEM_SELECTABLE;
501
502     if (m_object->isMultiSelectable())
503         state |= STATE_SYSTEM_EXTSELECTABLE | STATE_SYSTEM_MULTISELECTABLE;
504
505     if (!m_object->isVisible())
506         state |= STATE_SYSTEM_INVISIBLE;
507
508     if (m_object->isCollapsed())
509         state |= STATE_SYSTEM_COLLAPSED;
510
511     if (m_object->roleValue() == PopUpButtonRole) {
512         state |= STATE_SYSTEM_HASPOPUP;
513
514         if (!m_object->isCollapsed())
515             state |= STATE_SYSTEM_EXPANDED;
516     }
517
518     return state;
519 }
520
521 HRESULT AccessibleBase::get_accState(VARIANT vChild, VARIANT* pvState)
522 {
523     if (!pvState)
524         return E_POINTER;
525
526     ::VariantInit(pvState);
527
528     AccessibilityObject* childObj;
529     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
530
531     if (FAILED(hr))
532         return hr;
533
534     pvState->vt = VT_I4;
535     pvState->lVal = wrapper(childObj)->state();
536
537     return S_OK;
538 }
539
540 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accHelp(VARIANT vChild, BSTR* helpText)
541 {
542     if (!helpText)
543         return E_POINTER;
544
545     *helpText = 0;
546
547     AccessibilityObject* childObj;
548     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
549
550     if (FAILED(hr))
551         return hr;
552
553     if (*helpText = BString(childObj->helpText()).release())
554         return S_OK;
555     return S_FALSE;
556 }
557
558 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accKeyboardShortcut(VARIANT vChild, BSTR* shortcut)
559 {
560     if (!shortcut)
561         return E_POINTER;
562
563     *shortcut = 0;
564
565     AccessibilityObject* childObj;
566     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
567
568     if (FAILED(hr))
569         return hr;
570
571     String accessKey = childObj->accessKey();
572     if (accessKey.isNull())
573         return S_FALSE;
574
575     static String accessKeyModifiers;
576     if (accessKeyModifiers.isNull()) {
577         StringBuilder accessKeyModifiersBuilder;
578         unsigned modifiers = EventHandler::accessKeyModifiers();
579         // Follow the same order as Mozilla MSAA implementation:
580         // Ctrl+Alt+Shift+Meta+key. MSDN states that keyboard shortcut strings
581         // should not be localized and defines the separator as "+".
582         if (modifiers & PlatformEvent::CtrlKey)
583             accessKeyModifiersBuilder.appendLiteral("Ctrl+");
584         if (modifiers & PlatformEvent::AltKey)
585             accessKeyModifiersBuilder.appendLiteral("Alt+");
586         if (modifiers & PlatformEvent::ShiftKey)
587             accessKeyModifiersBuilder.appendLiteral("Shift+");
588         if (modifiers & PlatformEvent::MetaKey)
589             accessKeyModifiersBuilder.appendLiteral("Win+");
590         accessKeyModifiers = accessKeyModifiersBuilder.toString();
591     }
592     *shortcut = BString(String(accessKeyModifiers + accessKey)).release();
593     return S_OK;
594 }
595
596 HRESULT STDMETHODCALLTYPE AccessibleBase::accSelect(long selectionFlags, VARIANT vChild)
597 {
598     // According to MSDN, these combinations are invalid.
599     if (((selectionFlags & (SELFLAG_ADDSELECTION | SELFLAG_REMOVESELECTION)) == (SELFLAG_ADDSELECTION | SELFLAG_REMOVESELECTION))
600         || ((selectionFlags & (SELFLAG_ADDSELECTION | SELFLAG_TAKESELECTION)) == (SELFLAG_ADDSELECTION | SELFLAG_TAKESELECTION))
601         || ((selectionFlags & (SELFLAG_REMOVESELECTION | SELFLAG_TAKESELECTION)) == (SELFLAG_REMOVESELECTION | SELFLAG_TAKESELECTION))
602         || ((selectionFlags & (SELFLAG_EXTENDSELECTION | SELFLAG_TAKESELECTION)) == (SELFLAG_EXTENDSELECTION | SELFLAG_TAKESELECTION)))
603         return E_INVALIDARG;
604
605     AccessibilityObject* childObject;
606     HRESULT hr = getAccessibilityObjectForChild(vChild, childObject);
607
608     if (FAILED(hr))
609         return hr;
610
611     if (selectionFlags & SELFLAG_TAKEFOCUS)
612         childObject->setFocused(true);
613
614     AccessibilityObject* parentObject = childObject->parentObject();
615     if (!parentObject)
616         return E_INVALIDARG;
617
618     if (selectionFlags & SELFLAG_TAKESELECTION) {
619         if (parentObject->isListBox()) {
620             Vector<RefPtr<AccessibilityObject> > selectedChildren(1);
621             selectedChildren[0] = childObject;
622             toAccessibilityListBox(parentObject)->setSelectedChildren(selectedChildren);
623         } else { // any element may be selectable by virtue of it having the aria-selected property
624             ASSERT(!parentObject->isMultiSelectable());
625             childObject->setSelected(true);
626         }
627     }
628
629     // MSDN says that ADD, REMOVE, and EXTENDSELECTION with no other flags are invalid for
630     // single-select.
631     const long allSELFLAGs = SELFLAG_TAKEFOCUS | SELFLAG_TAKESELECTION | SELFLAG_EXTENDSELECTION | SELFLAG_ADDSELECTION | SELFLAG_REMOVESELECTION;
632     if (!parentObject->isMultiSelectable()
633         && (((selectionFlags & allSELFLAGs) == SELFLAG_ADDSELECTION)
634         || ((selectionFlags & allSELFLAGs) == SELFLAG_REMOVESELECTION)
635         || ((selectionFlags & allSELFLAGs) == SELFLAG_EXTENDSELECTION)))
636         return E_INVALIDARG;
637
638     if (selectionFlags & SELFLAG_ADDSELECTION)
639         childObject->setSelected(true);
640
641     if (selectionFlags & SELFLAG_REMOVESELECTION)
642         childObject->setSelected(false);
643
644     // FIXME: Should implement SELFLAG_EXTENDSELECTION. For now, we just return
645     // S_OK, matching Firefox.
646
647     return S_OK;
648 }
649
650 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accSelection(VARIANT*)
651 {
652     return E_NOTIMPL;
653 }
654
655 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accFocus(VARIANT* pvFocusedChild)
656 {
657     if (!pvFocusedChild)
658         return E_POINTER;
659
660     ::VariantInit(pvFocusedChild);
661
662     if (!m_object)
663         return E_FAIL;
664
665     AccessibilityObject* focusedObj = m_object->focusedUIElement();
666     if (!focusedObj)
667         return S_FALSE;
668
669     if (focusedObj == m_object) {
670         V_VT(pvFocusedChild) = VT_I4;
671         V_I4(pvFocusedChild) = CHILDID_SELF;
672         return S_OK;
673     }
674
675     V_VT(pvFocusedChild) = VT_DISPATCH;
676     V_DISPATCH(pvFocusedChild) = wrapper(focusedObj);
677     V_DISPATCH(pvFocusedChild)->AddRef();
678     return S_OK;
679 }
680
681 HRESULT STDMETHODCALLTYPE AccessibleBase::get_accDefaultAction(VARIANT vChild, BSTR* action)
682 {
683     if (!action)
684         return E_POINTER;
685
686     *action = 0;
687
688     AccessibilityObject* childObj;
689     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
690
691     if (FAILED(hr))
692         return hr;
693
694     if (*action = BString(childObj->actionVerb()).release())
695         return S_OK;
696     return S_FALSE;
697 }
698
699 HRESULT STDMETHODCALLTYPE AccessibleBase::accLocation(long* left, long* top, long* width, long* height, VARIANT vChild)
700 {
701     if (!left || !top || !width || !height)
702         return E_POINTER;
703
704     *left = *top = *width = *height = 0;
705
706     AccessibilityObject* childObj;
707     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
708
709     if (FAILED(hr))
710         return hr;
711
712     if (!childObj->documentFrameView())
713         return E_FAIL;
714
715     IntRect screenRect(childObj->documentFrameView()->contentsToScreen(snappedIntRect(childObj->elementRect())));
716     *left = screenRect.x();
717     *top = screenRect.y();
718     *width = screenRect.width();
719     *height = screenRect.height();
720     return S_OK;
721 }
722
723 HRESULT STDMETHODCALLTYPE AccessibleBase::accNavigate(long direction, VARIANT vFromChild, VARIANT* pvNavigatedTo)
724 {
725     if (!pvNavigatedTo)
726         return E_POINTER;
727
728     ::VariantInit(pvNavigatedTo);
729
730     AccessibilityObject* childObj = 0;
731
732     switch (direction) {
733         case NAVDIR_DOWN:
734         case NAVDIR_UP:
735         case NAVDIR_LEFT:
736         case NAVDIR_RIGHT:
737             // These directions are not implemented, matching Mozilla and IE.
738             return E_NOTIMPL;
739         case NAVDIR_LASTCHILD:
740         case NAVDIR_FIRSTCHILD:
741             // MSDN states that navigating to first/last child can only be from self.
742             if (vFromChild.lVal != CHILDID_SELF)
743                 return E_INVALIDARG;
744
745             if (!m_object)
746                 return E_FAIL;
747
748             if (direction == NAVDIR_FIRSTCHILD)
749                 childObj = m_object->firstChild();
750             else
751                 childObj = m_object->lastChild();
752             break;
753         case NAVDIR_NEXT:
754         case NAVDIR_PREVIOUS: {
755             // Navigating to next and previous is allowed from self or any of our children.
756             HRESULT hr = getAccessibilityObjectForChild(vFromChild, childObj);
757             if (FAILED(hr))
758                 return hr;
759
760             if (direction == NAVDIR_NEXT)
761                 childObj = childObj->nextSibling();
762             else
763                 childObj = childObj->previousSibling();
764             break;
765         }
766         default:
767             ASSERT_NOT_REACHED();
768             return E_INVALIDARG;
769     }
770
771     if (!childObj)
772         return S_FALSE;
773
774     V_VT(pvNavigatedTo) = VT_DISPATCH;
775     V_DISPATCH(pvNavigatedTo) = wrapper(childObj);
776     V_DISPATCH(pvNavigatedTo)->AddRef();
777     return S_OK;
778 }
779
780 HRESULT STDMETHODCALLTYPE AccessibleBase::accHitTest(long x, long y, VARIANT* pvChildAtPoint)
781 {
782     if (!pvChildAtPoint)
783         return E_POINTER;
784
785     ::VariantInit(pvChildAtPoint);
786
787     if (!m_object || !m_object->documentFrameView())
788         return E_FAIL;
789
790     IntPoint point = m_object->documentFrameView()->screenToContents(IntPoint(x, y));
791     AccessibilityObject* childObj = m_object->accessibilityHitTest(point);
792
793     if (!childObj) {
794         // If we did not hit any child objects, test whether the point hit us, and
795         // report that.
796         if (!m_object->boundingBoxRect().contains(point))
797             return S_FALSE;
798         childObj = m_object;
799     }
800
801     if (childObj == m_object) {
802         V_VT(pvChildAtPoint) = VT_I4;
803         V_I4(pvChildAtPoint) = CHILDID_SELF;
804     } else {
805         V_VT(pvChildAtPoint) = VT_DISPATCH;
806         V_DISPATCH(pvChildAtPoint) = static_cast<IDispatch*>(wrapper(childObj));
807         V_DISPATCH(pvChildAtPoint)->AddRef();
808     }
809     return S_OK;
810 }
811
812 HRESULT STDMETHODCALLTYPE AccessibleBase::accDoDefaultAction(VARIANT vChild)
813 {
814     AccessibilityObject* childObj;
815     HRESULT hr = getAccessibilityObjectForChild(vChild, childObj);
816
817     if (FAILED(hr))
818         return hr;
819
820     if (!childObj->performDefaultAction())
821         return S_FALSE;
822
823     return S_OK;
824 }
825
826 // AccessibleBase
827 String AccessibleBase::name() const
828 {
829     return m_object->nameForMSAA();
830 }
831
832 String AccessibleBase::value() const
833 {
834     return m_object->stringValueForMSAA();
835 }
836
837 static long MSAARole(AccessibilityRole role)
838 {
839     switch (role) {
840         case WebCore::ButtonRole:
841             return ROLE_SYSTEM_PUSHBUTTON;
842         case WebCore::RadioButtonRole:
843             return ROLE_SYSTEM_RADIOBUTTON;
844         case WebCore::CheckBoxRole:
845             return ROLE_SYSTEM_CHECKBUTTON;
846         case WebCore::SliderRole:
847             return ROLE_SYSTEM_SLIDER;
848         case WebCore::TabGroupRole:
849         case WebCore::TabListRole:
850             return ROLE_SYSTEM_PAGETABLIST;
851         case WebCore::TextFieldRole:
852         case WebCore::TextAreaRole:
853         case WebCore::EditableTextRole:
854             return ROLE_SYSTEM_TEXT;
855         case WebCore::HeadingRole:
856         case WebCore::ListMarkerRole:
857         case WebCore::StaticTextRole:
858             return ROLE_SYSTEM_STATICTEXT;
859         case WebCore::OutlineRole:
860             return ROLE_SYSTEM_OUTLINE;
861         case WebCore::ColumnRole:
862             return ROLE_SYSTEM_COLUMN;
863         case WebCore::RowRole:
864             return ROLE_SYSTEM_ROW;
865         case WebCore::GroupRole:
866         case WebCore::RadioGroupRole:
867             return ROLE_SYSTEM_GROUPING;
868         case WebCore::DescriptionListRole:
869         case WebCore::DirectoryRole:
870         case WebCore::ListRole:
871         case WebCore::ListBoxRole:
872         case WebCore::MenuListPopupRole:
873             return ROLE_SYSTEM_LIST;
874         case WebCore::GridRole:
875         case WebCore::TableRole:
876             return ROLE_SYSTEM_TABLE;
877         case WebCore::ImageMapLinkRole:
878         case WebCore::LinkRole:
879         case WebCore::WebCoreLinkRole:
880             return ROLE_SYSTEM_LINK;
881         case WebCore::CanvasRole:
882         case WebCore::ImageMapRole:
883         case WebCore::ImageRole:
884             return ROLE_SYSTEM_GRAPHIC;
885         case WebCore::ListItemRole:
886             return ROLE_SYSTEM_LISTITEM;
887         case WebCore::ListBoxOptionRole:
888         case WebCore::MenuListOptionRole:
889             return ROLE_SYSTEM_STATICTEXT;
890         case WebCore::ComboBoxRole:
891         case WebCore::PopUpButtonRole:
892             return ROLE_SYSTEM_COMBOBOX;
893         case WebCore::DivRole:
894         case WebCore::FooterRole:
895         case WebCore::FormRole:
896         case WebCore::LabelRole:
897         case WebCore::ParagraphRole:
898             return ROLE_SYSTEM_GROUPING;
899         case WebCore::HorizontalRuleRole:
900         case WebCore::SplitterRole:
901             return ROLE_SYSTEM_SEPARATOR;
902         case WebCore::ApplicationAlertRole:
903         case WebCore::ApplicationAlertDialogRole:
904             return ROLE_SYSTEM_ALERT;
905         case WebCore::DisclosureTriangleRole:
906             return ROLE_SYSTEM_BUTTONDROPDOWN;
907         case WebCore::IncrementorRole:
908         case WebCore::SpinButtonRole:
909             return ROLE_SYSTEM_SPINBUTTON;
910         case WebCore::SpinButtonPartRole:
911             return ROLE_SYSTEM_PUSHBUTTON;
912         case WebCore::ToggleButtonRole:
913             return ROLE_SYSTEM_PUSHBUTTON;
914         case WebCore::ToolbarRole:
915             return ROLE_SYSTEM_TOOLBAR;
916         case WebCore::UserInterfaceTooltipRole:
917             return ROLE_SYSTEM_TOOLTIP;
918         case WebCore::TreeRole:
919         case WebCore::TreeGridRole:
920             return ROLE_SYSTEM_OUTLINE;
921         case WebCore::TreeItemRole:
922             return ROLE_SYSTEM_OUTLINEITEM;
923         case WebCore::TabPanelRole:
924             return ROLE_SYSTEM_GROUPING;
925         case WebCore::TabRole:
926             return ROLE_SYSTEM_PAGETAB;
927         case WebCore::ApplicationRole:
928             return ROLE_SYSTEM_APPLICATION;
929         case WebCore::ApplicationDialogRole:
930             return ROLE_SYSTEM_DIALOG;
931         case WebCore::ApplicationLogRole:
932         case WebCore::ApplicationMarqueeRole:
933             return ROLE_SYSTEM_GROUPING;
934         case WebCore::ApplicationStatusRole:
935             return ROLE_SYSTEM_STATUSBAR;
936         case WebCore::ApplicationTimerRole:
937             return ROLE_SYSTEM_CLOCK;
938         case WebCore::CellRole:
939             return ROLE_SYSTEM_CELL;
940         case WebCore::ColumnHeaderRole:
941             return ROLE_SYSTEM_COLUMNHEADER;
942         case WebCore::DefinitionRole:
943         case WebCore::DescriptionListDetailRole:
944         case WebCore::DescriptionListTermRole:
945         case WebCore::DocumentRole:
946         case WebCore::DocumentArticleRole:
947         case WebCore::DocumentNoteRole:
948         case WebCore::DocumentRegionRole:
949             return ROLE_SYSTEM_GROUPING;
950         case WebCore::DocumentMathRole:
951         case WebCore::MathElementRole:
952             return ROLE_SYSTEM_EQUATION;
953         case WebCore::HelpTagRole:
954             return ROLE_SYSTEM_HELPBALLOON;
955         case WebCore::LandmarkApplicationRole:
956         case WebCore::LandmarkBannerRole:
957         case WebCore::LandmarkComplementaryRole:
958         case WebCore::LandmarkContentInfoRole:
959         case WebCore::LandmarkMainRole:
960         case WebCore::LandmarkNavigationRole:
961         case WebCore::LandmarkSearchRole:
962         case WebCore::LegendRole:
963             return ROLE_SYSTEM_GROUPING;
964         case WebCore::MenuRole:
965             return ROLE_SYSTEM_MENUPOPUP;
966         case WebCore::MenuItemRole:
967         case WebCore::MenuButtonRole:
968             return ROLE_SYSTEM_MENUITEM;
969         case WebCore::MenuBarRole:
970             return ROLE_SYSTEM_MENUBAR;
971         case WebCore::ProgressIndicatorRole:
972             return ROLE_SYSTEM_PROGRESSBAR;
973         case WebCore::RowHeaderRole:
974             return ROLE_SYSTEM_ROWHEADER;
975         case WebCore::ScrollBarRole:
976             return ROLE_SYSTEM_SCROLLBAR;
977         case WebCore::SVGRootRole:
978             return ROLE_SYSTEM_GROUPING;
979         case WebCore::TableHeaderContainerRole:
980             return ROLE_SYSTEM_GROUPING;
981         case WebCore::WindowRole:
982             return ROLE_SYSTEM_WINDOW;
983         default:
984             // This is the default role for MSAA.
985             return ROLE_SYSTEM_CLIENT;
986     }
987 }
988
989 long AccessibleBase::role() const
990 {
991     return MSAARole(m_object->roleValueForMSAA());
992 }
993
994 HRESULT AccessibleBase::getAccessibilityObjectForChild(VARIANT vChild, AccessibilityObject*& childObj) const
995 {
996     childObj = 0;
997
998     if (!m_object)
999         return E_FAIL;
1000
1001     if (vChild.vt != VT_I4)
1002         return E_INVALIDARG;
1003
1004     if (vChild.lVal == CHILDID_SELF)
1005         childObj = m_object;
1006     else if (vChild.lVal < 0) {
1007         // When broadcasting MSAA events, we negate the AXID and pass it as the
1008         // child ID.
1009         Document* document = m_object->document();
1010         if (!document)
1011             return E_FAIL;
1012
1013         childObj = document->axObjectCache()->objectFromAXID(-vChild.lVal);
1014     } else {
1015         size_t childIndex = static_cast<size_t>(vChild.lVal - 1);
1016
1017         if (childIndex >= m_object->children().size())
1018             return E_FAIL;
1019         childObj = m_object->children().at(childIndex).get();
1020     }
1021
1022     if (!childObj)
1023         return E_FAIL;
1024
1025     return S_OK;
1026 }
1027
1028 AccessibleBase* AccessibleBase::wrapper(AccessibilityObject* obj) const
1029 {
1030     AccessibleBase* result = static_cast<AccessibleBase*>(obj->wrapper());
1031     if (!result)
1032         result = createInstance(obj, m_window);
1033     return result;
1034 }
1035
1036 HRESULT AccessibleBase::isSameObject(IAccessibleComparable* other, BOOL* result)
1037 {
1038     COMPtr<AccessibleBase> otherAccessibleBase(Query, other);
1039     *result = (otherAccessibleBase == this || otherAccessibleBase->m_object == m_object);
1040     return S_OK;
1041 }