1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2003
20 * the Initial Developer. All Rights Reserved.
23 * Original Author: Aaron Leventhal (aaronl@netscape.com)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsAccessibleWrap.h"
41 #include "nsAccessibilityAtoms.h"
42 #include "nsAccUtils.h"
43 #include "nsCoreUtils.h"
44 #include "nsRelUtils.h"
46 #include "nsIAccessibleDocument.h"
47 #include "nsIAccessibleSelectable.h"
48 #include "nsIAccessibleEvent.h"
49 #include "nsIAccessibleWin32Object.h"
51 #include "Accessible2_i.c"
52 #include "AccessibleStates.h"
54 #include "nsIMutableArray.h"
55 #include "nsIDOMDocument.h"
57 #include "nsIScrollableFrame.h"
58 #include "nsINameSpaceManager.h"
59 #include "nsINodeInfo.h"
60 #include "nsIPrefService.h"
61 #include "nsRootAccessible.h"
62 #include "nsIServiceManager.h"
63 #include "nsTextFormatter.h"
65 #include "nsIViewManager.h"
66 #include "nsRoleMap.h"
67 #include "nsEventMap.h"
68 #include "nsArrayUtils.h"
70 /* For documentation of the accessibility architecture,
71 * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
77 static gAccessibles
= 0;
80 EXTERN_C GUID CDECL CLSID_Accessible
=
81 { 0x61044601, 0xa811, 0x4e2b, { 0xbb, 0xba, 0x17, 0xbf, 0xab, 0xd3, 0x29, 0xd7 } };
83 static const PRInt32 kIEnumVariantDisconnected
= -1;
85 ////////////////////////////////////////////////////////////////////////////////
87 ////////////////////////////////////////////////////////////////////////////////
89 //-----------------------------------------------------
91 //-----------------------------------------------------
93 nsAccessibleWrap(nsIContent
*aContent
, nsIWeakReference
*aShell
) :
94 nsAccessible(aContent
, aShell
), mEnumVARIANTPosition(0), mTypeInfo(NULL
)
98 //-----------------------------------------------------
100 //-----------------------------------------------------
101 nsAccessibleWrap::~nsAccessibleWrap()
104 mTypeInfo
->Release();
107 NS_IMPL_ISUPPORTS_INHERITED0(nsAccessibleWrap
, nsAccessible
);
109 //-----------------------------------------------------
110 // IUnknown interface methods - see iunknown.h for documentation
111 //-----------------------------------------------------
113 // Microsoft COM QueryInterface
114 STDMETHODIMP
nsAccessibleWrap::QueryInterface(REFIID iid
, void** ppv
)
119 if (IID_IUnknown
== iid
|| IID_IDispatch
== iid
|| IID_IAccessible
== iid
)
120 *ppv
= static_cast<IAccessible
*>(this);
121 else if (IID_IEnumVARIANT
== iid
&& !gIsEnumVariantSupportDisabled
) {
123 get_accChildCount(&numChildren
);
124 if (numChildren
> 0) // Don't support this interface for leaf elements
125 *ppv
= static_cast<IEnumVARIANT
*>(this);
126 } else if (IID_IServiceProvider
== iid
)
127 *ppv
= static_cast<IServiceProvider
*>(this);
128 else if (IID_IAccessible2
== iid
&& !gIsIA2Disabled
)
129 *ppv
= static_cast<IAccessible2
*>(this);
132 HRESULT hr
= CAccessibleComponent::QueryInterface(iid
, ppv
);
138 HRESULT hr
= CAccessibleHyperlink::QueryInterface(iid
, ppv
);
144 HRESULT hr
= CAccessibleValue::QueryInterface(iid
, ppv
);
150 return nsAccessNodeWrap::QueryInterface(iid
, ppv
);
152 (reinterpret_cast<IUnknown
*>(*ppv
))->AddRef();
153 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
157 //-----------------------------------------------------
158 // IAccessible methods
159 //-----------------------------------------------------
162 STDMETHODIMP
nsAccessibleWrap::AccessibleObjectFromWindow(HWND hwnd
,
167 // open the dll dynamically
169 gmAccLib
=::LoadLibraryW(L
"OLEACC.DLL");
172 if (!gmAccessibleObjectFromWindow
)
173 gmAccessibleObjectFromWindow
= (LPFNACCESSIBLEOBJECTFROMWINDOW
)GetProcAddress(gmAccLib
,"AccessibleObjectFromWindow");
175 if (gmAccessibleObjectFromWindow
)
176 return gmAccessibleObjectFromWindow(hwnd
, dwObjectID
, riid
, ppvObject
);
182 STDMETHODIMP
nsAccessibleWrap::NotifyWinEvent(DWORD event
,
187 if (gmNotifyWinEvent
)
188 return gmNotifyWinEvent(event
, hwnd
, idObjectType
, idObject
);
193 STDMETHODIMP
nsAccessibleWrap::get_accParent( IDispatch __RPC_FAR
*__RPC_FAR
*ppdispParent
)
196 *ppdispParent
= NULL
;
198 return E_FAIL
; // We've been shut down
200 nsIFrame
*frame
= GetFrame();
203 nsIView
*view
= frame
->GetViewExternal();
205 // This code is essentially our implementation of WindowFromAccessibleObject,
206 // because MSAA iterates get_accParent() until it sees an object of ROLE_WINDOW
207 // to know where the window for a given accessible is. We must expose the native
208 // window accessible that MSAA creates for us. This must be done for the document
209 // object as well as any layout that creates its own window (e.g. via overflow: scroll)
210 nsIWidget
*widget
= view
->GetWidget();
212 hwnd
= (HWND
)widget
->GetNativeData(NS_NATIVE_WINDOW
);
213 NS_ASSERTION(hwnd
, "No window handle for window");
215 nsIViewManager
* viewManager
= view
->GetViewManager();
220 viewManager
->GetRootView(rootView
);
221 if (rootView
== view
) {
222 // If the client accessible (OBJID_CLIENT) has a window but its window
223 // was created by an outer window then we want the native accessible
224 // for that outer window. If the accessible was created for outer
225 // window (if the outer window has inner windows then they share the
226 // same client accessible with it) then return native accessible for
228 HWND parenthwnd
= ::GetParent(hwnd
);
232 NS_ASSERTION(hwnd
, "No window handle for window");
236 // If a frame is a scrollable frame, then it has one window for the client area,
237 // not an extra parent window for just the scrollbars
238 nsIScrollableFrame
*scrollFrame
= do_QueryFrame(frame
);
240 hwnd
= (HWND
)scrollFrame
->GetScrolledFrame()->GetNearestWidget()->GetNativeData(NS_NATIVE_WINDOW
);
241 NS_ASSERTION(hwnd
, "No window handle for window");
246 if (hwnd
&& SUCCEEDED(AccessibleObjectFromWindow(hwnd
, OBJID_WINDOW
, IID_IAccessible
,
247 (void**)ppdispParent
))) {
252 nsAccessible
* xpParentAcc
= GetParent();
253 NS_ASSERTION(xpParentAcc
,
254 "No parent accessible where we're not direct child of window");
259 *ppdispParent
= NativeAccessible(xpParentAcc
);
261 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
265 STDMETHODIMP
nsAccessibleWrap::get_accChildCount( long __RPC_FAR
*pcountChildren
)
269 if (nsAccUtils::MustPrune(this))
273 GetChildCount(&numChildren
);
274 *pcountChildren
= numChildren
;
275 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
280 STDMETHODIMP
nsAccessibleWrap::get_accChild(
281 /* [in] */ VARIANT varChild
,
282 /* [retval][out] */ IDispatch __RPC_FAR
*__RPC_FAR
*ppdispChild
)
286 if (!mWeakShell
|| varChild
.vt
!= VT_I4
)
289 if (varChild
.lVal
== CHILDID_SELF
) {
290 *ppdispChild
= static_cast<IDispatch
*>(this);
295 if (!nsAccUtils::MustPrune(this)) {
296 nsAccessible
* child
= GetChildAt(varChild
.lVal
- 1);
298 *ppdispChild
= NativeAccessible(child
);
301 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
303 return (*ppdispChild
)? S_OK
: E_FAIL
;
306 STDMETHODIMP
nsAccessibleWrap::get_accName(
307 /* [optional][in] */ VARIANT varChild
,
308 /* [retval][out] */ BSTR __RPC_FAR
*pszName
)
312 nsAccessible
*xpAccessible
= GetXPAccessibleFor(varChild
);
316 nsresult rv
= xpAccessible
->GetName(name
);
318 return GetHRESULT(rv
);
321 // Valid return value for the name:
322 // The name was not provided, e.g. no alt attribute for an image.
323 // A screen reader may choose to invent its own accessible name, e.g. from
324 // an image src attribute.
325 // See nsHTMLImageAccessible::GetName()
329 *pszName
= ::SysAllocStringLen(name
.get(), name
.Length());
331 return E_OUTOFMEMORY
;
333 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
339 STDMETHODIMP
nsAccessibleWrap::get_accValue(
340 /* [optional][in] */ VARIANT varChild
,
341 /* [retval][out] */ BSTR __RPC_FAR
*pszValue
)
345 nsAccessible
*xpAccessible
= GetXPAccessibleFor(varChild
);
348 if (NS_FAILED(xpAccessible
->GetValue(value
)))
351 // see bug 438784: Need to expose URL on doc's value attribute.
352 // For this, reverting part of fix for bug 425693 to make this MSAA method
353 // behave IAccessible2-style.
357 *pszValue
= ::SysAllocStringLen(value
.get(), value
.Length());
359 return E_OUTOFMEMORY
;
361 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
366 nsAccessibleWrap::get_accDescription(VARIANT varChild
,
367 BSTR __RPC_FAR
*pszDescription
)
370 *pszDescription
= NULL
;
372 nsAccessible
*xpAccessible
= GetXPAccessibleFor(varChild
);
376 // For items that are a choice in a list of choices, use MSAA description
377 // field to shoehorn positional info, it's becoming a defacto standard use for
380 nsAutoString description
;
382 // Try to get group position to make a positional description string.
383 PRInt32 groupLevel
= 0;
384 PRInt32 itemsInGroup
= 0;
385 PRInt32 positionInGroup
= 0;
386 GroupPosition(&groupLevel
, &itemsInGroup
, &positionInGroup
);
388 if (positionInGroup
> 0) {
389 if (groupLevel
> 0) {
390 // XXX: How do we calculate the number of children? Now we append
391 // " with [numChildren]c" for tree item. In the future we may need to
392 // use the ARIA owns property to calculate that if it's present.
393 PRInt32 numChildren
= 0;
395 PRUint32 currentRole
= nsAccUtils::Role(xpAccessible
);
396 if (currentRole
== nsIAccessibleRole::ROLE_OUTLINEITEM
) {
397 PRInt32 childCount
= xpAccessible
->GetChildCount();
398 for (PRInt32 childIdx
= 0; childIdx
< childCount
; childIdx
++) {
399 nsAccessible
*child
= xpAccessible
->GetChildAt(childIdx
);
400 currentRole
= nsAccUtils::Role(child
);
401 if (currentRole
== nsIAccessibleRole::ROLE_GROUPING
) {
402 PRInt32 groupChildCount
= child
->GetChildCount();
403 for (PRInt32 groupChildIdx
= 0; groupChildIdx
< groupChildCount
;
405 nsAccessible
*groupChild
= child
->GetChildAt(groupChildIdx
);
406 currentRole
= nsAccUtils::Role(groupChild
);
408 (currentRole
== nsIAccessibleRole::ROLE_OUTLINEITEM
);
416 nsTextFormatter::ssprintf(description
,
417 NS_LITERAL_STRING("L%d, %d of %d with %d").get(),
418 groupLevel
, positionInGroup
, itemsInGroup
,
421 nsTextFormatter::ssprintf(description
,
422 NS_LITERAL_STRING("L%d, %d of %d").get(),
423 groupLevel
, positionInGroup
, itemsInGroup
);
425 } else { // Position has no level
426 nsTextFormatter::ssprintf(description
,
427 NS_LITERAL_STRING("%d of %d").get(),
428 positionInGroup
, itemsInGroup
);
430 } else if (groupLevel
> 0) {
431 nsTextFormatter::ssprintf(description
, NS_LITERAL_STRING("L%d").get(),
435 if (description
.IsEmpty())
436 xpAccessible
->GetDescription(description
);
438 *pszDescription
= ::SysAllocStringLen(description
.get(),
439 description
.Length());
440 return *pszDescription
? S_OK
: E_OUTOFMEMORY
;
442 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
446 STDMETHODIMP
nsAccessibleWrap::get_accRole(
447 /* [optional][in] */ VARIANT varChild
,
448 /* [retval][out] */ VARIANT __RPC_FAR
*pvarRole
)
451 VariantInit(pvarRole
);
453 nsAccessible
*xpAccessible
= GetXPAccessibleFor(varChild
);
458 NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(xpAccessible
),
459 "Does not support nsIAccessibleText when it should");
462 PRUint32 xpRole
= 0, msaaRole
= 0;
463 if (NS_FAILED(xpAccessible
->GetRole(&xpRole
)))
466 msaaRole
= gWindowsRoleMap
[xpRole
].msaaRole
;
467 NS_ASSERTION(gWindowsRoleMap
[nsIAccessibleRole::ROLE_LAST_ENTRY
].msaaRole
== ROLE_WINDOWS_LAST_ENTRY
,
468 "MSAA role map skewed");
470 // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call the MSAA role
471 // a ROLE_OUTLINEITEM for consistency and compatibility.
472 // We need this because ARIA has a role of "row" for both grid and treegrid
473 if (xpRole
== nsIAccessibleRole::ROLE_ROW
) {
474 if (nsAccUtils::Role(GetParent()) == nsIAccessibleRole::ROLE_TREE_TABLE
)
475 msaaRole
= ROLE_SYSTEM_OUTLINEITEM
;
478 // -- Try enumerated role
479 if (msaaRole
!= USE_ROLE_STRING
) {
480 pvarRole
->vt
= VT_I4
;
481 pvarRole
->lVal
= msaaRole
; // Normal enumerated role
486 // Could not map to known enumerated MSAA role like ROLE_BUTTON
487 // Use BSTR role to expose role attribute or tag name + namespace
488 nsIContent
*content
= xpAccessible
->GetContent();
492 if (content
->IsElement()) {
493 nsAutoString roleString
;
494 if (msaaRole
!= ROLE_SYSTEM_CLIENT
&&
495 !content
->GetAttr(kNameSpaceID_None
, nsAccessibilityAtoms::role
, roleString
)) {
496 nsIDocument
* document
= content
->GetCurrentDoc();
500 nsINodeInfo
*nodeInfo
= content
->NodeInfo();
501 nodeInfo
->GetName(roleString
);
503 // Only append name space if different from that of current document.
504 if (!nodeInfo
->NamespaceEquals(document
->GetDefaultNamespaceID())) {
505 nsAutoString nameSpaceURI
;
506 nodeInfo
->GetNamespaceURI(nameSpaceURI
);
507 roleString
+= NS_LITERAL_STRING(", ") + nameSpaceURI
;
511 if (!roleString
.IsEmpty()) {
512 pvarRole
->vt
= VT_BSTR
;
513 pvarRole
->bstrVal
= ::SysAllocString(roleString
.get());
517 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
521 STDMETHODIMP
nsAccessibleWrap::get_accState(
522 /* [optional][in] */ VARIANT varChild
,
523 /* [retval][out] */ VARIANT __RPC_FAR
*pvarState
)
526 VariantInit(pvarState
);
527 pvarState
->vt
= VT_I4
;
530 nsAccessible
*xpAccessible
= GetXPAccessibleFor(varChild
);
535 if (NS_FAILED(xpAccessible
->GetState(&state
, nsnull
)))
538 pvarState
->lVal
= state
;
539 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
544 STDMETHODIMP
nsAccessibleWrap::get_accHelp(
545 /* [optional][in] */ VARIANT varChild
,
546 /* [retval][out] */ BSTR __RPC_FAR
*pszHelp
)
552 } __except(FilterA11yExceptions(::GetExceptionCode(),
553 GetExceptionInformation())) { }
557 STDMETHODIMP
nsAccessibleWrap::get_accHelpTopic(
558 /* [out] */ BSTR __RPC_FAR
*pszHelpFile
,
559 /* [optional][in] */ VARIANT varChild
,
560 /* [retval][out] */ long __RPC_FAR
*pidTopic
)
567 } __except(FilterA11yExceptions(::GetExceptionCode(),
568 GetExceptionInformation())) { }
572 STDMETHODIMP
nsAccessibleWrap::get_accKeyboardShortcut(
573 /* [optional][in] */ VARIANT varChild
,
574 /* [retval][out] */ BSTR __RPC_FAR
*pszKeyboardShortcut
)
577 *pszKeyboardShortcut
= NULL
;
578 nsAccessible
*xpAccessible
= GetXPAccessibleFor(varChild
);
580 nsAutoString shortcut
;
581 nsresult rv
= xpAccessible
->GetKeyboardShortcut(shortcut
);
585 *pszKeyboardShortcut
= ::SysAllocStringLen(shortcut
.get(),
587 return *pszKeyboardShortcut
? S_OK
: E_OUTOFMEMORY
;
589 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
593 STDMETHODIMP
nsAccessibleWrap::get_accFocus(
594 /* [retval][out] */ VARIANT __RPC_FAR
*pvarChild
)
596 // VT_EMPTY: None. This object does not have the keyboard focus itself
597 // and does not contain a child that has the keyboard focus.
598 // VT_I4: lVal is CHILDID_SELF. The object itself has the keyboard focus.
599 // VT_I4: lVal contains the child ID of the child element with the keyboard focus.
600 // VT_DISPATCH: pdispVal member is the address of the IDispatch interface
601 // for the child object with the keyboard focus.
606 VariantInit(pvarChild
);
608 // Return the current IAccessible child that has focus
609 nsCOMPtr
<nsIAccessible
> focusedAccessible
;
610 GetFocusedChild(getter_AddRefs(focusedAccessible
));
611 if (focusedAccessible
== this) {
612 pvarChild
->vt
= VT_I4
;
613 pvarChild
->lVal
= CHILDID_SELF
;
615 else if (focusedAccessible
) {
616 pvarChild
->vt
= VT_DISPATCH
;
617 pvarChild
->pdispVal
= NativeAccessible(focusedAccessible
);
620 pvarChild
->vt
= VT_EMPTY
; // No focus or focus is not a child
623 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
627 // This helper class implements IEnumVARIANT for a nsIArray containing nsIAccessible objects.
629 class AccessibleEnumerator
: public IEnumVARIANT
632 AccessibleEnumerator(nsIArray
* aArray
) : mArray(aArray
), mCurIndex(0) { }
633 AccessibleEnumerator(const AccessibleEnumerator
& toCopy
) :
634 mArray(toCopy
.mArray
), mCurIndex(toCopy
.mCurIndex
) { }
635 ~AccessibleEnumerator() { }
638 STDMETHODIMP
QueryInterface(REFIID iid
, void ** ppvObject
);
639 STDMETHODIMP_(ULONG
) AddRef(void);
640 STDMETHODIMP_(ULONG
) Release(void);
643 STDMETHODIMP
Next(unsigned long celt
, VARIANT FAR
* rgvar
, unsigned long FAR
* pceltFetched
);
644 STDMETHODIMP
Skip(unsigned long celt
);
650 STDMETHODIMP
Clone(IEnumVARIANT FAR
* FAR
* ppenum
);
653 nsCOMPtr
<nsIArray
> mArray
;
655 nsAutoRefCnt mRefCnt
;
659 AccessibleEnumerator::QueryInterface(REFIID iid
, void ** ppvObject
)
662 if (iid
== IID_IEnumVARIANT
) {
663 *ppvObject
= static_cast<IEnumVARIANT
*>(this);
667 if (iid
== IID_IUnknown
) {
668 *ppvObject
= static_cast<IUnknown
*>(this);
674 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
675 return E_NOINTERFACE
;
679 AccessibleEnumerator::AddRef(void)
685 AccessibleEnumerator::Release(void)
694 AccessibleEnumerator::Next(unsigned long celt
, VARIANT FAR
* rgvar
, unsigned long FAR
* pceltFetched
)
698 mArray
->GetLength(&length
);
702 // Can't get more elements than there are...
703 if (celt
> length
- mCurIndex
) {
705 celt
= length
- mCurIndex
;
708 for (PRUint32 i
= 0; i
< celt
; ++i
, ++mCurIndex
) {
709 // Copy the elements of the array into rgvar
710 nsCOMPtr
<nsIAccessible
> accel(do_QueryElementAt(mArray
, mCurIndex
));
711 NS_ASSERTION(accel
, "Invalid pointer in mArray");
714 rgvar
[i
].vt
= VT_DISPATCH
;
715 rgvar
[i
].pdispVal
= nsAccessibleWrap::NativeAccessible(accel
);
720 *pceltFetched
= celt
;
723 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
729 AccessibleEnumerator::Clone(IEnumVARIANT FAR
* FAR
* ppenum
)
732 *ppenum
= new AccessibleEnumerator(*this);
734 return E_OUTOFMEMORY
;
736 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
741 AccessibleEnumerator::Skip(unsigned long celt
)
745 mArray
->GetLength(&length
);
746 // Check if we can skip the requested number of elements
747 if (celt
> length
- mCurIndex
) {
752 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
757 * This method is called when a client wants to know which children of a node
758 * are selected. Note that this method can only find selected children for
759 * nsIAccessible object which implement nsIAccessibleSelectable.
761 * The VARIANT return value arguement is expected to either contain a single IAccessible
762 * or an IEnumVARIANT of IAccessibles. We return the IEnumVARIANT regardless of the number
763 * of children selected, unless there are none selected in which case we return an empty
766 * We get the selected options from the select's accessible object and wrap
767 * those in an AccessibleEnumerator which we then put in the return VARIANT.
769 * returns a VT_EMPTY VARIANT if:
770 * - there are no selected children for this object
771 * - the object is not the type that can have children selected
773 STDMETHODIMP
nsAccessibleWrap::get_accSelection(VARIANT __RPC_FAR
*pvarChildren
)
776 VariantInit(pvarChildren
);
777 pvarChildren
->vt
= VT_EMPTY
;
779 nsCOMPtr
<nsIAccessibleSelectable
>
780 select(do_QueryInterface(static_cast<nsIAccessible
*>(this)));
782 if (select
) { // do we have an nsIAccessibleSelectable?
783 // we have an accessible that can have children selected
784 nsCOMPtr
<nsIArray
> selectedOptions
;
785 // gets the selected options as nsIAccessibles.
786 select
->GetSelectedChildren(getter_AddRefs(selectedOptions
));
787 if (selectedOptions
) { // false if the select has no children or none are selected
788 // 1) Create and initialize the enumeration
789 nsRefPtr
<AccessibleEnumerator
> pEnum
= new AccessibleEnumerator(selectedOptions
);
791 // 2) Put the enumerator in the VARIANT
793 return E_OUTOFMEMORY
;
794 pvarChildren
->vt
= VT_UNKNOWN
; // this must be VT_UNKNOWN for an IEnumVARIANT
795 NS_ADDREF(pvarChildren
->punkVal
= pEnum
);
798 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
802 STDMETHODIMP
nsAccessibleWrap::get_accDefaultAction(
803 /* [optional][in] */ VARIANT varChild
,
804 /* [retval][out] */ BSTR __RPC_FAR
*pszDefaultAction
)
807 *pszDefaultAction
= NULL
;
808 nsAccessible
*xpAccessible
= GetXPAccessibleFor(varChild
);
810 nsAutoString defaultAction
;
811 if (NS_FAILED(xpAccessible
->GetActionName(0, defaultAction
)))
814 *pszDefaultAction
= ::SysAllocStringLen(defaultAction
.get(),
815 defaultAction
.Length());
816 return *pszDefaultAction
? S_OK
: E_OUTOFMEMORY
;
819 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
823 STDMETHODIMP
nsAccessibleWrap::accSelect(
824 /* [in] */ long flagsSelect
,
825 /* [optional][in] */ VARIANT varChild
)
828 // currently only handle focus and selection
829 nsAccessible
*xpAccessible
= GetXPAccessibleFor(varChild
);
830 NS_ENSURE_TRUE(xpAccessible
, E_FAIL
);
832 if (flagsSelect
& (SELFLAG_TAKEFOCUS
|SELFLAG_TAKESELECTION
|SELFLAG_REMOVESELECTION
))
834 if (flagsSelect
& SELFLAG_TAKEFOCUS
)
835 xpAccessible
->TakeFocus();
837 if (flagsSelect
& SELFLAG_TAKESELECTION
)
838 xpAccessible
->TakeSelection();
840 if (flagsSelect
& SELFLAG_ADDSELECTION
)
841 xpAccessible
->SetSelected(PR_TRUE
);
843 if (flagsSelect
& SELFLAG_REMOVESELECTION
)
844 xpAccessible
->SetSelected(PR_FALSE
);
846 if (flagsSelect
& SELFLAG_EXTENDSELECTION
)
847 xpAccessible
->ExtendSelection();
852 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
856 STDMETHODIMP
nsAccessibleWrap::accLocation(
857 /* [out] */ long __RPC_FAR
*pxLeft
,
858 /* [out] */ long __RPC_FAR
*pyTop
,
859 /* [out] */ long __RPC_FAR
*pcxWidth
,
860 /* [out] */ long __RPC_FAR
*pcyHeight
,
861 /* [optional][in] */ VARIANT varChild
)
864 nsAccessible
*xpAccessible
= GetXPAccessibleFor(varChild
);
867 PRInt32 x
, y
, width
, height
;
868 if (NS_FAILED(xpAccessible
->GetBounds(&x
, &y
, &width
, &height
)))
877 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
882 STDMETHODIMP
nsAccessibleWrap::accNavigate(
883 /* [in] */ long navDir
,
884 /* [optional][in] */ VARIANT varStart
,
885 /* [retval][out] */ VARIANT __RPC_FAR
*pvarEndUpAt
)
888 nsAccessible
*xpAccessibleStart
= GetXPAccessibleFor(varStart
);
889 if (!xpAccessibleStart
)
892 VariantInit(pvarEndUpAt
);
894 nsCOMPtr
<nsIAccessible
> xpAccessibleResult
;
895 PRUint32 xpRelation
= 0;
899 xpAccessibleStart
->GetAccessibleBelow(getter_AddRefs(xpAccessibleResult
));
901 case NAVDIR_FIRSTCHILD
:
902 if (!nsAccUtils::MustPrune(xpAccessibleStart
))
903 xpAccessibleStart
->GetFirstChild(getter_AddRefs(xpAccessibleResult
));
905 case NAVDIR_LASTCHILD
:
906 if (!nsAccUtils::MustPrune(xpAccessibleStart
))
907 xpAccessibleStart
->GetLastChild(getter_AddRefs(xpAccessibleResult
));
910 xpAccessibleStart
->GetAccessibleToLeft(getter_AddRefs(xpAccessibleResult
));
913 xpAccessibleStart
->GetNextSibling(getter_AddRefs(xpAccessibleResult
));
915 case NAVDIR_PREVIOUS
:
916 xpAccessibleStart
->GetPreviousSibling(getter_AddRefs(xpAccessibleResult
));
919 xpAccessibleStart
->GetAccessibleToRight(getter_AddRefs(xpAccessibleResult
));
922 xpAccessibleStart
->GetAccessibleAbove(getter_AddRefs(xpAccessibleResult
));
925 // MSAA relationship extensions to accNavigate
926 case NAVRELATION_CONTROLLED_BY
:
927 xpRelation
= nsIAccessibleRelation::RELATION_CONTROLLED_BY
;
929 case NAVRELATION_CONTROLLER_FOR
:
930 xpRelation
= nsIAccessibleRelation::RELATION_CONTROLLER_FOR
;
932 case NAVRELATION_LABEL_FOR
:
933 xpRelation
= nsIAccessibleRelation::RELATION_LABEL_FOR
;
935 case NAVRELATION_LABELLED_BY
:
936 xpRelation
= nsIAccessibleRelation::RELATION_LABELLED_BY
;
938 case NAVRELATION_MEMBER_OF
:
939 xpRelation
= nsIAccessibleRelation::RELATION_MEMBER_OF
;
941 case NAVRELATION_NODE_CHILD_OF
:
942 xpRelation
= nsIAccessibleRelation::RELATION_NODE_CHILD_OF
;
944 case NAVRELATION_FLOWS_TO
:
945 xpRelation
= nsIAccessibleRelation::RELATION_FLOWS_TO
;
947 case NAVRELATION_FLOWS_FROM
:
948 xpRelation
= nsIAccessibleRelation::RELATION_FLOWS_FROM
;
950 case NAVRELATION_SUBWINDOW_OF
:
951 xpRelation
= nsIAccessibleRelation::RELATION_SUBWINDOW_OF
;
953 case NAVRELATION_EMBEDS
:
954 xpRelation
= nsIAccessibleRelation::RELATION_EMBEDS
;
956 case NAVRELATION_EMBEDDED_BY
:
957 xpRelation
= nsIAccessibleRelation::RELATION_EMBEDDED_BY
;
959 case NAVRELATION_POPUP_FOR
:
960 xpRelation
= nsIAccessibleRelation::RELATION_POPUP_FOR
;
962 case NAVRELATION_PARENT_WINDOW_OF
:
963 xpRelation
= nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF
;
965 case NAVRELATION_DEFAULT_BUTTON
:
966 xpRelation
= nsIAccessibleRelation::RELATION_DEFAULT_BUTTON
;
968 case NAVRELATION_DESCRIBED_BY
:
969 xpRelation
= nsIAccessibleRelation::RELATION_DESCRIBED_BY
;
971 case NAVRELATION_DESCRIPTION_FOR
:
972 xpRelation
= nsIAccessibleRelation::RELATION_DESCRIPTION_FOR
;
976 pvarEndUpAt
->vt
= VT_EMPTY
;
979 xpAccessibleResult
= nsRelUtils::GetRelatedAccessible(this, xpRelation
);
981 if (xpAccessibleResult
) {
982 pvarEndUpAt
->pdispVal
= NativeAccessible(xpAccessibleResult
);
983 pvarEndUpAt
->vt
= VT_DISPATCH
;
986 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
990 STDMETHODIMP
nsAccessibleWrap::accHitTest(
991 /* [in] */ long xLeft
,
992 /* [in] */ long yTop
,
993 /* [retval][out] */ VARIANT __RPC_FAR
*pvarChild
)
996 VariantInit(pvarChild
);
998 // convert to window coords
999 nsCOMPtr
<nsIAccessible
> xpAccessible
;
1004 if (nsAccUtils::MustPrune(this)) {
1005 xpAccessible
= this;
1008 GetChildAtPoint(xLeft
, yTop
, getter_AddRefs(xpAccessible
));
1011 // if we got a child
1013 // if the child is us
1014 if (xpAccessible
== static_cast<nsIAccessible
*>(this)) {
1015 pvarChild
->vt
= VT_I4
;
1016 pvarChild
->lVal
= CHILDID_SELF
;
1017 } else { // its not create an Accessible for it.
1018 pvarChild
->vt
= VT_DISPATCH
;
1019 pvarChild
->pdispVal
= NativeAccessible(xpAccessible
);
1020 nsCOMPtr
<nsIAccessNode
> accessNode(do_QueryInterface(xpAccessible
));
1021 NS_ASSERTION(accessNode
, "Unable to QI to nsIAccessNode");
1022 nsCOMPtr
<nsIDOMNode
> domNode
;
1023 accessNode
->GetDOMNode(getter_AddRefs(domNode
));
1025 // Has already been shut down
1026 pvarChild
->vt
= VT_EMPTY
;
1031 // no child at that point
1032 pvarChild
->vt
= VT_EMPTY
;
1035 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1040 STDMETHODIMP
nsAccessibleWrap::accDoDefaultAction(
1041 /* [optional][in] */ VARIANT varChild
)
1044 nsAccessible
*xpAccessible
= GetXPAccessibleFor(varChild
);
1045 if (!xpAccessible
|| FAILED(xpAccessible
->DoAction(0))) {
1048 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1052 STDMETHODIMP
nsAccessibleWrap::put_accName(
1053 /* [optional][in] */ VARIANT varChild
,
1054 /* [in] */ BSTR szName
)
1059 STDMETHODIMP
nsAccessibleWrap::put_accValue(
1060 /* [optional][in] */ VARIANT varChild
,
1061 /* [in] */ BSTR szValue
)
1068 ////////////////////////////////////////////////////////////////////////////////
1069 // nsAccessibleWrap. IEnumVariant
1072 nsAccessibleWrap::Next(ULONG aNumElementsRequested
, VARIANT FAR
* aPVar
,
1073 ULONG FAR
* aNumElementsFetched
)
1075 // Children already cached via QI to IEnumVARIANT
1077 *aNumElementsFetched
= 0;
1079 if (aNumElementsRequested
<= 0 || !aPVar
)
1080 return E_INVALIDARG
;
1082 if (mEnumVARIANTPosition
== kIEnumVariantDisconnected
)
1083 return CO_E_OBJNOTCONNECTED
;
1085 PRUint32 numElementsFetched
= 0;
1086 for (; numElementsFetched
< aNumElementsRequested
;
1087 numElementsFetched
++, mEnumVARIANTPosition
++) {
1089 nsAccessible
* accessible
= GetChildAt(mEnumVARIANTPosition
);
1093 VariantInit(&aPVar
[numElementsFetched
]);
1095 aPVar
[numElementsFetched
].pdispVal
= NativeAccessible(accessible
);
1096 aPVar
[numElementsFetched
].vt
= VT_DISPATCH
;
1099 (*aNumElementsFetched
) = numElementsFetched
;
1101 return numElementsFetched
< aNumElementsRequested
? S_FALSE
: S_OK
;
1103 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1108 nsAccessibleWrap::Skip(ULONG aNumElements
)
1111 if (mEnumVARIANTPosition
== kIEnumVariantDisconnected
)
1112 return CO_E_OBJNOTCONNECTED
;
1114 mEnumVARIANTPosition
+= aNumElements
;
1116 PRInt32 numChildren
;
1117 GetChildCount(&numChildren
);
1119 if (mEnumVARIANTPosition
> numChildren
)
1121 mEnumVARIANTPosition
= numChildren
;
1124 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1129 nsAccessibleWrap::Reset(void)
1131 mEnumVARIANTPosition
= 0;
1136 nsAccessibleWrap::Clone(IEnumVARIANT FAR
* FAR
* ppenum
)
1141 nsCOMPtr
<nsIArray
> childArray
;
1142 nsresult rv
= GetChildren(getter_AddRefs(childArray
));
1144 *ppenum
= new AccessibleEnumerator(childArray
);
1146 return E_OUTOFMEMORY
;
1149 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1153 ////////////////////////////////////////////////////////////////////////////////
1154 // nsAccessibleWrap. IAccessible2
1157 nsAccessibleWrap::get_nRelations(long *aNRelations
)
1161 nsresult rv
= GetRelationsCount(&count
);
1162 *aNRelations
= count
;
1164 return GetHRESULT(rv
);
1166 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1171 nsAccessibleWrap::get_relation(long aRelationIndex
,
1172 IAccessibleRelation
**aRelation
)
1177 nsCOMPtr
<nsIAccessibleRelation
> relation
;
1178 nsresult rv
= GetRelation(aRelationIndex
, getter_AddRefs(relation
));
1180 return GetHRESULT(rv
);
1182 nsCOMPtr
<nsIWinAccessNode
> winAccessNode(do_QueryInterface(relation
));
1186 void *instancePtr
= NULL
;
1187 rv
= winAccessNode
->QueryNativeInterface(IID_IAccessibleRelation
,
1190 return GetHRESULT(rv
);
1192 *aRelation
= static_cast<IAccessibleRelation
*>(instancePtr
);
1195 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1200 nsAccessibleWrap::get_relations(long aMaxRelations
,
1201 IAccessibleRelation
**aRelation
,
1208 nsCOMPtr
<nsIArray
> relations
;
1209 nsresult rv
= GetRelations(getter_AddRefs(relations
));
1211 return GetHRESULT(rv
);
1213 PRUint32 length
= 0;
1214 rv
= relations
->GetLength(&length
);
1216 return GetHRESULT(rv
);
1221 PRUint32 count
= length
< (PRUint32
)aMaxRelations
? length
: aMaxRelations
;
1224 for (; index
< count
; index
++) {
1225 nsCOMPtr
<nsIWinAccessNode
> winAccessNode
=
1226 do_QueryElementAt(relations
, index
, &rv
);
1230 void *instancePtr
= NULL
;
1231 nsresult rv
= winAccessNode
->QueryNativeInterface(IID_IAccessibleRelation
,
1236 aRelation
[index
] = static_cast<IAccessibleRelation
*>(instancePtr
);
1239 if (NS_FAILED(rv
)) {
1240 for (PRUint32 index2
= 0; index2
< index
; index2
++) {
1241 aRelation
[index2
]->Release();
1242 aRelation
[index2
] = NULL
;
1244 return GetHRESULT(rv
);
1247 *aNRelations
= count
;
1250 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1255 nsAccessibleWrap::role(long *aRole
)
1260 PRUint32 xpRole
= 0;
1261 nsresult rv
= GetRole(&xpRole
);
1263 return GetHRESULT(rv
);
1265 NS_ASSERTION(gWindowsRoleMap
[nsIAccessibleRole::ROLE_LAST_ENTRY
].ia2Role
== ROLE_WINDOWS_LAST_ENTRY
,
1266 "MSAA role map skewed");
1268 *aRole
= gWindowsRoleMap
[xpRole
].ia2Role
;
1270 // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call
1271 // the IA2 role a ROLE_OUTLINEITEM.
1272 if (xpRole
== nsIAccessibleRole::ROLE_ROW
) {
1273 if (nsAccUtils::Role(GetParent()) == nsIAccessibleRole::ROLE_TREE_TABLE
)
1274 *aRole
= ROLE_SYSTEM_OUTLINEITEM
;
1279 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1284 nsAccessibleWrap::scrollTo(enum IA2ScrollType aScrollType
)
1287 nsresult rv
= ScrollTo(aScrollType
);
1288 return GetHRESULT(rv
);
1290 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1295 nsAccessibleWrap::scrollToPoint(enum IA2CoordinateType aCoordType
,
1299 PRUint32 geckoCoordType
= (aCoordType
== IA2_COORDTYPE_SCREEN_RELATIVE
) ?
1300 nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
:
1301 nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE
;
1303 nsresult rv
= ScrollToPoint(geckoCoordType
, aX
, aY
);
1304 return GetHRESULT(rv
);
1306 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1311 nsAccessibleWrap::get_groupPosition(long *aGroupLevel
,
1312 long *aSimilarItemsInGroup
,
1313 long *aPositionInGroup
)
1316 PRInt32 groupLevel
= 0;
1317 PRInt32 similarItemsInGroup
= 0;
1318 PRInt32 positionInGroup
= 0;
1320 nsresult rv
= GroupPosition(&groupLevel
, &similarItemsInGroup
,
1323 return GetHRESULT(rv
);
1325 // Group information for accessibles having level only (like html headings
1326 // elements) isn't exposed by this method. AT should look for 'level' object
1328 if (!similarItemsInGroup
&& !positionInGroup
)
1331 *aGroupLevel
= groupLevel
;
1332 *aSimilarItemsInGroup
= similarItemsInGroup
;
1333 *aPositionInGroup
= positionInGroup
;
1337 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1342 nsAccessibleWrap::get_states(AccessibleStates
*aStates
)
1347 // XXX: bug 344674 should come with better approach that we have here.
1349 PRUint32 states
= 0, extraStates
= 0;
1350 nsresult rv
= GetState(&states
, &extraStates
);
1352 return GetHRESULT(rv
);
1354 if (states
& nsIAccessibleStates::STATE_INVALID
)
1355 *aStates
|= IA2_STATE_INVALID_ENTRY
;
1356 if (states
& nsIAccessibleStates::STATE_REQUIRED
)
1357 *aStates
|= IA2_STATE_REQUIRED
;
1359 // The following IA2 states are not supported by Gecko
1361 // IA2_STATE_MANAGES_DESCENDANTS
1362 // IA2_STATE_ICONIFIED
1363 // IA2_STATE_INVALID // This is not a state, it is the absence of a state
1365 if (extraStates
& nsIAccessibleStates::EXT_STATE_ACTIVE
)
1366 *aStates
|= IA2_STATE_ACTIVE
;
1367 if (extraStates
& nsIAccessibleStates::EXT_STATE_DEFUNCT
)
1368 *aStates
|= IA2_STATE_DEFUNCT
;
1369 if (extraStates
& nsIAccessibleStates::EXT_STATE_EDITABLE
)
1370 *aStates
|= IA2_STATE_EDITABLE
;
1371 if (extraStates
& nsIAccessibleStates::EXT_STATE_HORIZONTAL
)
1372 *aStates
|= IA2_STATE_HORIZONTAL
;
1373 if (extraStates
& nsIAccessibleStates::EXT_STATE_MODAL
)
1374 *aStates
|= IA2_STATE_MODAL
;
1375 if (extraStates
& nsIAccessibleStates::EXT_STATE_MULTI_LINE
)
1376 *aStates
|= IA2_STATE_MULTI_LINE
;
1377 if (extraStates
& nsIAccessibleStates::EXT_STATE_OPAQUE
)
1378 *aStates
|= IA2_STATE_OPAQUE
;
1379 if (extraStates
& nsIAccessibleStates::EXT_STATE_SELECTABLE_TEXT
)
1380 *aStates
|= IA2_STATE_SELECTABLE_TEXT
;
1381 if (extraStates
& nsIAccessibleStates::EXT_STATE_SINGLE_LINE
)
1382 *aStates
|= IA2_STATE_SINGLE_LINE
;
1383 if (extraStates
& nsIAccessibleStates::EXT_STATE_STALE
)
1384 *aStates
|= IA2_STATE_STALE
;
1385 if (extraStates
& nsIAccessibleStates::EXT_STATE_SUPPORTS_AUTOCOMPLETION
)
1386 *aStates
|= IA2_STATE_SUPPORTS_AUTOCOMPLETION
;
1387 if (extraStates
& nsIAccessibleStates::EXT_STATE_TRANSIENT
)
1388 *aStates
|= IA2_STATE_TRANSIENT
;
1389 if (extraStates
& nsIAccessibleStates::EXT_STATE_VERTICAL
)
1390 *aStates
|= IA2_STATE_VERTICAL
;
1394 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1399 nsAccessibleWrap::get_extendedRole(BSTR
*aExtendedRole
)
1402 *aExtendedRole
= NULL
;
1403 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1409 nsAccessibleWrap::get_localizedExtendedRole(BSTR
*aLocalizedExtendedRole
)
1412 *aLocalizedExtendedRole
= NULL
;
1413 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1419 nsAccessibleWrap::get_nExtendedStates(long *aNExtendedStates
)
1422 *aNExtendedStates
= 0;
1423 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1429 nsAccessibleWrap::get_extendedStates(long aMaxExtendedStates
,
1430 BSTR
**aExtendedStates
,
1431 long *aNExtendedStates
)
1434 *aExtendedStates
= NULL
;
1435 *aNExtendedStates
= 0;
1436 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1442 nsAccessibleWrap::get_localizedExtendedStates(long aMaxLocalizedExtendedStates
,
1443 BSTR
**aLocalizedExtendedStates
,
1444 long *aNLocalizedExtendedStates
)
1447 *aLocalizedExtendedStates
= NULL
;
1448 *aNLocalizedExtendedStates
= 0;
1449 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1455 nsAccessibleWrap::get_uniqueID(long *uniqueID
)
1459 nsresult rv
= GetUniqueID(&id
);
1461 return GetHRESULT(rv
);
1463 *uniqueID
= - reinterpret_cast<long>(id
);
1466 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1471 nsAccessibleWrap::get_windowHandle(HWND
*aWindowHandle
)
1479 void *handle
= nsnull
;
1480 nsresult rv
= GetOwnerWindow(&handle
);
1482 return GetHRESULT(rv
);
1484 *aWindowHandle
= reinterpret_cast<HWND
>(handle
);
1487 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1492 nsAccessibleWrap::get_indexInParent(long *aIndexInParent
)
1495 *aIndexInParent
= -1;
1498 nsresult rv
= GetIndexInParent(&index
);
1500 return GetHRESULT(rv
);
1505 *aIndexInParent
= index
;
1508 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1513 nsAccessibleWrap::get_locale(IA2Locale
*aLocale
)
1516 // Language codes consist of a primary code and a possibly empty series of
1517 // subcodes: language-code = primary-code ( "-" subcode )*
1518 // Two-letter primary codes are reserved for [ISO639] language abbreviations.
1519 // Any two-letter subcode is understood to be a [ISO3166] country code.
1522 nsresult rv
= GetLanguage(lang
);
1524 return GetHRESULT(rv
);
1526 // If primary code consists from two letters then expose it as language.
1527 PRInt32 offset
= lang
.FindChar('-', 0);
1529 if (lang
.Length() == 2) {
1530 aLocale
->language
= ::SysAllocString(lang
.get());
1533 } else if (offset
== 2) {
1534 aLocale
->language
= ::SysAllocStringLen(lang
.get(), 2);
1536 // If the first subcode consists from two letters then expose it as
1538 offset
= lang
.FindChar('-', 3);
1540 if (lang
.Length() == 5) {
1541 aLocale
->country
= ::SysAllocString(lang
.get() + 3);
1544 } else if (offset
== 5) {
1545 aLocale
->country
= ::SysAllocStringLen(lang
.get() + 3, 2);
1549 // Expose as a string if primary code or subcode cannot point to language or
1550 // country abbreviations or if there are more than one subcode.
1551 aLocale
->variant
= ::SysAllocString(lang
.get());
1554 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1559 nsAccessibleWrap::get_attributes(BSTR
*aAttributes
)
1561 // The format is name:value;name:value; with \ for escaping these
1562 // characters ":;=,\".
1564 *aAttributes
= NULL
;
1566 nsCOMPtr
<nsIPersistentProperties
> attributes
;
1567 nsresult rv
= GetAttributes(getter_AddRefs(attributes
));
1569 return GetHRESULT(rv
);
1571 return ConvertToIA2Attributes(attributes
, aAttributes
);
1573 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1577 ////////////////////////////////////////////////////////////////////////////////
1581 nsAccessibleWrap::GetTypeInfoCount(UINT
*pctinfo
)
1588 nsAccessibleWrap::GetTypeInfo(UINT iTInfo
, LCID lcid
, ITypeInfo
**ppTInfo
)
1593 return DISP_E_BADINDEX
;
1595 ITypeInfo
* typeInfo
= GetTI(lcid
);
1600 *ppTInfo
= typeInfo
;
1606 nsAccessibleWrap::GetIDsOfNames(REFIID riid
, LPOLESTR
*rgszNames
,
1607 UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
1609 ITypeInfo
*typeInfo
= GetTI(lcid
);
1613 HRESULT hr
= DispGetIDsOfNames(typeInfo
, rgszNames
, cNames
, rgDispId
);
1618 nsAccessibleWrap::Invoke(DISPID dispIdMember
, REFIID riid
,
1619 LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
1620 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
,
1623 ITypeInfo
*typeInfo
= GetTI(lcid
);
1627 return typeInfo
->Invoke(static_cast<IAccessible
*>(this), dispIdMember
,
1628 wFlags
, pDispParams
, pVarResult
, pExcepInfo
,
1633 // nsIAccessible method
1634 NS_IMETHODIMP
nsAccessibleWrap::GetNativeInterface(void **aOutAccessible
)
1636 *aOutAccessible
= static_cast<IAccessible
*>(this);
1644 nsAccessibleWrap::HandleAccEvent(nsAccEvent
*aEvent
)
1646 nsresult rv
= nsAccessible::HandleAccEvent(aEvent
);
1647 NS_ENSURE_SUCCESS(rv
, rv
);
1649 return FirePlatformEvent(aEvent
);
1653 nsAccessibleWrap::FirePlatformEvent(nsAccEvent
*aEvent
)
1655 PRUint32 eventType
= aEvent
->GetEventType();
1657 NS_ENSURE_TRUE(eventType
> 0 &&
1658 eventType
< nsIAccessibleEvent::EVENT_LAST_ENTRY
,
1661 PRUint32 winLastEntry
= gWinEventMap
[nsIAccessibleEvent::EVENT_LAST_ENTRY
];
1662 NS_ASSERTION(winLastEntry
== kEVENT_LAST_ENTRY
,
1663 "MSAA event map skewed");
1665 PRUint32 winEvent
= gWinEventMap
[eventType
];
1669 // Means we're not active.
1670 NS_ENSURE_TRUE(mWeakShell
, NS_ERROR_FAILURE
);
1672 nsAccessible
*accessible
= aEvent
->GetAccessible();
1676 if (eventType
== nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED
||
1677 eventType
== nsIAccessibleEvent::EVENT_FOCUS
) {
1678 UpdateSystemCaret();
1681 PRInt32 childID
= GetChildIDFor(accessible
); // get the id for the accessible
1683 return NS_OK
; // Can't fire an event without a child ID
1685 // See if we're in a scrollable area with its own window
1686 nsAccessible
*newAccessible
= nsnull
;
1687 if (eventType
== nsIAccessibleEvent::EVENT_HIDE
) {
1688 // Don't use frame from current accessible when we're hiding that
1690 newAccessible
= accessible
->GetCachedParent();
1692 newAccessible
= accessible
;
1695 HWND hWnd
= GetHWNDFor(newAccessible
);
1696 NS_ENSURE_TRUE(hWnd
, NS_ERROR_FAILURE
);
1698 // Gecko uses two windows for every scrollable area. One window contains
1699 // scrollbars and the child window contains only the client area.
1700 // Details of the 2 window system:
1701 // * Scrollbar window: caret drawing window & return value for WindowFromAccessibleObject()
1702 // * Client area window: text drawing window & MSAA event window
1704 // Fire MSAA event for client area window.
1705 NotifyWinEvent(winEvent
, hWnd
, OBJID_CLIENT
, childID
);
1707 // If the accessible children are changed then drop the IEnumVariant current
1708 // position of the accessible.
1709 if (eventType
== nsIAccessibleEvent::EVENT_REORDER
)
1710 UnattachIEnumVariant();
1715 //------- Helper methods ---------
1717 PRInt32
nsAccessibleWrap::GetChildIDFor(nsIAccessible
* aAccessible
)
1719 // A child ID of the window is required, when we use NotifyWinEvent,
1720 // so that the 3rd party application can call back and get the IAccessible
1721 // the event occurred on.
1723 void *uniqueID
= nsnull
;
1724 nsCOMPtr
<nsIAccessNode
> accessNode(do_QueryInterface(aAccessible
));
1728 accessNode
->GetUniqueID(&uniqueID
);
1730 // Yes, this means we're only compatibible with 32 bit
1731 // MSAA is only available for 32 bit windows, so it's okay
1732 return - NS_PTR_TO_INT32(uniqueID
);
1736 nsAccessibleWrap::GetHWNDFor(nsAccessible
*aAccessible
)
1742 nsIFrame
*frame
= aAccessible
->GetFrame();
1744 nsIWidget
*window
= frame
->GetNearestWidget();
1746 window
->IsVisible(isVisible
);
1748 // Short explanation:
1749 // If HWND for frame is inside a hidden window, fire the event on the
1750 // containing document's visible window.
1752 // Long explanation:
1753 // This is really just to fix combo boxes with JAWS. Window-Eyes already
1754 // worked with combo boxes because they use the value change event in
1755 // the closed combo box case. JAWS will only pay attention to the focus
1756 // events on the list items. The JAWS developers haven't fixed that, so
1757 // we'll use the focus events to make JAWS work. However, JAWS is
1758 // ignoring events on a hidden window. So, in order to fix the bug where
1759 // JAWS doesn't echo the current option as it changes in a closed
1760 // combo box, we need to use an ensure that we never fire an event with
1761 // an HWND for a hidden window.
1762 hWnd
= (HWND
)frame
->GetNearestWidget()->GetNativeData(NS_NATIVE_WINDOW
);
1767 void* handle
= nsnull
;
1768 nsDocAccessible
*accessibleDoc
= aAccessible
->GetDocAccessible();
1772 accessibleDoc
->GetWindowHandle(&handle
);
1773 hWnd
= (HWND
)handle
;
1780 nsAccessibleWrap::ConvertToIA2Attributes(nsIPersistentProperties
*aAttributes
,
1781 BSTR
*aIA2Attributes
)
1783 *aIA2Attributes
= NULL
;
1785 // The format is name:value;name:value; with \ for escaping these
1786 // characters ":;=,\".
1791 nsCOMPtr
<nsISimpleEnumerator
> propEnum
;
1792 aAttributes
->Enumerate(getter_AddRefs(propEnum
));
1796 nsAutoString strAttrs
;
1798 const char kCharsToEscape
[] = ":;=,\\";
1800 PRBool hasMore
= PR_FALSE
;
1801 while (NS_SUCCEEDED(propEnum
->HasMoreElements(&hasMore
)) && hasMore
) {
1802 nsCOMPtr
<nsISupports
> propSupports
;
1803 propEnum
->GetNext(getter_AddRefs(propSupports
));
1805 nsCOMPtr
<nsIPropertyElement
> propElem(do_QueryInterface(propSupports
));
1810 if (NS_FAILED(propElem
->GetKey(name
)))
1813 PRUint32 offset
= 0;
1814 while ((offset
= name
.FindCharInSet(kCharsToEscape
, offset
)) != kNotFound
) {
1815 name
.Insert('\\', offset
);
1820 if (NS_FAILED(propElem
->GetValue(value
)))
1824 while ((offset
= value
.FindCharInSet(kCharsToEscape
, offset
)) != kNotFound
) {
1825 value
.Insert('\\', offset
);
1829 AppendUTF8toUTF16(name
, strAttrs
);
1830 strAttrs
.Append(':');
1831 strAttrs
.Append(value
);
1832 strAttrs
.Append(';');
1835 if (strAttrs
.IsEmpty())
1838 *aIA2Attributes
= ::SysAllocStringLen(strAttrs
.get(), strAttrs
.Length());
1839 return *aIA2Attributes
? S_OK
: E_OUTOFMEMORY
;
1842 IDispatch
*nsAccessibleWrap::NativeAccessible(nsIAccessible
*aXPAccessible
)
1844 if (!aXPAccessible
) {
1845 NS_WARNING("Not passing in an aXPAccessible");
1849 nsCOMPtr
<nsIAccessibleWin32Object
> accObject(do_QueryInterface(aXPAccessible
));
1851 void* hwnd
= nsnull
;
1852 accObject
->GetHwnd(&hwnd
);
1854 IDispatch
*retval
= nsnull
;
1855 AccessibleObjectFromWindow(reinterpret_cast<HWND
>(hwnd
),
1856 OBJID_WINDOW
, IID_IAccessible
, (void **) &retval
);
1861 IAccessible
*msaaAccessible
;
1862 aXPAccessible
->GetNativeInterface((void**)&msaaAccessible
);
1864 return static_cast<IDispatch
*>(msaaAccessible
);
1868 nsAccessibleWrap::UnattachIEnumVariant()
1870 if (mEnumVARIANTPosition
> 0)
1871 mEnumVARIANTPosition
= kIEnumVariantDisconnected
;
1875 nsAccessibleWrap::GetXPAccessibleFor(const VARIANT
& aVarChild
)
1880 // if its us real easy - this seems to always be the case
1881 if (aVarChild
.lVal
== CHILDID_SELF
)
1884 if (nsAccUtils::MustPrune(this))
1887 return GetChildAt(aVarChild
.lVal
);
1890 void nsAccessibleWrap::UpdateSystemCaret()
1892 // Move the system caret so that Windows Tablet Edition and tradional ATs with
1893 // off-screen model can follow the caret
1896 nsRefPtr
<nsRootAccessible
> rootAccessible
= GetRootAccessible();
1897 if (!rootAccessible
) {
1901 nsRefPtr
<nsCaretAccessible
> caretAccessible
= rootAccessible
->GetCaretAccessible();
1902 if (!caretAccessible
) {
1907 nsIntRect caretRect
= caretAccessible
->GetCaretRect(&widget
);
1909 if (caretRect
.IsEmpty() || !(caretWnd
= (HWND
)widget
->GetNativeData(NS_NATIVE_WINDOW
))) {
1913 // Create invisible bitmap for caret, otherwise its appearance interferes
1915 HBITMAP caretBitMap
= CreateBitmap(1, caretRect
.height
, 1, 1, NULL
);
1916 if (::CreateCaret(caretWnd
, caretBitMap
, 1, caretRect
.height
)) { // Also destroys the last caret
1917 ::ShowCaret(caretWnd
);
1919 ::GetWindowRect(caretWnd
, &windowRect
);
1920 ::SetCaretPos(caretRect
.x
- windowRect
.left
, caretRect
.y
- windowRect
.top
);
1921 ::DeleteObject(caretBitMap
);
1926 nsAccessibleWrap::GetTI(LCID lcid
)
1931 ITypeLib
*typeLib
= NULL
;
1932 HRESULT hr
= LoadRegTypeLib(LIBID_Accessibility
, 1, 0, lcid
, &typeLib
);
1936 hr
= typeLib
->GetTypeInfoOfGuid(IID_IAccessible
, &mTypeInfo
);