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"
40 #include "nsAccessibilityAtoms.h"
42 #include "nsIAccessibleDocument.h"
43 #include "nsIAccessibleSelectable.h"
44 #include "nsIAccessibleEvent.h"
45 #include "nsIAccessibleWin32Object.h"
47 #include "Accessible2_i.c"
48 #include "AccessibleStates.h"
50 #include "nsIMutableArray.h"
51 #include "nsIDOMDocument.h"
53 #include "nsIScrollableFrame.h"
54 #include "nsINameSpaceManager.h"
55 #include "nsINodeInfo.h"
56 #include "nsIPrefService.h"
57 #include "nsRootAccessible.h"
58 #include "nsIServiceManager.h"
59 #include "nsTextFormatter.h"
61 #include "nsRoleMap.h"
62 #include "nsEventMap.h"
63 #include "nsArrayUtils.h"
65 /* For documentation of the accessibility architecture,
66 * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
72 static gAccessibles
= 0;
75 EXTERN_C GUID CDECL CLSID_Accessible
=
76 { 0x61044601, 0xa811, 0x4e2b, { 0xbb, 0xba, 0x17, 0xbf, 0xab, 0xd3, 0x29, 0xd7 } };
78 static const PRInt32 kIEnumVariantDisconnected
= -1;
81 * Class nsAccessibleWrap
84 //-----------------------------------------------------
86 //-----------------------------------------------------
87 nsAccessibleWrap::nsAccessibleWrap(nsIDOMNode
* aNode
, nsIWeakReference
*aShell
):
88 nsAccessible(aNode
, aShell
), mEnumVARIANTPosition(0)
92 //-----------------------------------------------------
94 //-----------------------------------------------------
95 nsAccessibleWrap::~nsAccessibleWrap()
99 NS_IMPL_ISUPPORTS_INHERITED0(nsAccessibleWrap
, nsAccessible
);
101 //-----------------------------------------------------
102 // IUnknown interface methods - see iunknown.h for documentation
103 //-----------------------------------------------------
105 // Microsoft COM QueryInterface
106 STDMETHODIMP
nsAccessibleWrap::QueryInterface(REFIID iid
, void** ppv
)
111 if (IID_IUnknown
== iid
|| IID_IDispatch
== iid
|| IID_IAccessible
== iid
)
112 *ppv
= static_cast<IAccessible
*>(this);
113 else if (IID_IEnumVARIANT
== iid
&& !gIsEnumVariantSupportDisabled
) {
115 get_accChildCount(&numChildren
);
116 if (numChildren
> 0) // Don't support this interface for leaf elements
117 *ppv
= static_cast<IEnumVARIANT
*>(this);
118 } else if (IID_IServiceProvider
== iid
)
119 *ppv
= static_cast<IServiceProvider
*>(this);
120 else if (IID_IAccessible2
== iid
&& !gIsIA2Disabled
)
121 *ppv
= static_cast<IAccessible2
*>(this);
124 HRESULT hr
= CAccessibleComponent::QueryInterface(iid
, ppv
);
130 HRESULT hr
= CAccessibleHyperlink::QueryInterface(iid
, ppv
);
136 HRESULT hr
= CAccessibleValue::QueryInterface(iid
, ppv
);
142 return nsAccessNodeWrap::QueryInterface(iid
, ppv
);
144 (reinterpret_cast<IUnknown
*>(*ppv
))->AddRef();
145 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
149 //-----------------------------------------------------
150 // IAccessible methods
151 //-----------------------------------------------------
154 STDMETHODIMP
nsAccessibleWrap::AccessibleObjectFromWindow(HWND hwnd
,
159 // open the dll dynamically
161 gmAccLib
=::LoadLibraryW(L
"OLEACC.DLL");
164 if (!gmAccessibleObjectFromWindow
)
165 gmAccessibleObjectFromWindow
= (LPFNACCESSIBLEOBJECTFROMWINDOW
)GetProcAddress(gmAccLib
,"AccessibleObjectFromWindow");
167 if (gmAccessibleObjectFromWindow
)
168 return gmAccessibleObjectFromWindow(hwnd
, dwObjectID
, riid
, ppvObject
);
174 STDMETHODIMP
nsAccessibleWrap::NotifyWinEvent(DWORD event
,
179 if (gmNotifyWinEvent
)
180 return gmNotifyWinEvent(event
, hwnd
, idObjectType
, idObject
);
185 STDMETHODIMP
nsAccessibleWrap::get_accParent( IDispatch __RPC_FAR
*__RPC_FAR
*ppdispParent
)
188 *ppdispParent
= NULL
;
190 return E_FAIL
; // We've been shut down
192 nsIFrame
*frame
= GetFrame();
195 nsIView
*view
= frame
->GetViewExternal();
197 // This code is essentially our implementation of WindowFromAccessibleObject,
198 // because MSAA iterates get_accParent() until it sees an object of ROLE_WINDOW
199 // to know where the window for a given accessible is. We must expose the native
200 // window accessible that MSAA creates for us. This must be done for the document
201 // object as well as any layout that creates its own window (e.g. via overflow: scroll)
202 nsIWidget
*widget
= view
->GetWidget();
204 hwnd
= (HWND
)widget
->GetNativeData(NS_NATIVE_WINDOW
);
205 NS_ASSERTION(hwnd
, "No window handle for window");
207 view
->GetViewManager()->GetRootView(rootView
);
208 if (rootView
== view
) {
209 // If the current object has a widget but was created by an
210 // outer object with its own outer window, then
211 // we want the native accessible for that outer window
212 hwnd
= ::GetParent(hwnd
);
213 NS_ASSERTION(hwnd
, "No window handle for window");
217 // If a frame is a scrollable frame, then it has one window for the client area,
218 // not an extra parent window for just the scrollbars
219 nsIScrollableFrame
*scrollFrame
= nsnull
;
220 CallQueryInterface(frame
, &scrollFrame
);
222 hwnd
= (HWND
)scrollFrame
->GetScrolledFrame()->GetWindow()->GetNativeData(NS_NATIVE_WINDOW
);
223 NS_ASSERTION(hwnd
, "No window handle for window");
228 if (hwnd
&& SUCCEEDED(AccessibleObjectFromWindow(hwnd
, OBJID_WINDOW
, IID_IAccessible
,
229 (void**)ppdispParent
))) {
234 nsCOMPtr
<nsIAccessible
> xpParentAccessible(GetParent());
235 NS_ASSERTION(xpParentAccessible
, "No parent accessible where we're not direct child of window");
236 if (!xpParentAccessible
) {
239 *ppdispParent
= NativeAccessible(xpParentAccessible
);
241 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
245 STDMETHODIMP
nsAccessibleWrap::get_accChildCount( long __RPC_FAR
*pcountChildren
)
249 if (nsAccUtils::MustPrune(this))
253 GetChildCount(&numChildren
);
254 *pcountChildren
= numChildren
;
255 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
260 STDMETHODIMP
nsAccessibleWrap::get_accChild(
261 /* [in] */ VARIANT varChild
,
262 /* [retval][out] */ IDispatch __RPC_FAR
*__RPC_FAR
*ppdispChild
)
266 if (!mWeakShell
|| varChild
.vt
!= VT_I4
)
269 if (varChild
.lVal
== CHILDID_SELF
) {
270 *ppdispChild
= static_cast<IDispatch
*>(this);
275 nsCOMPtr
<nsIAccessible
> childAccessible
;
276 if (!nsAccUtils::MustPrune(this)) {
277 GetChildAt(varChild
.lVal
- 1, getter_AddRefs(childAccessible
));
278 if (childAccessible
) {
279 *ppdispChild
= NativeAccessible(childAccessible
);
282 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
284 return (*ppdispChild
)? S_OK
: E_FAIL
;
287 STDMETHODIMP
nsAccessibleWrap::get_accName(
288 /* [optional][in] */ VARIANT varChild
,
289 /* [retval][out] */ BSTR __RPC_FAR
*pszName
)
293 nsCOMPtr
<nsIAccessible
> xpAccessible
;
294 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
298 nsresult rv
= xpAccessible
->GetName(name
);
300 return GetHRESULT(rv
);
303 // Valid return value for the name:
304 // The name was not provided, e.g. no alt attribute for an image.
305 // A screen reader may choose to invent its own accessible name, e.g. from
306 // an image src attribute.
307 // See nsHTMLImageAccessible::GetName()
311 *pszName
= ::SysAllocStringLen(name
.get(), name
.Length());
313 return E_OUTOFMEMORY
;
316 NS_ASSERTION(mIsInitialized
, "Access node was not initialized");
318 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
324 STDMETHODIMP
nsAccessibleWrap::get_accValue(
325 /* [optional][in] */ VARIANT varChild
,
326 /* [retval][out] */ BSTR __RPC_FAR
*pszValue
)
330 nsCOMPtr
<nsIAccessible
> xpAccessible
;
331 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
334 if (NS_FAILED(xpAccessible
->GetValue(value
)))
337 // see bug 438784: Need to expose URL on doc's value attribute.
338 // For this, reverting part of fix for bug 425693 to make this MSAA method
339 // behave IAccessible2-style.
343 *pszValue
= ::SysAllocStringLen(value
.get(), value
.Length());
345 return E_OUTOFMEMORY
;
347 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
352 nsAccessibleWrap::get_accDescription(VARIANT varChild
,
353 BSTR __RPC_FAR
*pszDescription
)
356 *pszDescription
= NULL
;
358 nsCOMPtr
<nsIAccessible
> xpAccessible
;
359 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
363 // For items that are a choice in a list of choices, use MSAA description
364 // field to shoehorn positional info, it's becoming a defacto standard use for
367 nsAutoString description
;
369 // Try to get group attributes to make a positional description string. We
370 // can't use nsIAccessible::groupPosition because the method isn't supposed
371 // to work with elements exposing 'level' attribute only (like HTML headings).
372 nsCOMPtr
<nsIPersistentProperties
> attributes
;
373 nsresult rv
= xpAccessible
->GetAttributes(getter_AddRefs(attributes
));
374 NS_ENSURE_SUCCESS(rv
, rv
);
376 return NS_ERROR_FAILURE
;
378 PRInt32 groupLevel
= 0;
379 PRInt32 itemsInGroup
= 0;
380 PRInt32 positionInGroup
= 0;
381 nsAccUtils::GetAccGroupAttrs(attributes
, &groupLevel
, &positionInGroup
,
384 if (positionInGroup
> 0) {
385 if (groupLevel
> 0) {
386 // XXX: How do we calculate the number of children? Now we append
387 // " with [numChildren]c" for tree item. In the future we may need to
388 // use the ARIA owns property to calculate that if it's present.
389 PRInt32 numChildren
= 0;
391 PRUint32 currentRole
= 0;
392 rv
= xpAccessible
->GetFinalRole(¤tRole
);
393 if (NS_SUCCEEDED(rv
) &&
394 currentRole
== nsIAccessibleRole::ROLE_OUTLINEITEM
) {
395 nsCOMPtr
<nsIAccessible
> child
;
396 xpAccessible
->GetFirstChild(getter_AddRefs(child
));
398 child
->GetFinalRole(¤tRole
);
399 if (currentRole
== nsIAccessibleRole::ROLE_GROUPING
) {
400 nsCOMPtr
<nsIAccessible
> groupChild
;
401 child
->GetFirstChild(getter_AddRefs(groupChild
));
403 groupChild
->GetFinalRole(¤tRole
);
405 (currentRole
== nsIAccessibleRole::ROLE_OUTLINEITEM
);
406 nsCOMPtr
<nsIAccessible
> nextGroupChild
;
407 groupChild
->GetNextSibling(getter_AddRefs(nextGroupChild
));
408 groupChild
.swap(nextGroupChild
);
412 nsCOMPtr
<nsIAccessible
> nextChild
;
413 child
->GetNextSibling(getter_AddRefs(nextChild
));
414 child
.swap(nextChild
);
419 nsTextFormatter::ssprintf(description
,
420 NS_LITERAL_STRING("L%d, %d of %d with %d").get(),
421 groupLevel
, positionInGroup
, itemsInGroup
,
424 nsTextFormatter::ssprintf(description
,
425 NS_LITERAL_STRING("L%d, %d of %d").get(),
426 groupLevel
, positionInGroup
, itemsInGroup
);
428 } else { // Position has no level
429 nsTextFormatter::ssprintf(description
,
430 NS_LITERAL_STRING("%d of %d").get(),
431 positionInGroup
, itemsInGroup
);
433 } else if (groupLevel
> 0) {
434 nsTextFormatter::ssprintf(description
, NS_LITERAL_STRING("L%d").get(),
438 if (!description
.IsEmpty()) {
439 *pszDescription
= ::SysAllocStringLen(description
.get(),
440 description
.Length());
441 return *pszDescription
? S_OK
: E_OUTOFMEMORY
;
444 xpAccessible
->GetDescription(description
);
445 if (!description
.IsEmpty()) {
446 // Signal to screen readers that this description is speakable
447 // and is not a formatted positional information description
448 // Don't localize the "Description: " part of this string, it will be
449 // parsed out by assistive technologies.
450 description
= NS_LITERAL_STRING("Description: ") + description
;
453 *pszDescription
= ::SysAllocStringLen(description
.get(),
454 description
.Length());
455 return *pszDescription
? S_OK
: E_OUTOFMEMORY
;
457 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
461 STDMETHODIMP
nsAccessibleWrap::get_accRole(
462 /* [optional][in] */ VARIANT varChild
,
463 /* [retval][out] */ VARIANT __RPC_FAR
*pvarRole
)
466 VariantInit(pvarRole
);
468 nsCOMPtr
<nsIAccessible
> xpAccessible
;
469 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
475 NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(xpAccessible
),
476 "Does not support nsIAccessibleText when it should");
479 PRUint32 xpRole
= 0, msaaRole
= 0;
480 if (NS_FAILED(xpAccessible
->GetFinalRole(&xpRole
)))
483 msaaRole
= gWindowsRoleMap
[xpRole
].msaaRole
;
484 NS_ASSERTION(gWindowsRoleMap
[nsIAccessibleRole::ROLE_LAST_ENTRY
].msaaRole
== ROLE_WINDOWS_LAST_ENTRY
,
485 "MSAA role map skewed");
487 // Special case, if there is a ROLE_ROW inside of a ROLE_TREE_TABLE, then call the MSAA role
488 // a ROLE_OUTLINEITEM for consistency and compatibility.
489 // We need this because ARIA has a role of "row" for both grid and treegrid
490 if (xpRole
== nsIAccessibleRole::ROLE_ROW
) {
491 nsCOMPtr
<nsIAccessible
> parent
= GetParent();
492 if (nsAccUtils::Role(parent
) == nsIAccessibleRole::ROLE_TREE_TABLE
)
493 msaaRole
= ROLE_SYSTEM_OUTLINEITEM
;
496 // -- Try enumerated role
497 if (msaaRole
!= USE_ROLE_STRING
) {
498 pvarRole
->vt
= VT_I4
;
499 pvarRole
->lVal
= msaaRole
; // Normal enumerated role
504 // Could not map to known enumerated MSAA role like ROLE_BUTTON
505 // Use BSTR role to expose role attribute or tag name + namespace
506 nsCOMPtr
<nsIDOMNode
> domNode
;
507 nsCOMPtr
<nsIAccessNode
> accessNode(do_QueryInterface(xpAccessible
));
511 accessNode
->GetDOMNode(getter_AddRefs(domNode
));
512 nsIContent
*content
= nsCoreUtils::GetRoleContent(domNode
);
516 if (content
->IsNodeOfType(nsINode::eELEMENT
)) {
517 nsAutoString roleString
;
518 if (msaaRole
!= ROLE_SYSTEM_CLIENT
&&
519 !content
->GetAttr(kNameSpaceID_None
, nsAccessibilityAtoms::role
, roleString
)) {
520 nsINodeInfo
*nodeInfo
= content
->NodeInfo();
521 nodeInfo
->GetName(roleString
);
522 nsAutoString nameSpaceURI
;
523 nodeInfo
->GetNamespaceURI(nameSpaceURI
);
524 if (!nameSpaceURI
.IsEmpty()) {
525 // Only append name space if different from that of current document
526 roleString
+= NS_LITERAL_STRING(", ") + nameSpaceURI
;
529 if (!roleString
.IsEmpty()) {
530 pvarRole
->vt
= VT_BSTR
;
531 pvarRole
->bstrVal
= ::SysAllocString(roleString
.get());
535 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
539 STDMETHODIMP
nsAccessibleWrap::get_accState(
540 /* [optional][in] */ VARIANT varChild
,
541 /* [retval][out] */ VARIANT __RPC_FAR
*pvarState
)
544 VariantInit(pvarState
);
545 pvarState
->vt
= VT_I4
;
548 nsCOMPtr
<nsIAccessible
> xpAccessible
;
549 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
554 if (NS_FAILED(xpAccessible
->GetState(&state
, nsnull
)))
557 pvarState
->lVal
= state
;
558 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
563 STDMETHODIMP
nsAccessibleWrap::get_accHelp(
564 /* [optional][in] */ VARIANT varChild
,
565 /* [retval][out] */ BSTR __RPC_FAR
*pszHelp
)
571 STDMETHODIMP
nsAccessibleWrap::get_accHelpTopic(
572 /* [out] */ BSTR __RPC_FAR
*pszHelpFile
,
573 /* [optional][in] */ VARIANT varChild
,
574 /* [retval][out] */ long __RPC_FAR
*pidTopic
)
581 STDMETHODIMP
nsAccessibleWrap::get_accKeyboardShortcut(
582 /* [optional][in] */ VARIANT varChild
,
583 /* [retval][out] */ BSTR __RPC_FAR
*pszKeyboardShortcut
)
586 *pszKeyboardShortcut
= NULL
;
587 nsCOMPtr
<nsIAccessible
> xpAccessible
;
588 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
590 nsAutoString shortcut
;
591 nsresult rv
= xpAccessible
->GetKeyboardShortcut(shortcut
);
595 *pszKeyboardShortcut
= ::SysAllocStringLen(shortcut
.get(),
597 return *pszKeyboardShortcut
? S_OK
: E_OUTOFMEMORY
;
599 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
603 STDMETHODIMP
nsAccessibleWrap::get_accFocus(
604 /* [retval][out] */ VARIANT __RPC_FAR
*pvarChild
)
606 // VT_EMPTY: None. This object does not have the keyboard focus itself
607 // and does not contain a child that has the keyboard focus.
608 // VT_I4: lVal is CHILDID_SELF. The object itself has the keyboard focus.
609 // VT_I4: lVal contains the child ID of the child element with the keyboard focus.
610 // VT_DISPATCH: pdispVal member is the address of the IDispatch interface
611 // for the child object with the keyboard focus.
614 return E_FAIL
; // This node is shut down
617 VariantInit(pvarChild
);
619 // Return the current IAccessible child that has focus
620 nsCOMPtr
<nsIAccessible
> focusedAccessible
;
621 GetFocusedChild(getter_AddRefs(focusedAccessible
));
622 if (focusedAccessible
== this) {
623 pvarChild
->vt
= VT_I4
;
624 pvarChild
->lVal
= CHILDID_SELF
;
626 else if (focusedAccessible
) {
627 pvarChild
->vt
= VT_DISPATCH
;
628 pvarChild
->pdispVal
= NativeAccessible(focusedAccessible
);
631 pvarChild
->vt
= VT_EMPTY
; // No focus or focus is not a child
634 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
638 // This helper class implements IEnumVARIANT for a nsIArray containing nsIAccessible objects.
640 class AccessibleEnumerator
: public IEnumVARIANT
643 AccessibleEnumerator(nsIArray
* aArray
) : mArray(aArray
), mCurIndex(0) { }
644 AccessibleEnumerator(const AccessibleEnumerator
& toCopy
) :
645 mArray(toCopy
.mArray
), mCurIndex(toCopy
.mCurIndex
) { }
646 ~AccessibleEnumerator() { }
649 STDMETHODIMP
QueryInterface(REFIID iid
, void ** ppvObject
);
650 STDMETHODIMP_(ULONG
) AddRef(void);
651 STDMETHODIMP_(ULONG
) Release(void);
654 STDMETHODIMP
Next(unsigned long celt
, VARIANT FAR
* rgvar
, unsigned long FAR
* pceltFetched
);
655 STDMETHODIMP
Skip(unsigned long celt
);
661 STDMETHODIMP
Clone(IEnumVARIANT FAR
* FAR
* ppenum
);
664 nsCOMPtr
<nsIArray
> mArray
;
666 nsAutoRefCnt mRefCnt
;
670 AccessibleEnumerator::QueryInterface(REFIID iid
, void ** ppvObject
)
673 if (iid
== IID_IEnumVARIANT
) {
674 *ppvObject
= static_cast<IEnumVARIANT
*>(this);
678 if (iid
== IID_IUnknown
) {
679 *ppvObject
= static_cast<IUnknown
*>(this);
685 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
686 return E_NOINTERFACE
;
690 AccessibleEnumerator::AddRef(void)
696 AccessibleEnumerator::Release(void)
705 AccessibleEnumerator::Next(unsigned long celt
, VARIANT FAR
* rgvar
, unsigned long FAR
* pceltFetched
)
709 mArray
->GetLength(&length
);
713 // Can't get more elements than there are...
714 if (celt
> length
- mCurIndex
) {
716 celt
= length
- mCurIndex
;
719 for (PRUint32 i
= 0; i
< celt
; ++i
, ++mCurIndex
) {
720 // Copy the elements of the array into rgvar
721 nsCOMPtr
<nsIAccessible
> accel(do_QueryElementAt(mArray
, mCurIndex
));
722 NS_ASSERTION(accel
, "Invalid pointer in mArray");
725 rgvar
[i
].vt
= VT_DISPATCH
;
726 rgvar
[i
].pdispVal
= nsAccessibleWrap::NativeAccessible(accel
);
731 *pceltFetched
= celt
;
734 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
740 AccessibleEnumerator::Clone(IEnumVARIANT FAR
* FAR
* ppenum
)
743 *ppenum
= new AccessibleEnumerator(*this);
745 return E_OUTOFMEMORY
;
747 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
752 AccessibleEnumerator::Skip(unsigned long celt
)
756 mArray
->GetLength(&length
);
757 // Check if we can skip the requested number of elements
758 if (celt
> length
- mCurIndex
) {
763 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
768 * This method is called when a client wants to know which children of a node
769 * are selected. Note that this method can only find selected children for
770 * nsIAccessible object which implement nsIAccessibleSelectable.
772 * The VARIANT return value arguement is expected to either contain a single IAccessible
773 * or an IEnumVARIANT of IAccessibles. We return the IEnumVARIANT regardless of the number
774 * of children selected, unless there are none selected in which case we return an empty
777 * We get the selected options from the select's accessible object and wrap
778 * those in an AccessibleEnumerator which we then put in the return VARIANT.
780 * returns a VT_EMPTY VARIANT if:
781 * - there are no selected children for this object
782 * - the object is not the type that can have children selected
784 STDMETHODIMP
nsAccessibleWrap::get_accSelection(VARIANT __RPC_FAR
*pvarChildren
)
787 VariantInit(pvarChildren
);
788 pvarChildren
->vt
= VT_EMPTY
;
790 nsCOMPtr
<nsIAccessibleSelectable
>
791 select(do_QueryInterface(static_cast<nsIAccessible
*>(this)));
793 if (select
) { // do we have an nsIAccessibleSelectable?
794 // we have an accessible that can have children selected
795 nsCOMPtr
<nsIArray
> selectedOptions
;
796 // gets the selected options as nsIAccessibles.
797 select
->GetSelectedChildren(getter_AddRefs(selectedOptions
));
798 if (selectedOptions
) { // false if the select has no children or none are selected
799 // 1) Create and initialize the enumeration
800 nsRefPtr
<AccessibleEnumerator
> pEnum
= new AccessibleEnumerator(selectedOptions
);
802 // 2) Put the enumerator in the VARIANT
804 return E_OUTOFMEMORY
;
805 pvarChildren
->vt
= VT_UNKNOWN
; // this must be VT_UNKNOWN for an IEnumVARIANT
806 NS_ADDREF(pvarChildren
->punkVal
= pEnum
);
809 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
813 STDMETHODIMP
nsAccessibleWrap::get_accDefaultAction(
814 /* [optional][in] */ VARIANT varChild
,
815 /* [retval][out] */ BSTR __RPC_FAR
*pszDefaultAction
)
818 *pszDefaultAction
= NULL
;
819 nsCOMPtr
<nsIAccessible
> xpAccessible
;
820 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
822 nsAutoString defaultAction
;
823 if (NS_FAILED(xpAccessible
->GetActionName(0, defaultAction
)))
826 *pszDefaultAction
= ::SysAllocStringLen(defaultAction
.get(),
827 defaultAction
.Length());
828 return *pszDefaultAction
? S_OK
: E_OUTOFMEMORY
;
831 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
835 STDMETHODIMP
nsAccessibleWrap::accSelect(
836 /* [in] */ long flagsSelect
,
837 /* [optional][in] */ VARIANT varChild
)
840 // currently only handle focus and selection
841 nsCOMPtr
<nsIAccessible
> xpAccessible
;
842 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
843 NS_ENSURE_TRUE(xpAccessible
, E_FAIL
);
845 if (flagsSelect
& (SELFLAG_TAKEFOCUS
|SELFLAG_TAKESELECTION
|SELFLAG_REMOVESELECTION
))
847 if (flagsSelect
& SELFLAG_TAKEFOCUS
)
848 xpAccessible
->TakeFocus();
850 if (flagsSelect
& SELFLAG_TAKESELECTION
)
851 xpAccessible
->TakeSelection();
853 if (flagsSelect
& SELFLAG_ADDSELECTION
)
854 xpAccessible
->SetSelected(PR_TRUE
);
856 if (flagsSelect
& SELFLAG_REMOVESELECTION
)
857 xpAccessible
->SetSelected(PR_FALSE
);
859 if (flagsSelect
& SELFLAG_EXTENDSELECTION
)
860 xpAccessible
->ExtendSelection();
865 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
869 STDMETHODIMP
nsAccessibleWrap::accLocation(
870 /* [out] */ long __RPC_FAR
*pxLeft
,
871 /* [out] */ long __RPC_FAR
*pyTop
,
872 /* [out] */ long __RPC_FAR
*pcxWidth
,
873 /* [out] */ long __RPC_FAR
*pcyHeight
,
874 /* [optional][in] */ VARIANT varChild
)
877 nsCOMPtr
<nsIAccessible
> xpAccessible
;
878 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
881 PRInt32 x
, y
, width
, height
;
882 if (NS_FAILED(xpAccessible
->GetBounds(&x
, &y
, &width
, &height
)))
891 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
896 STDMETHODIMP
nsAccessibleWrap::accNavigate(
897 /* [in] */ long navDir
,
898 /* [optional][in] */ VARIANT varStart
,
899 /* [retval][out] */ VARIANT __RPC_FAR
*pvarEndUpAt
)
902 nsCOMPtr
<nsIAccessible
> xpAccessibleStart
, xpAccessibleResult
;
903 GetXPAccessibleFor(varStart
, getter_AddRefs(xpAccessibleStart
));
904 if (!xpAccessibleStart
)
907 VariantInit(pvarEndUpAt
);
908 PRUint32 xpRelation
= 0;
912 xpAccessibleStart
->GetAccessibleBelow(getter_AddRefs(xpAccessibleResult
));
914 case NAVDIR_FIRSTCHILD
:
915 if (!nsAccUtils::MustPrune(xpAccessibleStart
))
916 xpAccessibleStart
->GetFirstChild(getter_AddRefs(xpAccessibleResult
));
918 case NAVDIR_LASTCHILD
:
919 if (!nsAccUtils::MustPrune(xpAccessibleStart
))
920 xpAccessibleStart
->GetLastChild(getter_AddRefs(xpAccessibleResult
));
923 xpAccessibleStart
->GetAccessibleToLeft(getter_AddRefs(xpAccessibleResult
));
926 xpAccessibleStart
->GetNextSibling(getter_AddRefs(xpAccessibleResult
));
928 case NAVDIR_PREVIOUS
:
929 xpAccessibleStart
->GetPreviousSibling(getter_AddRefs(xpAccessibleResult
));
932 xpAccessibleStart
->GetAccessibleToRight(getter_AddRefs(xpAccessibleResult
));
935 xpAccessibleStart
->GetAccessibleAbove(getter_AddRefs(xpAccessibleResult
));
938 // MSAA relationship extensions to accNavigate
939 case NAVRELATION_CONTROLLED_BY
:
940 xpRelation
= nsIAccessibleRelation::RELATION_CONTROLLED_BY
;
942 case NAVRELATION_CONTROLLER_FOR
:
943 xpRelation
= nsIAccessibleRelation::RELATION_CONTROLLER_FOR
;
945 case NAVRELATION_LABEL_FOR
:
946 xpRelation
= nsIAccessibleRelation::RELATION_LABEL_FOR
;
948 case NAVRELATION_LABELLED_BY
:
949 xpRelation
= nsIAccessibleRelation::RELATION_LABELLED_BY
;
951 case NAVRELATION_MEMBER_OF
:
952 xpRelation
= nsIAccessibleRelation::RELATION_MEMBER_OF
;
954 case NAVRELATION_NODE_CHILD_OF
:
955 xpRelation
= nsIAccessibleRelation::RELATION_NODE_CHILD_OF
;
957 case NAVRELATION_FLOWS_TO
:
958 xpRelation
= nsIAccessibleRelation::RELATION_FLOWS_TO
;
960 case NAVRELATION_FLOWS_FROM
:
961 xpRelation
= nsIAccessibleRelation::RELATION_FLOWS_FROM
;
963 case NAVRELATION_SUBWINDOW_OF
:
964 xpRelation
= nsIAccessibleRelation::RELATION_SUBWINDOW_OF
;
966 case NAVRELATION_EMBEDS
:
967 xpRelation
= nsIAccessibleRelation::RELATION_EMBEDS
;
969 case NAVRELATION_EMBEDDED_BY
:
970 xpRelation
= nsIAccessibleRelation::RELATION_EMBEDDED_BY
;
972 case NAVRELATION_POPUP_FOR
:
973 xpRelation
= nsIAccessibleRelation::RELATION_POPUP_FOR
;
975 case NAVRELATION_PARENT_WINDOW_OF
:
976 xpRelation
= nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF
;
978 case NAVRELATION_DEFAULT_BUTTON
:
979 xpRelation
= nsIAccessibleRelation::RELATION_DEFAULT_BUTTON
;
981 case NAVRELATION_DESCRIBED_BY
:
982 xpRelation
= nsIAccessibleRelation::RELATION_DESCRIBED_BY
;
984 case NAVRELATION_DESCRIPTION_FOR
:
985 xpRelation
= nsIAccessibleRelation::RELATION_DESCRIPTION_FOR
;
989 pvarEndUpAt
->vt
= VT_EMPTY
;
992 nsresult rv
= GetAccessibleRelated(xpRelation
,
993 getter_AddRefs(xpAccessibleResult
));
994 if (rv
== NS_ERROR_NOT_IMPLEMENTED
) {
999 if (xpAccessibleResult
) {
1000 pvarEndUpAt
->pdispVal
= NativeAccessible(xpAccessibleResult
);
1001 pvarEndUpAt
->vt
= VT_DISPATCH
;
1004 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1008 STDMETHODIMP
nsAccessibleWrap::accHitTest(
1009 /* [in] */ long xLeft
,
1010 /* [in] */ long yTop
,
1011 /* [retval][out] */ VARIANT __RPC_FAR
*pvarChild
)
1014 VariantInit(pvarChild
);
1016 // convert to window coords
1017 nsCOMPtr
<nsIAccessible
> xpAccessible
;
1022 if (nsAccUtils::MustPrune(this)) {
1023 xpAccessible
= this;
1026 GetChildAtPoint(xLeft
, yTop
, getter_AddRefs(xpAccessible
));
1029 // if we got a child
1031 // if the child is us
1032 if (xpAccessible
== static_cast<nsIAccessible
*>(this)) {
1033 pvarChild
->vt
= VT_I4
;
1034 pvarChild
->lVal
= CHILDID_SELF
;
1035 } else { // its not create an Accessible for it.
1036 pvarChild
->vt
= VT_DISPATCH
;
1037 pvarChild
->pdispVal
= NativeAccessible(xpAccessible
);
1038 nsCOMPtr
<nsIAccessNode
> accessNode(do_QueryInterface(xpAccessible
));
1039 NS_ASSERTION(accessNode
, "Unable to QI to nsIAccessNode");
1040 nsCOMPtr
<nsIDOMNode
> domNode
;
1041 accessNode
->GetDOMNode(getter_AddRefs(domNode
));
1043 // Has already been shut down
1044 pvarChild
->vt
= VT_EMPTY
;
1049 // no child at that point
1050 pvarChild
->vt
= VT_EMPTY
;
1053 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1058 STDMETHODIMP
nsAccessibleWrap::accDoDefaultAction(
1059 /* [optional][in] */ VARIANT varChild
)
1062 nsCOMPtr
<nsIAccessible
> xpAccessible
;
1063 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
1065 if (!xpAccessible
|| FAILED(xpAccessible
->DoAction(0))) {
1068 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1072 STDMETHODIMP
nsAccessibleWrap::put_accName(
1073 /* [optional][in] */ VARIANT varChild
,
1074 /* [in] */ BSTR szName
)
1079 STDMETHODIMP
nsAccessibleWrap::put_accValue(
1080 /* [optional][in] */ VARIANT varChild
,
1081 /* [in] */ BSTR szValue
)
1088 ////////////////////////////////////////////////////////////////////////////////
1089 // nsAccessibleWrap. IEnumVariant
1092 nsAccessibleWrap::Next(ULONG aNumElementsRequested
, VARIANT FAR
* aPVar
,
1093 ULONG FAR
* aNumElementsFetched
)
1095 // Children already cached via QI to IEnumVARIANT
1097 *aNumElementsFetched
= 0;
1099 if (aNumElementsRequested
<= 0 || !aPVar
)
1100 return E_INVALIDARG
;
1102 if (mEnumVARIANTPosition
== kIEnumVariantDisconnected
)
1103 return CO_E_OBJNOTCONNECTED
;
1105 nsCOMPtr
<nsIAccessible
> traversedAcc
;
1106 nsresult rv
= GetChildAt(mEnumVARIANTPosition
, getter_AddRefs(traversedAcc
));
1110 for (PRUint32 i
= 0; i
< aNumElementsRequested
; i
++) {
1111 VariantInit(&aPVar
[i
]);
1113 aPVar
[i
].pdispVal
= NativeAccessible(traversedAcc
);
1114 aPVar
[i
].vt
= VT_DISPATCH
;
1115 (*aNumElementsFetched
)++;
1117 nsCOMPtr
<nsIAccessible
> nextAcc
;
1118 traversedAcc
->GetNextSibling(getter_AddRefs(nextAcc
));
1122 traversedAcc
= nextAcc
;
1125 mEnumVARIANTPosition
+= *aNumElementsFetched
;
1126 return (*aNumElementsFetched
) < aNumElementsRequested
? S_FALSE
: S_OK
;
1128 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1133 nsAccessibleWrap::Skip(ULONG aNumElements
)
1136 if (mEnumVARIANTPosition
== kIEnumVariantDisconnected
)
1137 return CO_E_OBJNOTCONNECTED
;
1139 mEnumVARIANTPosition
+= aNumElements
;
1141 PRInt32 numChildren
;
1142 GetChildCount(&numChildren
);
1144 if (mEnumVARIANTPosition
> numChildren
)
1146 mEnumVARIANTPosition
= numChildren
;
1149 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1154 nsAccessibleWrap::Reset(void)
1156 mEnumVARIANTPosition
= 0;
1161 nsAccessibleWrap::Clone(IEnumVARIANT FAR
* FAR
* ppenum
)
1166 nsCOMPtr
<nsIArray
> childArray
;
1167 nsresult rv
= GetChildren(getter_AddRefs(childArray
));
1169 *ppenum
= new AccessibleEnumerator(childArray
);
1171 return E_OUTOFMEMORY
;
1174 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1178 ////////////////////////////////////////////////////////////////////////////////
1179 // nsAccessibleWrap. IAccessible2
1182 nsAccessibleWrap::get_nRelations(long *aNRelations
)
1186 nsresult rv
= GetRelationsCount(&count
);
1187 *aNRelations
= count
;
1189 return GetHRESULT(rv
);
1191 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1196 nsAccessibleWrap::get_relation(long aRelationIndex
,
1197 IAccessibleRelation
**aRelation
)
1202 nsCOMPtr
<nsIAccessibleRelation
> relation
;
1203 nsresult rv
= GetRelation(aRelationIndex
, getter_AddRefs(relation
));
1205 return GetHRESULT(rv
);
1207 nsCOMPtr
<nsIWinAccessNode
> winAccessNode(do_QueryInterface(relation
));
1211 void *instancePtr
= NULL
;
1212 rv
= winAccessNode
->QueryNativeInterface(IID_IAccessibleRelation
,
1215 return GetHRESULT(rv
);
1217 *aRelation
= static_cast<IAccessibleRelation
*>(instancePtr
);
1220 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1225 nsAccessibleWrap::get_relations(long aMaxRelations
,
1226 IAccessibleRelation
**aRelation
,
1233 nsCOMPtr
<nsIArray
> relations
;
1234 nsresult rv
= GetRelations(getter_AddRefs(relations
));
1236 return GetHRESULT(rv
);
1238 PRUint32 length
= 0;
1239 rv
= relations
->GetLength(&length
);
1241 return GetHRESULT(rv
);
1246 PRUint32 count
= length
< (PRUint32
)aMaxRelations
? length
: aMaxRelations
;
1249 for (; index
< count
; index
++) {
1250 nsCOMPtr
<nsIWinAccessNode
> winAccessNode
=
1251 do_QueryElementAt(relations
, index
, &rv
);
1255 void *instancePtr
= NULL
;
1256 nsresult rv
= winAccessNode
->QueryNativeInterface(IID_IAccessibleRelation
,
1261 aRelation
[index
] = static_cast<IAccessibleRelation
*>(instancePtr
);
1264 if (NS_FAILED(rv
)) {
1265 for (PRUint32 index2
= 0; index2
< index
; index2
++) {
1266 aRelation
[index2
]->Release();
1267 aRelation
[index2
] = NULL
;
1269 return GetHRESULT(rv
);
1272 *aNRelations
= count
;
1275 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1280 nsAccessibleWrap::role(long *aRole
)
1285 PRUint32 xpRole
= 0;
1286 nsresult rv
= GetFinalRole(&xpRole
);
1288 return GetHRESULT(rv
);
1290 NS_ASSERTION(gWindowsRoleMap
[nsIAccessibleRole::ROLE_LAST_ENTRY
].ia2Role
== ROLE_WINDOWS_LAST_ENTRY
,
1291 "MSAA role map skewed");
1293 *aRole
= gWindowsRoleMap
[xpRole
].ia2Role
;
1296 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1301 nsAccessibleWrap::scrollTo(enum IA2ScrollType aScrollType
)
1304 nsresult rv
= ScrollTo(aScrollType
);
1305 return GetHRESULT(rv
);
1307 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1312 nsAccessibleWrap::scrollToPoint(enum IA2CoordinateType aCoordType
,
1316 PRUint32 geckoCoordType
= (aCoordType
== IA2_COORDTYPE_SCREEN_RELATIVE
) ?
1317 nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
:
1318 nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE
;
1320 nsresult rv
= ScrollToPoint(geckoCoordType
, aX
, aY
);
1321 return GetHRESULT(rv
);
1323 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1328 nsAccessibleWrap::get_groupPosition(long *aGroupLevel
,
1329 long *aSimilarItemsInGroup
,
1330 long *aPositionInGroup
)
1333 PRInt32 groupLevel
= 0;
1334 PRInt32 similarItemsInGroup
= 0;
1335 PRInt32 positionInGroup
= 0;
1336 nsresult rv
= GroupPosition(&groupLevel
, &similarItemsInGroup
,
1339 *aGroupLevel
= groupLevel
;
1340 *aSimilarItemsInGroup
= similarItemsInGroup
;
1341 *aPositionInGroup
= positionInGroup
;
1344 return GetHRESULT(rv
);
1346 if (groupLevel
==0 && similarItemsInGroup
== 0 && positionInGroup
== 0)
1350 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1355 nsAccessibleWrap::get_states(AccessibleStates
*aStates
)
1360 // XXX: bug 344674 should come with better approach that we have here.
1362 PRUint32 states
= 0, extraStates
= 0;
1363 nsresult rv
= GetState(&states
, &extraStates
);
1365 return GetHRESULT(rv
);
1367 if (states
& nsIAccessibleStates::STATE_INVALID
)
1368 *aStates
|= IA2_STATE_INVALID_ENTRY
;
1369 if (states
& nsIAccessibleStates::STATE_REQUIRED
)
1370 *aStates
|= IA2_STATE_REQUIRED
;
1372 // The following IA2 states are not supported by Gecko
1374 // IA2_STATE_MANAGES_DESCENDANTS
1375 // IA2_STATE_ICONIFIED
1376 // IA2_STATE_INVALID // This is not a state, it is the absence of a state
1378 if (extraStates
& nsIAccessibleStates::EXT_STATE_ACTIVE
)
1379 *aStates
|= IA2_STATE_ACTIVE
;
1380 if (extraStates
& nsIAccessibleStates::EXT_STATE_DEFUNCT
)
1381 *aStates
|= IA2_STATE_DEFUNCT
;
1382 if (extraStates
& nsIAccessibleStates::EXT_STATE_EDITABLE
)
1383 *aStates
|= IA2_STATE_EDITABLE
;
1384 if (extraStates
& nsIAccessibleStates::EXT_STATE_HORIZONTAL
)
1385 *aStates
|= IA2_STATE_HORIZONTAL
;
1386 if (extraStates
& nsIAccessibleStates::EXT_STATE_MODAL
)
1387 *aStates
|= IA2_STATE_MODAL
;
1388 if (extraStates
& nsIAccessibleStates::EXT_STATE_MULTI_LINE
)
1389 *aStates
|= IA2_STATE_MULTI_LINE
;
1390 if (extraStates
& nsIAccessibleStates::EXT_STATE_OPAQUE
)
1391 *aStates
|= IA2_STATE_OPAQUE
;
1392 if (extraStates
& nsIAccessibleStates::EXT_STATE_SELECTABLE_TEXT
)
1393 *aStates
|= IA2_STATE_SELECTABLE_TEXT
;
1394 if (extraStates
& nsIAccessibleStates::EXT_STATE_SINGLE_LINE
)
1395 *aStates
|= IA2_STATE_SINGLE_LINE
;
1396 if (extraStates
& nsIAccessibleStates::EXT_STATE_STALE
)
1397 *aStates
|= IA2_STATE_STALE
;
1398 if (extraStates
& nsIAccessibleStates::EXT_STATE_SUPPORTS_AUTOCOMPLETION
)
1399 *aStates
|= IA2_STATE_SUPPORTS_AUTOCOMPLETION
;
1400 if (extraStates
& nsIAccessibleStates::EXT_STATE_TRANSIENT
)
1401 *aStates
|= IA2_STATE_TRANSIENT
;
1402 if (extraStates
& nsIAccessibleStates::EXT_STATE_VERTICAL
)
1403 *aStates
|= IA2_STATE_VERTICAL
;
1407 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1412 nsAccessibleWrap::get_extendedRole(BSTR
*aExtendedRole
)
1415 *aExtendedRole
= NULL
;
1416 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1422 nsAccessibleWrap::get_localizedExtendedRole(BSTR
*aLocalizedExtendedRole
)
1425 *aLocalizedExtendedRole
= NULL
;
1426 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1432 nsAccessibleWrap::get_nExtendedStates(long *aNExtendedStates
)
1435 *aNExtendedStates
= 0;
1436 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1442 nsAccessibleWrap::get_extendedStates(long aMaxExtendedStates
,
1443 BSTR
**aExtendedStates
,
1444 long *aNExtendedStates
)
1447 *aExtendedStates
= NULL
;
1448 *aNExtendedStates
= 0;
1449 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1455 nsAccessibleWrap::get_localizedExtendedStates(long aMaxLocalizedExtendedStates
,
1456 BSTR
**aLocalizedExtendedStates
,
1457 long *aNLocalizedExtendedStates
)
1460 *aLocalizedExtendedStates
= NULL
;
1461 *aNLocalizedExtendedStates
= 0;
1462 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1468 nsAccessibleWrap::get_uniqueID(long *uniqueID
)
1472 nsresult rv
= GetUniqueID(&id
);
1474 return GetHRESULT(rv
);
1476 *uniqueID
= - reinterpret_cast<long>(id
);
1479 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1484 nsAccessibleWrap::get_windowHandle(HWND
*aWindowHandle
)
1492 void *handle
= nsnull
;
1493 nsresult rv
= GetOwnerWindow(&handle
);
1495 return GetHRESULT(rv
);
1497 *aWindowHandle
= reinterpret_cast<HWND
>(handle
);
1500 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1505 nsAccessibleWrap::get_indexInParent(long *aIndexInParent
)
1508 *aIndexInParent
= -1;
1511 nsresult rv
= GetIndexInParent(&index
);
1513 return GetHRESULT(rv
);
1518 *aIndexInParent
= index
;
1521 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1526 nsAccessibleWrap::get_locale(IA2Locale
*aLocale
)
1529 // Language codes consist of a primary code and a possibly empty series of
1530 // subcodes: language-code = primary-code ( "-" subcode )*
1531 // Two-letter primary codes are reserved for [ISO639] language abbreviations.
1532 // Any two-letter subcode is understood to be a [ISO3166] country code.
1535 nsresult rv
= GetLanguage(lang
);
1537 return GetHRESULT(rv
);
1539 // If primary code consists from two letters then expose it as language.
1540 PRInt32 offset
= lang
.FindChar('-', 0);
1542 if (lang
.Length() == 2) {
1543 aLocale
->language
= ::SysAllocString(lang
.get());
1546 } else if (offset
== 2) {
1547 aLocale
->language
= ::SysAllocStringLen(lang
.get(), 2);
1549 // If the first subcode consists from two letters then expose it as
1551 offset
= lang
.FindChar('-', 3);
1553 if (lang
.Length() == 5) {
1554 aLocale
->country
= ::SysAllocString(lang
.get() + 3);
1557 } else if (offset
== 5) {
1558 aLocale
->country
= ::SysAllocStringLen(lang
.get() + 3, 2);
1562 // Expose as a string if primary code or subcode cannot point to language or
1563 // country abbreviations or if there are more than one subcode.
1564 aLocale
->variant
= ::SysAllocString(lang
.get());
1567 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1572 nsAccessibleWrap::get_attributes(BSTR
*aAttributes
)
1574 // The format is name:value;name:value; with \ for escaping these
1575 // characters ":;=,\".
1577 *aAttributes
= NULL
;
1579 nsCOMPtr
<nsIPersistentProperties
> attributes
;
1580 nsresult rv
= GetAttributes(getter_AddRefs(attributes
));
1582 return GetHRESULT(rv
);
1584 return ConvertToIA2Attributes(attributes
, aAttributes
);
1586 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1590 // For IDispatch support
1592 nsAccessibleWrap::GetTypeInfoCount(UINT
*p
)
1598 // For IDispatch support
1599 STDMETHODIMP
nsAccessibleWrap::GetTypeInfo(UINT i
, LCID lcid
, ITypeInfo
**ppti
)
1605 // For IDispatch support
1607 nsAccessibleWrap::GetIDsOfNames(REFIID riid
, LPOLESTR
*rgszNames
,
1608 UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
1613 // For IDispatch support
1614 STDMETHODIMP
nsAccessibleWrap::Invoke(DISPID dispIdMember
, REFIID riid
,
1615 LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
1616 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
1622 NS_IMETHODIMP
nsAccessibleWrap::GetNativeInterface(void **aOutAccessible
)
1624 *aOutAccessible
= static_cast<IAccessible
*>(this);
1632 nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent
*aEvent
)
1634 NS_ENSURE_ARG(aEvent
);
1636 nsresult rv
= nsAccessible::FireAccessibleEvent(aEvent
);
1637 NS_ENSURE_SUCCESS(rv
, rv
);
1639 return FirePlatformEvent(aEvent
);
1643 nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent
*aEvent
)
1645 PRUint32 eventType
= 0;
1646 aEvent
->GetEventType(&eventType
);
1648 NS_ENSURE_TRUE(eventType
> 0 &&
1649 eventType
< nsIAccessibleEvent::EVENT_LAST_ENTRY
,
1652 PRUint32 winLastEntry
= gWinEventMap
[nsIAccessibleEvent::EVENT_LAST_ENTRY
];
1653 NS_ASSERTION(winLastEntry
== kEVENT_LAST_ENTRY
,
1654 "MSAA event map skewed");
1656 PRUint32 winEvent
= gWinEventMap
[eventType
];
1660 // Means we're not active.
1661 NS_ENSURE_TRUE(mWeakShell
, NS_ERROR_FAILURE
);
1663 nsCOMPtr
<nsIAccessible
> accessible
;
1664 aEvent
->GetAccessible(getter_AddRefs(accessible
));
1668 if (eventType
== nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED
||
1669 eventType
== nsIAccessibleEvent::EVENT_FOCUS
) {
1670 UpdateSystemCaret();
1673 PRInt32 childID
= GetChildIDFor(accessible
); // get the id for the accessible
1675 return NS_OK
; // Can't fire an event without a child ID
1677 // See if we're in a scrollable area with its own window
1678 nsCOMPtr
<nsIAccessible
> newAccessible
;
1679 if (eventType
== nsIAccessibleEvent::EVENT_ASYNCH_HIDE
||
1680 eventType
== nsIAccessibleEvent::EVENT_DOM_DESTROY
) {
1681 // Don't use frame from current accessible when we're hiding that
1683 accessible
->GetParent(getter_AddRefs(newAccessible
));
1685 newAccessible
= accessible
;
1688 HWND hWnd
= GetHWNDFor(newAccessible
);
1689 NS_ENSURE_TRUE(hWnd
, NS_ERROR_FAILURE
);
1691 // Gecko uses two windows for every scrollable area. One window contains
1692 // scrollbars and the child window contains only the client area.
1693 // Details of the 2 window system:
1694 // * Scrollbar window: caret drawing window & return value for WindowFromAccessibleObject()
1695 // * Client area window: text drawing window & MSAA event window
1697 // Fire MSAA event for client area window.
1698 NotifyWinEvent(winEvent
, hWnd
, OBJID_CLIENT
, childID
);
1700 // If the accessible children are changed then drop the IEnumVariant current
1701 // position of the accessible.
1702 if (eventType
== nsIAccessibleEvent::EVENT_REORDER
)
1703 UnattachIEnumVariant();
1708 //------- Helper methods ---------
1710 PRInt32
nsAccessibleWrap::GetChildIDFor(nsIAccessible
* aAccessible
)
1712 // A child ID of the window is required, when we use NotifyWinEvent,
1713 // so that the 3rd party application can call back and get the IAccessible
1714 // the event occured on.
1716 void *uniqueID
= nsnull
;
1717 nsCOMPtr
<nsIAccessNode
> accessNode(do_QueryInterface(aAccessible
));
1721 accessNode
->GetUniqueID(&uniqueID
);
1723 // Yes, this means we're only compatibible with 32 bit
1724 // MSAA is only available for 32 bit windows, so it's okay
1725 return - NS_PTR_TO_INT32(uniqueID
);
1729 nsAccessibleWrap::GetHWNDFor(nsIAccessible
*aAccessible
)
1731 nsRefPtr
<nsAccessNode
> accessNode
= nsAccUtils::QueryAccessNode(aAccessible
);
1736 nsIFrame
*frame
= accessNode
->GetFrame();
1738 nsIWidget
*window
= frame
->GetWindow();
1740 window
->IsVisible(isVisible
);
1742 // Short explanation:
1743 // If HWND for frame is inside a hidden window, fire the event on the
1744 // containing document's visible window.
1746 // Long explanation:
1747 // This is really just to fix combo boxes with JAWS. Window-Eyes already
1748 // worked with combo boxes because they use the value change event in
1749 // the closed combo box case. JAWS will only pay attention to the focus
1750 // events on the list items. The JAWS developers haven't fixed that, so
1751 // we'll use the focus events to make JAWS work. However, JAWS is
1752 // ignoring events on a hidden window. So, in order to fix the bug where
1753 // JAWS doesn't echo the current option as it changes in a closed
1754 // combo box, we need to use an ensure that we never fire an event with
1755 // an HWND for a hidden window.
1756 hWnd
= (HWND
)frame
->GetWindow()->GetNativeData(NS_NATIVE_WINDOW
);
1761 void* handle
= nsnull
;
1762 nsCOMPtr
<nsIAccessibleDocument
> accessibleDoc
;
1763 accessNode
->GetAccessibleDocument(getter_AddRefs(accessibleDoc
));
1767 accessibleDoc
->GetWindowHandle(&handle
);
1768 hWnd
= (HWND
)handle
;
1775 nsAccessibleWrap::ConvertToIA2Attributes(nsIPersistentProperties
*aAttributes
,
1776 BSTR
*aIA2Attributes
)
1778 *aIA2Attributes
= NULL
;
1780 // The format is name:value;name:value; with \ for escaping these
1781 // characters ":;=,\".
1786 nsCOMPtr
<nsISimpleEnumerator
> propEnum
;
1787 aAttributes
->Enumerate(getter_AddRefs(propEnum
));
1791 nsAutoString strAttrs
;
1793 const char kCharsToEscape
[] = ":;=,\\";
1795 PRBool hasMore
= PR_FALSE
;
1796 while (NS_SUCCEEDED(propEnum
->HasMoreElements(&hasMore
)) && hasMore
) {
1797 nsCOMPtr
<nsISupports
> propSupports
;
1798 propEnum
->GetNext(getter_AddRefs(propSupports
));
1800 nsCOMPtr
<nsIPropertyElement
> propElem(do_QueryInterface(propSupports
));
1805 if (NS_FAILED(propElem
->GetKey(name
)))
1808 PRUint32 offset
= 0;
1809 while ((offset
= name
.FindCharInSet(kCharsToEscape
, offset
)) != kNotFound
) {
1810 name
.Insert('\\', offset
);
1815 if (NS_FAILED(propElem
->GetValue(value
)))
1819 while ((offset
= value
.FindCharInSet(kCharsToEscape
, offset
)) != kNotFound
) {
1820 value
.Insert('\\', offset
);
1824 AppendUTF8toUTF16(name
, strAttrs
);
1825 strAttrs
.Append(':');
1826 strAttrs
.Append(value
);
1827 strAttrs
.Append(';');
1830 if (strAttrs
.IsEmpty())
1833 *aIA2Attributes
= ::SysAllocStringLen(strAttrs
.get(), strAttrs
.Length());
1834 return *aIA2Attributes
? S_OK
: E_OUTOFMEMORY
;
1837 IDispatch
*nsAccessibleWrap::NativeAccessible(nsIAccessible
*aXPAccessible
)
1839 if (!aXPAccessible
) {
1840 NS_WARNING("Not passing in an aXPAccessible");
1844 nsCOMPtr
<nsIAccessibleWin32Object
> accObject(do_QueryInterface(aXPAccessible
));
1846 void* hwnd
= nsnull
;
1847 accObject
->GetHwnd(&hwnd
);
1849 IDispatch
*retval
= nsnull
;
1850 AccessibleObjectFromWindow(reinterpret_cast<HWND
>(hwnd
),
1851 OBJID_WINDOW
, IID_IAccessible
, (void **) &retval
);
1856 IAccessible
*msaaAccessible
;
1857 aXPAccessible
->GetNativeInterface((void**)&msaaAccessible
);
1859 return static_cast<IDispatch
*>(msaaAccessible
);
1863 nsAccessibleWrap::UnattachIEnumVariant()
1865 if (mEnumVARIANTPosition
> 0)
1866 mEnumVARIANTPosition
= kIEnumVariantDisconnected
;
1869 void nsAccessibleWrap::GetXPAccessibleFor(const VARIANT
& aVarChild
, nsIAccessible
**aXPAccessible
)
1871 *aXPAccessible
= nsnull
;
1873 return; // Fail, we don't want to do anything after we've shut down
1875 // if its us real easy - this seems to always be the case
1876 if (aVarChild
.lVal
== CHILDID_SELF
) {
1877 *aXPAccessible
= static_cast<nsIAccessible
*>(this);
1879 else if (nsAccUtils::MustPrune(this)) {
1883 // XXX It is rare to use a VARIANT with a child num
1884 // so optimizing this is not a priority
1885 // We can come back it do it later, if there are perf problems
1886 // with a specific assistive technology
1887 nsCOMPtr
<nsIAccessible
> xpAccessible
, nextAccessible
;
1888 GetFirstChild(getter_AddRefs(xpAccessible
));
1889 for (PRInt32 index
= 0; xpAccessible
; index
++) {
1892 if (aVarChild
.lVal
== index
) {
1893 *aXPAccessible
= xpAccessible
;
1896 nextAccessible
= xpAccessible
;
1897 nextAccessible
->GetNextSibling(getter_AddRefs(xpAccessible
));
1900 NS_IF_ADDREF(*aXPAccessible
);
1903 void nsAccessibleWrap::UpdateSystemCaret()
1905 // Move the system caret so that Windows Tablet Edition and tradional ATs with
1906 // off-screen model can follow the caret
1909 nsRefPtr
<nsRootAccessible
> rootAccessible
= GetRootAccessible();
1910 if (!rootAccessible
) {
1914 nsRefPtr
<nsCaretAccessible
> caretAccessible
= rootAccessible
->GetCaretAccessible();
1915 if (!caretAccessible
) {
1920 nsRect caretRect
= caretAccessible
->GetCaretRect(&widget
);
1922 if (caretRect
.IsEmpty() || !(caretWnd
= (HWND
)widget
->GetNativeData(NS_NATIVE_WINDOW
))) {
1926 // Create invisible bitmap for caret, otherwise its appearance interferes
1928 HBITMAP caretBitMap
= CreateBitmap(1, caretRect
.height
, 1, 1, NULL
);
1929 if (::CreateCaret(caretWnd
, caretBitMap
, 1, caretRect
.height
)) { // Also destroys the last caret
1930 ::ShowCaret(caretWnd
);
1932 ::GetWindowRect(caretWnd
, &windowRect
);
1933 ::SetCaretPos(caretRect
.x
- windowRect
.left
, caretRect
.y
- windowRect
.top
);
1934 ::DeleteObject(caretBitMap
);