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